v0.16.0
Loading...
Searching...
No Matches
mofem/atom_tests/higher_derivatives.cpp

Testing higher derivatives of base functions

/**
* \example mofem/atom_tests/higher_derivatives.cpp
*
* Testing higher derivatives of base functions
*
*/
#include <MoFEM.hpp>
using namespace MoFEM;
static char help[] = "...\n\n";
constexpr char FIELD_NAME[] = "U";
constexpr int BASE_DIM = 1;
constexpr int FIELD_DIM = 1;
constexpr int SPACE_DIM = 2;
template <int DIM> struct ElementsAndOps {};
template <> struct ElementsAndOps<2> {
using DomainEleOp = DomainEle::UserDataOperator;
};
using DomainEle = ElementsAndOps<SPACE_DIM>::DomainEle; ///< Finite elenent type
using DomainEleOp =
DomainEle::UserDataOperator; ///< Finire element operator type
using EntData = EntitiesFieldData::EntData; ///< Data on entities
/**
* @brief Function to approximate
*
*/
auto fun = [](const double x, const double y, const double z) {
return x * x + y * y + x * y + pow(x, 3) + pow(y, 3) + pow(x, 4) + pow(y, 4);
};
/**
* @brief Function derivative
*
*/
auto diff_fun = [](const double x, const double y, const double z) {
2 * x + y + 3 * pow(x, 2) + 4 * pow(x, 3),
2 * y + x + 3 * pow(y, 2) + 4 * pow(y, 3)};
};
/**
* @brief Function second derivative
*
*/
auto diff2_fun = [](const double x, const double y, const double z) {
2 + 6 * x + 12 * pow(x, 2), 1.,
1., 2 + 6 * y + 12 * pow(y, 2)};
};
/**
* @brief OPerator to integrate mass matrix for least square approximation
*
*/
/**
* @brief Operator to integrate the right hand side matrix for the problem
*
*/
struct AtomTest {
AtomTest(MoFEM::Interface &m_field) : mField(m_field) {}
private:
/**
* @brief Collected data use d by operator to evaluate errors for the test
*
*/
struct CommonData {
boost::shared_ptr<MatrixDouble> invJacPtr;
boost::shared_ptr<VectorDouble> approxVals;
boost::shared_ptr<MatrixDouble> approxGradVals;
boost::shared_ptr<MatrixDouble> approxHessianVals;
};
/**
* @brief Operator to evaluate errors
*
*/
struct OpError;
};
/**
* @brief Operator to evaluate errors
*
*/
struct AtomTest::OpError : public DomainEleOp {
boost::shared_ptr<CommonData> commonDataPtr;
OpError(boost::shared_ptr<CommonData> &common_data_ptr)
: DomainEleOp(FIELD_NAME, OPROW), commonDataPtr(common_data_ptr) {
std::fill(doEntities.begin(), doEntities.end(), false);
doEntities[MBVERTEX] = true;
}
MoFEMErrorCode doWork(int side, EntityType type, EntData &data) {
const int nb_integration_pts = getGaussPts().size2();
auto t_w = getFTensor0IntegrationWeight(); // ger integration weights
auto t_val = getFTensor0FromVec(*(
commonDataPtr->approxVals)); // get function approximation at gauss pts
auto t_grad_val = getFTensor1FromMat<SPACE_DIM>(
->approxGradVals)); // get gradient of approximation at gauss pts
auto t_hessian_val = getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(
*(commonDataPtr)->approxHessianVals); // get hessian of approximation
// at integration pts
auto t_inv_jac = getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(
*(commonDataPtr->invJacPtr)); // get inverse of element jacobian
auto t_coords = getFTensor1CoordsAtGaussPts(); // get coordinates of
// integration points
// Indices used for tensor operations
FTensor::Index<'i', 2> i;
FTensor::Index<'j', 2> j;
FTensor::Index<'k', 2> k;
FTensor::Index<'l', 2> l;
const double volume = getMeasure(); // get finite element area
std::array<double, 3> error = {0, 0,
0}; // array for storing operator errors
for (int gg = 0; gg != nb_integration_pts; ++gg) {
const double alpha = t_w * volume;
// Calculate errors
double diff = t_val - fun(t_coords(0), t_coords(1), t_coords(2));
error[0] += alpha * pow(diff, 2);
auto t_diff_grad = diff_fun(t_coords(0), t_coords(1), t_coords(2));
t_diff_grad(i) -= t_grad_val(i);
error[1] += alpha * t_diff_grad(i) *
t_diff_grad(i); // note push forward derivatives
MOFEM_LOG("SELF", Sev::noisy) << "t_hessian_val " << t_hessian_push;
// hessian expected to have symmetry
if (std::abs(t_hessian_val(0, 1) - t_hessian_val(1, 0)) >
std::numeric_limits<float>::epsilon()) {
MOFEM_LOG("SELF", Sev::error) << "t_hessian_val " << t_hessian_val;
SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
"Hessian should be symmetric");
}
auto t_diff_hessian = diff2_fun(t_coords(0), t_coords(1), t_coords(2));
t_diff_hessian(i, j) -= t_hessian_val(i, j);
error[2] = t_diff_hessian(i, j) * t_diff_hessian(i, j);
// move data to next integration point
++t_w;
++t_val;
++t_grad_val;
++t_hessian_val;
++t_inv_jac;
++t_coords;
}
// assemble error vector
std::array<int, 3> index = {0, 1, 2};
CHKERR VecSetValues(commonDataPtr->L2Vec, 3, index.data(), error.data(),
ADD_VALUES);
}
};
//! [Run programme]
}
//! [Run programme]
//! [Read mesh]
}
//! [Read mesh]
//! [Set up problem]
// Add field
constexpr int order = 4;
}
//! [Set up problem]
//! [Push operators to pipeline]
auto rule = [](int, int, int p) -> int { return 2 * p; };
CHKERR pipeline_mng->setDomainLhsIntegrationRule(rule);
CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
auto beta = [](const double, const double, const double) { return 1; };
pipeline_mng->getOpDomainLhsPipeline().push_back(
pipeline_mng->getOpDomainRhsPipeline().push_back(
}
//! [Push operators to pipeline]
//! [Solve]
MOFEM_LOG("WORLD", Sev::inform) << "Solve problem";
auto solver = pipeline_mng->createKSP();
CHKERR KSPSetFromOptions(solver);
CHKERR KSPSetUp(solver);
auto dm = simpleInterface->getDM();
auto D = createDMVector(dm);
auto F = vectorDuplicate(D);
CHKERR KSPSolve(solver, F, D);
CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
}
//! [Check results]
auto rule = [](int, int, int p) -> int { return 2 * p; };
CHKERR pipeline_mng->setEvaluationIntegrationRule(rule);
// create data structures for operator
auto common_data_ptr = boost::make_shared<CommonData>();
common_data_ptr->L2Vec = createVectorMPI(
mField.get_comm(), (!mField.get_comm_rank()) ? 3 : 0, 3);
common_data_ptr->approxVals = boost::make_shared<VectorDouble>();
common_data_ptr->approxGradVals = boost::make_shared<MatrixDouble>();
common_data_ptr->approxHessianVals = boost::make_shared<MatrixDouble>();
// create data strutires for evaluation of higher order derivatives
auto base_mass = boost::make_shared<MatrixDouble>();
auto data_l2 = boost::make_shared<EntitiesFieldData>(MBENTITYSET);
auto jac_ptr = boost::make_shared<MatrixDouble>();
auto det_ptr = boost::make_shared<VectorDouble>();
auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
common_data_ptr->invJacPtr = inv_jac_ptr;
// calculate jacobian at integration points
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpCalculateHOJacForFace(jac_ptr));
// calculate incerse of jacobian at integration points
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpInvertMatrix<SPACE_DIM>(jac_ptr, det_ptr, inv_jac_ptr));
// calculate mass matrix to project derivatives
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpBaseDerivativesMass<BASE_DIM>(base_mass, data_l2,
// calculate second derivative of base functions, i.e. hessian
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpBaseDerivativesNext<BASE_DIM>(BaseDerivatives::SecondDerivative,
base_mass, data_l2,
// calculate third derivative
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpBaseDerivativesNext<BASE_DIM>(BaseDerivatives::ThirdDerivative,
base_mass, data_l2,
// calculate forth derivative
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpBaseDerivativesNext<BASE_DIM>(BaseDerivatives::ForthDerivative,
base_mass, data_l2,
// push first base derivatives tp physical element shape
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpSetInvJacH1ForFace<1>(inv_jac_ptr));
// push second base derivatives tp physical element shape
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpSetInvJacH1ForFace<2>(inv_jac_ptr));
// calculate value of function at integration points
pipeline_mng->getOpEvaluationPipeline().push_back(
common_data_ptr->approxVals));
// calculate gradient at integration points
pipeline_mng->getOpEvaluationPipeline().push_back(
FIELD_NAME, common_data_ptr->approxGradVals));
// calculate hessian at integration points
pipeline_mng->getOpEvaluationPipeline().push_back(
FIELD_NAME, common_data_ptr->approxHessianVals));
//FIXME: Note third and forth derivative is calculated but not properly tested
// push operator to evaluate errors
pipeline_mng->getOpEvaluationPipeline().push_back(
new OpError(common_data_ptr));
// zero error vector and iterate over all elements on the mesh
CHKERR VecZeroEntries(common_data_ptr->L2Vec);
// assemble error vector
CHKERR VecAssemblyBegin(common_data_ptr->L2Vec);
CHKERR VecAssemblyEnd(common_data_ptr->L2Vec);
// check if errors are small and print results
constexpr double eps = 1e-8;
const double *array;
CHKERR VecGetArrayRead(common_data_ptr->L2Vec, &array);
MOFEM_LOG_C("WORLD", Sev::inform,
"Error %6.4e Diff Error %6.4e Diff2 Error %6.4e\n",
std::sqrt(array[0]), std::sqrt(array[1]), std::sqrt(array[2]));
if (std::sqrt(array[0]) > eps)
SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID, "Wrong function value");
if (std::sqrt(array[1]) > eps)
SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
"Wrong function first direcative");
if (std::sqrt(array[2]) > eps)
SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
"Wrong function second direcative");
CHKERR VecRestoreArrayRead(common_data_ptr->L2Vec, &array);
}
//! [Check results]
int main(int argc, char *argv[]) {
// Initialisation of MoFEM/PETSc and MOAB data structures
MoFEM::Core::Initialize(&argc, &argv, NULL, help);
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]
//! [AtomTest]
AtomTest ex(m_field);
CHKERR ex.runProblem();
//! [AtomTest]
}
}
std::string type
#define MOFEM_LOG_C(channel, severity, format,...)
static char help[]
int main()
static const double eps
constexpr char FIELD_NAME[]
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< 1, FIELD_DIM > OpDomainSource
constexpr int SPACE_DIM
constexpr int FIELD_DIM
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, FIELD_DIM > OpDomainMass
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ L2
field with C-1 continuity
Definition definitions.h:88
@ H1
continuous field
Definition definitions.h:85
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
auto fun
constexpr int BASE_DIM
constexpr int order
@ F
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
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
MoFEMErrorCode loopFiniteElementsEvaluation(SmartPetscObj< DM > dm=nullptr)
Iterate evaluation finite elements.
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
SmartPetscObj< KSP > createKSP(SmartPetscObj< DM > dm=nullptr)
Create KSP (linear) solver.
boost::ptr_deque< UserDataOperator > & getOpDomainRhsPipeline()
Get the Op Domain Rhs Pipeline object.
boost::ptr_deque< UserDataOperator > & getOpEvaluationPipeline()
Get the Op Domain Evaluation Pipeline object.
@ PETSC
Standard PETSc assembly.
#define MOFEM_LOG(channel, severity)
Log.
FTensor::Index< 'i', SPACE_DIM > i
auto diff2_fun
Function second derivative.
constexpr char FIELD_NAME[]
auto fun
Function to approximate.
constexpr int FIELD_DIM
auto diff_fun
Function derivative.
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< BASE_DIM, FIELD_DIM > OpDomainMass
OPerator to integrate mass matrix for least square approximation.
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< BASE_DIM, FIELD_DIM > OpDomainSource
Operator to integrate the right hand side matrix for the problem.
double D
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
OpCalculateHOJacForFaceImpl< 2 > OpCalculateHOJacForFace
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
MoFEMErrorCode VecSetValues(Vec V, const EntitiesFieldData::EntData &data, const double *ptr, InsertMode iora)
Assemble PETSc vector.
boost::shared_ptr< VectorDouble > approxVals
SmartPetscObj< Vec > L2Vec
boost::shared_ptr< MatrixDouble > invJacPtr
boost::shared_ptr< MatrixDouble > approxHessianVals
boost::shared_ptr< MatrixDouble > approxGradVals
Operator to evaluate errors.
boost::shared_ptr< CommonData > commonDataPtr
MoFEMErrorCode doWork(int side, EntityType type, EntData &data)
Simple * simpleInterface
MoFEMErrorCode checkResults()
[Solve]
MoFEMErrorCode solveSystem()
[Push operators to pipeline]
MoFEMErrorCode setupProblem()
[Read mesh]
MoFEMErrorCode readMesh()
[Run programme]
MoFEMErrorCode assembleSystem()
[Push operators to pipeline]
MoFEM::Interface & mField
MoFEMErrorCode runProblem()
[Run programme]
[Operators_definition]
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
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
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Evaluate field gradient values for scalar field, i.e. gradient is tensor rank 1 (vector),...
Specialization for double precision scalar field values calculation.
Operator for inverting matrices at integration points.
PipelineManager interface.
MoFEMErrorCode setEvaluationIntegrationRule(RuleHookFun rule)
Set integration rule for domain evaluation finite element.
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain right-hand side finite element.
MoFEMErrorCode setDomainLhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain left-hand side finite element.
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 loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
Definition Simple.cpp:191
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
Definition Simple.cpp:575
MoFEMErrorCode setUp(const PetscBool is_partitioned=PETSC_TRUE)
Setup problem.
Definition Simple.cpp:735
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.