v0.16.0
Loading...
Searching...
No Matches
VEC-1: Eigen elastic
Note
Prerequisites of this tutorial include MSH-1: Create a 2D mesh from Gmsh


Note
Intended learning outcome:
  • general structure of a program developed using MoFEM
  • idea of Simple Interface in MoFEM and how to use it
  • solving eigen problem
  • Use of form integrators
  • How to push the developed UDOs to the Pipeline

Introduction

This tutorial presents the solution of an eigen-elastic problem using the operator OpGradSymTensorGrad, together with the SLEPc EPS solver.

Notation description

Contraction: given a fourth-order tensor \( A_{n_1 \times n_2 \times n_3 \times n_4} \) and a matrix \( B_{n_3 \times n_4} \), their contraction is written as \( C = A : B \), with

\[ C_{ij} = \sum_{k l} A_{i j k l} B_{k l}. \label{contraction} \]

Einstein notation:
repeated indices imply summation. For instance,

\[ \label{einstein} y=\sum^{n}_{i=1}a_{i}x_{i}\quad \Leftrightarrow \quad y=a_ix_i \]

Using this rule, the contraction above becomes

\[ C_{ij}=A_{ijkl}B_{kl} \]

Problem statement

Strong form

For a time-dependent elastic problem, the displacement field \(\mathbf{u}\) and the stress \(\pmb{\sigma}\) satisfy balance of linear momentum:

\[ \label{eq:time_elastic} \rho \frac{\partial^{2} \mathbf{u}}{\partial t^{2}} = \nabla \cdot \pmb{\sigma}\quad \text{in } \Omega \]

where \(\rho\) is the material density.

The stress is related to strain via tensor contraction:

\[ \label{eq:stress-strain} {\pmb{\sigma}(\mathbf{u})}=\mathbf{C}:\pmb{\varepsilon}(\mathbf{u}) \]

with the strain

\[ \begin{equation} \varepsilon(\mathbf{u}) = \frac{1}{2} \big(\nabla \mathbf{u} + \nabla \mathbf{u}^T \big). \end{equation} \]

The stiffness tensor \(\mathbf{C}\) depends on Young's modulus \(E\) and Poisson ratio \(\nu\).

As this problem focuses on determining the natural frequencies of a tuning fork in free vibration, which is treated as an eigenvalue problem later, the displacement \(\mathbf{u}(\mathbf{x},t)\) is decomposed into position-dependent part and time-dependent phase:

\[ \label{eq:time_harmonic} \mathbf{u}(\mathbf{x},t) = \mathbf{\hat{u}}(\mathbf{x}) e^{i \omega t} \]

Combining Eqs. \eqref{eq:time_elastic} and \eqref{eq:time_harmonic} leads to:

\[ \label{eq:static} \nabla \cdot \pmb{\sigma}(\mathbf{\hat{u}}) + \rho \omega^2 \mathbf{\hat{u}} = 0 \]

The bulk modulus \(K\) and the shear modulus \(G\) are related to \(E\) and \(\nu\) by:

\[ \label{eq:bulk_mod} K = \frac{E}{3(1-2\nu)}, \quad G = \frac{E}{2(1+\nu)} \]

Then the stiffness tensor is

\[ \label{eq:stiffness_coe} \mathbf{C}_{ijkl} = 2G \delta_{ik}\delta_{jl} + A \Big(K - \frac{2}{3} G \Big) \delta_{ij} \delta_{kl} \]

where \(A = \frac{2G}{K+\frac{4}{3}G}\) for 2D plane strain and \(A = 1\) for 3D.

Therefore we get the final strong form of the problem:

\[ \begin{align} \label{eq:strong_form_domain} \nabla \!\cdot\! \left[\mathbf{C} : \varepsilon(\hat{\mathbf{u}})\right] + \rho \omega^2 \hat{\mathbf{u}} &= 0, && \text{in } \Omega, \\[2mm] \label{eq:strong_form_boundary} \pmb{\sigma}(\hat{\mathbf{u}}) \cdot \mathbf{n}&= 0, && \text{on } \Gamma. \end{align} \]

Weak form

Denote \(\delta\mathbf{\hat{u}}\) as the test function for the displacement. As \(\mathbf{C}:\varepsilon(\hat{\mathbf{u}})\) is symmetric, we have

\[ \nabla \delta \mathbf{\hat{u}}:\mathbf{C}:\varepsilon(\hat{\mathbf{u}})=\varepsilon(\delta \mathbf{\hat{u}}) : \mathbf{C} : \varepsilon(\mathbf{\hat{u}}) \]

Starting from Eq. \eqref{eq:strong_form_domain} and \eqref{eq:strong_form_boundary}, the weak form is:

Find \(\mathbf{\hat{u}} \in \mathrm{H}^1(\Omega)\) such that

\[ \label{eq:weak_form} \int_{\Omega} \varepsilon(\delta \mathbf{\hat{u}}) : \mathbf{C} : \varepsilon(\mathbf{\hat{u}}) \, d\Omega -\int_{\Gamma} (\delta \mathbf{\hat{u}})\cdot \left[\mathbf{C} : \varepsilon(\mathbf{\hat{u}})\right] \cdot \mathbf{n} \, d\Gamma = \omega^2 \int_{\Omega} \rho (\delta \mathbf{\hat{u}})\cdot \mathbf{\hat{u}} \, d\Omega, \quad \forall \delta \mathbf{\hat{u}} \in \mathrm{H}^1(\Omega) \]

According to the natural boundary condition in Eq. \eqref{eq:strong_form_boundary}, the second term on the left-hand side vanishes.

Approximating test and trial functions using shape functions \(\pmb{\phi}\)

\[ \label{eq:shape_functions} \begin{align} \delta\mathbf{\hat{u}}\approx\delta\mathbf{\hat{u}}^h&=\sum_{i=1}^{n}\pmb{\phi}_i\delta\mathbf{\hat{u}}_i, \\[4pt] \mathbf{\hat{u}}\approx\mathbf{\hat{u}}^h&=\sum_{j=1}^{n}\pmb{\phi}_j\mathbf{\hat{u}}_j \end{align} \]

