2222
2323"""Provides the ``MatmlWriter`` class."""
2424
25+ from dataclasses import dataclass
2526import os
2627from typing import BinaryIO , Dict , Optional , Sequence , Union
2728import xml .etree .ElementTree as ET
2829
30+ import ansys .units
31+
32+ from ansys .materials .manager ._models ._matml .property_info import (
33+ property_infos as matml_property_infos ,
34+ )
2935from ansys .materials .manager .material import Material
3036
3137from .matml_parser import (
3238 BULKDATA_KEY ,
3339 MATERIALS_ELEMENT_KEY ,
3440 MATML_DOC_KEY ,
3541 METADATA_KEY ,
42+ NAME_ATTR ,
43+ NAME_KEY ,
44+ POWER_ATTR ,
45+ UNIT_KEY ,
3646 UNITLESS_KEY ,
47+ UNITS_KEY ,
3748 WBTRANSFER_KEY ,
3849)
3950from .matml_property_map import MATML_PROPERTY_MAP
4556VERSION_DATE = "29.08.2016 15:02:00"
4657
4758
59+ @dataclass
60+ class MetadataParameter :
61+ """Name of the parameter, for example pa74."""
62+
63+ name : str
64+
65+ """The material model name."""
66+ model_name : str
67+
68+ """The parameter value unit."""
69+ unit : Optional [str ]
70+
71+
4872class MatmlWriter :
4973 """
5074 Exports a list of MAPDL materials to an engineering data XML file.
@@ -57,7 +81,7 @@ class MatmlWriter:
5781
5882 _materials : Sequence [Material ]
5983 _metadata_property_sets : Dict
60- _metadata_parameters : Dict
84+ _metadata_parameters : Dict [ str , MetadataParameter ]
6185
6286 def __init__ (self , materials : Sequence [Material ]):
6387 """Construct a Matml writer."""
@@ -68,18 +92,22 @@ def __init__(self, materials: Sequence[Material]):
6892 def _add_parameters (self , property_element : ET .Element , material : Material , parameters : Dict ):
6993 # add the parameters of a property set to the tree
7094 for mat_key , matml_key in parameters .items ():
95+ model = material .get_model_by_name (mat_key )
96+ assert len (model ) == 1
97+ model = model [0 ]
98+
7199 if matml_key in self ._metadata_parameters .keys ():
72100 para_key = self ._metadata_parameters [matml_key ]
73101 else :
74102 index = len (self ._metadata_parameters ) + 1
75- para_key = f"pa{ index } "
103+ para_key = MetadataParameter ( f"pa{ index } " , model . name , model . unit )
76104 self ._metadata_parameters [matml_key ] = para_key
77105
78106 param_element = ET .SubElement (
79- property_element , "ParameterValue" , {"format" : "float" , "parameter" : para_key }
107+ property_element , "ParameterValue" , {"format" : "float" , "parameter" : para_key . name }
80108 )
81109 data_element = ET .SubElement (param_element , "Data" )
82- data_element .text = str (material . get_model_by_name ( mat_key )[ 0 ] .value )
110+ data_element .text = str (model .value )
83111 qualifier_element = ET .SubElement (param_element , "Qualifier" , {"name" : "Variable Type" })
84112 qualifier_element .text = "Dependent"
85113
@@ -95,6 +123,7 @@ def _add_property_set(
95123 # check if at least one parameter is specified (case-insensitive)
96124 # and build a map from material to Matml properties
97125 available_mat_properties = [model .name .lower () for model in material .models ]
126+ # print(available_mat_properties)
98127 property_set_parameters = {item : item for item in parameter_map ["properties" ]}
99128 for key , mapped_properties in parameter_map ["mappings" ].items ():
100129 property_set_parameters .update ({item : key for item in mapped_properties })
@@ -157,7 +186,53 @@ def _add_materials(self, materials_element: ET.Element):
157186 behavior ,
158187 )
159188
189+ def _write_unit (self , prop_element : ET .Element , value : MetadataParameter ):
190+ """Write unit in one of the following valid forms.
191+
192+ If there is a unit:
193+ <Units name="Density">
194+ <Unit>
195+ <Name>kg</Name>
196+ </Unit>
197+ <Unit power="-3">
198+ <Name>m</Name>
199+ </Unit>
200+ </Units>
201+
202+ If there is a unit for a property with no unit category defined:
203+ <Units>
204+ <Unit>
205+ <Name>kg</Name>
206+ </Unit>
207+ <Unit power="-3">
208+ <Name>m</Name>
209+ </Unit>
210+ </Units>
211+ If there is no unit:
212+ <Unitless />
213+ """
214+ if value .unit is None :
215+ ET .SubElement (prop_element , UNITLESS_KEY )
216+ else :
217+ unit_tokens = value .unit .split (" " )
218+ matml_property_info = matml_property_infos [value .model_name ]
219+ unit_category = matml_property_info .unit_category
220+ unit_name_dict = {}
221+ if unit_category is not None :
222+ unit_name_dict [NAME_ATTR ] = unit_category
223+ units_element = ET .SubElement (prop_element , UNITS_KEY , unit_name_dict )
224+ for unit_token in unit_tokens :
225+ _ , term , exp = ansys .units .unit ._filter_unit_term (unit_token )
226+ power = int (exp )
227+ power_dict = {}
228+ if power != 1 :
229+ power_dict [POWER_ATTR ] = str (power )
230+ unit_element = ET .SubElement (units_element , UNIT_KEY , power_dict )
231+ unit_name_element = ET .SubElement (unit_element , NAME_KEY )
232+ unit_name_element .text = term
233+
160234 def _add_metadata (self , metadata_element : ET .Element ):
235+
161236 # add the metadata to the XML tree
162237 for key , value in self ._metadata_property_sets .items ():
163238 prop_element = ET .SubElement (metadata_element , "PropertyDetails" , {"id" : value })
@@ -166,23 +241,32 @@ def _add_metadata(self, metadata_element: ET.Element):
166241 name_element .text = key
167242
168243 for key , value in self ._metadata_parameters .items ():
169- prop_element = ET .SubElement (metadata_element , "ParameterDetails" , {"id" : value })
170- ET . SubElement ( prop_element , UNITLESS_KEY )
244+ prop_element = ET .SubElement (metadata_element , "ParameterDetails" , {"id" : value . name })
245+
171246 name_element = ET .SubElement (prop_element , "Name" )
172247 name_element .text = key
173248
249+ self ._write_unit (prop_element , value )
250+
174251 def _add_transfer_ids (self , root : ET .Element ) -> None :
175252 # add the WB transfer IDs to the XML tree
176253 wb_transfer_element = ET .SubElement (root , WBTRANSFER_KEY )
177254 materials_element = ET .SubElement (wb_transfer_element , MATERIALS_ELEMENT_KEY )
255+ any_uuid = False
178256 for mat in self ._materials :
179- mat_element = ET .SubElement (materials_element , "Material" )
180- name_element = ET .SubElement (mat_element , "Name" )
181- name_element .text = mat .name
182- transfer_element = ET .SubElement (mat_element , "DataTransferID" )
183- transfer_element .text = mat .uuid
184-
185- def _to_etree (self ) -> ET .ElementTree :
257+ if len (mat .uuid ) > 0 :
258+ any_uuid = True
259+ mat_element = ET .SubElement (materials_element , "Material" )
260+ name_element = ET .SubElement (mat_element , "Name" )
261+ name_element .text = mat .name
262+ transfer_element = ET .SubElement (mat_element , "DataTransferID" )
263+ transfer_element .text = mat .uuid
264+ if not any_uuid :
265+ root .remove (wb_transfer_element )
266+
267+ def _to_etree (
268+ self ,
269+ ) -> ET .ElementTree :
186270 root = ET .Element (ROOT_ELEMENT )
187271 tree = ET .ElementTree (root )
188272
0 commit comments