element_preparation.hpp array cmath expected memory utility serif/backend/mfem/mapping/domain_mapper.hpp serif/backend/mfem/operators/element_data.hpp serif/backend/mfem/operators/operand_evaluation.hpp serif/backend/mfem/operators/quadrature.hpp serif/backend/mfem/operators/rejection.hpp serif/backend/mfem/discretization/term_coefficients.hpp serif/backend/mfem/operators/workspace.hpp serif/backend/mfem/shared/parallel.hpp serif/utils/misc/compensated_sum.hpp src/include/serif/backend/mfem/operators/volume_stages.hpp serif serif::operators serif::operators::backend serif::operators::backend::mfem #pragmaonce #include<array> #include<cmath> #include<expected> #include<memory> #include<utility> #include"serif/backend/mfem/mapping/domain_mapper.hpp" #include"serif/backend/mfem/operators/element_data.hpp" #include"serif/backend/mfem/operators/operand_evaluation.hpp" #include"serif/backend/mfem/operators/quadrature.hpp" #include"serif/backend/mfem/operators/rejection.hpp" #include"serif/backend/mfem/discretization/term_coefficients.hpp" #include"serif/backend/mfem/operators/workspace.hpp" #include"serif/backend/mfem/shared/parallel.hpp" #include"serif/utils/misc/compensated_sum.hpp" namespaceserif::operators::backend::mfem{ template<VolumeEquationEquationT,typenameContributionT> [[nodiscard]]std::expected<ElementBasis<EquationPlan<EquationT>::operand_count>,PreparationRejection>sample_element_basis( constContributionT&equation, intelement, constdiscretization::backend::mfem::DofMap&row, constdiscretization::backend::mfem::DofMap&displacement_binding, conststd::array<constdiscretization::backend::mfem::DofMap*,EquationPlan<EquationT>::column_count>&columns, constmapping::DomainMapper&mapper, constdiscretization::quadrature::Policy&policy, TensorBasisCache&basis_cache, ContractionModecontraction_mode ){ usingPlan=EquationPlan<EquationT>; usingTest=OperandEvaluator<equations::TestOperandOf<ContributionT>>; auto&transformation=*displacement_binding.space().GetElementTransformation(element); constauto&displacement_element=*displacement_binding.space().GetFE(element); constautomapping_kind=mapper.is_compactified_element(transformation)?discretization::quadrature::MappingKind::kelvin:discretization::quadrature::MappingKind::general; ElementBasis<Plan::operand_count>basis{ .element=element }; intreconstruction_order=0; constautoinclude_reconstruction=[&](constauto&binding){ if(binding.reconstruction_element(element)!=nullptr){ reconstruction_order=std::max(reconstruction_order,binding.reconstruction()->integration_order_increment()); } }; include_reconstruction(row); Plan::templatefor_each_input<ContributionT>([&]<typenameOperandT>(OperandT,std::size_t){ include_reconstruction(*columns[Plan::templatecolumn_index<OperandT>()]); }); basis.rule=&equation_rule<EquationT>(equation,policy,transformation,displacement_element,mapping_kind,reconstruction_order); basis.reference_geometry.reserve(basis.rule->GetNPoints()); for(intpoint=0;point<basis.rule->GetNPoints();++point){ autogeometry=mapping::sample_fixed_mesh_geometry(transformation,basis.rule->IntPoint(point)); if(!geometry){ returnstd::unexpected(PreparationRejection{ PreparationRejectionReason::MAPPING,geometry.error(),element,point,"Invalidreferencemeshgeometry." }); } basis.reference_geometry.push_back(std::move(*geometry)); } BasisWorkspaceworkspace; Test::sample_basis(row,element,*basis.rule,basis.reference_test_basis,basis_cache,contraction_mode,transformation,workspace); basis.displacement_basis.sample( displacement_element,*basis.rule,ReferenceOperation::value_and_gradient,3,basis_cache,contraction_mode ); Plan::templatefor_each_input<ContributionT>([&]<typenameOperandT>(OperandT,std::size_tindex){ static_assert(EvaluableOperand<OperandT>,"TheMFEMoperatorhasnoevaluatorforthisoperand."); constauto&binding=*columns[Plan::templatecolumn_index<OperandT>()]; OperandEvaluator<OperandT>::sample_basis( binding,element,*basis.rule,basis.reference_operand_basis[index],basis_cache,contraction_mode,transformation,workspace ); }); returnbasis; } template<VolumeEquationEquationT,EvaluableOperandOperandT,typenameBindingT> requiresstd::same_as<typenameBindingT::Term,typenameOperandT::term_type> [[nodiscard]]::mfem::Vectorsample_element_operand( constElementBasis<EquationPlan<EquationT>::operand_count>&basis, constCoefficientView<BindingT>&input, constdiscretization::backend::mfem::DofMap::Elements&elements, Workspace&workspace ){ usingPlan=EquationPlan<EquationT>; constexprstd::size_tindex=equations::OperandValues<typenamePlan::Operands>::templateindex<OperandT>(); ::mfem::Vectorvalues; elements.element_values(basis.element,input.values,workspace.element_values); OperandEvaluator<OperandT>::evaluate(basis.reference_operand_basis[index],workspace.element_values,values,workspace.basis); returnvalues; } template<VolumeEquationEquationT,typenameContributionT> [[nodiscard]]std::expected<ElementGeometry<EquationPlan<EquationT>::operand_count>,PreparationRejection>map_element_geometry( constElementBasis<EquationPlan<EquationT>::operand_count>&basis, constdiscretization::backend::mfem::DofMap&displacement_binding, constdiscretization::backend::mfem::DofMap::Elements&displacement_elements, const::mfem::Vector&displacement, constMappingCoefficients&compactification, constmapping::DomainMapper&mapper, Workspace&workspace ){ usingPlan=EquationPlan<EquationT>; usingTest=OperandEvaluator<equations::TestOperandOf<ContributionT>>; ElementGeometry<Plan::operand_count>geometry; ifconstexpr(Test::geometry_dependent){ geometry.test_basis.reset_from(basis.reference_test_basis,Test::components); }else{ geometry.test_basis=basis.reference_test_basis; } Plan::templatefor_each_input<ContributionT>([&]<typenameOperandT>(OperandT,std::size_tindex){ usingEvaluator=OperandEvaluator<OperandT>; ifconstexpr(Evaluator::geometry_dependent){ geometry.operand_basis[index].reset_from(basis.reference_operand_basis[index],Evaluator::components); }else{ geometry.operand_basis[index]=basis.reference_operand_basis[index]; } }); displacement_elements.element_values(basis.element,displacement,geometry.displacement); ::mfem::Array<int>compactification_dofs; //AlocalDofTransformationkeepsconcurrentelementloopsoffthespace'ssharedone. ::mfem::DofTransformationcompactification_transform; compactification.binding.GetElementVDofs(basis.element,compactification_dofs,compactification_transform); compactification.values.GetSubVector(compactification_dofs,geometry.compactification); if(compactification_transform.GetDofTransformation()!=nullptr){ compactification_transform.InvTransformPrimal(geometry.compactification); } basis.displacement_basis.evaluate(geometry.displacement,workspace.displacement_samples,workspace.basis); constauto&displacement_element=*displacement_binding.space().GetFE(basis.element); constautodisplacement_data=mapping::element_displacement_data_from_element_vdofs(displacement_element,geometry.displacement); constmapping::ElementCompactificationDatacompactification_data( *compactification.binding.GetFE(basis.element),geometry.compactification ); constmapping::ElementMappingDatamapping_data{displacement_data,compactification_data}; ::mfem::IsoparametricTransformationtransformation; ::serif::utils::parallel::element_transformation(*displacement_binding.space().GetMesh(),basis.element,transformation); constintpoint_count=basis.rule->GetNPoints(); geometry.mapping.set_size(point_count,3); for(intpoint=0;point<point_count;++point){ for(intaxis=0;axis<3;++axis){ workspace.displacement_value[axis]=workspace.displacement_samples[12*point+4*axis]; for(intderivative=0;derivative<3;++derivative){ workspace.displacement_gradient(axis,derivative)=workspace.displacement_samples[12*point+4*axis+derivative+1]; } } constmapping::DMReferenceDisplacementSamplesample{workspace.displacement_value,workspace.displacement_gradient}; constautostatus=mapper.evaluate_volume( mapping_data,transformation,basis.rule->IntPoint(point), workspace.mapping_workspace,workspace.mapping_context,&sample,&basis.reference_geometry[point] ); if(status!=mapping::MappingStatus::VALID){ returnstd::unexpected(PreparationRejection{ PreparationRejectionReason::MAPPING,status,basis.element,point,"Invalidequationgeometry." }); } geometry.mapping.store(point,workspace.mapping_context); constauto&context=workspace.mapping_context.mapping; ifconstexpr(Test::geometry_dependent){ Test::map_basis_point(point,context,basis.reference_test_basis,geometry.test_basis,workspace.basis); } Plan::templatefor_each_input<ContributionT>([&]<typenameOperandT>(OperandT,std::size_tindex){ ifconstexpr(OperandEvaluator<OperandT>::geometry_dependent){ OperandEvaluator<OperandT>::map_basis_point(point,context,basis.reference_operand_basis[index],geometry.operand_basis[index],workspace.basis); } }); } returngeometry; } template<EvaluableOperandOperandT,std::size_tCount> [[nodiscard]]::mfem::Vectormap_element_operand( const::mfem::Vector&reference, constElementGeometry<Count>&geometry, Workspace&workspace ){ usingEvaluator=OperandEvaluator<OperandT>; constintpoint_count=geometry.mapping.get_point_count(); ::mfem::Vectorvalues(point_count*Evaluator::components); for(intpoint=0;point<point_count;++point){ geometry.mapping.load(point,workspace.mapping_context); constautovalue=Evaluator::physical_value( Evaluator::reference_value(reference,point),workspace.mapping_context.mapping ); for(intcomponent=0;component<Evaluator::components;++component){ values[point*Evaluator::components+component]=discretization::forms::component(value,component); } } returnvalues; } template<VolumeEquationEquationT,typenameContributionT> [[nodiscard]]equations::EquationPoint<typenameContributionT::Operands>element_equation_point( conststd::array<std::shared_ptr<const::mfem::Vector>,EquationPlan<EquationT>::operand_count>&physical_values, constmapping::MappingPointContext&context, intpoint ){ usingPlan=EquationPlan<EquationT>; equations::EquationPoint<typenameContributionT::Operands>values; Plan::templatefor_each_input<ContributionT>([&]<typenameOperandT>(OperandT,std::size_tindex){ usingEvaluator=OperandEvaluator<OperandT>; auto&value=values.fields.templateget<OperandT>(); for(intcomponent=0;component<Evaluator::components;++component){ discretization::forms::component(value,component)=(*physical_values[index])[point*Evaluator::components+component]; } }); for(intaxis=0;axis<3;++axis){ values.position[axis]=context.physical_position[axis]; } returnvalues; } template<VolumeEquationEquationT,typenameContributionT> [[nodiscard]]boolstore_element_linearization( constequations::PointLinearization<typenameContributionT::Operands,typenameOperandEvaluator<equations::TestOperandOf<ContributionT>>::Value>&physics, intpoint, doubleweight, ElementData<EquationPlan<EquationT>::operand_count>&data ){ usingPlan=EquationPlan<EquationT>; usingTest=OperandEvaluator<equations::TestOperandOf<ContributionT>>; usingResult=typenameTest::Value; boolfinite=true; for(intoutput=0;output<Test::components;++output){ constintrow_index=point*Test::components+output; data.weighted_residual[row_index]=weight*discretization::forms::component(physics.residual,output); finite=finite&&std::isfinite(data.weighted_residual[row_index]); Plan::templatefor_each_input<ContributionT>([&]<typenameOperandT>(OperandT,std::size_t){ usingInput=typenameOperandEvaluator<OperandT>::Value; for(intinput=0;input<OperandEvaluator<OperandT>::components;++input){ auto&derivative=data.weighted_field_derivatives(row_index,Plan::templatecomponent_offset<OperandT>()+input); derivative=weight*discretization::forms::derivative_component<Result, Input>( physics.field_derivatives.templateget<OperandT>(),output,input ); finite=finite&&std::isfinite(derivative); } }); for(intaxis=0;axis<3;++axis){ auto&derivative=data.weighted_position_derivative(row_index,axis); derivative=weight*discretization::forms::derivative_component<Result, discretization::forms::VectorValue>( physics.position_derivative,output,axis ); finite=finite&&std::isfinite(derivative); } } returnfinite; } template<VolumeEquationEquationT,typenameContributionT> [[nodiscard]]std::expected<ElementData<EquationPlan<EquationT>::operand_count>,PreparationRejection>evaluate_element_equation( constContributionT&equation, doublecoefficient, std::shared_ptr<constElementBasis<EquationPlan<EquationT>::operand_count>>basis, std::shared_ptr<constElementGeometry<EquationPlan<EquationT>::operand_count>>geometry, std::array<std::shared_ptr<const::mfem::Vector>,EquationPlan<EquationT>::operand_count>reference_values, conststd::array<std::shared_ptr<const::mfem::Vector>,EquationPlan<EquationT>::operand_count>&physical_values, Workspace&workspace ){ usingPlan=EquationPlan<EquationT>; usingTest=OperandEvaluator<equations::TestOperandOf<ContributionT>>; usingResult=typenameTest::Value; ElementData<Plan::operand_count>data{ .element=basis->element, .basis=std::move(basis), .geometry=std::move(geometry), .reference_operand_values=std::move(reference_values) }; constintpoint_count=data.basis->rule->GetNPoints(); data.weighted_residual.SetSize(point_count*Test::components); data.weighted_field_derivatives.SetSize(point_count*Test::components,Plan::component_count); data.weighted_field_derivatives=0.0; data.weighted_position_derivative.SetSize(point_count*Test::components,3); utils::CompensatedSumelement_validation; for(intpoint=0;point<point_count;++point){ data.geometry->mapping.load(point,workspace.mapping_context); constautovalues=element_equation_point<EquationT, ContributionT>( physical_values,workspace.mapping_context.mapping,point ); equations::PointLinearization<typenameContributionT::Operands,Result>physics; try{ physics=equation.evaluate(values); ifconstexpr(requires{equation.validate_integral(0.0);}){ //Physicaladmissibilityisindependentofequationarithmeticcoefficients. element_validation.add( workspace.mapping_context.quadrature.physical_integration_weight*equation.validation_integrand(values,physics) ); } }catch(conststd::domain_error&error){ returnstd::unexpected(PreparationRejection{ PreparationRejectionReason::EQUATION,mapping::MappingStatus::VALID,data.element,point,error.what() }); } //Geometryvariationsstillneedtheunscaledphysicalintegrationweight. constdoubleweight=coefficient*workspace.mapping_context.quadrature.physical_integration_weight; if(!store_element_linearization<EquationT, ContributionT>(physics,point,weight,data)){ returnstd::unexpected(PreparationRejection{ PreparationRejectionReason::NON_FINITE,mapping::MappingStatus::VALID, data.element,point,"Non-finiteequationintegrandorderivative." }); } } data.validation_integral=element_validation.value(); returndata; } }//namespaceserif::operators::backend::mfem