boundary.hpp optional tuple vector serif/discretization/domain/concepts.hpp serif/discretization/domain/mesh/topology.hpp serif/discretization/domain/relation/relations.hpp serif/discretization/domain/relation/validation/runtime.hpp serif/discretization/domain/schema/concepts.hpp serif/discretization/domain/schema/validation/validator.hpp serif/utils/error/errors.hpp src/include/serif/discretization/domain/schema/validation/all.hpp serif::discretization::domain::schema::validation::RelationValidator< DomainBoundary< BoundaryT, DomainTs... > > serif::discretization::domain::schema::validation::DomainBoundary serif::discretization::domain::schema::validation::RelationValidationResult serif serif::discretization serif::discretization::domain serif::discretization::domain::schema serif::discretization::domain::schema::validation File containing the specialization of RelationValidator for DomainBoundary relations. This relation enforces that a boundary element is adjacent to exactly one or two volume elements. Emily M. Boudreaux #pragmaonce #include<optional> #include<tuple> #include<vector> #include"serif/discretization/domain/concepts.hpp" #include"serif/discretization/domain/mesh/topology.hpp" #include"serif/discretization/domain/relation/relations.hpp" #include"serif/discretization/domain/relation/validation/runtime.hpp" #include"serif/discretization/domain/schema/concepts.hpp" #include"serif/discretization/domain/schema/validation/validator.hpp" #include"serif/utils/error/errors.hpp" namespaceserif::discretization::domain::schema::validation{ usingrelation::DomainBoundary; usingrelation::validation::RelationValidationResult; usingrelation::validation::RelationValidationFailure; template<IsBoundaryBoundaryT,IsDomainOrSet...DomainTs> structRelationValidator<DomainBoundary<BoundaryT,DomainTs...>>{ template<IsSchemaSchemaT> [[nodiscard]]staticRelationValidationResultvalidate(constmesh::MeshTopology&topology){ constexprautoinvalidDomainTSizeEMSG=utils::types::ct_format<"DomainBoundaryrequiresexactlyoneortwodomains,got{}">(sizeof...(DomainTs)); utils::errors::serif_ensure<utils::errors::SERiFErrorCode::INVALID_SCHEMA_ARGUMENTS,sizeof...(DomainTs)==1||sizeof...(DomainTs)==2,invalidDomainTSizeEMSG>(); constexprautoinvalidBoundaryTEMSG=utils::types::ct_format<"DomainBoundaryrequirestheboundarytoberegisteredintheschema,itisnot">(); utils::errors::serif_ensure<utils::errors::SERiFErrorCode::INVALID_SCHEMA_ARGUMENTS, SchemaT::template contains_boundary<BoundaryT>(),invalidBoundaryTEMSG>(); constexprautoinvalidDomainTEMSG=utils::types::ct_format<"DomainBoundaryrequiresthedomaintoberegisteredintheschema,atleastoneisnot">(); utils::errors::serif_ensure<utils::errors::SERiFErrorCode::INVALID_SCHEMA_ARGUMENTS, (SchemaT::template contains_domain<DomainTs>()&&...),invalidDomainTEMSG>(); constexprintexpectedBoundaryID=SchemaT::templateboundary_id<BoundaryT>(); usingDomainsTuple=std::tuple<DomainTs...>; constautomake_diagnostics=[&](constintfaceID,constintboundaryElementID,conststd::optional<int>actualBoundaryID){ RelationValidationResult::DomainBoundaryDiagnosticsdiagnostics{ .faceID=faceID, .boundaryElementID=boundaryElementID, .expectedBoundaryID=expectedBoundaryID, .actualBoundaryID=actualBoundaryID }; if(faceID<0||faceID>=topology.face_count()){ returndiagnostics; } constmesh::FaceElementsfaceElements=topology.face_elements(faceID); diagnostics.firstElementID=faceElements.firstElementID; diagnostics.secondElementID=faceElements.secondElementID; if(diagnostics.firstElementID>=0){ diagnostics.firstDomainID=topology.element_domain_id(diagnostics.firstElementID); } if(diagnostics.secondElementID>=0){ diagnostics.secondDomainID=topology.element_domain_id(diagnostics.secondElementID); } returndiagnostics; }; //Checkonlythecardinality/topologicalshaperequiredbytherelation. // //One-domainform: // //Domain|computationalexterior // //Exactlyoneadjacentvolumeelementmustexist. // //Two-domainform: // //DomainA|DomainB // //Bothadjacentvolumeelementsmustexist. constautohas_required_topology=[](constintfirstElementID,constintsecondElementID)noexcept{ ifconstexpr(sizeof...(DomainTs)==1){ constboolfirstExists=firstElementID>=0; constboolsecondExists=secondElementID>=0; returnfirstExists!=secondExists; }else{ returnfirstElementID>=0&&secondElementID>=0; } }; //Determinewhetherafaceisexactlyoneofthefacesdescribedby //DomainBoundary<BoundaryT,DomainTs...>.Fortwodomains,ordering //isintentionallyirrelevant. constautoface_matches_domains=[&topology](constintfirstElementID,constintsecondElementID)noexcept{ ifconstexpr(sizeof...(DomainTs)==1){ usingDomainT=std::tuple_element_t<0,DomainsTuple>; constboolfirstExists=firstElementID>=0; constboolsecondExists=secondElementID>=0; if(firstExists==secondExists){ returnfalse; } constintelementID=firstExists?firstElementID:secondElementID; constintdomainID=topology.element_domain_id(elementID); returnSchemaT::templatedomain_id_belongs_to<DomainT>(domainID); }else{ usingFirstDomainT=std::tuple_element_t<0,DomainsTuple>; usingSecondDomainT=std::tuple_element_t<1,DomainsTuple>; if(firstElementID<0||secondElementID<0){ returnfalse; } constintfirstDomainID=topology.element_domain_id(firstElementID); constintsecondDomainID=topology.element_domain_id(secondElementID); constboolforwardMatch=SchemaT::templatedomain_id_belongs_to<FirstDomainT>(firstDomainID)&& SchemaT::templatedomain_id_belongs_to<SecondDomainT>(secondDomainID); constboolreverseMatch=SchemaT::templatedomain_id_belongs_to<SecondDomainT>(firstDomainID)&& SchemaT::templatedomain_id_belongs_to<FirstDomainT>(secondDomainID); returnforwardMatch||reverseMatch; } }; boolfoundTaggedBoundary=false; //Forwardvalidation:everyboundaryelementcarryingBoundaryTmust //lieonexactlytheinterfacedeclaredbyDomainBoundary. for(intboundaryElementID=0;boundaryElementID<topology.boundary_element_count();++boundaryElementID){ constintboundaryID=topology.boundary_element_boundary_id(boundaryElementID); if(boundaryID!=expectedBoundaryID){ continue; } foundTaggedBoundary=true; constintfaceID=topology.boundary_element_face(boundaryElementID); constauto[firstElementID,secondElementID]=topology.face_elements(faceID); if(!has_required_topology(firstElementID,secondElementID)){ return{ .failure=RelationValidationFailure::DomainBoundaryTaggedFaceHasWrongTopology, .domainBoundaryDiagnostics= std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>( make_diagnostics(faceID,boundaryElementID,boundaryID) ) }; } if(!face_matches_domains(firstElementID,secondElementID)){ return{ .failure=RelationValidationFailure::DomainBoundaryTaggedFaceTouchesUnexpectedDomain, .domainBoundaryDiagnostics= std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>( make_diagnostics(faceID,boundaryElementID,boundaryID) ) }; } } boolfoundExpectedFace=false; //Reversevalidation:everyfacehavingthedeclareddomain //adjacencymustcarryBoundaryT. for(intfaceID=0;faceID<topology.face_count();++faceID){ constauto[firstElementID,secondElementID]=topology.face_elements(faceID); if(!face_matches_domains(firstElementID,secondElementID)){ continue; } foundExpectedFace=true; conststd::vector<int>&boundaryElementIDs=topology.boundary_elements_on_face(faceID); if(boundaryElementIDs.empty()){ return{ .failure=RelationValidationFailure::DomainBoundaryExpectedFaceIsUntagged, .domainBoundaryDiagnostics= std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>( make_diagnostics(faceID,-1,std::nullopt) ) }; } for(constintboundaryElementID:boundaryElementIDs){ constintactualBoundaryID=topology.boundary_element_boundary_id(boundaryElementID); if(actualBoundaryID==expectedBoundaryID){ continue; } return{ .failure=RelationValidationFailure::DomainBoundaryExpectedFaceHasWrongID, .domainBoundaryDiagnostics= std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>( make_diagnostics(faceID,boundaryElementID,actualBoundaryID) ) }; } } //Ifneitheracorrectlytaggedboundarynorafacehavingthe //requiredsemantictopologyexists,thedeclaredDomainBoundary //simplyisnotrealizedbythismesh. if(!foundTaggedBoundary||!foundExpectedFace){ return{ .failure=RelationValidationFailure::DomainBoundaryAbsent, .domainBoundaryDiagnostics= std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>( make_diagnostics(-1,-1,std::nullopt) ) }; } return{}; } }; }