mass_diagonal.cpp serif/backend/mfem/discretization/mass_diagonal.hpp cmath memory algorithm utility vector mfem/fem/bilinearform.hpp mfem/fem/bilininteg.hpp mfem/general/forall.hpp serif/utils/error/errors.hpp serif/backend/mfem/discretization/element_coordinates.hpp serif/backend/mfem/shared/parallel.hpp serif serif::discretization serif::discretization::backend serif::discretization::backend::mfem #include"serif/backend/mfem/discretization/mass_diagonal.hpp" #include<cmath> #include<memory> #include<algorithm> #include<utility> #include<vector> #include"mfem/fem/bilinearform.hpp" #include"mfem/fem/bilininteg.hpp" #include"mfem/general/forall.hpp" #include"serif/utils/error/errors.hpp" #include"serif/backend/mfem/discretization/element_coordinates.hpp" #include"serif/backend/mfem/shared/parallel.hpp" namespaceserif::discretization::backend::mfem{ namespace{ [[nodiscard]]::mfem::Vectorscalar_mass_diagonal(constDofMap&binding,const::mfem::Array<int>&marker){ constautoelements=binding.validated_elements(); constauto&mesh=binding.mesh(); constauto*plan=binding.reconstruction().get(); structElementDiagonal{ std::vector<int>indices; std::vector<double>values; }; structWorkspace{ ::mfem::IsoparametricTransformationtransformation; ::mfem::Vectorshape,weighted; ::mfem::DenseMatrixderivatives; std::vector<int>local_of_reduced; }; std::vector<ElementDiagonal>results(static_cast<std::size_t>(mesh.GetNE())); std::vector<Workspace>workspaces(static_cast<std::size_t>(utils::parallel::worker_count())); utils::parallel::for_each_index(mesh.GetNE(),[&](constintelement,constintworker){ if(marker[mesh.GetAttribute(element)-1]==0){return;} Workspace&work=workspaces[static_cast<std::size_t>(worker)]; work.local_of_reduced.resize(static_cast<std::size_t>(binding.size()),-1); constauto&finite_element=*binding.space().GetFE(element); utils::parallel::element_transformation(mesh,element,work.transformation); constautocoordinates=elements.coordinates(element); ElementDiagonal&result=results[static_cast<std::size_t>(element)]; std::vector<std::vector<std::pair<int,double>>>constraint_rows(static_cast<std::size_t>(finite_element.GetDof())); for(intnode=0;node<finite_element.GetDof();++node){ coordinates.for_each_coefficient(node,[&](constintreduced,constdoubleweight){ int&local=work.local_of_reduced[static_cast<std::size_t>(reduced)]; if(local<0){ local=static_cast<int>(result.indices.size()); result.indices.push_back(reduced); } constraint_rows[static_cast<std::size_t>(node)].emplace_back(local,weight); }); } for(constintreduced:result.indices){work.local_of_reduced[static_cast<std::size_t>(reduced)]=-1;} result.values.assign(result.indices.size(),0.0); constauto*reconstruction=plan!=nullptr?binding.reconstruction_element(element):nullptr; intorder=::mfem::MassIntegrator::GetRule(finite_element,finite_element,work.transformation).GetOrder(); if(reconstruction!=nullptr){order+=plan->integration_order_increment();} constauto&rule=::mfem::IntRules.Get(finite_element.GetGeomType(),order); std::vector<double>combined(result.indices.size()); work.shape.SetSize(finite_element.GetDof()); for(intpoint=0;point<rule.GetNPoints();++point){ constauto&location=rule.IntPoint(point); const::mfem::Vector*shape=&work.shape; if(reconstruction!=nullptr){ reconstruction->sample(finite_element,location,work.weighted,work.derivatives); shape=&work.weighted; }else{ finite_element.CalcShape(location,work.shape); } std::fill(combined.begin(),combined.end(),0.0); for(intnode=0;node<finite_element.GetDof();++node){ for(constauto&[local,coefficient]:constraint_rows[static_cast<std::size_t>(node)]){ combined[static_cast<std::size_t>(local)]+=coefficient*(*shape)[node]; } } work.transformation.SetIntPoint(&location); constdoubleweight=location.weight*work.transformation.Weight(); for(std::size_tlocal=0;local<combined.size();++local){ result.values[local]+=weight*combined[local]*combined[local]; } } }); ::mfem::Vectordiagonal(binding.size()); diagonal=0.0; for(constauto&result:results){ for(std::size_tk=0;k<result.indices.size();++k){diagonal[result.indices[k]]+=result.values[k];} } returndiagonal; } } std::expected<std::vector<double>,std::string>detail::reference_mass_diagonal(constDofMap&binding){ usingnamespaceutils::errors; binding.validate(); if(binding.size()==0){ returnstd::vector<double>{}; } ::mfem::FiniteElementSpace&space=binding.space(); ::mfem::Array<int>marker(binding.mesh().attributes.Max()); marker=0; for(intelement=0;element<space.GetNE();++element){ if(binding.supports(element)){ marker[binding.mesh().GetAttribute(element)-1]=1; } } if(space.GetVDim()==1){ //Thescalarfields(density,potential)needonlydiag(P^TMP);assemblingMandP^TMPtoreadit //cost6sofa19sbenchmarksolve. const::mfem::Vectorsupported=scalar_mass_diagonal(binding,marker); std::vector<double>result(static_cast<std::size_t>(supported.Size())); for(intindex=0;index<supported.Size();++index){ if(!std::isfinite(supported[index])||supported[index]<=0.0){ returnstd::unexpected(format_error_message<SERiFErrorCode::NORMALIZATION_ERROR>("Referencemassdiagonalentry{}is{},buteverysupportedcoefficientrequirespositivefiniteentries.Checkthereferencemeshgeometryandfinite-elementsupport.",index,supported[index])); } result[static_cast<std::size_t>(index)]=supported[index]; } returnresult; } serif_ensure<SERiFErrorCode::NORMALIZATION_ERROR>(binding.reconstruction()==nullptr, "ReconstructedreferencemetricscurrentlyrequireascalarH1densityfield."); //VectorH1fieldsassembletheircomponentwisephysicalinnerproduct. ::mfem::BilinearFormmass(&space); autointegrator=std::make_unique<::mfem::VectorMassIntegrator>(); integrator->SetVDim(space.GetVDim()); mass.AddDomainIntegrator(integrator.release(),marker); mass.Assemble(); mass.Finalize(); if(binding.constrained()){ const::mfem::Array<int>essential_dofs; ::mfem::OperatorHandlesystem; mass.FormSystemMatrix(essential_dofs,system); } ::mfem::Vectordiagonal(binding.constrained()?space.GetTrueVSize():space.GetVSize()); mass.AssembleDiagonal(diagonal); ::mfem::Vectorsupported=binding.constrained()?binding.gather_true(diagonal):binding.gather(diagonal); std::vector<double>result(supported.Size()); for(intindex=0;index<supported.Size();++index){ if(!std::isfinite(supported[index])||supported[index]<=0.0){ returnstd::unexpected(format_error_message<SERiFErrorCode::NORMALIZATION_ERROR>("Referencemassdiagonalentry{}is{},buteverysupportedcoefficientrequirespositivefiniteentries.Checkthereferencemeshgeometryandfinite-elementsupport.",index,supported[index])); } result[index]=supported[index]; } returnresult; } }