where \(n\) is the total number of DOFs, we obtain the discrete form:

\[ \label{eq:discre_weak_form} \sum_{j=1}^n \int_{\Omega} \varepsilon(\pmb{\phi}_i) : \mathbf{C} : \varepsilon(\pmb{\phi}_j) \, d\Omega \, \mathbf{\hat{u}}_j = \sum_{j=1}^n \omega^2 \int_{\Omega} \rho \pmb{\phi}_i \pmb{\phi}_j \, d\Omega \, \mathbf{\hat{u}}_j, \quad \forall i = 1,2,...,n \]

The stiffness and mass matrices are defined as:

\[ \label{eq:K_matrix} \mathbf{K}_{ij} = \int_{\Omega} \varepsilon(\pmb{\phi}_i) : \mathbf{C} : \varepsilon(\pmb{\phi}_j) \, d\Omega \]

\[ \label{eq:M_matrix} \mathbf{M}_{ij} = \int_{\Omega} \rho \pmb{\phi}_i^T \pmb{\phi}_j \, d\Omega \]

To distinguish the material parameter from the stiffness matrix, \(\textbf{K}\) is adopted for the stiffness matrix.

This leads to the generalized eigenvalue problem:

\[ \begin{equation} \mathbf{K} \mathbf{\hat{u}} = \omega^2 \mathbf{M} \mathbf{\hat{u}} \label{eq:generalized_eigen} \end{equation} \]

where \(\lambda = \omega^2\) are the eigenvalues.

Rigid body motion modes

\[ \label{eq:rigid_motion} \begin{aligned} \mathbf{r_1} &= \begin{bmatrix} 1\\0\\0\\1\\0\\0\\\vdots \end{bmatrix}_{3n\times1}, \quad \mathbf{r_2} = \begin{bmatrix} 0\\1\\0\\0\\1\\0\\\vdots \end{bmatrix}_{3n\times1}, \quad \mathbf{r_3} = \begin{bmatrix} 0\\0\\1\\0\\0\\1\\\vdots \end{bmatrix}_{3n\times1}, \\[2mm] \mathbf{r_4} &= \begin{bmatrix} 0\\-z_1\\y_1\\0\\-z_2\\y_2\\\vdots \end{bmatrix}_{3n\times1}, \quad \mathbf{r_5} = \begin{bmatrix} z_1\\0\\-x_1\\z_2\\0\\-x_2\\\vdots \end{bmatrix}_{3n\times1}, \quad \mathbf{r_6} = \begin{bmatrix} -y_1\\x_1\\0\\-y_2\\x_2\\0\\\vdots \end{bmatrix}_{3n\times1}. \end{aligned} \]

In free vibration problems, rigid body modes naturally appear with zero frequency. These modes satisfy \(\mathbf{K}\mathbf{r}=0\), indicating that \(\mathbf{r}\) represent the eigenvectors of \(\mathbf{K}\) with eigenvalues of 0, which can be derived intuitively without solving the eigen problem shown in Eq. \eqref{eq:generalized_eigen}. Above expressions of \(\mathbf{r_1},\dots,\mathbf{r_6}\) only exhibit the values for vertices in \(\mathbf{\hat{u}}\). In a higher-order case, the values for higher-order entities are 0, which are placed after the vertex values. Here \(n\) is the number of mesh vertices. Each vertex has 3 DOFs, so vectors are with the size of \(3n\times1\). The vectors \(\mathbf{r_1}\), \(\mathbf{r_2}\) and \(\mathbf{r_3}\) stand for translation modes, and \(\mathbf{r_4}\), \(\mathbf{r_5}\) and \(\mathbf{r_6}\) stand for rotation modes.

Implementation

Definition of operators and physical parameters

Since this is a generalized eigenvalue problem, we use the EPS solver from SLEPc rather than KSP. ElementsAndOps defines a class DomainEle that later defines the operators required regardless of the space dimension:

OpDomainGradGrad assembles the stiffness matrix \(\mathbf{K}\) (see Eq. \eqref{eq:K_matrix}), while OpDomainMass assembles the mass matrix \(\mathbf{M}\) (see Eq. \eqref{eq:M_matrix}).

template <int DIM> struct ElementsAndOps {};
template <> struct ElementsAndOps<2> {
};
template <> struct ElementsAndOps<3> {
using DomainEle = VolumeElementForcesAndSourcesCore;
};
constexpr int SPACE_DIM =
EXECUTABLE_DIMENSION; //< Space dimension of problem, mesh
using DomainEleOp = DomainEle::UserDataOperator;
using PostProcEle = PostProcBrokenMeshInMoab<DomainEle>;
FormsIntegrators<DomainEleOp>::Assembly<PETSC>::BiLinearForm<
GAUSS>::OpGradSymTensorGrad<1, SPACE_DIM, SPACE_DIM, 0>;
using OpDomainMass = FormsIntegrators<DomainEleOp>::Assembly<
constexpr int SPACE_DIM
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, FIELD_DIM > OpDomainMass
@ GAUSS
Gaussian quadrature integration.
@ PETSC
Standard PETSc assembly.
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpGradGrad< 1, 1, SPACE_DIM > OpDomainGradGrad
Definition helmholtz.cpp:25
[Operators_definition]
#define EXECUTABLE_DIMENSION
Definition plastic.cpp:13
double rho = 7829e-9; // density in kg/mm^3
double young_modulus = 2.07e8; // Young's modulus E in [kPa]
double poisson_ratio = 0.33;
double bulk_modulus_K
double shear_modulus_G
double young_modulus
Young modulus.
Definition plastic.cpp:126
double rho
Definition plastic.cpp:145
double poisson_ratio
Poisson ratio.
Definition plastic.cpp:127

Example structure and problem setup

