Source code for ansys.dyna.core.lib.domain_mapper

# Copyright (C) 2023 - 2026 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""Maps keywords to logical domains based on their prefix.

This module is duplicated from codegen/keyword_generation/utils/domain_mapper.py
to enable runtime categorization of keywords without requiring codegen dependencies.
"""

import typing

if typing.TYPE_CHECKING:
    from ansys.dyna.core.lib.keyword_base import KeywordBase

# Define keyword prefix to domain mappings
[docs] KEYWORD_DOMAIN_MAPPING = { "MAT_": "mat", "SECTION_": "section", "DEFINE_": "define", "ELEMENT_": "element", "PART_": "part", "DISCRETE_": "part", "BOUNDARY_": "boundary", "INITIAL_": "boundary", "CONTACT_": "contact", "CONSTRAINT_": "constraint", "CONSTRAINED_": "constrained", "CONTROL_": "control", "SOLVER_": "control", "TIMESTEP_": "control", "DATABASE_": "database", "PRINT_": "print", "OUTPUT_": "output", "LOAD_": "load", "PRESSURE_": "load", "POINT_": "load", "BODY_": "load", "SENSOR_": "sensor", "SET_": "set", "HOURGLASS_": "hourglass", "DAMPING_": "damping", "PARAMETER_": "parameter", "INCLUDE_": "include", "INCLUDE_TRANSFORM": "include", "KEYWORD_OPTIMIZATION": "keyword", "OPTIMIZATION_": "optimization", "EM_": "em", "ELECTROMAGNETIC_": "em", "ICFD_": "icfd", "AIRBAG_": "airbag", "THERMAL_": "thermal", "HEAT_": "thermal", "NVH_": "nvh", "ISPH_": "isph", "FREQUENCY_": "frequency", "TABLE_": "table", "INTERFACE_": "interface", "RIGIDWALL_": "rigidwall", "NODE_": "node", "MESH_": "mesh", "MODULE_": "module", "PERTURBATION_": "perturbation", "RAIL_": "rail", "RIGID_": "rigid", "SECTION_ALE": "section", # First-token domains (replacing misc) "ALE_": "ale", "BATTERY_": "battery", "CASE": "case", "CASE_": "case", "CESE_": "cese", "CHANGE_": "change", "CHEMISTRY_": "chemistry", "COMMENT": "comment", "COMPONENT_": "component", "CONTROLLER_": "controller", "COSIM_": "cosim", "DEFORMABLE_": "deformable", "DELETE_": "delete", "DUALCESE_": "dualcese", "EF_": "ef", "EOS": "eos", "EOS_": "eos", "FATIGUE_": "fatigue", "IGA_": "iga", "INTEGRATION_": "integration", "LSO_": "lso", "PARTICLE_": "particle", "RVE_": "rve", "TITLE": "title", }
def _extract_keyword_name(keyword: typing.Union["KeywordBase", str]) -> str: """Extract the keyword name from a KeywordBase or string keyword. Parameters ---------- keyword : Union[KeywordBase, str] A keyword object or raw string. Returns ------- str The extracted keyword name (e.g., "SECTION_SHELL", "MAT_ELASTIC"). """ from ansys.dyna.core.lib.keyword_base import KeywordBase if isinstance(keyword, KeywordBase): # For KeywordBase objects, construct the full name if keyword.subkeyword: return f"{keyword.keyword}_{keyword.subkeyword}" return keyword.keyword elif isinstance(keyword, str): # For string keywords, extract from the first line # Handle both actual newlines and literal \n in test strings keyword_text = keyword.replace("\\n", "\n") lines = keyword_text.strip().split("\n") for line in lines: line = line.strip() # Skip comments if line.startswith("$"): continue # Look for keyword line starting with * if line.startswith("*"): # Remove leading * and any trailing comments/options kwd_name = line[1:].split()[0] return kwd_name # If no keyword found, return empty string return "" else: return ""
[docs] def by_domain(keyword: typing.Union["KeywordBase", str]) -> str: """Categorize a keyword by domain based on its prefix. This function can be used as a key function for splitting decks by domain. Parameters ---------- keyword : Union[KeywordBase, str] The keyword to categorize (either a KeywordBase object or raw string). Returns ------- str The domain name (e.g., "mat", "section", "control", "other"). Examples -------- >>> from ansys.dyna.core.lib.deck import Deck >>> from ansys.dyna.core.lib.domain_mapper import by_domain >>> deck = Deck() >>> # ... populate deck ... >>> decks_by_domain = deck.split(by_domain) >>> mat_deck = decks_by_domain["mat"] """ keyword_name = _extract_keyword_name(keyword) for prefix, domain in KEYWORD_DOMAIN_MAPPING.items(): if keyword_name.startswith(prefix): return domain # Default to 'other' if no prefix matches return "other"
[docs] def get_all_domains() -> typing.List[str]: """Get a sorted list of all unique domains. Returns ------- List[str] A sorted list of all domain names. """ return sorted(set(KEYWORD_DOMAIN_MAPPING.values()))