/*!
 Recompute the stress on each block based on the slip deficits of all the other blocks.
 */
void UpdateBlockStress::stressRecompute(void) {
	BlockList::iterator	it;
	
	// Reset the shear and normal stress, and set the update field to be the slip deficit
    for(it=sim->begin();it!=sim->end();++it) {
		sim->setShearStress(it->getBlockID(), 0.0);
        sim->setNormalStress(it->getBlockID(), it->getRhogd());
		sim->setUpdateField(it->getBlockID(), it->state.slipDeficit);
    }
	
	// Distribute the new update field over all nodes
	sim->distributeUpdateField(false);
	
	// Multiply the Greens shear function by the slipDeficit vector
	// to get shear on local blocks
	sim->matrixVectorMultiplyAccum(sim->getShearStressPtr(),
								   sim->greenShear(),
								   sim->getUpdateFieldPtr(),
								   true);
	
	if (sim->doNormalStress()) {
		sim->matrixVectorMultiplyAccum(sim->getNormalStressPtr(),
									   sim->greenNormal(),
									   sim->getUpdateFieldPtr(),
									   true);
	}
	
	// Recompute the CFF on blocks based on the new shear/normal stresses
    sim->computeCFFs(false);
    
}
/*!
 Initialize the stress calculation by setting initial block slip and stresses
 then calculating the stress in the whole system.
 */
void UpdateBlockStress::init(SimFramework *_sim) {
	BlockList::iterator	it;
	BlockID				bid;
	
	sim = static_cast<VCSimulation*>(_sim);
	tmpBuffer = new double[sim->numGlobalBlocks()];
	
    for(it=sim->begin();it!=sim->end();++it) {
		bid = it->getBlockID();
		
		// Set stresses to their specified initial values
		sim->setShearStress(bid, it->getInitShearStress());
		sim->setNormalStress(bid, it->getInitNormalStress());
		
		// Give each block a different random seed based on the block ID
        it->state.rand.init(bid*17);
        //double a = sim->getSlipDeficitNoise();		// TODO: move slip deficit noise to AddNoise class
        // noise in the range [1-a, 1+a)
        //double rn = (1.0-a) + 2*a*it->state.rand.nextDouble();
        //it->state.slipDeficit = -0.5*rn*it->slipCharacteristic();
        it->state.slipDeficit = 0;
		if (sim->isLocalBlockID(bid)) {
			sim->decompressNormalRow(bid);
			//sim->setGreenNormal(bid, bid, 0.0);  // Erase diagonal for normal Greens matrix
			sim->compressNormalRow(bid, 0.7);
		}
    }
	
	// Compute initial stress on all blocks
    stressRecompute();
}
Esempio n. 3
0
void GreensFuncCalcBarnesHut::CalculateGreens(Simulation *sim) {
    BlockList::iterator     bit;
    quakelib::Octree<3>     *tree;
    quakelib::RectBound<3>  total_bound;
    unsigned int            n;
    int                     t_num;

    // Get a list of 3D midpoints of all segments
    for (bit=sim->begin(); bit!=sim->end(); ++bit) {
        total_bound.extend_bound(bit->center());
    }

    // Set up an octree of the model space
    tree = new quakelib::Octree<3>(total_bound);

    // Fill the octree with center points of the faults
    for (bit=sim->begin(); bit!=sim->end(); ++bit) {
        tree->add_point(bit->center(), bit->getBlockID());
    }

    // Get the current thread # for OpenMP to avoid printing multiple progress bars.
#ifdef _OPENMP
    t_num = omp_get_thread_num();
#else
    t_num = 0;
#endif

    // TO FIX: Problem with shared global variables (run_bounds)
    //#pragma omp parallel for shared(last_update) schedule(static,1)
    for (n=0; n<sim->numLocalBlocks(); ++n) {
        progressBar(sim, t_num, n);

        bhInnerCalc(sim, tree, sim->getGlobalBID(n));
    }

    // TODO: symmetrize Greens matrix
}
/*!
 Determine the next time step in the simulation when a failure occurs.
 Return the block ID of the block responsible for the failure and the timestep until the failure.
 */