The major functions required for the FEM implementation are readMesh(), setupProblem(), createCommonData(), boundaryCondition(), assembleSystem(), solveSystem(), outputResults() and checkResults(). The matrices \(\mathbf{M}\) and \(\mathbf{K}\) correspond to those defined in Eq. \eqref{eq:K_matrix} and Eq. \eqref{eq:M_matrix}, respectively. The pointer matDPtr is used to construct the fourth-order tensor \(\mathbf{C}\) in Eq. \eqref{eq:stiffness_coe}. rigidBodyMotion stores the six eigenvectors associated with the rigid body motion modes described in Eq. \eqref{eq:rigid_motion}. Each self-defined function in MoFEM starts with MoFEMFunctionBegin and ends with MoFEMFunctionReturn(0), with MoFEMErrorCode serving as the standard return type in MoFEM to report the success or failure of the function.

struct Example {
Example(MoFEM::Interface &m_field) : mField(m_field) {}
private:
boost::shared_ptr<MatrixDouble> matDPtr;
SmartPetscObj<Mat> M;
SmartPetscObj<Mat> K;
SmartPetscObj<EPS> ePS;
std::array<SmartPetscObj<Vec>, 6> rigidBodyMotion;
};
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
[Example]
Definition plastic.cpp:217
MoFEMErrorCode boundaryCondition()
[Set up problem]
MoFEMErrorCode assembleSystem()
[Push operators to pipeline]
MoFEMErrorCode readMesh()
[Run problem]
MoFEMErrorCode checkResults()
[Postprocess results]
MoFEMErrorCode solveSystem()
[Solve]
MoFEMErrorCode createCommonData()
[Set up problem]
Definition plastic.cpp:479
boost::shared_ptr< MatrixDouble > matDPtr
std::array< SmartPetscObj< Vec >, 6 > rigidBodyMotion
SmartPetscObj< Mat > M
MoFEMErrorCode runProblem()
[Run problem]
Definition plastic.cpp:255
SmartPetscObj< EPS > ePS
SmartPetscObj< Mat > K
MoFEM::Interface & mField
Reference to MoFEM interface.
Definition plastic.cpp:227
MoFEMErrorCode setupProblem()
[Run problem]
Definition plastic.cpp:274
MoFEMErrorCode outputResults()
[Solve]
Deprecated interface functions.

The Simple interface is called to load the mesh data, and register the solution field (displacement \(\mathbf{\hat{u}^h}\)) with the polynomial base AINSWORTH_BERNSTEIN_BEZIER_BASE approximated in the \(\mathrm{H}^1\) space.

MoFEMErrorCode Example::readMesh() {
auto simple = mField.getInterface<Simple>();
MOFEM_LOG("EXAMPLE", Sev::inform)
<< "Read mesh for problem in " << EXECUTABLE_DIMENSION;
CHKERR simple->getOptions();
CHKERR simple->loadFile();
}
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MOFEM_LOG(channel, severity)
Log.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
MoFEMErrorCode Example::setupProblem() {
auto *simple = mField.getInterface<Simple>();
// Add field
CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
CHKERR simple->setFieldOrder("U", order);
CHKERR simple->setUp();
}
@ AINSWORTH_BERNSTEIN_BEZIER_BASE
Definition definitions.h:64
@ H1
continuous field
Definition definitions.h:85
constexpr int order
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
constexpr int SPACE_DIM

Create common data

The default values of \(\rho\), \(E\) and \(\nu\) can be overriden from either the param_file.petsc file or the command line (if provided) by users, before the dependent variables \(K\) and \(G\) are calculated. Then the stiffness tensor \(\mathbf{C}\) is created using FTensor in the code. The relevant expressions are given in Eq. \eqref{eq:bulk_mod} - \eqref{eq:stiffness_coe}.

MoFEMErrorCode Example::createCommonData() {
CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-rho", &rho, PETSC_NULLPTR);
CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-young_modulus",
&young_modulus, PETSC_NULLPTR);
CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-poisson_ratio",
&poisson_ratio, PETSC_NULLPTR);
auto set_matrial_stiffens = [&]() {
auto t_D = getFTensor4DdgFromMat<SPACE_DIM, SPACE_DIM, 0>(*matDPtr);
const double A = (SPACE_DIM == 2)
: 1; // 2D plane strain or 3D
t_D(i, j, k, l) = 2 * shear_modulus_G * ((t_kd(i, k) ^ t_kd(j, l)) / 4.) +
A * (bulk_modulus_K - (2. / 3.) * shear_modulus_G) *
t_kd(i, j) * t_kd(k, l);
};
matDPtr = boost::make_shared<MatrixDouble>();
constexpr auto size_symm = (SPACE_DIM * (SPACE_DIM + 1)) / 2;
matDPtr->resize(1, size_symm * size_symm);
CHKERR set_matrial_stiffens();
}
Kronecker Delta class symmetric.
constexpr auto t_kd
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
PetscErrorCode PetscOptionsGetScalar(PetscOptions *, const char pre[], const char name[], PetscScalar *dval, PetscBool *set)
constexpr AssemblyType A
constexpr auto size_symm
Definition plastic.cpp:42

Apply boundary conditions

The six rigid body motion vectors are constructed as explained in Eq. \eqref{eq:rigid_motion}, with each assigned a value to every vertex DOF. getDofCoeffIdx() returns the coordinate index \(x,y\) or \(z\), while getPetscGlobalDofIdx() retrieves the corresponding global DOF index. lo_uid is used to access all the vertices in the mesh. The subsequent loop synchronizes the parallel processes by VecAssemblyBegin and VecAssemblyEnd. The functions VecGhostUpdateBegin and VecGhostUpdateEnd handle the exchange of information on the interfaces where data is not shared between adjacent entities.

MoFEMErrorCode Example::boundaryCondition() {
auto *simple = mField.getInterface<Simple>();
for (int n = 1; n != 6; ++n)
// Create space of vectors or rigid motion
auto problem_ptr = mField.get_problem(simple->getProblemName());
auto dofs = problem_ptr->getNumeredRowDofsPtr();
// Get all vertices
auto lo_uid =
DofEntity::getUniqueIdCalculate(0, get_id_for_min_type<MBVERTEX>());
auto hi = dofs->upper_bound(lo_uid);
std::array<double, 3> coords;
for (auto lo = dofs->lower_bound(lo_uid); lo != hi; ++lo) {
if ((*lo)->getPart() == mField.get_comm_rank()) {
auto ent = (*lo)->getEnt();
CHKERR mField.get_moab().get_coords(&ent, 1, coords.data());
if ((*lo)->getDofCoeffIdx() == 0) {
CHKERR VecSetValue(rigidBodyMotion[0], (*lo)->getPetscGlobalDofIdx(), 1,
INSERT_VALUES);
CHKERR VecSetValue(rigidBodyMotion[3], (*lo)->getPetscGlobalDofIdx(),
-coords[1], INSERT_VALUES);
if (SPACE_DIM == 3)
CHKERR VecSetValue(rigidBodyMotion[4], (*lo)->getPetscGlobalDofIdx(),
-coords[2], INSERT_VALUES);
} else if ((*lo)->getDofCoeffIdx() == 1) {
CHKERR VecSetValue(rigidBodyMotion[1], (*lo)->getPetscGlobalDofIdx(), 1,
INSERT_VALUES);
CHKERR VecSetValue(rigidBodyMotion[3], (*lo)->getPetscGlobalDofIdx(),
coords[0], INSERT_VALUES);
if (SPACE_DIM == 3)
CHKERR VecSetValue(rigidBodyMotion[5], (*lo)->getPetscGlobalDofIdx(),
-coords[2], INSERT_VALUES);
} else if ((*lo)->getDofCoeffIdx() == 2) {
if (SPACE_DIM == 3) {
CHKERR VecSetValue(rigidBodyMotion[2], (*lo)->getPetscGlobalDofIdx(),
1, INSERT_VALUES);
CHKERR VecSetValue(rigidBodyMotion[4], (*lo)->getPetscGlobalDofIdx(),
coords[0], INSERT_VALUES);
CHKERR VecSetValue(rigidBodyMotion[5], (*lo)->getPetscGlobalDofIdx(),
coords[1], INSERT_VALUES);
}
}
}
}
for (int n = 0; n != rigidBodyMotion.size(); ++n) {
CHKERR VecAssemblyBegin(rigidBodyMotion[n]);
CHKERR VecAssemblyEnd(rigidBodyMotion[n]);
CHKERR VecGhostUpdateBegin(rigidBodyMotion[n], INSERT_VALUES,
SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(rigidBodyMotion[n], INSERT_VALUES,
SCATTER_FORWARD);
}
}
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
virtual const Problem * get_problem(const std::string problem_name) const =0
Get the problem object.
const double n
refractive index of diffusive medium
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
virtual moab::Interface & get_moab()=0
virtual int get_comm_rank() const =0
auto & getNumeredRowDofsPtr() const
get access to numeredRowDofsPtr storing DOFs on rows

Assemble system

AddHOOps undertakes the same set of tasks as the following combination of individual operations:

auto det_ptr = boost::make_shared<VectorDouble>();
auto jac_ptr = boost::make_shared<MatrixDouble>();
auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
pipeline_mng->getOpDomainLhsPipeline().push_back(
new OpCalculateHOJac<SPACE_DIM>(jac_ptr));
pipeline_mng->getOpDomainLhsPipeline().push_back(
new OpInvertMatrix<SPACE_DIM>(jac_ptr, det_ptr, inv_jac_ptr));
pipeline_mng->getOpDomainLhsPipeline().push_back(
new OpSetHOInvJacToScalarBases<SPACE_DIM>(H1, inv_jac_ptr));
pipeline_mng->getOpDomainLhsPipeline().push_back(
new OpSetHOWeights(det_ptr));

The calculation above involves the Jacobian matrix \(J\) which maps the gradients expressed in the parent coordinate system to those in the global coordinate system, which are included in AddHOOps now. In this case, the two fields \(\delta\mathbf{\hat{u}}\) and \(\mathbf{\hat{u}}\) passed into OpDomainGradGrad below correspond to the shape functions \(\pmb{\phi}_i\) and \(\pmb{\phi}_j\) in Eq. \eqref{eq:K_matrix}. As \(\varepsilon\) serves as a function mapping the fields to their gradients, OpDomainGradGrad is doing exactly what is shown in Eq. \eqref{eq:K_matrix}. Similarly, OpDomainMass performs the operation described in Eq. \eqref{eq:M_matrix}. The difference in the integration order between the two operators arises from the presence of the two gradient operations in OpDomainGradGrad. Its quadrature order is therefore reduced by two relative to that of OpDomainMass. As we are dealing with a generalized eigenvalue problem, \(M\) and \(K\) need to be explicitly assigned into PipelineManager by pipeline_mng->getDomainLhsFE()->B = M and pipeline_mng->getDomainLhsFE()->B = K. MatZeroEntries is called to clear the matrix before assembly, and MatAssemblyBegin and MatAssemblyEnd are used to finalize the assembly process.

MoFEMErrorCode Example::assembleSystem() {
auto *simple = mField.getInterface<Simple>();
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto dm = simple->getDM();
M = matDuplicate(K, MAT_SHARE_NONZERO_PATTERN);
auto calculate_stiffness_matrix = [&]() {
pipeline_mng->getDomainLhsFE().reset();
pipeline_mng->getOpDomainLhsPipeline(), {H1});
pipeline_mng->getOpDomainLhsPipeline().push_back(
new OpDomainGradGrad("U", "U", matDPtr));
auto integration_rule = [](int, int, int approx_order) {
return 2 * (approx_order - 1);
};
CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
pipeline_mng->getDomainLhsFE()->B = K;
CHKERR MatZeroEntries(K);
CHKERR pipeline_mng->loopFiniteElements();
CHKERR MatAssemblyBegin(K, MAT_FINAL_ASSEMBLY);
CHKERR MatAssemblyEnd(K, MAT_FINAL_ASSEMBLY);
};
auto calculate_mass_matrix = [&]() {
pipeline_mng->getDomainLhsFE().reset();
pipeline_mng->getOpDomainLhsPipeline(), {H1});
auto get_rho = [](const double, const double, const double) { return rho; };
pipeline_mng->getOpDomainLhsPipeline().push_back(
new OpDomainMass("U", "U", get_rho));
auto integration_rule = [](int, int, int approx_order) {
return 2 * approx_order;
};
CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
CHKERR MatZeroEntries(M);
pipeline_mng->getDomainLhsFE()->B = M;
CHKERR pipeline_mng->loopFiniteElements();
CHKERR MatAssemblyBegin(M, MAT_FINAL_ASSEMBLY);
CHKERR MatAssemblyEnd(M, MAT_FINAL_ASSEMBLY);
};
CHKERR calculate_stiffness_matrix();
CHKERR calculate_mass_matrix();
}
auto integration_rule
PetscErrorCode DMCreateMatrix_MoFEM(DM dm, Mat *M)
Definition DMMoFEM.cpp:1188
SmartPetscObj< Mat > matDuplicate(Mat mat, MatDuplicateOption op)
static constexpr int approx_order

