Coverage for readers/gmsh/ui_versions/user_input_v2.py: 19%
137 statements
« prev ^ index » next coverage.py v7.7.0, created at 2025-03-20 20:51 +0100
« prev ^ index » next coverage.py v7.7.0, created at 2025-03-20 20:51 +0100
1import json
2import logging
3from collections import defaultdict
4from copy import deepcopy
6import yaml
8import nastranio.cards as nio_cards
9from nastranio.cards import PROP2ELTS
10from nastranio.constants import BOUNDARY
12DEFAULT_USERINPUT_TPL = {
13 "format": 2,
14 "exec": {"SOL": "SESTATIC"},
15 "params": {
16 "PRGPST": "YES",
17 "POST": -1,
18 "OGEOM": "NO",
19 "AUTOSPC": "YES",
20 "K6ROT": 100.0,
21 "GRDPNT": 0,
22 "SKIPMGG": "YES",
23 "CHKGRDS": "NO",
24 },
25 "cases": {
26 "default": {
27 "id": -1,
28 "TITLE": "LCID1",
29 "ECHO": "NONE",
30 "DISPLACEMENT(PLOT)": "ALL",
31 "$ SPC": 1,
32 "$ LOAD": 1,
33 }
34 },
35 "attributes": {
36 "materials": {
37 1: {"card": "MAT1", "params": {"E": 7e6, "NU": 0.33, "RHO": 5000.5}},
38 2: {"card": "MAT1", "params": {"E": 8e6, "NU": 0.33, "RHO": 5000.5}},
39 },
40 "properties": {
41 1: {
42 "card": "PBAR",
43 "params": {
44 "MID": 1,
45 "A": 50.0,
46 "I1": 18.0,
47 "I2": 18.0,
48 "J": 0.1,
49 "I12": 0.0,
50 },
51 },
52 2: {
53 "card": "PBUSH",
54 "params": {
55 "K": "K",
56 "K1": 1e4,
57 "K2": 1e4,
58 "K3": 1e4,
59 "K4": 1e4,
60 "K5": 1e4,
61 "K6": 1e4,
62 },
63 },
64 3: {
65 "card": "PSHELL",
66 "params": {"MID1": 1, "T": 3.0, "MID2": 1, "MID3": 1},
67 },
68 4: {
69 "card": "PCOMP",
70 "params": {
71 "NSM": 0.0,
72 },
73 "layup": [
74 {"MID": 1, "SOUT": "YES", "T": 0.018, "THETA": 0.0},
75 {"MID": 2, "SOUT": "YES", "T": 0.339, "THETA": 0.0},
76 {"MID": 1, "SOUT": "YES", "T": 0.018, "THETA": 5.0},
77 ],
78 },
79 },
80 "affectations": {},
81 "boundaries": {},
82 "loading": {},
83 },
84}
86DEFAULT_BOUNDARY_INPUT = {"card": "SPC1", "params": {"C": "123456"}}
87DEFAULT_LOADING_INPUT = {
88 "card": "FORCE",
89 "params": {
90 "CID": 0,
91 "F": 1.0,
92 "N1": 1.0,
93 "N2": 0.0,
94 "N3": 0.0,
95 "as_sum": False,
96 "exclusive": False,
97 },
98}
101def _from_v1_carddata(carddata):
102 """
103 was [<cardname>, <params>]
104 now {"card": <cardname>, "params": <params>}
105 """
106 try:
107 return {"card": carddata[0], "params": carddata[1]}
108 except:
109 logging.critical(f"cannot import {carddata} from V1")
112def from_v1(parameters):
113 parameters = deepcopy(parameters)
114 parameters["format"] = 2
115 for section_name in ("materials", "properties"):
116 section = parameters["attributes"][section_name]
117 for entry_id, carddata in section.items():
118 parameters["attributes"][section_name][entry_id] = _from_v1_carddata(
119 carddata
120 )
121 for section_name in ("boundaries", "loading"):
122 section = parameters["attributes"][section_name]
123 for sid, group2carddata in section.items():
124 for grpname, carddata in group2carddata.items():
125 parameters["attributes"][section_name][sid][
126 grpname
127 ] = _from_v1_carddata(carddata)
128 return parameters
131class UserInput:
132 def load_parameters(self, parameters):
133 convmap = {1: from_v1}
134 format = parameters["format"]
135 if format != DEFAULT_USERINPUT_TPL["format"]:
136 logging.warning(f"importing from deprecated {format=}")
137 parameters = convmap[format](parameters)
138 self.imported_from = format
139 else:
140 self.imported_from = None
141 self.parameters = parameters
142 self.attributes = parameters["attributes"]
144 def get_default_template(self):
145 return deepcopy(DEFAULT_USERINPUT_TPL)
147 def get_default_boundary_input(self):
148 return deepcopy(DEFAULT_BOUNDARY_INPUT)
150 def get_default_loading_input(self):
151 return deepcopy(DEFAULT_LOADING_INPUT)
153 def to_json(self, filepath=None, indent=2, sort_keys=False, **kwargs):
154 txt = json.dumps(self.parameters, indent=indent, sort_keys=sort_keys, **kwargs)
155 if filepath:
156 with open(filepath, "w") as fh:
157 fh.write(txt)
158 return filepath
159 return txt
161 def to_yaml(self, filepath=None, indent=2, sort_keys=False, **kwargs):
162 txt = yaml.dump(self.parameters, sort_keys=sort_keys, **kwargs)
163 if filepath:
164 with open(filepath, "w") as fh:
165 fh.write(txt)
166 return filepath
167 return txt
169 def get_card_data(self, carddata, **kwargs):
170 """merge user input with card definition"""
171 cardname = carddata["card"]
172 params = carddata["params"]
173 card = getattr(nio_cards, cardname)
174 params = params.copy()
175 if "XID" in kwargs:
176 kwargs[card.XID_FIELDNAME] = kwargs.pop("XID")
177 params.update(kwargs)
178 fields_info = card.fields_info()
179 mandatory = set(fields_info["mandatory"])
180 optional = fields_info["optional"]
181 all = mandatory | optional
182 unknown = set(params) - all
183 missing = mandatory - set(params)
184 ok_params = {k: v for k, v in params.items() if k in all}
185 ret = {
186 "card": card,
187 "params": ok_params,
188 }
189 if hasattr(card, "LOADING_TYPE") and card.LOADING_TYPE is not None:
190 ret["over"] = [card.LOADING_TYPE]
191 if card.type == BOUNDARY:
192 ret["over"] = ["nodes"]
193 if missing:
194 ret["missing"] = missing
195 # ---------------------------------------------------------------------
196 # repeated fields
197 repeated = fields_info.get("repeated", ())
198 # if cardname == "PCOMP":
199 # breakpoint()
200 if repeated:
201 repeated_data_raw = carddata.get(card.REPEATED_DATA_NAME)
202 if repeated_data_raw is None:
203 # SPC1 has a REPEATED_DATA_NAME, but not available at this point
204 ret["repeated"] = repeated
205 else:
206 # PCOMP has a REPEATED_DATA_NAME, and data are available
207 repeated_data = defaultdict(list)
208 for data in repeated_data_raw:
209 for fieldname, value in data.items():
210 repeated_data[fieldname + "i"].append(value)
211 ret["repeated"] = dict(repeated_data)
212 if unknown:
213 ret["unknown"] = {k: v for k, v in params.items() if k in unknown}
214 # eg for PCOMP:
215 # {
216 # 'card': <class 'nastranio.cards.properties.PCOMP'>,
217 # 'params': {'NSM': 0.0, 'PID': 4},
218 # 'repeated': {'MIDi': [1, 1, 1],
219 # 'THETAi': [0.0, 90.0, 0.0],
220 # 'Ti': [0.01, 0.05, 0.01]},
222 return ret
224 def get_materials(self):
225 ret = {}
226 for mid, carddata in self.attributes["materials"].items():
227 ret[mid] = self.get_card_data(carddata, XID=mid)
228 return ret
230 def get_properties(self):
231 """
232 return a dictionnary with cards specifications:
234 (Pdb++) pp(ret)
235 {1: {'card': <class 'nastranio.cards.properties.PBAR'>,
236 'params': {'A': 1.0, 'I1': 12.0, 'I2': 13.0, 'MID': 1, 'PID': 1}},
237 2: {'card': <class 'nastranio.cards.properties.PSHELL'>,
238 'params': {'MID1': 1, 'MID2': 1, 'MID3': 1, 'PID': 2, 'T': 0.08}},
239 3: {'card': <class 'nastranio.cards.properties.PSHELL'>,
240 'params': {'MID1': 1, 'MID2': 1, 'MID3': 1, 'PID': 3, 'T': 0.03}},
241 4: {'card': <class 'nastranio.cards.properties.PCOMP'>,
242 'params': {'NSM': 0.0, 'PID': 4},
243 'repeated': {'MIDi': [1, 1, 1],
244 'THETAi': [0.0, 90.0, 0.0],
245 'Ti': [0.01, 0.05, 0.01]}}}
246 """
247 ret = {}
248 for pid, carddata in self.attributes["properties"].items():
249 ret[pid] = self.get_card_data(carddata, XID=pid)
250 return ret
252 def get_loading(self):
253 ret = defaultdict(list)
254 for sid, data in self.attributes["loading"].items():
255 for grpname, carddata in data.items():
256 _data = self.get_card_data(carddata, XID=sid)
257 if grpname != "*":
258 _data["over"].append(grpname)
259 ret[sid].append(_data)
260 return dict(ret)
262 def get_boundaries(self):
263 ret = defaultdict(list)
264 for sid, data in self.attributes["boundaries"].items():
265 for grpname, carddata in data.items():
266 _data = self.get_card_data(carddata, XID=sid)
267 if grpname != "*":
268 _data["over"].append(grpname)
269 ret[sid].append(_data)
270 return dict(ret)
272 def get_affectations(self):
273 ret = {}
274 props = self.get_properties()
275 for grpname, params in self.attributes["affectations"].items():
276 prop_card = props[params["PID"]]["card"]
277 cards_choice = PROP2ELTS[prop_card.__name__]
278 card_by_type = {}
279 for cardname in cards_choice:
280 gmsh_elem_type = getattr(nio_cards, cardname).gmsh_eltype
281 _data = self.get_card_data(
282 carddata={"card": cardname, "params": params}
283 )
284 _data["over"] = ["elements", grpname]
285 card_by_type[gmsh_elem_type] = _data
286 ret[grpname] = card_by_type
287 return ret