numerics.hpp serif/utils/serialize/model.hpp serif/model/configured_discretization.hpp serif/solver/normalization/configuration.hpp serif/solver/normalization/diagonal.hpp serif/solver/normalization/plan.hpp serif/solver/preconditioner/default_preconditioners.hpp serif/solver/nonlinear/options.hpp serif/discretization/quadrature/policy.hpp serif/model/normalization/plan.hpp serif/geometry/deformation/computations.hpp src/include/serif/backend/mfem/serialize/configuration.hpp src/include/serif/backend/mfem/serialize/options.hpp src/include/serif/utils/serialize/solver.hpp serif::utils::serialize::Serializer< model::DiscretizationOptions< Model, FiniteElements, Normalization, Preconditioner > > serif::utils::serialize::RecipeSerializer serif::utils::serialize::Serializer< solver::Newton > serif::utils::serialize::Serializer< solver::Backtracking > serif::utils::serialize::Serializer< solver::linear::Control > serif::utils::serialize::Serializer< solver::linear::FGMRES > serif::utils::serialize::Serializer< solver::NormalizedResidualMetric > serif::utils::serialize::Serializer< solver::StandardNewton > serif::utils::serialize::Serializer< laneemden::IntegrationOptions > serif::utils::serialize::Serializer< solver::normalization::FromModel > serif::utils::serialize::Serializer< solver::normalization::AutomaticPlan > serif::utils::serialize::Serializer< solver::normalization::Dimensionless > serif::utils::serialize::Serializer< solver::normalization::StellarReferenceScales > serif::utils::serialize::Serializer< solver::normalization::UnitMetric > serif::utils::serialize::Serializer< solver::normalization::IdentityCoordinate > serif::utils::serialize::Serializer< model::preconditioning::None > serif::utils::serialize::Serializer< solver::preconditioner::strategies::inverse::Diagonal > serif::utils::serialize::Serializer< solver::preconditioner::strategies::inverse::DenseDirect > serif::utils::serialize::Serializer< solver::preconditioner::strategies::inverse::FixedAMG > serif::utils::serialize::Serializer< solver::preconditioner::strategies::inverse::SparseDirect > serif::utils::serialize::Serializer< solver::preconditioner::strategies::coupling::SecondThenFirst > serif::utils::serialize::Serializer< solver::SolverOptions< Metric, Strategies, Linear > > serif::utils::serialize::Serializer< solver::normalization::LaneEmdenApproximation< Mass, Density > > serif::utils::serialize::Serializer< solver::normalization::NormalizationOptions< Scheme, Coordinates, Plan, Sources, Computations > > serif::utils::serialize::Serializer< solver::preconditioner::BlockPreconditioner< Row, Field, Strategy > > serif::utils::serialize::Serializer< solver::preconditioner::CoupledPreconditioner< First, Second, Policy > > serif::utils::serialize::Serializer< solver::preconditioner::BorderedPreconditioner< Fields, Constraints > > serif::utils::serialize::Serializer< solver::normalization::DiagonalNormalization > serif::utils::serialize::SchemaSerializer serif::utils::serialize::Serializer< solver::normalization::ReferenceVolumeMetric< Term > > serif::utils::serialize::Serializer< geometry::deformation::keys::SurfaceMetric > serif::utils::serialize::Serializer< model::normalization::SurfaceRows > serif::utils::serialize::Serializer< solver::normalization::WithPointRows< Volume, Quantity, Selection > > serif::utils::serialize::Serializer< solver::normalization::PhysicalRieszCoordinate< Quantity, Metric > > serif::utils::serialize::Serializer< solver::normalization::DimensionlessRieszCoordinate< Quantity, Metric, Geometry > > serif::utils::serialize::Serializer< dependencies::Binding< Key, Target > > serif::utils::serialize::Serializer< dependencies::Bindings< Bindings... > > serif::utils::serialize::Serializer< solver::normalization::NormalizationPlan< Values, Residuals > > serif::utils::serialize::Serializer< discretization::quadrature::RuleControl > serif::utils::serialize::Serializer< discretization::quadrature::RuleSet > serif::utils::serialize::Serializer< discretization::quadrature::Policy > serif serif::utils serif::utils::serialize #pragmaonce #include"serif/utils/serialize/model.hpp" #include"serif/model/configured_discretization.hpp" #include"serif/solver/normalization/configuration.hpp" #include"serif/solver/normalization/diagonal.hpp" #include"serif/solver/normalization/plan.hpp" #include"serif/solver/preconditioner/default_preconditioners.hpp" #include"serif/solver/nonlinear/options.hpp" #include"serif/discretization/quadrature/policy.hpp" #include"serif/model/normalization/plan.hpp" #include"serif/geometry/deformation/computations.hpp" namespaceserif::utils::serialize{ template<model::StellarModelTypeModel,typenameFiniteElements,typenameNormalization,typenamePreconditioner> structSerializer<model::DiscretizationOptions<Model,FiniteElements,Normalization,Preconditioner>>{ usingT=model::DiscretizationOptions<Model, FiniteElements, Normalization, Preconditioner>; staticconstexprstd::string_viewkey="configuration"; staticconstexprstd::string_viewtype="model.configured_discretization"; [[nodiscard]]staticNodesave(constT&value){ returnobject(type,field("model",value.model),field("finite_elements",value.finite_elements), field("normalization",value.normalization),field("preconditioner",value.preconditioner)); } [[nodiscard]]staticResult<T>load(constNode&node){ returnread_object(node,type,[](Modelmodel,FiniteElementsfinite_elements,Normalizationnormalization,Preconditionerpreconditioner){ returnT{.model=std::move(model),.finite_elements=std::move(finite_elements), .normalization=std::move(normalization),.preconditioner=std::move(preconditioner)}; },member<Model>("model"),member<FiniteElements>("finite_elements"),member<Normalization>("normalization"),member<Preconditioner>("preconditioner")); } }; template<typenameT> structRecipeSerializer:StructSerializer<T>{ [[nodiscard]]staticNodesave(constT&value){ Noderesult=StructSerializer<T>::save(value); result.children.emplace("rows",encode(typenameT::Rows{})); result.children.emplace("values",encode(typenameT::Values{})); returnresult; } [[nodiscard]]staticResult<T>load(constNode&node){ autorows=read_field<typename T::Rows>(node,"rows"); if(!rows){returnstd::unexpected(rows.error());} autovalues=read_field<typename T::Values>(node,"values"); if(!values){returnstd::unexpected(values.error());} returnStructSerializer<T>::load(node); } }; template<> structSerializer<solver::Newton>:StructSerializer<solver::Newton>{ usingT=solver::Newton; staticconstexprstd::string_viewkey="solver.newton"; staticconstexprautomembers=std::tuple{ member_field("relative_tolerance",&T::relative_tolerance), member_field("absolute_tolerance",&T::absolute_tolerance), member_field("maximum_iterations",&T::maximum_iterations), member_field("linear_solve",&T::linear_solve) }; }; template<> structSerializer<solver::Backtracking>:StructSerializer<solver::Backtracking>{ usingT=solver::Backtracking; staticconstexprstd::string_viewkey="solver.backtracking"; staticconstexprautomembers=std::tuple{ member_field("initial_step",&T::initial_step), member_field("contraction",&T::contraction), member_field("fraction_to_boundary",&T::fraction_to_boundary), member_field("sufficient_decrease",&T::sufficient_decrease), member_field("minimum_step",&T::minimum_step), member_field("maximum_trials",&T::maximum_trials), member_field("geometry_preflight",&T::geometry_preflight) }; }; template<> structSerializer<solver::linear::Control>:StructSerializer<solver::linear::Control>{ usingT=solver::linear::Control; staticconstexprstd::string_viewkey="solver.linear.control"; staticconstexprautomembers=std::tuple{ member_field("relative_tolerance",&T::relative_tolerance), member_field("absolute_tolerance",&T::absolute_tolerance), member_field("maximum_iterations",&T::maximum_iterations) }; }; template<> structSerializer<solver::linear::FGMRES>:StructSerializer<solver::linear::FGMRES>{ usingT=solver::linear::FGMRES; staticconstexprstd::string_viewkey="solver.linear.fgmres"; staticconstexprautomembers=std::tuple{member_field("restart_length",&T::restart_length),member_field("print_level",&T::print_level)}; }; template<> structSerializer<solver::NormalizedResidualMetric>:StructSerializer<solver::NormalizedResidualMetric>{ usingT=solver::NormalizedResidualMetric; staticconstexprstd::string_viewkey="solver.metric.normalized_residual"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<solver::StandardNewton>:StructSerializer<solver::StandardNewton>{ usingT=solver::StandardNewton; staticconstexprstd::string_viewkey="solver.strategy.standard_newton"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<laneemden::IntegrationOptions>:StructSerializer<laneemden::IntegrationOptions>{ usingT=laneemden::IntegrationOptions; staticconstexprstd::string_viewkey="lane_emden.integration"; staticconstexprautomembers=std::tuple{ member_field("step",&T::step), member_field("maximum_radius",&T::maximum_radius), member_field("maximum_steps",&T::maximum_steps), member_field("surface_tolerance",&T::surface_tolerance), member_field("central_series_terms",&T::central_series_terms) }; [[nodiscard]]staticboolvalid(constT&value){ returnstd::isfinite(value.step)&&value.step>0.0&&std::isfinite(value.maximum_radius)&&value.maximum_radius>0.0&& std::isfinite(value.surface_tolerance)&&value.surface_tolerance>0.0&&value.surface_tolerance<0.01&& value.maximum_steps>0&&value.central_series_terms>=6&&value.central_series_terms<=64; } }; template<> structSerializer<solver::normalization::FromModel>:StructSerializer<solver::normalization::FromModel>{ usingT=solver::normalization::FromModel; staticconstexprstd::string_viewkey="normalization.from_model"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<solver::normalization::AutomaticPlan>:StructSerializer<solver::normalization::AutomaticPlan>{ usingT=solver::normalization::AutomaticPlan; staticconstexprstd::string_viewkey="normalization.automatic_plan"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<solver::normalization::Dimensionless>:StructSerializer<solver::normalization::Dimensionless>{ usingT=solver::normalization::Dimensionless; staticconstexprstd::string_viewkey="normalization.dimensionless"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<solver::normalization::StellarReferenceScales>:StructSerializer<solver::normalization::StellarReferenceScales>{ usingT=solver::normalization::StellarReferenceScales; staticconstexprstd::string_viewkey="normalization.reference_scales"; staticconstexprautomembers=std::tuple{ member_field("mass",&T::mass), member_field("radius",&T::radius), member_field("gravitational_constant",&T::gravitational_constant), member_field("density",&T::density), member_field("acceleration",&T::acceleration), member_field("inverse_time_squared",&T::inverse_time_squared), member_field("specific_energy",&T::specific_energy), member_field("pressure",&T::pressure), member_field("angular_velocity",&T::angular_velocity), member_field("angular_momentum",&T::angular_momentum), member_field("force",&T::force) }; [[nodiscard]]staticboolvalid(constT&value){ returnstd::apply([&](constauto&...fields){ return((std::isfinite((value.*fields.pointer).value())&&(value.*fields.pointer).value()>0.0)&&...); },members); } }; template<> structSerializer<solver::normalization::UnitMetric>:StructSerializer<solver::normalization::UnitMetric>{ usingT=solver::normalization::UnitMetric; staticconstexprstd::string_viewkey="normalization.metric.unit"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<solver::normalization::IdentityCoordinate>:StructSerializer<solver::normalization::IdentityCoordinate>{ usingT=solver::normalization::IdentityCoordinate; staticconstexprstd::string_viewkey="normalization.coordinate.identity"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<model::preconditioning::None>:StructSerializer<model::preconditioning::None>{ usingT=model::preconditioning::None; staticconstexprstd::string_viewkey="preconditioner.default"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<solver::preconditioner::strategies::inverse::Diagonal>:StructSerializer<solver::preconditioner::strategies::inverse::Diagonal>{ usingT=solver::preconditioner::strategies::inverse::Diagonal; staticconstexprstd::string_viewkey="preconditioner.inverse.diagonal"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<solver::preconditioner::strategies::inverse::DenseDirect>:StructSerializer<solver::preconditioner::strategies::inverse::DenseDirect>{ usingT=solver::preconditioner::strategies::inverse::DenseDirect; staticconstexprstd::string_viewkey="preconditioner.inverse.dense_direct"; staticconstexprautomembers=std::tuple{member_field("minimum_reciprocal_condition",&T::minimum_reciprocal_condition)}; [[nodiscard]]staticboolvalid(constT&value){ returnstd::isfinite(value.minimum_reciprocal_condition)&&value.minimum_reciprocal_condition>=0.0&&value.minimum_reciprocal_condition<=1.0; } }; template<> structSerializer<solver::preconditioner::strategies::inverse::FixedAMG>:StructSerializer<solver::preconditioner::strategies::inverse::FixedAMG>{ usingT=solver::preconditioner::strategies::inverse::FixedAMG; staticconstexprstd::string_viewkey="preconditioner.inverse.fixed_amg"; staticconstexprautomembers=std::tuple{member_field("cycles",&T::cycles)}; [[nodiscard]]staticboolvalid(constT&value){ returnvalue.cycles>0; } }; template<> structSerializer<solver::preconditioner::strategies::inverse::SparseDirect>:StructSerializer<solver::preconditioner::strategies::inverse::SparseDirect>{ usingT=solver::preconditioner::strategies::inverse::SparseDirect; staticconstexprstd::string_viewkey="preconditioner.inverse.sparse_direct"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<solver::preconditioner::strategies::coupling::SecondThenFirst>:StructSerializer<solver::preconditioner::strategies::coupling::SecondThenFirst>{ usingT=solver::preconditioner::strategies::coupling::SecondThenFirst; staticconstexprstd::string_viewkey="preconditioner.coupling.second_then_first"; staticconstexprautomembers=std::tuple{}; }; template<typenameMetric,typenameStrategies,typenameLinear> structSerializer<solver::SolverOptions<Metric,Strategies,Linear>>:StructSerializer<solver::SolverOptions<Metric,Strategies,Linear>>{ usingT=solver::SolverOptions<Metric, Strategies, Linear>; staticconstexprstd::string_viewkey="solver_options"; staticconstexprautomembers=std::tuple{ member_field("method",&T::method), member_field("linear_solver",&T::linear_solver), member_field("line_search",&T::line_search), member_field("metric",&T::metric), member_field("strategies",&T::strategies) }; }; template<typenameMass,typenameDensity> structSerializer<solver::normalization::LaneEmdenApproximation<Mass,Density>>:StructSerializer<solver::normalization::LaneEmdenApproximation<Mass,Density>>{ usingT=solver::normalization::LaneEmdenApproximation<Mass, Density>; staticconstexprstd::string_viewkey="normalization.lane_emden"; staticconstexprautomembers=std::tuple{ member_field("n",&T::n), member_field("mass",&T::mass), member_field("central_density",&T::central_density), member_field("integration",&T::integration) }; [[nodiscard]]staticboolvalid(constT&value){ returnstd::isfinite(value.n)&&value.n>=0.0&&[&]{ ifconstexpr(!std::same_as<Mass,solver::normalization::FromModel>){ if(!std::isfinite(value.mass.value())||value.mass.value()<=0.0){returnfalse;} } ifconstexpr(!std::same_as<Density,solver::normalization::FromModel>){ if(!std::isfinite(value.central_density.value())||value.central_density.value()<=0.0){returnfalse;} } returntrue; }(); } }; template<typenameScheme,typenameCoordinates,typenamePlan,typenameSources,typenameComputations> structSerializer<solver::normalization::NormalizationOptions<Scheme,Coordinates,Plan,Sources,Computations>>:StructSerializer<solver::normalization::NormalizationOptions<Scheme,Coordinates,Plan,Sources,Computations>>{ usingT=solver::normalization::NormalizationOptions<Scheme, Coordinates, Plan, Sources, Computations>; staticconstexprstd::string_viewkey="normalization"; staticconstexprautomembers=std::tuple{ member_field("scheme",&T::scheme), member_field("coordinates",&T::coordinates), member_field("plan",&T::plan), member_field("gravitational_constant",&T::gravitational_constant), member_field("sources",&T::sources), member_field("computations",&T::computations) }; [[nodiscard]]staticboolvalid(constT&value){ returnstd::isfinite(value.gravitational_constant.value())&&value.gravitational_constant.value()>0.0; } }; template<typenameRow,typenameField,typenameStrategy> structSerializer<solver::preconditioner::BlockPreconditioner<Row,Field,Strategy>>:RecipeSerializer<solver::preconditioner::BlockPreconditioner<Row,Field,Strategy>>{ usingT=solver::preconditioner::BlockPreconditioner<Row, Field, Strategy>; staticconstexprstd::string_viewkey="preconditioner.block"; staticconstexprautomembers=std::tuple{member_field("inverse",&T::inverse)}; }; template<typenameFirst,typenameSecond,typenamePolicy> structSerializer<solver::preconditioner::CoupledPreconditioner<First,Second,Policy>>:RecipeSerializer<solver::preconditioner::CoupledPreconditioner<First,Second,Policy>>{ usingT=solver::preconditioner::CoupledPreconditioner<First, Second, Policy>; staticconstexprstd::string_viewkey="preconditioner.coupled"; staticconstexprautomembers=std::tuple{member_field("first",&T::first),member_field("second",&T::second),member_field("coupling",&T::coupling)}; }; template<typenameFields,typenameConstraints> structSerializer<solver::preconditioner::BorderedPreconditioner<Fields,Constraints>>:RecipeSerializer<solver::preconditioner::BorderedPreconditioner<Fields,Constraints>>{ usingT=solver::preconditioner::BorderedPreconditioner<Fields, Constraints>; staticconstexprstd::string_viewkey="preconditioner.bordered"; staticconstexprautomembers=std::tuple{member_field("fields",&T::fields),member_field("constraint_inverse",&T::constraint_inverse)}; }; template<> structSerializer<solver::normalization::DiagonalNormalization>{ staticconstexprstd::string_viewkey="normalization.diagonal"; [[nodiscard]]staticNodesave(constsolver::normalization::DiagonalNormalization&value){ returnobject(key,field("state",std::vector<double>{value.state_factors().begin(),value.state_factors().end()}), field("residual",std::vector<double>{value.residual_factors().begin(),value.residual_factors().end()})); } [[nodiscard]]staticResult<solver::normalization::DiagonalNormalization>load(constNode&node){ autofactors=read_object(node,key,[](std::vector<double>state,std::vector<double>residual){ returnsolver::normalization::make_diagonal_normalization(std::move(state),std::move(residual)); },member<std::vector<double>>("state"),member<std::vector<double>>("residual")); if(!factors){returnstd::unexpected(factors.error());} if(!*factors){returnstd::unexpected(Error{"",factors->error()});} returnstd::move(**factors); } }; template<typenameT> structSchemaSerializer{ [[nodiscard]]staticNodesave(T){returnSerializer<T>::schema();} [[nodiscard]]staticResult<T>load(constNode&node){ autovalid=validate_schema(node,Serializer<T>::schema()); if(!valid){returnstd::unexpected(valid.error());} returnT{}; } }; template<typenameTerm> structSerializer<solver::normalization::ReferenceVolumeMetric<Term>>:SchemaSerializer<solver::normalization::ReferenceVolumeMetric<Term>>{ staticconstexprstd::string_viewkey="normalization.metric.volume"; [[nodiscard]]staticNodeschema(){returnobject(key,field("coordinate",term_schema<Term>()));} }; template<> structSerializer<geometry::deformation::keys::SurfaceMetric>:StructSerializer<geometry::deformation::keys::SurfaceMetric>{ staticconstexprstd::string_viewkey="normalization.metric.surface"; staticconstexprautomembers=std::tuple{}; }; template<> structSerializer<model::normalization::SurfaceRows>:StructSerializer<model::normalization::SurfaceRows>{ staticconstexprstd::string_viewkey="normalization.surface_rows"; staticconstexprautomembers=std::tuple{}; }; template<typenameVolume,typenameQuantity,typenameSelection> structSerializer<solver::normalization::WithPointRows<Volume,Quantity,Selection>>:SchemaSerializer<solver::normalization::WithPointRows<Volume,Quantity,Selection>>{ staticconstexprstd::string_viewkey="normalization.coordinate.point_rows"; [[nodiscard]]staticNodeschema(){ returnobject(key,field("volume",Volume{}),field("dimension",std::string{Quantity::identifier}),field("selection",Selection{})); } }; template<typenameQuantity,typenameMetric> structSerializer<solver::normalization::PhysicalRieszCoordinate<Quantity,Metric>>:SchemaSerializer<solver::normalization::PhysicalRieszCoordinate<Quantity,Metric>>{ staticconstexprstd::string_viewkey="normalization.coordinate.physical_riesz"; [[nodiscard]]staticNodeschema(){returnobject(key,field("dimension",std::string{Quantity::identifier}),field("metric",Metric{}));} }; template<typenameQuantity,typenameMetric,solver::normalization::ReferenceGeometryGeometry> structSerializer<solver::normalization::DimensionlessRieszCoordinate<Quantity,Metric,Geometry>>:SchemaSerializer<solver::normalization::DimensionlessRieszCoordinate<Quantity,Metric,Geometry>>{ staticconstexprstd::string_viewkey="normalization.coordinate.dimensionless_riesz"; [[nodiscard]]staticNodeschema(){ constexprstd::arraynames{"volume","surface","algebraic"}; returnobject(key,field("dimension",std::string{Quantity::identifier}),field("metric",Metric{}),field("geometry",std::string{names[static_cast<std::size_t>(Geometry)]})); } }; template<typenameKey,typenameTarget> structSerializer<dependencies::Binding<Key,Target>>:SchemaSerializer<dependencies::Binding<Key,Target>>{ staticconstexprstd::string_viewkey="normalization.rule"; [[nodiscard]]staticNodeschema(){returnobject(key,field("coordinate",term_schema<Key>()),field("method",Target{}));} }; template<typename...Bindings> structSerializer<dependencies::Bindings<Bindings...>>:SchemaSerializer<dependencies::Bindings<Bindings...>>{ staticconstexprstd::string_viewkey="normalization.rules"; [[nodiscard]]staticNodeschema(){returnobject(key,field("rules",std::tuple<Bindings...>{}));} }; template<typenameValues,typenameResiduals> structSerializer<solver::normalization::NormalizationPlan<Values,Residuals>>:SchemaSerializer<solver::normalization::NormalizationPlan<Values,Residuals>>{ staticconstexprstd::string_viewkey="normalization.plan"; [[nodiscard]]staticNodeschema(){returnobject(key,field("values",Values{}),field("residuals",Residuals{}));} }; template<> structSerializer<discretization::quadrature::RuleControl>:StructSerializer<discretization::quadrature::RuleControl>{ usingT=discretization::quadrature::RuleControl; staticconstexprstd::string_viewkey="quadrature.control"; staticconstexprautomembers=std::tuple{member_field("fixed_order",&T::fixed_order),member_field("boost",&T::boost)}; [[nodiscard]]staticboolvalid(constT&value){return!value.fixed_order||*value.fixed_order>=0;} }; template<> structSerializer<discretization::quadrature::RuleSet>{ usingT=discretization::quadrature::RuleSet; staticconstexprstd::string_viewkey="quadrature.rules"; [[nodiscard]]staticNodesave(constT&value){ usingRole=discretization::quadrature::QuadratureRole; Noderesult=object(key,field("discretization",value.role_control(Role::discretization)),field("preconditioner",value.role_control(Role::preconditioner)), field("diagnostic",value.role_control(Role::diagnostic)),field("projection",value.role_control(Role::projection)),field("fallback",value.fallback_control())); if(value.begin()!=value.end()){ Nodeforms=object("quadrature.form_rules"); forms.children.emplace("reconstruction",Node{.type="unsupported",.value=std::string{"Form-specificquadraturecontrolsrequireregisteredowningformdescriptors."}}); std::size_tindex=0; for(constauto&rule:value){ forms.children.emplace(std::to_string(index++),object("quadrature.form_rule", field("name",std::string{rule.form.name}),field("trial_field",std::string{rule.form.trial.field.name}), field("trial_term",std::string{rule.form.trial.name}),field("test_field",std::string{rule.form.test.field.name}), field("test_term",std::string{rule.form.test.name}),field("control",rule.control))); } result.children.emplace("forms",std::move(forms)); } returnresult; } [[nodiscard]]staticResult<T>load(constNode&node){ if(node.children.contains("forms")){returnstd::unexpected(Error{"forms","Form-specificquadraturedescriptorsarenotreconstructiblebythisloader."});} usingControl=discretization::quadrature::RuleControl; returnread_object(node,key,[](Controldiscretization,Controlpreconditioner,Controldiagnostic,Controlprojection,Controlfallback){ usingRole=discretization::quadrature::QuadratureRole; Tresult; result.set_role_control(Role::discretization,discretization); result.set_role_control(Role::preconditioner,preconditioner); result.set_role_control(Role::diagnostic,diagnostic); result.set_role_control(Role::projection,projection); result.set_fallback_control(fallback); returnresult; },member<Control>("discretization"),member<Control>("preconditioner"),member<Control>("diagnostic"),member<Control>("projection"),member<Control>("fallback")); } }; template<> structSerializer<discretization::quadrature::Policy>{ staticconstexprstd::string_viewkey="quadrature.policy"; [[nodiscard]]staticNodesave(constdiscretization::quadrature::Policy&value){returnobject(key,field("rules",value.rules()));} [[nodiscard]]staticResult<discretization::quadrature::Policy>load(constNode&node){ returnread_object(node,key,[](discretization::quadrature::RuleSetrules){returndiscretization::quadrature::Policy{std::move(rules)};},member<discretization::quadrature::RuleSet>("rules")); } }; }