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

#include <quasistatic_time_integrator.h>

Inheritance diagram for nimble::QuasistaticTimeIntegrator:
nimble::IntegratorBase

Public Member Functions

 QuasistaticTimeIntegrator (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

◆ QuasistaticTimeIntegrator()

nimble::QuasistaticTimeIntegrator::QuasistaticTimeIntegrator ( NimbleApplication & app,
GenesisMesh & mesh,
DataManager & data_manager )
117 : IntegratorBase(app, mesh, data_manager)
118{
119}
IntegratorBase(NimbleApplication &app, GenesisMesh &mesh, DataManager &data_manager)
Definition integrator_base.cc:47

Member Function Documentation

◆ Integrate()

int nimble::QuasistaticTimeIntegrator::Integrate ( )
overridevirtual

Implements nimble::IntegratorBase.

123{
124 auto& parser = App().GetParser();
125 auto& mesh = Mesh();
126 auto& data_manager = GetDataManager();
127
128 const int my_rank = parser.GetRankID();
129 const int num_ranks = parser.GetNumRanks();
130
131 if (num_ranks > 1) {
132 std::string msg =
133 " Quasi-statics currently not implemented in parallel "
134 "(work in progress).\n";
135 throw std::invalid_argument(msg);
136 }
137
138 int status = 0;
139
140 int dim = mesh.GetDim();
141 int num_nodes = static_cast<int>(mesh.GetNumNodes());
142 int num_blocks = static_cast<int>(mesh.GetNumBlocks());
143 const int* global_node_ids = mesh.GetNodeGlobalIds();
144
145 auto& bc = *(data_manager.GetBoundaryConditionManager());
146
147 // Store various mappings from global to local node ids
148 std::vector<int> linear_system_global_node_ids;
149 std::map<int, std::vector<int>> map_from_linear_system;
150 for (int n = 0; n < num_nodes; ++n) {
151 int global_node_id = global_node_ids[n];
152 linear_system_global_node_ids.push_back(global_node_id);
153 map_from_linear_system[global_node_id] = std::vector<int>();
154 map_from_linear_system[global_node_id].push_back(n);
155 }
156 int linear_system_num_nodes = static_cast<int>(map_from_linear_system.size());
157 int linear_system_num_unknowns = linear_system_num_nodes * dim;
158
159 std::vector<double> global_data;
160
161 auto* model_data_ptr = dynamic_cast<nimble::ModelData*>(data_manager.GetModelData().get());
162 if (model_data_ptr == nullptr) { throw std::invalid_argument(" Incompatible Model Data \n"); }
163 nimble::ModelData& model_data = *model_data_ptr;
164
165 // Set up the global vectors
166 unsigned int num_unknowns = num_nodes * mesh.GetDim();
167
168 auto reference_coordinate = model_data.GetVectorNodeData("reference_coordinate");
169 auto physical_displacement = model_data.GetVectorNodeData("displacement");
170 auto displacement_fluctuation = model_data.GetVectorNodeData("displacement_fluctuation");
171 auto trial_displacement = model_data.GetVectorNodeData("trial_displacement");
172
173 auto velocity = model_data.GetVectorNodeData("velocity");
174
175 auto internal_force = model_data.GetVectorNodeData("internal_force");
176 auto trial_internal_force = model_data.GetVectorNodeData("trial_internal_force");
177
178 std::vector<double> residual_vector(linear_system_num_unknowns, 0.0);
179 std::vector<double> trial_residual_vector(linear_system_num_unknowns, 0.0);
180 std::vector<double> linear_solver_solution(linear_system_num_unknowns, 0.0);
181
182 nimble::Viewify<2> displacement = physical_displacement;
183
184 nimble::CRSMatrixContainer tangent_stiffness;
185 nimble::CGScratchSpace cg_scratch;
186 std::vector<int> i_index, j_index;
187 nimble::DetermineTangentMatrixNonzeroStructure(mesh, linear_system_global_node_ids, i_index, j_index);
188 tangent_stiffness.AllocateNonzeros(i_index, j_index);
189 if (my_rank == 0) {
190 std::cout << "Number of nonzeros in tangent stiffness matrix = " << tangent_stiffness.NumNonzeros() << "\n"
191 << std::endl;
192 }
193
194#ifdef NIMBLE_HAVE_TRILINOS
195 // tpetra_container.AllocateTangentStiffnessMatrix(mesh);
196 // if (my_rank == 0) {
197 // std::cout << "Number of nonzeros in the crs tangent stiffness matrix = "
198 // << tpetra_container.TangentStiffnessMatrixNumNonzeros() << "\n" <<
199 // std::endl;
200 // }
201#endif
202
203 double initial_time = parser.InitialTime();
204 double final_time = parser.FinalTime();
205 double time_current{initial_time};
206 double time_previous{initial_time};
207 double delta_time{0.0};
208 int num_load_steps = parser.NumLoadSteps();
209 int output_frequency = parser.OutputFrequency();
210 double user_specified_time_step = (final_time - initial_time) / num_load_steps;
211
212 if (my_rank == 0 && final_time < initial_time) {
213 std::string msg = "Final time: " + std::to_string(final_time) +
214 " is less than initial time: " + std::to_string(initial_time) + "\n";
215 throw std::invalid_argument(msg);
216 }
217
218#ifdef NIMBLE_HAVE_UQ
219 if (parser.UseUQ()) NIMBLE_ABORT("\nError: UQ enabled but not implemented for quasistatics.\n");
220#endif
221
222 model_data.ApplyKinematicConditions(data_manager, time_current, time_previous);
223
224 std::vector<double> identity(dim * dim, 0.0);
225 for (int i = 0; i < dim; i++) { identity[i] = 1.0; }
226
227 auto& blocks = model_data.GetBlocks();
228
229 data_manager.WriteOutput(time_current);
230
231 if (my_rank == 0) { std::cout << "Beginning quasistatic time integration:" << std::endl; }
232
233 for (int step = 0; step < num_load_steps; step++) {
234 time_previous = time_current;
235 time_current += user_specified_time_step;
236 delta_time = time_current - time_previous;
237
238 bool is_output_step = false;
239 if (output_frequency != 0) {
240 if (step % output_frequency == 0 || step == num_load_steps - 1) { is_output_step = true; }
241 }
242
243 model_data.ApplyKinematicConditions(data_manager, time_current, time_previous);
244
245 // Compute the residual, which is a norm of the (rearranged) nodal force
246 // vector, with the dof associated with kinematic BC removed.
247 double residual = ComputeQuasistaticResidual(
248 mesh,
249 data_manager,
250 bc,
251 linear_system_num_unknowns,
252 linear_system_global_node_ids,
253 time_previous,
254 time_current,
255 displacement,
256 internal_force,
257 residual_vector.data(),
258 is_output_step);
259
260 int iteration(0);
261 int max_nonlinear_iterations = parser.NonlinearSolverMaxIterations();
262 double convergence_tolerance = parser.NonlinearSolverRelativeTolerance() * residual;
263
264 if (my_rank == 0) {
265 std::cout << "\nStep " << step + 1 << std::scientific << std::setprecision(3) << ", time " << time_current
266 << ", delta_time " << delta_time << ", convergence tolerance " << convergence_tolerance << std::endl;
267 std::cout << " iteration " << iteration << ": residual = " << residual << std::endl;
268 }
269
270 while (residual > convergence_tolerance && iteration < max_nonlinear_iterations) {
271 tangent_stiffness.SetAllValues(0.0);
272#ifdef NIMBLE_HAVE_TRILINOS
273 // tpetra_container.TangentStiffnessMatrixSetScalar(0.0);
274#endif
275 for (auto& block_it : blocks) {
276 int block_id = block_it.first;
277 int num_elem_in_block = mesh.GetNumElementsInBlock(block_id);
278 int const* elem_conn = mesh.GetConnectivity(block_id);
279 auto& block = block_it.second;
280 block->ComputeTangentStiffnessMatrix(
281 linear_system_num_unknowns,
282 reference_coordinate.data(),
283 displacement.data(),
284 num_elem_in_block,
285 elem_conn,
286 linear_system_global_node_ids.data(),
287 tangent_stiffness);
288 }
289
290 double diagonal_entry(0.0);
291 for (int i = 0; i < linear_system_num_unknowns; ++i) { diagonal_entry += std::abs(tangent_stiffness(i, i)); }
292 diagonal_entry /= linear_system_num_unknowns;
293
294 // For the dof with kinematic BC, zero out the rows and columns and put a
295 // non-zero on the diagonal
296 bc.ModifyTangentStiffnessMatrixForKinematicBC(
297 linear_system_num_unknowns, linear_system_global_node_ids.data(), diagonal_entry, tangent_stiffness);
298 bc.ModifyRHSForKinematicBC(linear_system_global_node_ids.data(), residual_vector.data());
299
300 // Solve the linear system with the tangent stiffness matrix
301 int num_cg_iterations(0);
302 std::fill(linear_solver_solution.begin(), linear_solver_solution.end(), 0.0);
303 bool success = nimble::CG_SolveSystem(
304 tangent_stiffness, residual_vector.data(), cg_scratch, linear_solver_solution.data(), num_cg_iterations);
305 if (!success) {
306 if (my_rank == 0) { std::cout << "\n**** CG solver failed to converge!\n" << std::endl; }
307 status = 1;
308 return status;
309 }
310
311 //
312 // Apply a line search
313 //
314
315 // evaluate residual for alpha = 1.0
316 for (int n = 0; n < linear_system_num_nodes; n++) {
317 std::vector<int> const& node_ids = map_from_linear_system[n];
318 for (auto const& node_id : node_ids) {
319 for (int dof = 0; dof < dim; dof++) {
320 int ls_index = n * dim + dof;
321#ifdef NIMBLE_DEBUG
322 if (ls_index < 0 || ls_index > linear_solver_solution.size() - 1) {
323 throw std::invalid_argument(
324 "\nError: Invalid index into linear solver solution in "
325 "QuasistaticTimeIntegrator().\n");
326 }
327#endif
328 trial_displacement(node_id, dof) = displacement(node_id, dof) - linear_solver_solution[ls_index];
329 }
330 }
331 }
332 double trial_residual = ComputeQuasistaticResidual(
333 mesh,
334 data_manager,
335 bc,
336 linear_system_num_unknowns,
337 linear_system_global_node_ids,
338 time_previous,
339 time_current,
340 trial_displacement,
341 trial_internal_force,
342 trial_residual_vector.data(),
343 is_output_step);
344
345 //
346 // secant line search
347 //
348 double sr = nimble::InnerProduct(linear_solver_solution, residual_vector);
349 double s_trial_r = nimble::InnerProduct(linear_solver_solution, trial_residual_vector);
350 double alpha = -1.0 * sr / (s_trial_r - sr);
351
352 // evaluate residual for alpha computed with secant line search
353 for (int n = 0; n < linear_system_num_nodes; n++) {
354 std::vector<int> const& node_ids = map_from_linear_system[n];
355 for (auto const& node_id : node_ids) {
356 for (int dof = 0; dof < dim; dof++) {
357 int ls_index = n * dim + dof;
358#ifdef NIMBLE_DEBUG
359 if (ls_index < 0 || ls_index > linear_solver_solution.size() - 1) {
360 throw std::invalid_argument(
361 "\nError: Invalid index into linear solver solution vector in "
362 "QuasistaticTimeIntegrator().\n");
363 }
364#endif
365 displacement(node_id, dof) -= alpha * linear_solver_solution[ls_index];
366 }
367 }
368 }
369 residual = ComputeQuasistaticResidual(
370 mesh,
371 data_manager,
372 bc,
373 linear_system_num_unknowns,
374 linear_system_global_node_ids,
375 time_previous,
376 time_current,
377 displacement,
378 internal_force,
379 residual_vector.data(),
380 is_output_step);
381
382 // if the alpha = 1.0 result was better, use alpha = 1.0
383 if (trial_residual < residual) {
384 residual = trial_residual;
385 displacement.copy(trial_displacement);
386 internal_force.copy(trial_internal_force);
387 for (int i = 0; i < linear_system_num_unknowns; i++) { residual_vector[i] = trial_residual_vector[i]; }
388 }
389
390 iteration += 1;
391
392 if (my_rank == 0) {
393 std::cout << " iteration " << iteration << ": residual = " << residual
394 << ", linear cg iterations = " << num_cg_iterations << std::endl;
395 }
396
397 } // while (residual > convergence_tolerance ... )
398
399 if (iteration == max_nonlinear_iterations) {
400 if (my_rank == 0) {
401 std::cout << "\n**** Nonlinear solver failed to converge!\n" << std::endl;
402 std::cout << "**** Relevant input deck parameters for the nonlinear solver:" << std::endl;
403 std::cout << "**** nonlinear solver relative tolerance: " << parser.NonlinearSolverRelativeTolerance()
404 << std::endl;
405 std::cout << "**** nonlinear solver maximum iterations: " << parser.NonlinearSolverMaxIterations()
406 << std::endl;
407 }
408 status = 1;
409 return status;
410 } else {
411 if (is_output_step) data_manager.WriteOutput(time_current);
412 }
413
414 // swap states
415 model_data.UpdateStates(data_manager);
416 }
417
418 if (my_rank == 0) { std::cout << "\nComplete.\n" << std::endl; }
419
420 return status;
421}
unsigned int NumNonzeros() const
Definition nimble_linear_solver.h:164
void AllocateNonzeros(std::vector< int > const &i_index, std::vector< int > const &j_index)
Definition nimble_linear_solver.cc:57
void SetAllValues(double value)
Definition nimble_linear_solver.h:146
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
virtual void ApplyKinematicConditions(nimble::DataManager &data_manager, double time_current, double time_previous)
Apply kinematic conditions.
Definition nimble_model_data_base.cc:93
std::map< int, std::shared_ptr< nimble::Block > > & GetBlocks()
Definition nimble_model_data.h:213
nimble::Viewify< 2 > GetVectorNodeData(int field_id) override
Get view of vector quantity defined on nodes.
Definition nimble_model_data.cc:541
void UpdateStates(const nimble::DataManager &data_manager) override
Copy time state (n+1) into time state (n)
Definition nimble_model_data.h:104
Parser & GetParser()
Definition nimble.cc:171
void copy(const Viewify< N > &ref)
Definition nimble_view.h:123
Scalar * data() const
Definition nimble_view.h:130
double InnerProduct(unsigned int num_entries, const double *vec_1, const double *vec_2)
Definition nimble_linear_solver.h:215
bool CG_SolveSystem(nimble::CRSMatrixContainer &A, const double *b, CGScratchSpace &cg_scratch, double *x, int &num_iterations, double cg_tol, int max_iterations)
Definition nimble_linear_solver.cc:155
void DetermineTangentMatrixNonzeroStructure(GenesisMesh const &mesh, std::vector< int > const &linear_system_node_ids, std::vector< int > &i_index, std::vector< int > &j_index)
Definition nimble_mesh_utils.cc:49
#define NIMBLE_ABORT(...)
Definition nimble_macros.h:87

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