// Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. #pragma once #include "iotm_export.h" // ####################### Start Clang Header Tool Managed Headers ######################## // clang-format off #include // for toupper #include // for size_t #include // for remove, etc #include // for insert_iterator #include #include // for set #include // for operator<<, etc #include // for basic_string, etc #include // for pair #include // for vector #include #include // for ostringstream #include #include #include #include #include #include "Iotm_TextMeshFuncs.h" #include "Iotm_TextMeshEntityGroup.h" // clang-format on // ####################### End Clang Header Tool Managed Headers ######################## namespace Iotm { namespace text_mesh { using ErrorHandler = std::function; enum AssemblyType { ASSEMBLY, BLOCK, SIDESET, NODESET, INVALID_ASSEMBLY }; inline std::ostream &operator<<(std::ostream &out, const AssemblyType &t) { switch (t) { case AssemblyType::ASSEMBLY: return out << "ASSEMBLY"; break; case AssemblyType::BLOCK: return out << "ELEMENT_BLOCK"; break; case AssemblyType::SIDESET: return out << "SIDESET"; break; case AssemblyType::NODESET: return out << "NODESET"; break; default: return out << "INVALID"; break; } return out << "INVALID[" << (unsigned)t << "]"; } using AssemblyDataType = std::string; struct IOTM_EXPORT AssemblyData : public EntityGroupData { using DataType = AssemblyDataType; void set_assembly_type(AssemblyType type_) { assemblyType = type_; } AssemblyType get_assembly_type() const { return assemblyType; } private: AssemblyType assemblyType = INVALID_ASSEMBLY; }; template class Assemblies : public EntityGroup { public: using BaseClass = EntityGroup; Assemblies() : EntityGroup("ASSEMBLY", "ASSEMBLY_", {"BLOCK_", "SURFACE_", "NODELIST_"}) { } bool is_cyclic(const std::string &assembly) const { initialize_graph(); return check_for_cycle(assembly); } bool is_cyclic() const { for (const std::string &assembly : BaseClass::get_part_names()) if (is_cyclic(assembly)) { return true; } return false; } std::vector &&get_forward_traversal_list(const std::string &assembly) const { initialize_graph(); fill_traversal(assembly); return std::move(m_traversalList); } std::vector &&get_reverse_traversal_list(const std::string &assembly) const { initialize_graph(); fill_traversal(assembly); std::reverse(m_traversalList.begin(), m_traversalList.end()); return std::move(m_traversalList); } private: // Walk the tree without cyclic dependency void fill_traversal(const std::string &assembly) const { const AssemblyData *assemblyData = BaseClass::get_group_data(assembly); if (nullptr != assemblyData) { if (m_visitedNodes[assembly] == false) { m_visitedNodes[assembly] = true; m_traversalList.push_back(assembly); if (assemblyData->get_assembly_type() == AssemblyType::ASSEMBLY) { for (const std::string &member : assemblyData->data) { fill_traversal(member); } } } } } bool check_for_cycle(const std::string &assembly) const { bool isCyclic = false; const AssemblyData *assemblyData = BaseClass::get_group_data(assembly); if (nullptr != assemblyData) { if (m_visitedNodes[assembly] == true) { isCyclic = true; } else { m_visitedNodes[assembly] = true; if (assemblyData->get_assembly_type() == AssemblyType::ASSEMBLY) { for (const std::string &member : assemblyData->data) { isCyclic |= check_for_cycle(member); } } } } return isCyclic; } void initialize_graph() const { m_traversalList.clear(); m_traversalList.reserve(BaseClass::size()); for (const std::string &name : BaseClass::get_part_names()) { m_visitedNodes[name] = false; } } mutable std::unordered_map m_visitedNodes; mutable std::vector m_traversalList; }; class IOTM_EXPORT AssemblyParser { public: AssemblyParser() : m_assemblyType(INVALID_ASSEMBLY) { ErrorHandler errorHandler = [](const std::ostringstream &errmsg) { default_error_handler(errmsg); }; set_error_handler(errorHandler); } void set_error_handler(ErrorHandler errorHandler) { m_errorHandler = errorHandler; } std::string get_name() { return m_name; } AssemblyType get_assembly_type() const { return m_assemblyType; } const std::vector &get_assembly_data() { return m_members; } // Expected format for assembly string data is: // "name=; type=; member=member_1,...,member_n;" // Only type keyword is required void parse(const std::string &parseData) { auto options = get_tokens(parseData, ";"); for (const auto &option : options) { parse_option_group(option); } } void verify_parse() const { if (m_assemblyType == INVALID_ASSEMBLY) { std::ostringstream errmsg; errmsg << "Error! Assembly with name: " << m_name << " does not have a defined type."; m_errorHandler(errmsg); } } private: void parse_option(std::string optionName, const std::string &optionValue) { convert_to_lower_case(optionName); if (optionName == "name") { parse_name(optionValue); } else if (optionName == "type") { parse_assembly_type(optionValue); } else if (optionName == "member") { parse_assembly_members(optionValue); } else { std::ostringstream errmsg; errmsg << "Unrecognized assembly option: " << optionName; m_errorHandler(errmsg); } } void parse_option_group(const std::string &option) { if (!option.empty()) { auto optionTokens = get_tokens(option, "="); if (optionTokens.size() != 2) { std::ostringstream errmsg; errmsg << "Unrecognized assembly option: " << option; m_errorHandler(errmsg); } parse_option(optionTokens[0], optionTokens[1]); } } void parse_name(const std::string &data) { m_name = data; } void parse_assembly_type(std::string type) { convert_to_lower_case(type); if (type == "assembly") { m_assemblyType = ASSEMBLY; } else if (type == "block") { m_assemblyType = BLOCK; } else if (type == "sideset") { m_assemblyType = SIDESET; } else if (type == "nodeset") { m_assemblyType = NODESET; } else { std::ostringstream errmsg; errmsg << "Unrecognized assembly type: " << type; m_errorHandler(errmsg); } } void parse_assembly_members(const std::string &data) { std::vector assemblyData = get_tokens(data, ","); for (std::string &member : assemblyData) { convert_to_upper_case(member); } m_members = assemblyData; } std::vector m_members{}; std::string m_name{}; AssemblyType m_assemblyType{INVALID_ASSEMBLY}; ErrorHandler m_errorHandler; }; } // namespace text_mesh } // namespace Iotm