The philosophy is to provide some structure to efficiently run a finite element simulation which remains customizable. Even more customization can be obtained by copy/pasting the source and modifying it to your need. The idea that is followed involves a hierarchy of three classes, whereby a class that is higher in hierarchy writes to some field of the class that is lower in hierarchy, runs a function, and reads from some field. In general:
Defines the discretized system, and assembles the (inverse) mass matrix, the displacement dependent forces, and the velocity dependent forces from element arrays that are provided by the element definition.
Provides the element arrays by performing numerical quadrature. At the integration point the constitutive response is probed from the quadrature point definition.
* **Quadrature point definition**
This class is not provided, and should be provided by the user.
// class which provides the constitutive response at each quadrature point
auto quadrature = std::make_shared<Quadrature>(40*40/4);
// class which provides the response of each element
using Elem = GooseFEM::Dynamics::Diagonal::LinearStrain::Quad4<Quadrature>;
auto elem = std::make_shared<Elem>(quadrature);
// class which provides the system and an increment
GooseFEM::Dynamics::Diagonal::Periodic<Elem> sim(
elem,
mesh.coor(),
mesh.conn(),
mesh.dofsPeriodic(),
1.e-2,
0.0
);
// loop over increments
for ( ... )
{
// - set displacement of fixed DOFs
...
// - compute time increment
sim.Verlet();
// - post-process
quadrature->Ebar = 0.0;
quadrature->Vbar = 0.0;
sim.post();
...
}
return 0;
}
Pseudo-code
-----------
What is happening inside ``Verlet`` is evaluating the forces (and the mass matrix), and updating the displacements by solving the system. In pseudo-code: