/*! Calculate the stress on all blocks and determine which block will be the next to fail and when it will fail. Use this to determine the slipDeficit on all blocks at the time of failure. Finally, use the new slipDeficit to recalculate the stress on all blocks at the time of failure. */ SimRequest UpdateBlockStress::run(SimFramework *_sim) { // Put a stress load on all blocks and determine which block will fail first int lid; BlockVal fail_time; quakelib::Conversion convert; // Calculate the current rates of stress change on all blocks stressRecompute(); // Given the rates of change, determine which block will fail next fail_time.block_id = UNDEFINED_BLOCK_ID; nextTimeStep(fail_time); // Increment the simulation year to the next failure time and // update the slip on all other blocks sim->incrementYear(fail_time.val); for(lid=0;lid<sim->numLocalBlocks();++lid) { Block &local_block = sim->getBlock(sim->getGlobalBID(lid)); local_block.state.slipDeficit -= local_block.slip_rate()*convert.year2sec(fail_time.val)*(1.0-local_block.aseismic()); } // Recalculate the stress on all blocks with the new slip deficits stressRecompute(); if (sim->getYear() > sim->getSimDuration()) return SIM_STOP_REQUIRED; else return SIM_CONTINUE; }
/*! Calculate the stress on all blocks and determine which block will be the next to fail and when it will fail. Use this to determine the slipDeficit on all blocks at the time of failure. Finally, use the new slipDeficit to recalculate the stress on all blocks at the time of failure. */ SimRequest UpdateBlockStress::run(SimFramework *_sim) { // Put a stress load on all blocks and determine which block will fail first int lid; BlockVal next_static_fail, next_aftershock, next_event, next_event_global; quakelib::Conversion convert; quakelib::ModelEvent new_event; // Calculate the current rates of stress change on all blocks stressRecompute(); // Given the rates of change, determine which block will fail next nextStaticFailure(next_static_fail); // Get the next aftershock event time nextAftershock(next_aftershock); // Take whichever is sooner, with ties going in favor of aftershocks if (next_static_fail.val < next_aftershock.val) { next_event.val = next_static_fail.val; next_event.block_id = next_static_fail.block_id; } else { next_event.val = next_aftershock.val; next_event.block_id = next_aftershock.block_id; } // Each node now has the time before the first failure among its blocks // Determine the time to first failure over all nodes sim->allReduceBlockVal(next_event, next_event_global, BLOCK_VAL_MIN); // If we didn't find any static failures or aftershocks, abort the simulation if (sim->isRootNode()) assertThrow(next_event_global.val < DBL_MAX, "System stuck, no blocks to move."); // Increment the simulation year to the next failure time and // update the slip on all other blocks sim->incrementYear(next_event_global.val); for (lid=0; lid<sim->numLocalBlocks(); ++lid) { BlockID gid = sim->getGlobalBID(lid); Block &local_block = sim->getBlock(gid); double cur_slip_deficit = sim->getSlipDeficit(gid); sim->setSlipDeficit(gid, cur_slip_deficit-local_block.slip_rate()*convert.year2sec(next_event_global.val)*(1.0-local_block.aseismic())); } // Recalculate the stress on all blocks with the new slip deficits stressRecompute(); // Record the current event new_event.setEventTriggerOnThisNode(next_event_global.block_id==next_static_fail.block_id); new_event.setEventTrigger(next_event_global.block_id); new_event.setEventYear(sim->getYear()); new_event.setEventNumber(sim->getEventCount()); sim->addEvent(new_event); if (sim->getYear() > sim->getSimDuration()) return SIM_STOP_REQUIRED; else return SIM_CONTINUE; }
/*! 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(); }
/*! 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(); }