Solve system

An EPS solver is applied with proper configurations applied. EPSSetProblemType(ePS, EPS_GHEP) specifies the problem is a generalized Hermitian eigenvalue problem, and EPS_SMALLEST_MAGNITUDE in EPSSetWhichEigenpairs tells only the eigenpairs with the smallest eigenvalues are required for computing. The six rigid body motion modes are eliminated by declaring them as a nullspace by EPSSetDeflationSpace. The print_info uses MOFEM_LOG_C for desired terminal output. Using plain std::cout is discouraged because it will not handle output properly when running in parallel.

MoFEMErrorCode Example::solveSystem() {
auto create_eps = [](MPI_Comm comm) {
EPS eps;
CHKERR EPSCreate(comm, &eps);
return SmartPetscObj<EPS>(eps);
};
auto deflate_vectors = [&]() {
// Deflate vectors
std::array<Vec, 6> deflate_vectors;
for (int n = 0; n != 6; ++n) {
deflate_vectors[n] = rigidBodyMotion[n];
}
CHKERR EPSSetDeflationSpace(ePS, 6, &deflate_vectors[0]);
};
auto print_info = [&]() {
ST st;
EPSType type;
PetscReal tol;
PetscInt nev, maxit, its;
// Optional: Get some information from the solver and display it
CHKERR EPSGetIterationNumber(ePS, &its);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
" Number of iterations of the method: %d", its);
CHKERR EPSGetST(ePS, &st);
CHKERR EPSGetType(ePS, &type);
MOFEM_LOG_C("EXAMPLE", Sev::inform, " Solution method: %s", type);
CHKERR EPSGetDimensions(ePS, &nev, NULL, NULL);
MOFEM_LOG_C("EXAMPLE", Sev::inform, " Number of requested eigenvalues: %d",
nev);
CHKERR EPSGetTolerances(ePS, &tol, &maxit);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
" Stopping condition: tol=%.4g, maxit=%d", (double)tol, maxit);
PetscScalar eigr, eigi;
for (int nn = 0; nn < nev; nn++) {
CHKERR EPSGetEigenpair(ePS, nn, &eigr, &eigi, PETSC_NULLPTR,
PETSC_NULLPTR);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
" ncov = %d eigr = %.4g eigi = %.4g (inv eigr = %.4g)", nn,
eigr, eigi, 1. / eigr);
}
};
auto setup_eps = [&]() {
CHKERR EPSSetProblemType(ePS, EPS_GHEP);
CHKERR EPSSetWhichEigenpairs(ePS, EPS_SMALLEST_MAGNITUDE);
CHKERR EPSSetFromOptions(ePS);
};
// Create eigensolver context
ePS = create_eps(mField.get_comm());
CHKERR EPSSetOperators(ePS, K, M);
// Setup eps
CHKERR setup_eps();
// Deflate vectors
CHKERR deflate_vectors();
// Solve problem
CHKERR EPSSolve(ePS);
// Print info
CHKERR print_info();
}
std::string type
#define MOFEM_LOG_C(channel, severity, format,...)
double tol
const double eps
Definition HenckyOps.hpp:13
virtual MPI_Comm & get_comm() const =0

Postprocess

This part handles postprocessing and writing the results to output files. Three quantities are written, displacement \(u\), strain \(\varepsilon\) and stress \(\sigma\). These are accessed through pointers such as u_ptr, strain_ptr, and stress_ptr. Statements like post_proc_fe->getOpPtrVector().push_back(new Opxxx(....)) add postprocessing operators that take the FEM solution and compute derived quantities, such as strain and stress. The operators Opxxxx() can either be built-in or user-defined. The call post_proc_fe->getOpPtrVector().push_back(new OpPPMap()) maps the output variables onto the mesh. The function EPSGetEigenpair retrives the eigenvalues and eigenvectors and stores them in eigr (real part of the eigenvalues), eigi (imaginary part of the eigenvalues) and D (real part of the eigenvectors). The imaginary part of eigenvectors are omitted as displacement in the real world can't be complex numbers. DMoFEMMeshToLocalVector transfers data either from a vector to the mesh or from the mesh to a vector, depending on whether the flag is SCATTER_REVERSE or SCATTER_FORWARD.