void UpdateBlockStress::nextTimeStep(BlockVal &fail_time) {
	BlockList::iterator		it;
	BlockVal				temp_block_fail;
	double					ts;
	VCEvent					new_event;
	BlockID					gid;
	int						lid;
    quakelib::Conversion	convert;
	
	// Set up the temporary buffer and update field
    for(it=sim->begin();it!=sim->end();++it) {
		tmpBuffer[it->getBlockID()] = 0.0;
		
		// Set the update field to be the slip rate of each block
		sim->setUpdateField(it->getBlockID(), it->slip_rate());
    }
	
	// update the temporary buffer with the Greens function applied to the block slip rates
	sim->matrixVectorMultiplyAccum(tmpBuffer,
								   sim->greenShear(),
								   sim->getUpdateFieldPtr(),
								   true);
	
	if (sim->doNormalStress()) {
		for(it=sim->begin();it!=sim->end();++it) {
            sim->setUpdateField(it->getBlockID(), -it->friction()*it->slip_rate());
        }
		sim->matrixVectorMultiplyAccum(tmpBuffer,
									   sim->greenNormal(),
									   sim->getUpdateFieldPtr(),
									   true);
	}
	
	// Go through the blocks and find which one will fail first
    temp_block_fail.val = DBL_MAX;
	temp_block_fail.block_id = UNDEFINED_BLOCK_ID;
	
    for(lid=0;lid<sim->numLocalBlocks();++lid) {
		gid = sim->getGlobalBID(lid);
		Block &block = sim->getBlock(gid);
		// Calculate the time until this block will fail
		// If the block has aseismic slip, the calculation is the exact solution of the
		// differential equation d(cff)/dt = rate_of_stress_change + cff*aseismic_frac*self_shear/recurrence
		if (block.aseismic() > 0) {
			double		A, B, K;
			A = -tmpBuffer[gid];
			B = -block.aseismic()*block.getSelfStresses()/block.getRecurrence();
			K = -log(A+B*block.getCFF())/B;
			ts = K + log(A)/B;
		} else {
			ts = convert.sec2year(block.getCFF()/tmpBuffer[gid]);
		}
		
		// Blocks with negative timesteps are skipped. These effectively mean the block
		// should have failed already but didn't. This can happen in the starting phase
		// of a simulation due to initial stresses. These blocks will fail anyway in the
		// event propagation section, so we can safely ignore them here. However, negative
		// timesteps should not happen after the simulation has progressed for a while.
		if (ts <= 0) continue;
		
		// If the time to slip is less than the current shortest time, record the block
        if(ts < temp_block_fail.val) {
            temp_block_fail.block_id = gid;
            temp_block_fail.val = ts;
        }
    }
	
	// Each node now has the time before the first failure among its blocks
	// Determine the time to first failure over all nodes
	sim->allReduceBlockVal(temp_block_fail, fail_time, BLOCK_VAL_MIN);
	
	// If we didn't find any blocks that slipped, abort the simulation
	assertThrow(fail_time.val < DBL_MAX, "System stuck, no blocks to move.");
	
	// Setup the current event to have the trigger block ID and time
	new_event.setEventTriggerOnThisNode(fail_time.block_id==temp_block_fail.block_id);
	new_event.setEventTrigger(fail_time.block_id);
	new_event.setEventYear(sim->getYear()+fail_time.val);
	new_event.setEventNumber(sim->getEventCount());
	sim->addEvent(new_event);
}
Esempio n. 5
0
/*!
 Initialize the stress calculation by setting initial block slip and stresses
 then calculating the stress in the whole system.
 */
