domain_mapper.cpp mfem/linalg/densemat.hpp serif/backend/mfem/mapping/domain_mapper.hpp serif/utils/error/errors.hpp serif/backend/mfem/shared/finite.hpp serif/backend/mfem/shared/invertible.hpp serif serif::mapping #include"mfem/linalg/densemat.hpp" #include"serif/backend/mfem/mapping/domain_mapper.hpp" #include"serif/utils/error/errors.hpp" #include"serif/backend/mfem/shared/finite.hpp" #include"serif/backend/mfem/shared/invertible.hpp" //Anonymousnamespacefortranslationunit-localhelperfunctionsandtypes namespace{ //TODO:Putsomethinginhereusingvariadicargstovalidatemultiplethingssatisfysomepredicate } namespaceserif::mapping{ usingnamespaceserif::utils::errors; usingnamespaceserif::utils::checks; DomainMapper::DomainMapper( utils::user_options::DomainMapperOptionsoptions, std::unique_ptr<constcompactification::ExteriorDomainMap>exterior_map ): m_options(options), m_exterior_map(std::move(exterior_map)){ if(m_options.dimension<=0){ serif_error<std::invalid_argument,SERiFErrorCode::INVALID_DIMENSION>("DomainMapperrequiresapositive,non-zero,dimension.Receiveddimension:{}",m_options.dimension); } if(m_options.vacuum_element_attribute_ID<=0){ serif_error<std::invalid_argument,SERiFErrorCode::INVALID_VACUUM_ELEMENT_ATTRIBUTE_ID>("DomainMapperrequiresapositive,non-zero,vacuumelementattributeID.ReceivedattributeID:{}",m_options.vacuum_element_attribute_ID); } if(!m_exterior_map){ serif_error<std::invalid_argument, SERiFErrorCode::MISSING_EXTERIOR_MAP>("DomainMapperrequiresavalidexteriormap.Onewasnotprovidedoranullptrwasprovided."); } } std::expected<DMFixedMeshGeometry,MappingStatus>sample_fixed_mesh_geometry( mfem::ElementTransformation&transformation,constmfem::IntegrationPoint&point ){ transformation.SetIntPoint(&point); DMFixedMeshGeometrygeometry; transformation.Transform(point,geometry.position); geometry.jacobian=transformation.Jacobian(); geometry.weight=transformation.Weight(); //CheckbeforeMFEMattemptsaninverse:singularreferenceelementsarenumericalfailures. if(!is_finite(geometry.position)||!is_finite(geometry.jacobian)||!is_finite(geometry.weight)){ returnstd::unexpected(MappingStatus::NON_FINITE_MAPPING_INPUT); } if(geometry.weight<=0.0|| (geometry.jacobian.Height()==geometry.jacobian.Width()&&!has_stable_inverse(geometry.jacobian))){ returnstd::unexpected(MappingStatus::NON_POSITIVE_DETERMINATE); } geometry.inverse_jacobian=transformation.InverseJacobian(); if(!is_finite(geometry.inverse_jacobian)){ returnstd::unexpected(MappingStatus::NON_FINITE_MAPPING_INPUT); } returngeometry; } MappingStatusDomainMapper::evaluate_point( constElementMappingData&element_data, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, DMWorkspace&workspace, MappingPointContext&context )const{ constautogeometry=sample_fixed_mesh_geometry(transformation,ip); if(!geometry){ returngeometry.error(); } returnevaluate_point_impl(element_data,transformation,ip,workspace,context,*geometry); } MappingStatusDomainMapper::evaluate_point( constElementMappingData&element_data, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, DMWorkspace&workspace, MappingPointContext&context, constDMFixedMeshGeometry&fixed_geometry )const{ if(fixed_geometry.position.Size()!=m_options.dimension|| fixed_geometry.jacobian.Height()!=m_options.dimension||fixed_geometry.jacobian.Width()!=m_options.dimension|| fixed_geometry.inverse_jacobian.Height()!=m_options.dimension||fixed_geometry.inverse_jacobian.Width()!=m_options.dimension){ returnMappingStatus::INVALID_DIMENSION; } if(!is_finite(fixed_geometry.position)||!is_finite(fixed_geometry.jacobian)|| !is_finite(fixed_geometry.inverse_jacobian)||!is_finite(fixed_geometry.weight)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } if(fixed_geometry.weight<=0.0||!has_stable_inverse(fixed_geometry.jacobian)){ returnMappingStatus::NON_POSITIVE_DETERMINATE; } transformation.SetIntPoint(&ip); returnevaluate_point_impl(element_data,transformation,ip,workspace,context,fixed_geometry); } MappingStatusDomainMapper::evaluate_volume( constElementMappingData&element_data, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, DMWorkspace&workspace, VolumeMappingContext&context, constDMReferenceDisplacementSample*displacement_sample, constDMFixedMeshGeometry*fixed_geometry )const{ transformation.SetIntPoint(&ip); std::expected<DMFixedMeshGeometry,MappingStatus>sampled_geometry; if(fixed_geometry==nullptr){ sampled_geometry=sample_fixed_mesh_geometry(transformation,ip); if(!sampled_geometry){ returnsampled_geometry.error(); } fixed_geometry=&*sampled_geometry; } constMappingStatuspoint_status=evaluate_point_impl( element_data, transformation, ip, workspace, context.mapping, *fixed_geometry, displacement_sample ); if(point_status!=MappingStatus::VALID){ returnpoint_status; } mfem::Mult(context.mapping.mapping_jacobian,fixed_geometry->jacobian,workspace.m_full_element_jacobian); context.quadrature.J_element_to_physical_inverse.SetSize(m_options.dimension,m_options.dimension); mfem::CalcInverse(workspace.m_full_element_jacobian,context.quadrature.J_element_to_physical_inverse); context.quadrature.mapping_determinate=context.mapping.mapping_determinate; context.quadrature.physical_integration_weight=ip.weight*fixed_geometry->weight*context.mapping.mapping_determinate; if(!is_finite(context.quadrature.J_element_to_physical_inverse)||!std::isfinite(context.quadrature.physical_integration_weight)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } if(context.quadrature.physical_integration_weight<=0.0){ returnMappingStatus::NON_POSITIVE_DETERMINATE; } returnMappingStatus::VALID; } MappingStatusDomainMapper::evaluate_face( constElementMappingData&element_data, mfem::FaceElementTransformations&transformation, constFaceElementSideside, constmfem::IntegrationPoint&ip, DMWorkspace&workspace, FaceMappingContext&context )const{ transformation.SetAllIntPoints(&ip); mfem::ElementTransformation&element_transformation=select_face_element_transformation(transformation,side); constmfem::IntegrationPoint&element_integration_point=select_face_element_integration_point(transformation,side); constMappingStatuspoint_status=evaluate_point(element_data,element_transformation,element_integration_point,workspace,context.mapping); if(point_status!=MappingStatus::VALID){ returnpoint_status; } //Getthenormalvectorfromthefaceinreferencespace workspace.m_reference_normal.SetSize(m_options.dimension); mfem::CalcOrtho(transformation.Jacobian(),workspace.m_reference_normal); if(side==FaceElementSide::ELEMENT_2){ workspace.m_reference_normal*=-1.0;//Flipthenormalforthesecondelement(e.g.the"other"sideoftheface) } constdoublereference_normal_magnitude=workspace.m_reference_normal.Norml2(); if(!is_finite(reference_normal_magnitude)||reference_normal_magnitude<=0.0){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } context.reference_normal.SetSize(m_options.dimension); context.reference_normal=workspace.m_reference_normal; context.reference_normal/=reference_normal_magnitude; //Getthenormalvectorfromthefaceinphysicalspace context.mapping.inverse_mapping_jacobian.MultTranspose(workspace.m_reference_normal,workspace.m_mapped_normal); workspace.m_mapped_normal*=context.mapping.mapping_determinate; constdoublemapped_normal_magnitude=workspace.m_mapped_normal.Norml2(); if(!is_finite(mapped_normal_magnitude)||mapped_normal_magnitude<=0.0){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } context.quadrature.normal.SetSize(m_options.dimension); context.quadrature.normal=workspace.m_mapped_normal; context.quadrature.normal/=mapped_normal_magnitude; context.reference_surface_weight=ip.weight*reference_normal_magnitude; context.physical_surface_weight=ip.weight*mapped_normal_magnitude; context.quadrature.ds=context.reference_surface_weight; context.quadrature.v_dot_n_scale=mapped_normal_magnitude/reference_normal_magnitude; if(!is_finite(context.quadrature.normal)||!is_finite(context.reference_surface_weight)||!is_finite(context.physical_surface_weight)||!is_finite(context.quadrature.v_dot_n_scale)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } returnMappingStatus::VALID; } MappingStatusDomainMapper::evaluate_point_variation( constElementMappingData&element_data, constElementDisplacementData&direction, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, constMappingPointContext&context, DMWorkspace&workspace, MappingPointVariation&variation )const{ returnevaluate_point_variation_impl(element_data,direction,transformation,ip,context,workspace,variation,nullptr); } MappingStatusDomainMapper::evaluate_point_variation( constElementMappingData&element_data, constElementDisplacementData&direction, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, constMappingPointContext&context, DMWorkspace&workspace, MappingPointVariation&variation, constmfem::DenseMatrix&inverse_mesh_jacobian )const{ if(inverse_mesh_jacobian.Height()!=m_options.dimension||inverse_mesh_jacobian.Width()!=m_options.dimension){ returnMappingStatus::INVALID_DIMENSION; } if(!is_finite(inverse_mesh_jacobian)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } if(direction.get_element().GetMapType()!=mfem::FiniteElement::VALUE){ //OnlyVALUEfieldsadmitthereference-gradientpullbackusedbythereusepath. returnevaluate_point_variation(element_data,direction,transformation,ip,context,workspace,variation); } returnevaluate_point_variation_impl(element_data,direction,transformation,ip,context,workspace,variation,&inverse_mesh_jacobian); } MappingStatusDomainMapper::evaluate_volume_direction_variation( constElementMappingData&element_data, constElementDisplacementData&direction, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, constVolumeMappingContext&context, DMWorkspace&workspace, VolumeMappingVariation&variation, constDMReferenceDisplacementSample&direction_sample, constCompactificationPointData*compactification_sample, constmfem::DenseMatrix&inverse_mesh_jacobian )const{ if(inverse_mesh_jacobian.Height()!=m_options.dimension||inverse_mesh_jacobian.Width()!=m_options.dimension){ returnMappingStatus::INVALID_DIMENSION; } constMappingStatuspoint_status=evaluate_point_variation_impl(element_data,direction,transformation,ip,context.mapping,workspace,variation.mapping,&inverse_mesh_jacobian,&direction_sample,compactification_sample); if(point_status!=MappingStatus::VALID){ returnpoint_status; } variation.weight_variation=(context.quadrature.physical_integration_weight/context.mapping.mapping_determinate)*variation.mapping.mapping_determinate_variation; if(!is_finite(variation.weight_variation)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } returnMappingStatus::VALID; } MappingStatusDomainMapper::evaluate_face_variation( constElementMappingData&element_data, constElementDisplacementData&direction, mfem::FaceElementTransformations&transformation, FaceElementSideside, constmfem::IntegrationPoint&ip, constFaceMappingContext&context, DMWorkspace&workspace, FaceMappingVariation&variation )const{ transformation.SetAllIntPoints(&ip); mfem::ElementTransformation&element_transformation=select_face_element_transformation(transformation,side); constmfem::IntegrationPoint&element_integration_point=select_face_element_integration_point(transformation,side); constMappingStatuspoint_status=evaluate_point_variation(element_data,direction,element_transformation,element_integration_point,context.mapping,workspace,variation.mapping); if(point_status!=MappingStatus::VALID){ returnpoint_status; } workspace.m_reference_normal.SetSize(m_options.dimension); mfem::CalcOrtho(transformation.Jacobian(),workspace.m_reference_normal); if(side==FaceElementSide::ELEMENT_2){ workspace.m_reference_normal*=-1.0;//Flipthenormalforthesecondelement(e.g.the"other"sideoftheface) } constdoublereference_normal_magnitude=workspace.m_reference_normal.Norml2(); if(!is_finite(reference_normal_magnitude)||reference_normal_magnitude<=0){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } context.mapping.inverse_mapping_jacobian.MultTranspose(workspace.m_reference_normal,workspace.m_vector_temp); workspace.m_mapped_normal=workspace.m_vector_temp; workspace.m_mapped_normal*=context.mapping.mapping_determinate; variation.physical_normal_variation.SetSize(m_options.dimension); variation.mapping.inverse_mapping_jacobian_variation.MultTranspose(workspace.m_reference_normal,variation.physical_normal_variation); variation.physical_normal_variation*=context.mapping.mapping_determinate; variation.physical_normal_variation.Add(variation.mapping.mapping_determinate_variation,workspace.m_vector_temp); constdoublemapped_normal_magnitude=workspace.m_mapped_normal.Norml2(); if(!is_finite(mapped_normal_magnitude)||mapped_normal_magnitude<=0){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } constdoublemapped_normal_magnitude_variation=context.quadrature.normal*variation.physical_normal_variation; variation.physical_normal_variation.Add(-mapped_normal_magnitude_variation,context.quadrature.normal); variation.physical_normal_variation/=mapped_normal_magnitude; variation.physical_surface_weight_variation=ip.weight*mapped_normal_magnitude_variation; variation.normal_flux_scale_variation=mapped_normal_magnitude_variation/reference_normal_magnitude; if(!is_finite(variation.physical_normal_variation)||!std::isfinite(variation.physical_surface_weight_variation)||!std::isfinite(variation.normal_flux_scale_variation)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } returnMappingStatus::VALID; } boolDomainMapper::is_compactified_element(constmfem::ElementTransformation&transformation)constnoexcept{ returntransformation.Attribute==m_options.vacuum_element_attribute_ID; } intDomainMapper::get_dimension()constnoexcept{ returnm_options.dimension; } constcompactification::ExteriorDomainMap&DomainMapper::get_exterior_map()constnoexcept{ return*m_exterior_map; } MappingStatusDomainMapper::evaluate_point_impl( constElementMappingData&element_data, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, DMWorkspace&workspace, MappingPointContext&context, constDMFixedMeshGeometry&geometry, constDMReferenceDisplacementSample*displacement_sample )const{ validate_element_data(element_data); //TODO:Factorintoitsownfunction //TODO:Consideriftheseshouldreturnorthrow. if(workspace.get_dimension()!=m_options.dimension){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_DIMENSION>("WorkspacedimensiondoesnotmatchDomainMapperdimension.Workspacedimension:{},DomainMapperdimension:{}",workspace.get_dimension(),m_options.dimension); } if(transformation.GetSpaceDim()!=m_options.dimension){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_DIMENSION>("ElementtransformationspacedimensiondoesnotmatchDomainMapperdimension.Elementtransformationspacedimension:{},DomainMapperdimension:{}",transformation.GetSpaceDim(),m_options.dimension); } if(transformation.GetGeometryType()!=element_data.displacement.get_element().GetGeomType()){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_ELEMENT_GEOMETRY>("Elementtransformationgeometrytypedoesnotmatchelementgeometrytype.Elementtransformationgeometrytype:{},Elementgeometrytype:{}",transformation.GetGeometryType(),element_data.displacement.get_element().GetGeomType()); } context.reference_position=geometry.position; //GetthedisplacementfieldvalueanditsJacobianattheintegrationpoint.NotethesemaybeincurrentworkspacetoavoidrepeatedallocationsandMultiplies. if(displacement_sample){ //TODO:Generallygothroughandrefactortheselargechecksintotheirownfunctions,attheveryleastitwillbeeasiertoread if(element_data.displacement.get_element().GetMapType()!=mfem::FiniteElement::VALUE||displacement_sample->value.Size()!=m_options.dimension||displacement_sample->gradient.Height()!=m_options.dimension||displacement_sample->gradient.Width()!=m_options.dimension){ returnMappingStatus::INVALID_DIMENSION; } workspace.m_field_value=displacement_sample->value; workspace.m_field_jacobian.SetSize(m_options.dimension); mfem::Mult(displacement_sample->gradient,geometry.inverse_jacobian,workspace.m_field_jacobian); }else{ evaluate_displacement_field(element_data.displacement,transformation,ip,workspace,workspace.m_field_value,workspace.m_field_jacobian,&geometry.inverse_jacobian); } if(!is_finite(context.reference_position)||!is_finite(workspace.m_field_value)||!is_finite(workspace.m_field_jacobian)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } context.displaced_position.SetSize(m_options.dimension); //Getthepositionofthepointinphysicalspacebyaddingthedisplacementtothereferenceposition.NoteMFEMreallydislikesrawarithmeticoperators //soweneedtofirstassignthereferencepositionthenusetheinplace+=operator. context.displaced_position=context.reference_position; context.displaced_position+=workspace.m_field_value; context.displacement_jacobian.SetSize(m_options.dimension,m_options.dimension); context.displacement_jacobian=workspace.m_field_jacobian; //EnsurethatthediagonalofthedisplacementJacobianisincrementedby1.0toaccountfortheidentitymappingfromreferencetophysicalspace. //recallthatr=x+d(wheredistheworkspace.m_field_valueandxiscontext.reference_position)thenwecandifferentiatethis //componentwisetofindthegradientofthedisplacedpositionwrt.themeshcoordinate(referenceposition).E.gasyoumovealong //themeshcoordinatehowmuchdoesthephysicalcoordinatechangeandinwhatdirection.LetscallthisF //F=\frac{\partialr_i}{\partialx_j}whereristhedisplacedpositionandxisthemeshposition. //WethenhaveF=\frac{\partialx_i}{\partialx_j}+\frac{\partiald_i}{x_j}wheredisthedisplacement(recallr=x+d) //Bydefinitionthefirsttermistheidentitymatrix.ThesecondtermwegetoutofEvaluateField.Thuswhyweneedtoaddtheidentitymatrixhere for(inti=0;i<m_options.dimension;++i){ context.displacement_jacobian(i,i)+=1.0; } context.compactified=is_compactified_element(transformation); //Thisbranchonlyrunsforvacuumelements if(context.compactified){ //Therearetwothingsthatweneedtothemapping.Firstisareferencecoordinatewhichstroidembedsintothemeshatmeshgenerationtime,thisis //parameterizedfrom0-1where0isthemodelsurfaceand1isthemeshexterior(whatwillbecomesthecompactifiedinfinity,notealsoweneveractuallyevaluateats=1;ratherwedefinesomearbitrarysmalltolerancetoapproachs=1).Letscallthiss.Wealsoneed //thegradientofsaswemovealongthemeshcoordinates.Allofthisisstasheswithinworkspace.m_compactification_point. constMappingStatuscoordinate_status=evaluate_compactification_coordinate(element_data.compactification,transformation,ip,workspace,workspace.m_compactification_point,&geometry.inverse_jacobian); if(coordinate_status!=MappingStatus::VALID){ returncoordinate_status; } constcompactification::ExteriorMapInputexterior_input{ .reference_position=context.reference_position, .displaced_position=context.displaced_position, .displacement_jacobian=context.displacement_jacobian, .compactification_coordinate_gradient=workspace.m_compactification_point.coordinate_gradient, .compactification_coordinate=workspace.m_compactification_point.compactification_coordinate, }; //Thisapplywhatevertheexteriormapistogeneratethenewphysicalexteriorcoordinateandjacobianbetweenphysicalandreferencespace. //Ingeneralwehaveonlyimplementedakelvinmapping;however,infutureadditionalmappingsmaybeimplemented. constMappingStatusexterior_status=m_exterior_map->evaluate(exterior_input,workspace.m_exterior_result); if(exterior_status!=MappingStatus::VALID){ returnexterior_status; } context.physical_position=workspace.m_exterior_result.physical_position; context.mapping_jacobian=workspace.m_exterior_result.mapping_jacobian; }else{ context.physical_position=context.displaced_position; context.mapping_jacobian=context.displacement_jacobian; } //Validationwork if(!is_finite(context.physical_position)||!is_finite(context.mapping_jacobian)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } context.mapping_determinate=context.mapping_jacobian.Det(); if(!std::isfinite(context.mapping_determinate)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } if(context.mapping_determinate<=0.0){ //Thisisthemostcommonerrorweseecomeoutofthisfunction,specificallyitiscommonwhenwetrytodeformthemeshtoomuchinonestep. returnMappingStatus::NON_POSITIVE_DETERMINATE; } context.inverse_mapping_jacobian.SetSize(m_options.dimension,m_options.dimension); //Finallywegettheinversejacobian. mfem::CalcInverse(context.mapping_jacobian,context.inverse_mapping_jacobian); if(!is_finite(context.inverse_mapping_jacobian)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } returnMappingStatus::VALID; } voidDomainMapper::validate_element_data(constElementMappingData&element_data)const{ constElementDisplacementData&displacement=element_data.displacement; constElementCompactificationData&compactification=element_data.compactification; if(displacement.get_dimension()!=m_options.dimension){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_DIMENSION>("ElementdisplacementdimensiondoesnotmatchDomainMapperdimension.Elementdisplacementdimension:{},DomainMapperdimension:{}",displacement.get_dimension(),m_options.dimension); } if(displacement.get_element().GetDim()!=m_options.dimension){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_DIMENSION>("ElementdisplacementfiniteelementdimensiondoesnotmatchDomainMapperdimension.Elementdisplacementfiniteelementdimension:{},DomainMapperdimension:{}",displacement.get_element().GetDim(),m_options.dimension); } if(compactification.get_element().GetDim()!=m_options.dimension){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_DIMENSION>("ElementcompactificationfiniteelementdimensiondoesnotmatchDomainMapperdimension.Elementcompactificationfiniteelementdimension:{},DomainMapperdimension:{}",compactification.get_element().GetDim(),m_options.dimension); } if(displacement.get_element().GetGeomType()!=compactification.get_element().GetGeomType()){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_ELEMENT_GEOMETRY>("Elementdisplacementfiniteelementgeometrytypedoesnotmatchelementcompactificationfiniteelementgeometrytype.Elementdisplacementfiniteelementgeometrytype:{},Elementcompactificationfiniteelementgeometrytype:{}",displacement.get_element().GetGeomType(),compactification.get_element().GetGeomType()); } if(compactification.get_element().GetRangeType()!=mfem::FiniteElement::SCALAR){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_COMPACTIFICATION_RANK>("Elementcompactificationfiniteelementrangetypeisnotscalar.Elementcompactificationfiniteelementrangetype:{}",compactification.get_element().GetRangeType()); } if(compactification.get_element().GetMapType()!=mfem::FiniteElement::VALUE){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_COMPACTIFICATION_TYPE>("Elementcompactificationfiniteelementmaptypeisnotvalue.Elementcompactificationfiniteelementmaptype:{}",compactification.get_element().GetMapType()); } if(compactification.get_element().GetDerivType()!=mfem::FiniteElement::GRAD){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_COMPACTIFICATION_DERIVATIVE_TYPE>("Elementcompactificationfiniteelementderivativetypeisnotgradient.Elementcompactificationfiniteelementderivativetype:{}",compactification.get_element().GetDerivType()); } if(compactification.get_dof_count()!=compactification.get_element().GetDof()){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_DOF_COUNT>("ElementcompactificationfiniteelementDOFcountdoesnotmatchthenumberofDOFsinthefiniteelement.ElementcompactificationfiniteelementDOFcount:{},FiniteelementDOFcount:{}",compactification.get_dof_count(),compactification.get_element().GetDof()); } } //Notethatthereisnothingpreventingthisfunctionfrombeingusedwithsomefieldotherthandisplacement;perhapsweshouldtightenthis? voidDomainMapper::evaluate_displacement_field( constElementDisplacementData&field, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, DMWorkspace&workspace, mfem::Vector&value, mfem::DenseMatrix&jacobian, constmfem::DenseMatrix*inverse_mesh_jacobian )const{ constmfem::FiniteElement&element=field.get_element(); constmfem::DenseMatrix&dof_matrix=field.get_dof_matrix(); workspace.m_shape.SetSize(element.GetDof()); element.CalcShape(ip,workspace.m_shape); value.SetSize(m_options.dimension); dof_matrix.MultTranspose(workspace.m_shape,value); jacobian.SetSize(m_options.dimension,m_options.dimension); if(inverse_mesh_jacobian!=nullptr||element.GetMapType()==mfem::FiniteElement::VALUE){ workspace.m_reference_dshape.SetSize(element.GetDof(),m_options.dimension); element.CalcDShape(ip,workspace.m_reference_dshape); //ContractDOFsbeforeapplyingfixed-meshgeometry. mfem::MultAtB(dof_matrix,workspace.m_reference_dshape,workspace.m_reference_field_jacobian); constmfem::DenseMatrix&inverseMeshJacobian=inverse_mesh_jacobian!=nullptr?*inverse_mesh_jacobian:transformation.InverseJacobian(); mfem::Mult(workspace.m_reference_field_jacobian,inverseMeshJacobian,jacobian); }else{ //Retaintheoriginalfinite-element-specificphysical-gradient //pathformappingtypeswithouttheordinaryVALUEpullback. workspace.m_mesh_dshape.SetSize(element.GetDof(),m_options.dimension); element.CalcPhysDShape(transformation,workspace.m_mesh_dshape); mfem::MultAtB(dof_matrix,workspace.m_mesh_dshape,jacobian); } } MappingStatusDomainMapper::evaluate_compactification_coordinate( constElementCompactificationData&compactification, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, DMWorkspace&workspace, CompactificationPointData&point_data, constmfem::DenseMatrix*inverse_mesh_jacobian )const{ constmfem::FiniteElement&element=compactification.get_element(); constmfem::Vector&dofs=compactification.get_dofs(); constintdof_count=element.GetDof(); if(workspace.get_dimension()!=m_options.dimension||transformation.GetSpaceDim()!=m_options.dimension||element.GetDim()!=m_options.dimension){ returnMappingStatus::INVALID_DIMENSION; } if(dofs.Size()!=dof_count){ returnMappingStatus::INVALID_DIMENSION; } for(inti=0;i<dof_count;++i){ if(!is_finite(dofs(i))){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } } if(inverse_mesh_jacobian!=nullptr){ if(inverse_mesh_jacobian->Height()!=m_options.dimension||inverse_mesh_jacobian->Width()!=m_options.dimension){ returnMappingStatus::INVALID_DIMENSION; } if(!is_finite(*inverse_mesh_jacobian)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } } transformation.SetIntPoint(&ip); workspace.m_compactification_shape.SetSize(dof_count); workspace.m_compactification_dshape.SetSize(dof_count,m_options.dimension); element.CalcShape(ip,workspace.m_compactification_shape); if(inverse_mesh_jacobian!=nullptr){ workspace.m_reference_dshape.SetSize(dof_count,m_options.dimension); element.CalcDShape(ip,workspace.m_reference_dshape); mfem::Mult(workspace.m_reference_dshape,*inverse_mesh_jacobian,workspace.m_compactification_dshape); }else{ element.CalcPhysDShape(transformation,workspace.m_compactification_dshape); } point_data.compactification_coordinate=dofs*workspace.m_compactification_shape; point_data.coordinate_gradient.SetSize(m_options.dimension); workspace.m_compactification_dshape.MultTranspose(dofs,point_data.coordinate_gradient); if(!is_finite(point_data.compactification_coordinate)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } for(intd=0;d<point_data.coordinate_gradient.Size();++d){ if(!is_finite(point_data.coordinate_gradient(d))){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } } returnMappingStatus::VALID; } MappingStatusDomainMapper::evaluate_point_variation_impl( constElementMappingData&element_data, constElementDisplacementData&direction, mfem::ElementTransformation&transformation, constmfem::IntegrationPoint&ip, constMappingPointContext&context, DMWorkspace&workspace, MappingPointVariation&variation, constmfem::DenseMatrix*inverse_mesh_jacobian, constDMReferenceDisplacementSample*direction_sample, constCompactificationPointData*compactification_sample )const{ validate_element_data(element_data); //Adirectionthatistheelement'sowndisplacementdatawasvalidatedjustabove. if(&direction!=&element_data.displacement){ constElementMappingDatadirection_data{ .displacement=direction, .compactification=element_data.compactification }; validate_element_data(direction_data); } if(element_data.displacement.get_dof_count()!=direction.get_dof_count()){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_DOF_COUNT>("ElementdisplacementDOFcountdoesnotmatchdirectionDOFcount.ElementdisplacementDOFcount:{},DirectionDOFcount:{}",element_data.displacement.get_dof_count(),direction.get_dof_count()); } if(workspace.get_dimension()!=m_options.dimension){ serif_error<std::invalid_argument, SERiFErrorCode::INVALID_DIMENSION>("WorkspacedimensiondoesnotmatchDomainMapperdimension.Workspacedimension:{},DomainMapperdimension:{}",workspace.get_dimension(),m_options.dimension); } if(context.compactified!=is_compactified_element(transformation)){ serif_error<std::invalid_argument, SERiFErrorCode::COMPACTIFICATION_MISMATCH>("Mappingcontextcompactificationstatusdoesnotmatchelementtransformationcompactificationstatus.Mappingcontextcompactified:{},Elementtransformationcompactified:{}",context.compactified,is_compactified_element(transformation)); } transformation.SetIntPoint(&ip); //Tensorcontractionsandtransposeactionscansupplycanonicalvalue/gradientsamplesdirectly. if(direction_sample){ if(direction.get_element().GetMapType()!=mfem::FiniteElement::VALUE||direction_sample->value.Size()!=m_options.dimension||direction_sample->gradient.Height()!=m_options.dimension||direction_sample->gradient.Width()!=m_options.dimension){ returnMappingStatus::INVALID_DIMENSION; } workspace.m_field_value=direction_sample->value; workspace.m_field_jacobian.SetSize(m_options.dimension); mfem::Mult(direction_sample->gradient,inverse_mesh_jacobian?*inverse_mesh_jacobian:transformation.InverseJacobian(),workspace.m_field_jacobian); }else{ evaluate_displacement_field(direction,transformation,ip,workspace,workspace.m_field_value,workspace.m_field_jacobian,inverse_mesh_jacobian); } if(!is_finite(workspace.m_field_jacobian)||!is_finite(workspace.m_field_value)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } variation.displacement_variation=workspace.m_field_value; variation.displacement_jacobian_variation=workspace.m_field_jacobian; if(context.compactified){ if(compactification_sample==nullptr){ constMappingStatuscoordinate_status=evaluate_compactification_coordinate(element_data.compactification,transformation,ip,workspace,workspace.m_compactification_point,inverse_mesh_jacobian); if(coordinate_status!=MappingStatus::VALID){ returncoordinate_status; } compactification_sample=&workspace.m_compactification_point; } if(compactification_sample->coordinate_gradient.Size()!=m_options.dimension){ returnMappingStatus::INVALID_DIMENSION; } if(!is_finite(compactification_sample->compactification_coordinate)||!is_finite(compactification_sample->coordinate_gradient)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } constcompactification::ExteriorMapInputexterior_input{ .reference_position=context.reference_position, .displaced_position=context.displaced_position, .displacement_jacobian=context.displacement_jacobian, .compactification_coordinate_gradient=compactification_sample->coordinate_gradient, .compactification_coordinate=compactification_sample->compactification_coordinate, }; workspace.m_exterior_result.physical_position=context.physical_position; workspace.m_exterior_result.mapping_jacobian=context.mapping_jacobian; constcompactification::ExteriorMapDirectionexterior_direction{ .displaced_position_variation=variation.displacement_variation, .displacement_jacobian_variation=variation.displacement_jacobian_variation }; constMappingStatusexterior_status=m_exterior_map->evaluate_variation(exterior_input,workspace.m_exterior_result,exterior_direction,workspace.m_exterior_variation); if(exterior_status!=MappingStatus::VALID){ returnexterior_status; } variation.physical_position_variation=workspace.m_exterior_variation.physical_position_variation; variation.mapping_jacobian_variation=workspace.m_exterior_variation.mapping_jacobian_variation; }else{ variation.physical_position_variation=variation.displacement_variation; variation.mapping_jacobian_variation=variation.displacement_jacobian_variation; } mfem::Mult(context.inverse_mapping_jacobian,variation.mapping_jacobian_variation,workspace.m_matrix_temp_1); doubletrace=0.0; for(intdimID=0;dimID<m_options.dimension;++dimID){ trace+=workspace.m_matrix_temp_1(dimID,dimID); } variation.mapping_determinate_variation=context.mapping_determinate*trace; variation.inverse_mapping_jacobian_variation.SetSize(m_options.dimension,m_options.dimension); mfem::Mult(workspace.m_matrix_temp_1,context.inverse_mapping_jacobian,variation.inverse_mapping_jacobian_variation); variation.inverse_mapping_jacobian_variation*=-1.0; if(!is_finite(variation.physical_position_variation)||!is_finite(variation.mapping_jacobian_variation)||!std::isfinite(variation.mapping_determinate_variation)||!is_finite(variation.inverse_mapping_jacobian_variation)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } returnMappingStatus::VALID; } mfem::ElementTransformation&DomainMapper::select_face_element_transformation( constmfem::FaceElementTransformations&transformations, constFaceElementSideside ){ if(side==FaceElementSide::ELEMENT_1){ serif_assert<SERiFErrorCode::MISSING_FACE_ELEMENT>(transformations.Elem1!=nullptr,"FaceelementtransformationforELEMENT_1isnull."); return*transformations.Elem1; } serif_assert<SERiFErrorCode::MISSING_FACE_ELEMENT>(transformations.Elem2!=nullptr,"FaceelementtransformationforELEMENT_2isnull."); return*transformations.Elem2; } constmfem::IntegrationPoint&DomainMapper::select_face_element_integration_point( constmfem::FaceElementTransformations&transformations, constFaceElementSideside ){ mfem::ElementTransformation&element_transformation=select_face_element_transformation(transformations,side); returnelement_transformation.GetIntPoint(); } }