NimbleSM
NimbleSM is a solid mechanics simulation code for dynamic systems
Loading...
Searching...
No Matches
nimble::ExplicitTimeIntegrator Class Reference

#include <explicit_time_integrator.h>

Inheritance diagram for nimble::ExplicitTimeIntegrator:
nimble::IntegratorBase

Public Member Functions

 ExplicitTimeIntegrator (NimbleApplication &app, GenesisMesh &mesh, DataManager &data_manager)
 
int Integrate () override
 
- Public Member Functions inherited from nimble::IntegratorBase
 IntegratorBase (NimbleApplication &app, GenesisMesh &mesh, DataManager &data_manager)
 
virtual ~IntegratorBase ()
 
NimbleApplicationApp () noexcept
 
const GenesisMeshMesh () const noexcept
 
GenesisMeshMesh () noexcept
 
DataManagerGetDataManager () noexcept
 

Constructor & Destructor Documentation

◆ ExplicitTimeIntegrator()

nimble::ExplicitTimeIntegrator::ExplicitTimeIntegrator ( NimbleApplication & app,
GenesisMesh & mesh,
DataManager & data_manager )
57 : IntegratorBase(app, mesh, data_manager)
58{}
IntegratorBase(NimbleApplication &app, GenesisMesh &mesh, DataManager &data_manager)
Definition integrator_base.cc:47

Member Function Documentation

◆ Integrate()

int nimble::ExplicitTimeIntegrator::Integrate ( )
overridevirtual

Implements nimble::IntegratorBase.

