basis_evaluation.cpp algorithm vector mfem/fem/fe/fe_base.hpp mfem/fem/intrules.hpp mfem/linalg/vector.hpp mfem/linalg/densemat.hpp serif/backend/mfem/discretization/basis_evaluation.hpp serif/backend/mfem/discretization/tensor_basis.hpp serif/utils/error/errors.hpp serif serif::discretization serif::discretization::backend serif::discretization::backend::mfem #include<algorithm> #include<vector> #include"mfem/fem/fe/fe_base.hpp" #include"mfem/fem/intrules.hpp" #include"mfem/linalg/vector.hpp" #include"mfem/linalg/densemat.hpp" #include"serif/backend/mfem/discretization/basis_evaluation.hpp" #include"serif/backend/mfem/discretization/tensor_basis.hpp" #include"serif/utils/error/errors.hpp" namespaceserif::discretization::backend::mfem{ voidBasisEvaluation::sample( const::mfem::FiniteElement&element, const::mfem::IntegrationRule&rule, constReferenceOperationoperation, constintcopies, TensorBasisCache&cache, constContractionModemode, constElementReconstruction*reconstruction ){ usingnamespaceutils::errors; constboolmapping_supported=element.GetRangeType()==::mfem::FiniteElement::SCALAR&&element.GetMapType()==::mfem::FiniteElement::VALUE; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>(element.GetDim()==3&&copies>0&&mapping_supported,"Canonicalbasissamplingrequires3DscalarVALUEbases."); serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(reconstruction==nullptr||copies==1, "RadialreconstructioncurrentlysupportsscalarH1valuesandgradientsonly."); constintsamples=operation==ReferenceOperation::gradient?3:operation==ReferenceOperation::value_and_gradient?4:1; m_components=copies*samples; m_points=rule.GetNPoints(); m_width=copies*element.GetDof(); m_tensor=mode==ContractionMode::automatic?cache.get(element,rule,operation,copies,reconstruction):nullptr; m_identity_mapping=static_cast<bool>(m_tensor); if(m_tensor){ m_dense.Clear(); m_mapping.Clear(); return; } m_mapping.SetSize(0,0); m_dense.SetSize(m_points*m_components,m_width); m_dense=0.0; ::mfem::Vectorshape(element.GetDof()); ::mfem::DenseMatrixgradients(element.GetDof(),3); for(intq=0;q<m_points;++q){ if(reconstruction!=nullptr){ reconstruction->sample(element,rule.IntPoint(q),shape,gradients); }else{ element.CalcShape(rule.IntPoint(q),shape); if(samples>1){ element.CalcDShape(rule.IntPoint(q),gradients); } } for(intcopy=0;copy<copies;++copy){ for(intsample=0;sample<samples;++sample){ constintderivative=operation==ReferenceOperation::gradient?sample:sample-1; for(intdof=0;dof<element.GetDof();++dof){ constdoublevalue=samples==1||derivative<0?shape[dof]:gradients(dof,derivative); m_dense(q*m_components+copy*samples+sample,copy*element.GetDof()+dof)=value; } } } } } voidBasisEvaluation::set_constant(constintpoints){ m_tensor.reset(); m_identity_mapping=false; m_components=1; m_points=points; m_width=1; m_dense.SetSize(points,1); m_dense=1.0; m_mapping.SetSize(0,0); } voidBasisEvaluation::reset_from(constBasisEvaluation&reference,constintcomponents){ m_tensor=reference.m_tensor; m_identity_mapping=false; m_points=reference.m_points; m_width=reference.m_width; m_components=components; if(m_tensor){ m_mapping.SetSize(m_points*components,m_tensor->components()); m_dense.SetSize(0,0); }else{ m_dense.SetSize(m_points*components,m_width); m_mapping.SetSize(0,0); } } voidBasisEvaluation::evaluate(const::mfem::Vector&coefficients,::mfem::Vector&values,BasisWorkspace&workspace)const{ usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::INVALID_DOF_COUNT,std::invalid_argument>( coefficients.Size()==m_width, "Basisevaluationcoefficientcountdoesnotmatchitselement." ); if(!m_tensor){ workspace.reference_values.SetSize(height()); m_dense.Mult(coefficients,workspace.reference_values); values=workspace.reference_values; return; } m_tensor->apply(coefficients,workspace.reference_values,workspace.tensor); if(m_identity_mapping){ //Keeptheworkspacecopy:callersmayreuseonevectorforinputandoutput. values=workspace.reference_values; return; } values.SetSize(height()); constintreference_components=m_tensor->components(); constintmapping_stride=m_mapping.Height(); constdouble*mapping=m_mapping.GetData(); constdouble*reference=workspace.reference_values.GetData(); double*destination=values.GetData(); for(intq=0;q<m_points;++q){ constintoutput_offset=q*m_components; constintinput_offset=q*reference_components; for(intoutput=0;output<m_components;++output){ constintrow=output_offset+output; doublevalue=0.0; for(intinput=0;input<reference_components;++input){ value+=mapping[input*mapping_stride+row]*reference[input_offset+input]; } destination[row]=value; } } } voidBasisEvaluation::evaluate_many(const::mfem::Vector&coefficients,::mfem::Vector&values,constintlanes,BasisWorkspace&workspace)const{ usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::INVALID_DOF_COUNT,std::invalid_argument>( lanes>0&&coefficients.Size()==m_width*lanes, "Batchedbasisevaluationcoefficientcountdoesnotmatchitselement." ); if(!m_tensor){ //DenseevaluationkeepsMFEM'smatrix-vectorproduct,onelaneatatime. ::mfem::Vectorlane_coefficients(m_width),lane_values(height()); values.SetSize(height()*lanes); for(intlane=0;lane<lanes;++lane){ for(inti=0;i<m_width;++i){ lane_coefficients[i]=coefficients[i*lanes+lane]; } m_dense.Mult(lane_coefficients,lane_values); for(inti=0;i<height();++i){ values[i*lanes+lane]=lane_values[i]; } } return; } m_tensor->apply_many(coefficients,workspace.reference_values,lanes,workspace.tensor); if(m_identity_mapping){ values=workspace.reference_values; return; } values.SetSize(height()*lanes); constintreference_components=m_tensor->components(); constintmapping_stride=m_mapping.Height(); constdouble*mapping=m_mapping.GetData(); constdouble*reference=workspace.reference_values.GetData(); double*destination=values.GetData(); std::vector<double>lane_values(static_cast<std::size_t>(lanes)); for(intq=0;q<m_points;++q){ constintoutput_offset=q*m_components; constintinput_offset=q*reference_components; for(intoutput=0;output<m_components;++output){ constintrow=output_offset+output; std::fill(lane_values.begin(),lane_values.end(),0.0); for(intinput=0;input<reference_components;++input){ constdoubleweight=mapping[input*mapping_stride+row]; for(intlane=0;lane<lanes;++lane){ lane_values[static_cast<std::size_t>(lane)]+=weight*reference[(input_offset+input)*lanes+lane]; } } for(intlane=0;lane<lanes;++lane){ destination[row*lanes+lane]=lane_values[static_cast<std::size_t>(lane)]; } } } } voidBasisEvaluation::integrate(const::mfem::Vector&values,::mfem::Vector&coefficients,BasisWorkspace&workspace)const{ usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::INVALID_DOF_COUNT,std::invalid_argument>( values.Size()==height(), "Basistransposequadraturesizedoesnotmatchitsrule." ); if(!m_tensor){ workspace.reference_values.SetSize(m_width); m_dense.MultTranspose(values,workspace.reference_values); coefficients=workspace.reference_values; return; } if(m_identity_mapping){ workspace.reference_values=values; }else{ constintreference_components=m_tensor->components(); constintmapping_stride=m_mapping.Height(); constdouble*mapping=m_mapping.GetData(); constdouble*source=values.GetData(); workspace.reference_values.SetSize(m_points*reference_components); double*reference=workspace.reference_values.GetData(); for(intq=0;q<m_points;++q){ constintoutput_offset=q*m_components; constintinput_offset=q*reference_components; for(intinput=0;input<reference_components;++input){ constintcolumn=input*mapping_stride; doublevalue=0.0; for(intoutput=0;output<m_components;++output){ constintrow=output_offset+output; value+=mapping[column+row]*source[row]; } reference[input_offset+input]=value; } } } m_tensor->apply(workspace.reference_values,coefficients,workspace.tensor,true); } intBasisEvaluation::height()constnoexcept{ returnm_points*m_components; } intBasisEvaluation::width()constnoexcept{ returnm_width; } boolBasisEvaluation::uses_tensor()constnoexcept{ returnstatic_cast<bool>(m_tensor); } }