/*! 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(); }
/*! 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); }
void AddNoise::init(SimFramework *_sim) { VCSimulation *sim = static_cast<VCSimulation*>(_sim); double stress_noise, stress_res_dist, cur_noise, old_stress_drop; std::map<quakelib::Vec<3>, double> centers_noise; quakelib::Vec<3> mid_pt; std::map<quakelib::Vec<3>, double>::iterator cit; BlockList::iterator it; stress_noise = sim->getStressNoise(); stress_res_dist = sim->getStressNoiseResolution(); //! For each block in the simulation, get the midpoint and record the noise added to the block. //! Each block within a specified radius of the selected block will have the same level of noise added. //! The noise is defined as a modification of the stress drop from x to x +/- stress_noise. for (it=sim->begin();it!=sim->end();++it) { cur_noise = 1.0e10; mid_pt = it->center(); for (cit=centers_noise.begin();cit!=centers_noise.end();++cit) { if (mid_pt.dist(cit->first) <= stress_res_dist) { cur_noise = cit->second; break; } } if (cur_noise > 1.0e9) { cur_noise = (1.0-stress_noise) + 2*stress_noise*sim->randDouble(); centers_noise.insert(std::make_pair(mid_pt, cur_noise)); } old_stress_drop = it->getStressDrop(); it->setStressDrop(old_stress_drop*cur_noise); } }
BasicBlock::EdgeList::iterator BasicBlock::get_edge(BlockList::iterator b) { for (EdgePointerVector::iterator edge = out_edges.begin(); edge != out_edges.end(); ++edge) { if ((*edge)->tail == b) return *edge; } assertM(false, "No edge from " << label() << " to " << b->label()); return EdgeList::iterator(); }
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); }
/*! 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(); }
/*! 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); } } }