62{
63 auto &mesh = Mesh();
64 auto &parser = App().GetParser();
65 auto &data_manager = GetDataManager();
66 auto contact_interface = App().GetContactInterface();
67 int dim = mesh.GetDim();
68 int num_nodes = static_cast<int>(mesh.GetNumNodes());
69 int num_blocks = static_cast<int>(mesh.GetNumBlocks());
70 const int my_rank = App().Rank();
71 const int num_ranks = App().NumRanks();
72 const long num_unknowns = num_nodes * mesh.GetDim();
73
74 auto contact_manager = nimble::GetContactManager(contact_interface, data_manager);
75
76 bool contact_enabled = parser.HasContact();
77 bool contact_visualization = parser.ContactVisualization();
78
79 auto myVectorCommunicator = data_manager.GetVectorCommunicator();
80 nimble::ProfilingTimer watch_simulation;
81
82 if (contact_enabled) {
83 std::vector<std::string> contact_primary_block_names, contact_secondary_block_names;
84 double penalty_parameter;
86 parser.ContactString(), contact_primary_block_names, contact_secondary_block_names, penalty_parameter);
87 std::vector<int> contact_primary_block_ids, contact_secondary_block_ids;
88 mesh.BlockNamesToOnProcessorBlockIds(contact_primary_block_names, contact_primary_block_ids);
89 mesh.BlockNamesToOnProcessorBlockIds(contact_secondary_block_names, contact_secondary_block_ids);
90 contact_manager->SetPenaltyParameter(penalty_parameter);
91 contact_manager->CreateContactEntities(
92 mesh, *myVectorCommunicator, contact_primary_block_ids, contact_secondary_block_ids);
93 if (contact_visualization) {
94 std::string tag = "out";
95 std::string contact_visualization_exodus_file_name =
96 nimble::IOFileName(parser.ContactVisualizationFileName(), "e", tag, my_rank, num_ranks);
97 contact_manager->InitializeContactVisualization(contact_visualization_exodus_file_name);
98 }
99 }
100
101 auto& model_data = *(data_manager.GetModelData());
102
103 int status = 0;
104
105 //
106 // Extract view for global field vectors
107 //
108 auto reference_coordinate = model_data.GetVectorNodeData("reference_coordinate");
109 auto displacement = model_data.GetVectorNodeData("displacement");
110 auto velocity = model_data.GetVectorNodeData("velocity");
111 auto acceleration = model_data.GetVectorNodeData("acceleration");
112
113 //
114 // "View" objects for storing the internal and external forces
115 // These forces will be filled and updated inside ModelData member routines.
116 //
117 auto internal_force = model_data.GetVectorNodeData("internal_force");
118 auto external_force = model_data.GetVectorNodeData("external_force");
119
120 nimble::Viewify<2> contact_force;
121 if (contact_enabled) contact_force = model_data.GetVectorNodeData("contact_force");
122
123 model_data.ComputeLumpedMass(data_manager);
124
125 double critical_time_step = model_data.GetCriticalTimeStep();
126 auto const lumped_mass = model_data.GetScalarNodeData("lumped_mass");
127
128 double initial_time = parser.InitialTime();
129 double final_time = parser.FinalTime();
130 double time_current{initial_time};
131 double time_previous{initial_time};
132 double delta_time{0.0};
133 double half_delta_time{0.0};
134 int num_load_steps = parser.NumLoadSteps();
135 int output_frequency = parser.OutputFrequency();
136 double user_specified_time_step = (final_time - initial_time) / num_load_steps;
137
138 if (my_rank == 0 && final_time < initial_time) {
139 std::string msg = "Final time: " + std::to_string(final_time)
140 + " is less than initial time: " + std::to_string(initial_time)
141 + "\n";
142 throw std::invalid_argument(msg);
143 }
144
145 watch_simulation.push_region("BC enforcement");
146 model_data.ApplyInitialConditions(data_manager);
147 model_data.ApplyKinematicConditions(data_manager, 0.0, 0.0);
148 watch_simulation.pop_region_and_report_time();
149
150 data_manager.WriteOutput(time_current);
151
152 if (contact_visualization) { contact_manager->ContactVisualizationWriteStep(time_current); }
153
154 if (my_rank == 0) {
155 std::cout << "\nUser specified time step: " << user_specified_time_step << std::endl;
156 std::cout << "Approximate maximum stable time step: " << critical_time_step << "\n" << std::endl;
157 if (user_specified_time_step > critical_time_step) {
158 std::cout << "**** WARNING: The user specified time step exceeds the "
159 "computed maximum stable time step.\n"
160 << std::endl;
161 }
162 std::cout << "Explicit time integration:\n 0% complete" << std::endl;
163 }
164
165 //
166 // Timing records
167 //
168
169 double total_vector_reduction_time = 0.0;
170 double total_dynamics_time = 0.0, total_exodus_write_time = 0.0;
171 double total_force_time = 0.0, total_contact_time = 0.0;
172 watch_simulation.push_region("Time stepping loop");
173
174 nimble::ProfilingTimer watch_internal;
175 std::map<int, std::size_t> contactInfo;
176
177 for (int step = 0; step < num_load_steps; step++) {
178 if (my_rank == 0) {
179 if (10 * (step + 1) % num_load_steps == 0 && step != num_load_steps - 1) {
180 std::cout << " " << static_cast<int>(100.0 * static_cast<double>(step + 1) / num_load_steps) << "% complete"
181 << std::endl
182 << std::flush;
183 } else if (step == num_load_steps - 1) {
184 std::cout << " 100% complete\n" << std::endl << std::flush;
185 }
186 }
187 bool is_output_step = false;
188 if (output_frequency != 0) {
189 if (step % output_frequency == 0 || step == num_load_steps - 1) { is_output_step = true; }
190 }
191
192 time_previous = time_current;
193 time_current += user_specified_time_step;
194 delta_time = time_current - time_previous;
195 half_delta_time = 0.5 * delta_time;
196
197 watch_internal.push_region("Time Integration Scheme");
198 // V^{n+1/2} = V^{n} + (dt/2) * A^{n}
199 velocity += half_delta_time * acceleration;
200
201 model_data.UpdateWithNewVelocity(data_manager, half_delta_time);
202 total_dynamics_time += watch_internal.pop_region_and_report_time();
203
204 watch_internal.push_region("BC enforcement");
205 model_data.ApplyKinematicConditions(data_manager, time_current, time_previous);
206 watch_internal.pop_region_and_report_time();
207
208 watch_internal.push_region("Time Integration Scheme");
209 // U^{n+1} = U^{n} + (dt)*V^{n+1/2}
210 displacement += delta_time * velocity;
211
212 model_data.UpdateWithNewDisplacement(data_manager, delta_time);
213 total_dynamics_time += watch_internal.pop_region_and_report_time();
214
215 watch_internal.push_region("BC enforcement");
216 model_data.ApplyKinematicConditions(data_manager, time_current, time_previous);
217 watch_internal.pop_region_and_report_time();
218
219 //
220 // Evaluate external body forces
221 //
222 watch_internal.push_region("Force calculation");
223 model_data.ComputeExternalForce(data_manager, time_previous, time_current, is_output_step);
224
225 //
226 // Evaluate the internal force
227 //
228 model_data.ComputeInternalForce(
229 data_manager, time_previous, time_current, is_output_step, displacement, internal_force);
230 total_force_time += watch_internal.pop_region_and_report_time();
231
232 // Evaluate the contact force
233 if (contact_enabled) {
234 watch_internal.push_region("Contact");
235 contact_manager->ComputeContactForce(step + 1, contact_visualization && is_output_step, contact_force);
236 total_contact_time += watch_internal.pop_region_and_report_time();
237 auto tmpNum = contact_manager->numActiveContactFaces();
238 if (tmpNum) contactInfo.insert(std::make_pair(step, tmpNum));
239 }
240
241 // fill acceleration vector A^{n+1} = M^{-1} ( F^{n} + b^{n} )
242 watch_internal.push_region("Time Integration Scheme");
243 if (contact_enabled) {
244 for (int i = 0; i < num_nodes; ++i) {
245 const double oneOverM = 1.0 / lumped_mass(i);
246 acceleration(i, 0) = oneOverM * (internal_force(i, 0) + external_force(i, 0) + contact_force(i, 0));
247 acceleration(i, 1) = oneOverM * (internal_force(i, 1) + external_force(i, 1) + contact_force(i, 1));
248 acceleration(i, 2) = oneOverM * (internal_force(i, 2) + external_force(i, 2) + contact_force(i, 2));
249 }
250 } else {
251 for (int i = 0; i < num_nodes; ++i) {
252 const double oneOverM = 1.0 / lumped_mass(i);
253 acceleration(i, 0) = oneOverM * (internal_force(i, 0) + external_force(i, 0));
254 acceleration(i, 1) = oneOverM * (internal_force(i, 1) + external_force(i, 1));
255 acceleration(i, 2) = oneOverM * (internal_force(i, 2) + external_force(i, 2));
256 }
257 }
258
259 // V^{n+1} = V^{n+1/2} + (dt/2)*A^{n+1}
260 velocity += half_delta_time * acceleration;
261
262 model_data.UpdateWithNewVelocity(data_manager, half_delta_time);
263
264 total_dynamics_time += watch_internal.pop_region_and_report_time();
265
266 if (is_output_step) {
267 watch_internal.push_region("Output");
268 //
269 model_data.ApplyKinematicConditions(data_manager, time_current, time_previous);
270 //
271 data_manager.WriteOutput(time_current);
272 //
273 if (contact_visualization) { contact_manager->ContactVisualizationWriteStep(time_current); }
274 total_exodus_write_time += watch_internal.pop_region_and_report_time();
275 } // if (is_output_step)
276
277 model_data.UpdateStates(data_manager);
278 }
279 double total_simulation_time = watch_simulation.pop_region_and_report_time();
280
281 for (int irank = 0; irank < num_ranks; ++irank) {
282#ifdef NIMBLE_HAVE_MPI
283 MPI_Barrier(MPI_COMM_WORLD);
284#endif
285 if ((my_rank == irank) && (!contactInfo.empty())) {
286 std::cout << " Rank " << irank << " has " << contactInfo.size() << " contact entries "
287 << "(out of " << num_load_steps << " time steps)." << std::endl;
288 std::cout.flush();
289 }
290#ifdef NIMBLE_HAVE_MPI
291MPI_Barrier(MPI_COMM_WORLD);
292#endif
293 }
294
295 if (my_rank == 0 && parser.WriteTimingDataFile()) {
296 nimble::TimingInfo timing_writer{
297 num_ranks,
299 total_simulation_time,
300 total_force_time,
301 total_contact_time,
302 total_exodus_write_time,
303 total_vector_reduction_time};
304 timing_writer.BinaryWrite();
305 }
306
307 if (my_rank == 0) {
308 std::cout << "======== Timing data: ========\n";
309 std::cout << "Total step time = " << total_simulation_time << '\n';
310 std::cout << " --- Update A, V, U: " << total_dynamics_time << '\n';
311 std::cout << " --- Force: " << total_force_time << "\n";
312 if ((contact_enabled) && (contact_manager)) {
313 std::cout << " --- Contact time: " << total_contact_time << '\n';
314 auto list_timers = contact_manager->getTimers();
315 for (const auto& st_pair : list_timers)
316 std::cout << " --- >>> >>> " << st_pair.first << " = " << st_pair.second << "\n";
317 }
318 if (num_ranks > 1) std::cout << " --- Vector Reduction = " << total_vector_reduction_time << "\n";
319 //
320 std::cout << " --- Exodus Write = " << total_exodus_write_time << "\n";
321 //
322 }
323
324 return status;
325}
const GenesisMesh & Mesh() const noexcept
Definition integrator_base.h:63
NimbleApplication & App() noexcept
Definition integrator_base.h:62
DataManager & GetDataManager() noexcept
Definition integrator_base.h:65
Parser & GetParser()
Definition nimble.cc:171
int NumRanks() const noexcept
Definition nimble.cc:159
std::shared_ptr< ContactInterface > GetContactInterface()
Definition nimble.cc:165
int Rank() const noexcept
Definition nimble.cc:153
void push_region(const std::string &profiling_region_name)
Definition nimble_profiling_timer.h:72
double pop_region_and_report_time()
Definition nimble_profiling_timer.h:84
std::string IOFileName(std::string const &serial_name, std::string const &extension, std::string const &label, int my_rank, int num_ranks)
Definition nimble_parser.cc:58
void ParseContactCommand(std::string const &command, std::vector< std::string > &primary_block_names, std::vector< std::string > &secondary_block_names, double &penalty_parameter)
Definition nimble_contact_manager.cc:96
std::shared_ptr< nimble::ContactManager > GetContactManager(std::shared_ptr< ContactInterface > interface, nimble::DataManager &data_manager)
Definition nimble_contact_manager.cc:152
static std::string get_microsecond_timestamp()
Definition nimble.quanta.stopwatch.h:119

The documentation for this class was generated from the following files: