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:
* Writes element positions, displacements, and velocity of all elements to the *element definition*.
* Assembles the diagonal (inverse) mass matrix, the displacement dependent forces, the velocity dependent forces, and the diagonal damping matrix from the element arrays computed in *element definition*.
Provides the element arrays by performing numerical quadrature. At the integration point the strain and strain-rate are computed and 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::SmallStrain::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: