#ifndef FESA_IO_ABAQUS_MATERIAL_PROPERTY_CANDIDATES_H_ #define FESA_IO_ABAQUS_MATERIAL_PROPERTY_CANDIDATES_H_ #include #include #include #include #include #include #include #include #include "fesa/model/model_types.h" #include "io/abaqus/mapping_diagnostics.h" namespace fesa::abaqus_internal { enum class ElementFamily; struct RawPart; struct RawSection { std::string element_set_name; std::string material_name; std::array properties; std::array first_axis; std::vector> section_points; SourceLocation location; }; struct RawShellSection { std::string element_set_name; std::string material_name; double thickness; SourceLocation location; }; struct RawSolidSection { std::string element_set_name; std::string material_name; SourceLocation location; }; /// @brief Owns source section candidates for one part before resolution. struct PartPropertyCandidates { std::vector sections; std::vector shell_sections; std::vector solid_sections; }; /// @brief Supplies procedure policy without giving material mapping step state. struct MaterialProcedureView { struct Surface { SourceLocation location; std::string name; }; bool frequency; bool dynamic; const SourceLocation& location; const std::string& name_raw; std::optional first_surface; const std::optional& physical_constants_location; }; /// @brief Owns material candidates, their validation, and section assignments. /// @note The context-owned diagnostics, input, and family outlive this object. class MaterialPropertyCandidates { public: using Assignments = std::map>; /// @brief Borrows context services while owning this uncommitted mapping /// stage. MaterialPropertyCandidates(MappingDiagnostics& diagnostics, const ParsedInput& input, const std::optional& family) : diagnostics_{diagnostics}, input_{input}, model_element_family_{family} {} /// @brief Returns the source material declaration count. std::size_t Count() const noexcept { return materials_.size(); } /// @brief Reports whether no source material has been declared. bool Empty() const noexcept { return materials_.empty(); } /// @brief Reports whether a material child may follow the current /// declaration. bool HasActiveMaterial() const noexcept { return material_eligible_.has_value(); } /// @brief Ends the optional section-point continuation scope. void EndSection() noexcept { pending_section_.reset(); } /// @brief Ends the material-child continuation scope. void EndMaterial() noexcept { material_eligible_.reset(); } /// @brief Borrows resolved beam section and material indices for one part. const Assignments& BeamAssignments(std::size_t part) const { return part_section_assignments_[part]; } /// @brief Borrows resolved shell or solid property and material indices for /// one part. const Assignments& ShellAssignments(std::size_t part) const { return part_shell_section_assignments_[part]; } /// @brief Parses material-only solid assignments without introducing /// thickness. void ParseSolidSection(const KeywordBlock& block, PartPropertyCandidates& properties); /// @brief Parses centered shell thickness and source integration-point /// metadata. void ParseShellSection(const KeywordBlock& block, PartPropertyCandidates& properties); /// @brief Parses general beam properties and their global guide vector. void ParseBeamSection(const KeywordBlock& block, PartPropertyCandidates& properties); /// @brief Parses optional beam stress points in the active section scope. void ParseSectionPoints(const KeywordBlock& block, PartPropertyCandidates& properties); /// @brief Starts one source material after syntax ordering has been checked. void ParseMaterial(const KeywordBlock& block); /// @brief Parses an elastic row without conflating beam and shell material /// ranges. void ParseElastic(const KeywordBlock& block); /// @brief Parses positive finite density with its source-specific failure /// policy. void ParseDensity(const KeywordBlock& block); /// @brief Parses constant conductivity or specific heat in the thermal /// subset. void ParseThermalProperty(const KeywordBlock& block, bool conductivity); /// @brief Appends validated material definitions in source order. void FinalizeMaterials(ModelDefinition& definition); /// @brief Validates part references and unique section/material assignments. void FinalizePartsAndSections(const std::vector& parts, ModelDefinition& definition); /// @brief Checks procedure policy before appending active material densities. void FinalizeDensities(const MaterialProcedureView& procedure, ModelDefinition& definition); private: struct RawMaterial { std::string name; double youngs_modulus{0.0}; double poisson_ratio{0.0}; bool has_elastic{false}; std::optional density; std::optional conductivity; std::optional specific_heat; SourceLocation location; SourceLocation elastic_location; SourceLocation density_location; }; bool ParseDensityValue(const std::string& text, double& value, const SourceLocation& location); std::optional FindMaterialIndex(const std::string& name) const; void ValidateFrequencyPreprint(ModelDefinition& definition); void ValidateDynamicPreprint(); bool ContainsName(const std::vector& values, const std::string& name) const; MappingDiagnostics& diagnostics_; const ParsedInput& input_; const std::optional& model_element_family_; std::vector materials_; std::optional material_eligible_; std::optional pending_section_; std::vector part_section_assignments_; std::vector part_shell_section_assignments_; }; } // namespace fesa::abaqus_internal #endif // FESA_IO_ABAQUS_MATERIAL_PROPERTY_CANDIDATES_H_