void UpdateBlockStress::init(SimFramework *_sim) {
    BlockList::iterator nt;
    BlockID             gid;
    int                 lid;
    double              stress_drop, norm_velocity;

    sim = static_cast<Simulation *>(_sim);
    tmpBuffer = new double[sim->numGlobalBlocks()];

    // All processes need the friction values for all blocks, so we set rhogd here
    // and transfer stress drop values between nodes later
    for (lid=0; lid<sim->numLocalBlocks(); ++lid) {
        double rho = 5.515e3;      // density of rock in kg m^-3
        double g = 9.81;           // force of gravity in m s^-2
        double depth = -sim->getBlock(gid).center()[2];  // depth of block center in m

        gid = sim->getGlobalBID(lid);

        sim->setRhogd(gid, rho*g*depth);       // kg m^-3 * m s^-2 * m = kg m^-1 * s^-2 = Pa

        sim->setDynamicVal(gid, sim->getDynamic());
        sim->setFailed(gid, false);

        // Set stresses to their specified initial values
        sim->setShearStress(gid, sim->getInitShearStress(gid));
        sim->setNormalStress(gid, sim->getInitNormalStress(gid));

        // Set the stress drop based on the Greens function calculations
        stress_drop = 0;
        norm_velocity = sim->getBlock(gid).slip_rate();

        for (nt=sim->begin(); nt!=sim->end(); ++nt) {
            stress_drop += (nt->slip_rate()/norm_velocity)*sim->getGreenShear(gid, nt->getBlockID());
        }

        sim->setStressDrop(gid, sim->getBlock(gid).max_slip()*stress_drop);

        // noise in the range [1-a, 1+a)
        sim->setSlipDeficit(gid, 0);

        if (sim->isLocalBlockID(gid)) {
            sim->decompressNormalRow(gid);
            //sim->setGreenNormal(bid, bid, 0.0);  // Erase diagonal for normal Greens matrix
            sim->compressNormalRow(gid, 0.7);
        }
    }

#ifdef MPI_C_FOUND

    // Transfer stress drop values between nodes
    // This is needed for normal stress Green's calculations
    for (gid=0; gid<sim->numGlobalBlocks(); ++gid) {
        double     stress_drop;

        if (sim->isLocalBlockID(gid)) {
            stress_drop = sim->getStressDrop(gid);
        }

        MPI_Bcast(&stress_drop, 1, MPI_DOUBLE, sim->getBlockNode(gid), MPI_COMM_WORLD);

        if (!sim->isLocalBlockID(gid)) {
            sim->setStressDrop(gid, stress_drop);
        }
    }

#endif

    // Compute initial stress on all blocks
    stressRecompute();
}
Esempio n. 6
0
/*!
 Determine the next time step in the simulation when a failure occurs.
 Return the block ID of the block responsible for the failure and the timestep until the failure.
 */
void UpdateBlockStress::nextStaticFailure(BlockVal &next_static_fail) {
    BlockList::iterator     it;
    double                  ts;
    BlockID                 gid;
    int                     lid;
    quakelib::Conversion    convert;

    // Set up the temporary buffer and update field
    for (it=sim->begin(); it!=sim->end(); ++it) {
        tmpBuffer[it->getBlockID()] = 0.0;

        // Set the update field to be the slip rate of each block
        sim->setUpdateField(it->getBlockID(), it->slip_rate());
    }

    // update the temporary buffer with the Greens function applied to the block slip rates
    sim->matrixVectorMultiplyAccum(tmpBuffer,
                                   sim->greenShear(),
                                   sim->getUpdateFieldPtr(),
                                   true);

    if (sim->doNormalStress()) {
        for (it=sim->begin(); it!=sim->end(); ++it) {
            BlockID gid = it->getBlockID();
            sim->setUpdateField(gid, -sim->getFriction(gid)*it->slip_rate());
        }

        sim->matrixVectorMultiplyAccum(tmpBuffer,
                                       sim->greenNormal(),
                                       sim->getUpdateFieldPtr(),
                                       true);
    }

    // Go through the blocks and find which one will fail first
    next_static_fail.val = DBL_MAX;
    next_static_fail.block_id = UNDEFINED_ELEMENT_ID;

    for (lid=0; lid<sim->numLocalBlocks(); ++lid) {
        gid = sim->getGlobalBID(lid);
        Block &block = sim->getBlock(gid);

        // Calculate the time until this block will fail
        // If the block has aseismic slip, the calculation is the exact solution of the
        // differential equation d(cff)/dt = rate_of_stress_change + cff*aseismic_frac*self_shear/recurrence
        if (block.aseismic() > 0) {
            double      A, B, K;
            A = -tmpBuffer[gid];
            B = -block.aseismic()*sim->getSelfStresses(gid)/sim->getRecurrence(gid);
            K = -log(A+B*sim->getCFF(gid))/B;
            ts = K + log(A)/B;
        } else {
            ts = convert.sec2year(sim->getCFF(gid)/tmpBuffer[gid]);
        }

        // Blocks with negative timesteps are skipped. These effectively mean the block
        // should have failed already but didn't. This can happen in the starting phase
        // of a simulation due to initial stresses. These blocks will fail anyway in the
        // event propagation section, so we can safely ignore them here. However, negative
        // timesteps should not happen after the simulation has progressed for a while.
        if (ts <= 0) continue;

        // If the time to slip is less than the current shortest time, record the block
        // To ensure reproducibility with multiple processes, if multiple blocks fail
        // at the same time then we choose the block with the lowest ID over all the processes
        if (ts < next_static_fail.val) {
            next_static_fail.block_id = gid;
            next_static_fail.val = ts;
        } else if (ts == next_static_fail.val) {
            next_static_fail.block_id = (gid < next_static_fail.block_id ? gid : next_static_fail.block_id);
        }
    }
}