discretization.hpp optional tuple type_traits serif/backend/mfem/model/discretization.hpp serif/backend/mfem/serialize/resources.hpp serif/utils/serialize/model.hpp serif/utils/serialize/physics.hpp src/include/serif/backend/mfem/serialize/configuration.hpp serif::utils::serialize::Serializer< model::backend::mfem::StellarDiscretization< Owner, Bindings, Deformation > > serif::backend::mfem::serialize::detail::OwnedBindings serif serif::backend serif::backend::mfem serif::backend::mfem::serialize serif::backend::mfem::serialize::detail serif::utils serif::utils::serialize #pragmaonce #include<optional> #include<tuple> #include<type_traits> #include"serif/backend/mfem/model/discretization.hpp" #include"serif/backend/mfem/serialize/resources.hpp" #include"serif/utils/serialize/model.hpp" #include"serif/utils/serialize/physics.hpp" namespaceserif::backend::mfem::serialize{ namespacedetail{ usingdiscretization::backend::mfem::OwnedBindings; template<typenameSchema> [[nodiscard]]utils::serialize::Nodedomain_schema(){ usingnamespaceutils::serialize; std::vector<Node>domains; std::vector<Node>boundaries; for(constauto&descriptor:Schema::domain_descriptors()){ domains.push_back(object("mfem.domain",field("name",descriptor.name),field("attribute",descriptor.ID))); } for(constauto&descriptor:Schema::boundary_descriptors()){ boundaries.push_back(object("mfem.boundary",field("name",descriptor.name),field("attribute",descriptor.ID))); } returnobject("mfem.schema",field("domains",domains),field("boundaries",boundaries)); } template<typenameKey,typenameContext,typenameKeys> [[nodiscard]]utils::serialize::Result<void>restore_binding(constutils::serialize::Node&node,OwnedBindings<Context, Keys>&owner){ usingnamespaceutils::serialize; usingBinding=typenameOwnedBindings<Context, Keys>::templateBinding<Key>; autoterm=read_field<Node>(node,"term"); autoschema=read_field<Node>(node,"schema"); autocoordinates=read_field<Node>(node,"coordinates"); if(node.type!="mfem.term_binding"|| (node.version!=1&&node.version!=2)|| (node.version==2)!=node.children.contains("reconstruction")||!term||!schema||!coordinates||*term!=term_schema<Key>()|| *schema!=domain_schema<typename Binding::Schema>()||term->type=="unsupported"){ returnstd::unexpected(Error{"bindings","Savedtermordomainidentitydoesnotmatchtherequestedtypeddiscretization."}); } std::unique_ptr<Binding>binding; ifconstexpr(discretization::blocks::SpatialTerm<Key>){ autoindex=read_field<std::uint64_t>(node,"space"); if(!index||*index>=owner.resources.spaces.size()){ returnstd::unexpected(Error{"bindings/space","Termspaceismissingoroutsidetherestoredresourcetable."}); } binding=std::make_unique<Binding>(*owner.resources.spaces[*index]); if(constautosaved=node.children.find("reconstruction");saved!=node.children.end()){ ifconstexpr(!std::same_as<Key,discretization::blocks::density::mass>){ returnstd::unexpected(Error{"bindings/reconstruction","Surface-powerreconstructionsupportsonlymassdensity."}); }else{ constauto&representation=saved->second; autoexponent=read_field<double>(representation,"density_exponent"); autoboundary=read_field<std::string>(representation,"boundary"); if(representation.type!="mfem.surface_power"||representation.version!=1||!exponent||!boundary){ returnstd::unexpected(Error{"bindings/reconstruction","Unknownorincompletereconstruction;itsnumericalinterpretationcannotberestored."}); } constdiscretization::reconstruction::SurfacePower<Key>specification{ .density_exponent=*exponent,.region={*boundary}}; autoplan=discretization::backend::mfem::make_reconstruction(specification,*binding); binding=std::make_unique<Binding>(*owner.resources.spaces[*index],std::move(plan)); } } }else{ if(node.children.contains("reconstruction")){ returnstd::unexpected(Error{"bindings/reconstruction","Globalscalarfieldscannotcarryspatialreconstruction."}); } autoindex=read_field<std::uint64_t>(node,"mesh"); if(!index||*index>=owner.resources.meshes.size()){ returnstd::unexpected(Error{"bindings/mesh","Globalscalarmeshismissingoroutsidetherestoredresourcetable."}); } binding=std::make_unique<Binding>(*owner.resources.meshes[*index]); } if(*coordinates!=binding_coordinates(*binding)){ returnstd::unexpected(Error{"bindings/coordinates","Termdomainsupportorreducedcoefficientnumberingchangedduringreconstruction."}); } std::get<utils::dependencies::key_index<Key,Keys>()>(owner.bindings)=std::move(binding); return{}; } } template<typenameOriginal> usingRestoredDiscretization=model::backend::mfem::StellarDiscretization< detail::OwnedBindings<std::remove_cvref_t<decltype(std::declval<Original>().term_bindings)>>, decltype(std::declval<detail::OwnedBindings<std::remove_cvref_t<decltype(std::declval<Original>().term_bindings)>>>().context()), std::remove_cvref_t<decltype(std::declval<Original>().deformation)>>; template<typenameOwner,typenameBindings,typenameDeformation> [[nodiscard]]utils::serialize::Nodesave_discretization(constmodel::backend::mfem::StellarDiscretization<Owner, Bindings, Deformation>&value, SaveOptionsoptions={}){ usingnamespaceutils::serialize; ResourceWriterresources(options); Nodebindings{.type="array"}; [&]<typename...Keys>(utils::dependencies::KeyList<Keys...>){ std::size_tindex=0; ([&]{ usingBinding=std::remove_cvref_t<decltype(value.templatebinding<Keys>())>; constauto&binding=value.templatebinding<Keys>(); Noderecord=object("mfem.term_binding",field("term",term_schema<Keys>()), field("schema",detail::domain_schema<typename Binding::Schema>()),field("coordinates",binding_coordinates(binding))); ifconstexpr(discretization::blocks::SpatialTerm<Keys>){ record.children.emplace("space",encode(resources.space(binding.space()))); if(constauto&reconstruction=binding.reconstruction()){ //Version2preventsoldreadersfromsilentlytreatingweightedcoefficientsasordinarypolynomials. record.version=2; constauto*profile=dynamic_cast<constdiscretization::reconstruction::SurfacePowerProfile*>(&reconstruction->profile()); utils::errors::serif_ensure<utils::errors::SERiFErrorCode::INVALID_ARGUMENT>(profile!=nullptr, "Reconstruction'{}'hasnoarchivecodec;addonebeforesavingthisfield.",reconstruction->profile().name()); std::stringboundary_name; for(constauto&boundary:Binding::Schema::boundary_descriptors()){ if(boundary.ID==reconstruction->boundary_attribute()){boundary_name=boundary.name;} } utils::errors::serif_ensure<utils::errors::SERiFErrorCode::INVALID_ARGUMENT>(!boundary_name.empty(), "Cannotsaveareconstructionwhoseboundaryisabsentfromthefield'sschema."); record.children.emplace("reconstruction",object("mfem.surface_power", field("density_exponent",profile->density_exponent()),field("boundary",boundary_name))); } }else{ record.children.emplace("mesh",encode(resources.mesh(binding.mesh()))); } bindings.children.emplace(std::to_string(index++),std::move(record)); }(),...); }(typenameBindings::Keys{}); resources.mapping(value.compactification,value.mapper); Noderesult=object("mfem.stellar_discretization",field("bindings",bindings)); ifconstexpr(std::same_as<Deformation,model::backend::mfem::NoDeformation>){ result.children.emplace("deformation",Node{.type="mfem.no_deformation"}); }else{ result.children.emplace("deformation",encode(value.deformation.model)); result.children.emplace("reference",resources.reference(value.deformation.reference)); } result.children.emplace("resources",std::move(resources).finish()); returnresult; } template<typenameOriginal> [[nodiscard]]utils::serialize::Result<RestoredDiscretization<Original>>restore_discretization(constutils::serialize::Node&node, constMeshResolver&resolver={}){ usingnamespaceutils::serialize; usingContext=std::remove_cvref_t<decltype(std::declval<Original>().term_bindings)>; usingDeformation=std::remove_cvref_t<decltype(std::declval<Original>().deformation)>; if(node.type!="mfem.stellar_discretization"||node.version!=1){ returnstd::unexpected(Error{"discretization","UnsupportedMFEMstellardiscretizationschema."}); } try{ autoresources_node=read_field<Node>(node,"resources"); //Inspecteachbindingversionlocally;genericvectordecodingonlyacceptsversion-1children. autobindings=read_field<Node>(node,"bindings"); if(!resources_node||!bindings||bindings->type!="array"||!std::holds_alternative<std::monostate>(bindings->value)||bindings->children.size()!=utils::dependencies::key_count_v<typename Context::Keys>){ returnstd::unexpected(Error{"discretization","Missingresourcesorincompatibleterm-bindingcount."}); } autoresources=restore_resources(*resources_node,resolver); if(!resources){ returnstd::unexpected(resources.error()); } autoowner=std::make_shared<detail::OwnedBindings<Context>>(); owner->resources=std::move(*resources); std::optional<Error>error; [&]<typename...Keys>(utils::dependencies::KeyList<Keys...>){ std::size_tindex=0; ([&]{ if(!error){ constautosaved=bindings->children.find(std::to_string(index)); if(saved==bindings->children.end()){ error=Error{"bindings","Term-bindingarrayindicesarenotcontiguous."}; }else{ autostatus=detail::restore_binding<Keys>(saved->second,*owner); if(!status){error=status.error();} } } ++index; }(),...); }(typenameContext::Keys{}); if(error){ returnstd::unexpected(*error); } autobase=model::backend::mfem::make_stellar_discretization(owner,owner->context(),*owner->resources.compactification,*owner->resources.mapper); autodeformation=read_field<Node>(node,"deformation"); if(!deformation){ returnstd::unexpected(deformation.error()); } ifconstexpr(std::same_as<Deformation,model::backend::mfem::NoDeformation>){ if(deformation->type!="mfem.no_deformation"){ returnstd::unexpected(Error{"deformation","Savedshaperepresentationdiffersfromtherequestedfixed-geometrydiscretization."}); } returnbase; }else{ usingDomainModel=std::remove_cvref_t<decltype(std::declval<Deformation>().model)>; autodeformation_model=decode<DomainModel>(*deformation); autoreference_node=read_field<Node>(node,"reference"); if(!deformation_model||!reference_node){ returnstd::unexpected(Error{"deformation","Missingorunsupportedsurface/extensionprescriptionorreferencegeometry."}); } autoreference=restore_reference(*reference_node,owner->resources); if(!reference){ returnstd::unexpected(reference.error()); } returnmodel::backend::mfem::with_deformation(std::move(base),std::move(*deformation_model),std::move(*reference)); } }catch(conststd::exception&error){ returnstd::unexpected(Error{"discretization","Savednumericalinterpretationisinvalid:"+std::string{error.what()}}); } } } namespaceserif::utils::serialize{ template<typenameOwner,typenameBindings,typenameDeformation> structSerializer<model::backend::mfem::StellarDiscretization<Owner,Bindings,Deformation>>{ usingDiscretization=model::backend::mfem::StellarDiscretization<Owner, Bindings, Deformation>; staticconstexprstd::string_viewkey="discretization"; staticNodesave(constmodel::backend::mfem::StellarDiscretization<Owner, Bindings, Deformation>&value){ returnserif::backend::mfem::serialize::save_discretization(value); } staticResult<Discretization>load(constNode&){ returnstd::unexpected(Error{"discretization","Useserif::backend::mfem::serialize::restore_discretization<Original>(node)toreconstructanindependentlyownednumericaldiscretization."}); } }; }