MoFEMErrorCode Example::outputResults() {
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto *simple = mField.getInterface<Simple>();
auto post_proc_fe = boost::make_shared<PostProcEle>(mField);
post_proc_fe->getOpPtrVector(), {H1});
auto u_ptr = boost::make_shared<MatrixDouble>();
auto grad_ptr = boost::make_shared<MatrixDouble>();
auto strain_ptr = boost::make_shared<MatrixDouble>();
auto stress_ptr = boost::make_shared<MatrixDouble>();
post_proc_fe->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
post_proc_fe->getOpPtrVector().push_back(
new OpCalculateVectorFieldGradient<SPACE_DIM, SPACE_DIM>("U", grad_ptr));
post_proc_fe->getOpPtrVector().push_back(
new OpSymmetrizeTensor<SPACE_DIM>(grad_ptr, strain_ptr));
post_proc_fe->getOpPtrVector().push_back(
new OpTensorTimesSymmetricTensor<SPACE_DIM, SPACE_DIM>(
strain_ptr, stress_ptr, matDPtr));
using OpPPMap = OpPostProcMapInMoab<SPACE_DIM, SPACE_DIM>;
post_proc_fe->getOpPtrVector().push_back(
new OpPPMap(
post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
OpPPMap::DataMapVec{},
OpPPMap::DataMapMat{{"U", u_ptr}},
OpPPMap::DataMapMat{{"STRAIN", strain_ptr}, {"STRESS", stress_ptr}}
)
);
pipeline_mng->getDomainPostProcFE() = post_proc_fe;
auto dm = simple->getDM();
auto D = createDMVector(dm);
PetscInt nev;
CHKERR EPSGetDimensions(ePS, &nev, NULL, NULL);
PetscScalar eigr, eigi, nrm2r;
for (int nn = 0; nn < nev; nn++) {
CHKERR EPSGetEigenpair(ePS, nn, &eigr, &eigi, D, PETSC_NULLPTR);
CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecNorm(D, NORM_2, &nrm2r);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
" ncov = %d omega2 = %.8g omega = %.8g frequency = %.8g", nn,
eigr, std::sqrt(std::abs(eigr)),
std::sqrt(std::abs(eigr)) / (2 * M_PI));
CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
CHKERR pipeline_mng->loopFiniteElementsPostProc();
post_proc_fe->writeFile("out_eig_" + boost::lexical_cast<std::string>(nn) +
".h5m");
}
}
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
double D
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
std::map< std::string, boost::shared_ptr< MatrixDouble > > DataMapMat

Validate results

Check if the first eigenvalue matches the analytically predicted value.

MoFEMErrorCode Example::checkResults() {
PetscBool test_flg = PETSC_FALSE;
CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test", &test_flg,
PETSC_NULLPTR);
if (test_flg) {
PetscScalar eigr, eigi;
CHKERR EPSGetEigenpair(ePS, 0, &eigr, &eigi, PETSC_NULLPTR, PETSC_NULLPTR);
constexpr double regression_value = 12579658;
if (fabs(eigr - regression_value) > 1)
SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
"Regression test faileed; wrong eigen value.");
}
}
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)

Main function

This is the main function of the tutorial. No modifications are needed.

int main(int argc, char *argv[]) {
// Initialisation of MoFEM/PETSc and MOAB data structures
const char param_file[] = "param_file.petsc";
SlepcInitialize(&argc, &argv, param_file, help);
MoFEM::Core::Initialize(&argc, &argv, param_file, help);
// Add logging channel for example
auto core_log = logging::core::get();
core_log->add_sink(
LogManager::createSink(LogManager::getStrmWorld(), "EXAMPLE"));
LogManager::setLog("EXAMPLE");
MOFEM_LOG_TAG("EXAMPLE", "example");
try {
//! [Register MoFEM discrete manager in PETSc]
DMType dm_name = "DMMOFEM";
CHKERR DMRegister_MoFEM(dm_name);
//! [Register MoFEM discrete manager in PETSc
//! [Create MoAB]
moab::Core mb_instance; ///< mesh database
moab::Interface &moab = mb_instance; ///< mesh database interface
//! [Create MoAB]
//! [Create MoFEM]
MoFEM::Core core(moab); ///< finite element database
MoFEM::Interface &m_field = core; ///< finite element database insterface
//! [Create MoFEM]
//! [Example]
Example ex(m_field);
CHKERR ex.runProblem();
//! [Example]
}
SlepcFinalize();
}
static char help[]
int main()
#define CATCH_ERRORS
Catch errors.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
Core (interface) class.
Definition Core.hpp:83
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123

Results

The mesh is shown in Figure 1. The vibration modes corresponding to the six smallest natural frequencies are presented in Figure 2(a)-(f). A comparison between the Calculix and our implementation is given in Table 1. As shown, the deviations in our results are less than 1%, demonstrating good agreement between the two approaches.

Figure 1: Geometry of the problem


(a) Mode 1

(b) Mode 2

(c) Mode 3

(d) Mode 4

(e) Mode 5

(f) Mode 6
Figure 2: The 1st to 6th vibration modes for the tuning fork.

Table 1: Natural frequencies (Hz) of the tuning fork modes
Mode Calculix MoFEM
1 440.05 442.98
2 673.51 676.92
3 1689.30 1692.00
4 1825.55 1826.71
5 2777.73 2790.89

Source code

/**
* \file eigen_elastic.cpp
* \example mofem/tutorials/vec-1_eigen_elasticity/eigen_elastic.cpp
*
* Calculate natural frequencies in 2d and 3d problems.
*
*/
#include <MoFEM.hpp>
#undef EPS
#include <slepceps.h>
using namespace MoFEM;
//! [Operators_definition]
template <int DIM> struct ElementsAndOps {};
template <> struct ElementsAndOps<2> {
};
template <> struct ElementsAndOps<3> {
};
constexpr int SPACE_DIM =
EXECUTABLE_DIMENSION; //< Space dimension of problem, mesh
using DomainEleOp = DomainEle::UserDataOperator;
GAUSS>::OpGradSymTensorGrad<1, SPACE_DIM, SPACE_DIM, 0>;
//! [Operators_definition]
//! [Physical_parameters]
double rho = 7829e-9; // density in kg/mm^3
double young_modulus = 2.07e8; // Young's modulus E in [kPa]
double poisson_ratio = 0.33;
//! [Physical_parameters]
int order = 2;
//! [Create Example_struct]
struct Example {
Example(MoFEM::Interface &m_field) : mField(m_field) {}
private:
boost::shared_ptr<MatrixDouble> matDPtr;
std::array<SmartPetscObj<Vec>, 6> rigidBodyMotion;
};
//! [Create Example_struct]
//! [Create common data]
CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-rho", &rho, PETSC_NULLPTR);
CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-young_modulus",
&young_modulus, PETSC_NULLPTR);
CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-poisson_ratio",
&poisson_ratio, PETSC_NULLPTR);
auto set_matrial_stiffens = [&]() {
auto t_D = getFTensor4DdgFromMat<SPACE_DIM, SPACE_DIM, 0>(*matDPtr);
const double A = (SPACE_DIM == 2)
: 1; // 2D plane strain or 3D
t_D(i, j, k, l) = 2 * shear_modulus_G * ((t_kd(i, k) ^ t_kd(j, l)) / 4.) +
A * (bulk_modulus_K - (2. / 3.) * shear_modulus_G) *
t_kd(i, j) * t_kd(k, l);
};
matDPtr = boost::make_shared<MatrixDouble>();
constexpr auto size_symm = (SPACE_DIM * (SPACE_DIM + 1)) / 2;
matDPtr->resize(1, size_symm * size_symm);
CHKERR set_matrial_stiffens();
}
//! [Create common data]
//! [Run problem]
}
//! [Run problem]
//! [Read mesh]
MOFEM_LOG("EXAMPLE", Sev::inform)
<< "Read mesh for problem in " << EXECUTABLE_DIMENSION;
CHKERR simple->loadFile();
}
//! [Read mesh]
//! [Set up problem]
// Add field
CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
CHKERR simple->setFieldOrder("U", order);
CHKERR simple->setUp();
}
//! [Set up problem]
//! [Boundary condition]
for (int n = 1; n != 6; ++n)
// Create space of vectors or rigid motion
auto problem_ptr = mField.get_problem(simple->getProblemName());
auto dofs = problem_ptr->getNumeredRowDofsPtr();
// Get all vertices
auto lo_uid =
DofEntity::getUniqueIdCalculate(0, get_id_for_min_type<MBVERTEX>());
auto hi = dofs->upper_bound(lo_uid);
std::array<double, 3> coords;
for (auto lo = dofs->lower_bound(lo_uid); lo != hi; ++lo) {
if ((*lo)->getPart() == mField.get_comm_rank()) {
auto ent = (*lo)->getEnt();
CHKERR mField.get_moab().get_coords(&ent, 1, coords.data());
if ((*lo)->getDofCoeffIdx() == 0) {
CHKERR VecSetValue(rigidBodyMotion[0], (*lo)->getPetscGlobalDofIdx(), 1,
INSERT_VALUES);
CHKERR VecSetValue(rigidBodyMotion[3], (*lo)->getPetscGlobalDofIdx(),
-coords[1], INSERT_VALUES);
if (SPACE_DIM == 3)
CHKERR VecSetValue(rigidBodyMotion[4], (*lo)->getPetscGlobalDofIdx(),
-coords[2], INSERT_VALUES);
} else if ((*lo)->getDofCoeffIdx() == 1) {
CHKERR VecSetValue(rigidBodyMotion[1], (*lo)->getPetscGlobalDofIdx(), 1,
INSERT_VALUES);
CHKERR VecSetValue(rigidBodyMotion[3], (*lo)->getPetscGlobalDofIdx(),
coords[0], INSERT_VALUES);
if (SPACE_DIM == 3)
CHKERR VecSetValue(rigidBodyMotion[5], (*lo)->getPetscGlobalDofIdx(),
-coords[2], INSERT_VALUES);
} else if ((*lo)->getDofCoeffIdx() == 2) {
if (SPACE_DIM == 3) {
CHKERR VecSetValue(rigidBodyMotion[2], (*lo)->getPetscGlobalDofIdx(),
1, INSERT_VALUES);
CHKERR VecSetValue(rigidBodyMotion[4], (*lo)->getPetscGlobalDofIdx(),
coords[0], INSERT_VALUES);
CHKERR VecSetValue(rigidBodyMotion[5], (*lo)->getPetscGlobalDofIdx(),
coords[1], INSERT_VALUES);
}
}
}
}
for (int n = 0; n != rigidBodyMotion.size(); ++n) {
CHKERR VecAssemblyBegin(rigidBodyMotion[n]);
CHKERR VecAssemblyEnd(rigidBodyMotion[n]);
CHKERR VecGhostUpdateBegin(rigidBodyMotion[n], INSERT_VALUES,
SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(rigidBodyMotion[n], INSERT_VALUES,
SCATTER_FORWARD);
}
}
//! [Boundary condition]
//! [Assemble system]
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto dm = simple->getDM();
M = matDuplicate(K, MAT_SHARE_NONZERO_PATTERN);
auto calculate_stiffness_matrix = [&]() {
pipeline_mng->getDomainLhsFE().reset();
pipeline_mng->getOpDomainLhsPipeline(), {H1});
pipeline_mng->getOpDomainLhsPipeline().push_back(
new OpDomainGradGrad("U", "U", matDPtr));
auto integration_rule = [](int, int, int approx_order) {
return 2 * (approx_order - 1);
};
CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
pipeline_mng->getDomainLhsFE()->B = K;
CHKERR MatZeroEntries(K);
CHKERR pipeline_mng->loopFiniteElements();
CHKERR MatAssemblyBegin(K, MAT_FINAL_ASSEMBLY);
CHKERR MatAssemblyEnd(K, MAT_FINAL_ASSEMBLY);
};
auto calculate_mass_matrix = [&]() {
pipeline_mng->getDomainLhsFE().reset();
pipeline_mng->getOpDomainLhsPipeline(), {H1});
auto get_rho = [](const double, const double, const double) { return rho; };
pipeline_mng->getOpDomainLhsPipeline().push_back(
new OpDomainMass("U", "U", get_rho));
auto integration_rule = [](int, int, int approx_order) {
return 2 * approx_order;
};
CHKERR pipeline_mng->setDomainLhsIntegrationRule(integration_rule);
CHKERR MatZeroEntries(M);
pipeline_mng->getDomainLhsFE()->B = M;
CHKERR pipeline_mng->loopFiniteElements();
CHKERR MatAssemblyBegin(M, MAT_FINAL_ASSEMBLY);
CHKERR MatAssemblyEnd(M, MAT_FINAL_ASSEMBLY);
};
CHKERR calculate_stiffness_matrix();
CHKERR calculate_mass_matrix();
}
//! [Assemble system]
//! [Solve]
auto create_eps = [](MPI_Comm comm) {
EPS eps;
CHKERR EPSCreate(comm, &eps);
};
auto deflate_vectors = [&]() {
// Deflate vectors
std::array<Vec, 6> deflate_vectors;
for (int n = 0; n != 6; ++n) {
deflate_vectors[n] = rigidBodyMotion[n];
}
CHKERR EPSSetDeflationSpace(ePS, 6, &deflate_vectors[0]);
};
auto print_info = [&]() {
ST st;
EPSType type;
PetscReal tol;
PetscInt nev, maxit, its;
// Optional: Get some information from the solver and display it
CHKERR EPSGetIterationNumber(ePS, &its);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
" Number of iterations of the method: %d", its);
CHKERR EPSGetST(ePS, &st);
CHKERR EPSGetType(ePS, &type);
MOFEM_LOG_C("EXAMPLE", Sev::inform, " Solution method: %s", type);
CHKERR EPSGetDimensions(ePS, &nev, NULL, NULL);
MOFEM_LOG_C("EXAMPLE", Sev::inform, " Number of requested eigenvalues: %d",
nev);
CHKERR EPSGetTolerances(ePS, &tol, &maxit);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
" Stopping condition: tol=%.4g, maxit=%d", (double)tol, maxit);
PetscScalar eigr, eigi;
for (int nn = 0; nn < nev; nn++) {
CHKERR EPSGetEigenpair(ePS, nn, &eigr, &eigi, PETSC_NULLPTR,
PETSC_NULLPTR);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
" ncov = %d eigr = %.4g eigi = %.4g (inv eigr = %.4g)", nn,
eigr, eigi, 1. / eigr);
}
};
auto setup_eps = [&]() {
CHKERR EPSSetProblemType(ePS, EPS_GHEP);
CHKERR EPSSetWhichEigenpairs(ePS, EPS_SMALLEST_MAGNITUDE);
CHKERR EPSSetFromOptions(ePS);
};
// Create eigensolver context
ePS = create_eps(mField.get_comm());
CHKERR EPSSetOperators(ePS, K, M);
// Setup eps
CHKERR setup_eps();
// Deflate vectors
CHKERR deflate_vectors();
// Solve problem
CHKERR EPSSolve(ePS);
// Print info
CHKERR print_info();
}
//! [Solve]
//! [Postprocess results]
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto post_proc_fe = boost::make_shared<PostProcEle>(mField);
post_proc_fe->getOpPtrVector(), {H1});
auto u_ptr = boost::make_shared<MatrixDouble>();
auto grad_ptr = boost::make_shared<MatrixDouble>();
auto strain_ptr = boost::make_shared<MatrixDouble>();
auto stress_ptr = boost::make_shared<MatrixDouble>();
post_proc_fe->getOpPtrVector().push_back(
post_proc_fe->getOpPtrVector().push_back(
post_proc_fe->getOpPtrVector().push_back(
new OpSymmetrizeTensor<SPACE_DIM>(grad_ptr, strain_ptr));
post_proc_fe->getOpPtrVector().push_back(
strain_ptr, stress_ptr, matDPtr));
post_proc_fe->getOpPtrVector().push_back(
new OpPPMap(
post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
OpPPMap::DataMapVec{},
OpPPMap::DataMapMat{{"U", u_ptr}},
OpPPMap::DataMapMat{{"STRAIN", strain_ptr}, {"STRESS", stress_ptr}}
)
);
pipeline_mng->getDomainPostProcFE() = post_proc_fe;
auto dm = simple->getDM();
auto D = createDMVector(dm);
PetscInt nev;
CHKERR EPSGetDimensions(ePS, &nev, NULL, NULL);
PetscScalar eigr, eigi, nrm2r;
for (int nn = 0; nn < nev; nn++) {
CHKERR EPSGetEigenpair(ePS, nn, &eigr, &eigi, D, PETSC_NULLPTR);
CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecNorm(D, NORM_2, &nrm2r);
MOFEM_LOG_C("EXAMPLE", Sev::inform,
" ncov = %d omega2 = %.8g omega = %.8g frequency = %.8g", nn,
eigr, std::sqrt(std::abs(eigr)),
std::sqrt(std::abs(eigr)) / (2 * M_PI));
CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
CHKERR pipeline_mng->loopFiniteElementsPostProc();
post_proc_fe->writeFile("out_eig_" + boost::lexical_cast<std::string>(nn) +
".h5m");
}
}
//! [Postprocess results]
//! [Check]
PetscBool test_flg = PETSC_FALSE;
CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-test", &test_flg,
PETSC_NULLPTR);
if (test_flg) {
PetscScalar eigr, eigi;
CHKERR EPSGetEigenpair(ePS, 0, &eigr, &eigi, PETSC_NULLPTR, PETSC_NULLPTR);
constexpr double regression_value = 12579658;
if (fabs(eigr - regression_value) > 1)
SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
"Regression test faileed; wrong eigen value.");
}
}
//! [Check]
static char help[] = "...\n\n";
//! [Main]
int main(int argc, char *argv[]) {
// Initialisation of MoFEM/PETSc and MOAB data structures
const char param_file[] = "param_file.petsc";
SlepcInitialize(&argc, &argv, param_file, help);
MoFEM::Core::Initialize(&argc, &argv, param_file, help);
// Add logging channel for example
auto core_log = logging::core::get();
core_log->add_sink(
LogManager::createSink(LogManager::getStrmWorld(), "EXAMPLE"));
LogManager::setLog("EXAMPLE");
MOFEM_LOG_TAG("EXAMPLE", "example");
try {
//! [Register MoFEM discrete manager in PETSc]
DMType dm_name = "DMMOFEM";
//! [Register MoFEM discrete manager in PETSc
//! [Create MoAB]
moab::Core mb_instance; ///< mesh database
moab::Interface &moab = mb_instance; ///< mesh database interface
//! [Create MoAB]
//! [Create MoFEM]
MoFEM::Core core(moab); ///< finite element database
MoFEM::Interface &m_field = core; ///< finite element database insterface
//! [Create MoFEM]
//! [Example]
Example ex(m_field);
CHKERR ex.runProblem();
//! [Example]
}
SlepcFinalize();
}
//! [Main]
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for MatrixDouble vector field values calculation.
Post post-proc data at points from hash maps.
Operator for symmetrizing tensor fields.
PipelineManager interface.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode addDomainField(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_ZERO, int verb=-1)
Add field on domain.
Definition Simple.cpp:261
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
intrusive_ptr for managing petsc objects