Skip to content

Commit 47bcff4

Browse files
authored
Merge branch 'MYSTRANsolver:main' into main
2 parents 1a81a80 + 33be646 commit 47bcff4

17 files changed

Lines changed: 1847 additions & 385 deletions
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import os
2+
import numpy as np
3+
from pyNastran.bdf.bdf import BDF, CaseControlDeck
4+
5+
dirname = os.path.dirname(__file__)
6+
7+
bdf_filename = os.path.join(dirname, 'rbe3s.bdf')
8+
9+
load_id = 2
10+
spc_id = 3
11+
cc_lines = [
12+
'SUBCASE 1',
13+
f'LOAD = {load_id}',
14+
f'SPC = {spc_id}',
15+
'DISP(PRINT,PLOT)=ALL',
16+
'MPCFORCE(PRINT,PLOT)=ALL',
17+
'SPCFORCE(PRINT,PLOT)=ALL',
18+
]
19+
20+
xs = np.linspace(0., 1., num=5)
21+
ys = xs
22+
zs = xs
23+
model = BDF()
24+
model.sol = 101
25+
model.case_control_deck = CaseControlDeck(cc_lines)
26+
27+
eid = 1
28+
pid = 2
29+
mid = 3
30+
model.add_grid(1, [0., 0., -1.])
31+
model.add_grid(2, [1., 0., -1.])
32+
model.add_crod(eid, pid, [1, 2])
33+
model.add_prod(pid, mid, 1.0, j=1.0)
34+
model.add_mat1(mid, 3.0e7, None, 0.3)
35+
nid0 = 10
36+
37+
z = 0.
38+
for xi in xs:
39+
for yi in ys:
40+
for zi in zs:
41+
if xi == yi and xi == zi:
42+
continue
43+
model.add_grid(nid0+1, [0., 0., z])
44+
model.add_grid(nid0+2, [1., 0., z])
45+
model.add_grid(nid0+3, [1., 1., z])
46+
model.add_grid(nid0+4, [0., 1., z])
47+
model.add_grid(nid0+5, [0.5, 0.5, z])
48+
refc = '123456'
49+
comps = ['123'] * 4
50+
weights = [1.0] * 4
51+
Gijs = [nid0+1, nid0+2, nid0+3, nid0+4]
52+
refgrid = nid0+5
53+
model.add_rbe3(eid, refgrid, refc, weights, comps, Gijs, Gmi=None, Cmi=None, alpha=0.0, tref=0.0, comment='')
54+
model.add_spc1(spc_id, '123456', Gijs, comment='')
55+
56+
xyz = [xi, yi, zi]
57+
model.add_force(load_id, refgrid, 1.0, xyz, cid=0, comment='')
58+
eid += 5
59+
nid0 += 5
60+
z += 5.
61+
model.write_bdf(bdf_filename, enddata=True)
62+
x = 1
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
import os
2+
import shutil
3+
import subprocess
4+
from pathlib import Path
5+
import numpy as np
6+
import pandas as pd
7+
from pyNastran.bdf.bdf_interface.assign_type_force import parse_components, parse_components_or_blank
8+
9+
import pyNastran.bdf.bdf_interface.assign_type
10+
pyNastran.bdf.bdf_interface.assign_type.parse_components = parse_components
11+
pyNastran.bdf.bdf_interface.assign_type.parse_components_or_blank = parse_components_or_blank
12+
13+
from pyNastran.utils.dev import get_files_of_type
14+
15+
16+
def process_op2s_compare(baseline_op2_filenames,
17+
op2_filenames,
18+
convert_op2_to_excel=True):
19+
from pyNastran.op2.op2 import read_op2
20+
#from pyNastran.f06.csv_writer import write_csv
21+
build_dataframe = convert_op2_to_excel
22+
23+
assert len(baseline_op2_filenames) == len(op2_filenames)
24+
for baseline_op2_filename, op2_filename in zip(baseline_op2_filenames, op2_filenames):
25+
if not os.path.exists(op2_filename):
26+
print(f'*{op2_filename}')
27+
continue
28+
base = os.path.splitext(op2_filename)[0]
29+
#excel_filename = base + '.xlsx'
30+
#csv_filename = base + '.csv'
31+
try:
32+
model = read_op2(op2_filename, build_dataframe=build_dataframe, debug=False)
33+
except Exception as e:
34+
print(f'***{op2_filename}')
35+
continue
36+
37+
if os.path.getsize(baseline_op2_filename) == 0:
38+
print(f'***{baseline_op2_filename}')
39+
continue
40+
41+
model_baseline = read_op2(baseline_op2_filename, build_dataframe=build_dataframe, debug=False)
42+
rtol = 1.e-5
43+
atol = 1.e-8
44+
is_passed = is_op2_close(model_baseline, model, rtol=rtol, atol=atol)
45+
if not is_passed:
46+
print(f'*{op2_filename}')
47+
y = 1
48+
x = 1
49+
50+
#if convert_op2_to_excel:
51+
#op2_to_excel(model, excel_filename)
52+
return
53+
54+
def is_op2_close(model_baseline, model,
55+
rtol: float=1.e-5,
56+
atol: float=1.e-8) -> bool:
57+
is_passed = True
58+
#op2_filename = model.op2_filename
59+
log = model.log
60+
for datai in get_op2_results(model):
61+
if len(datai) == 2:
62+
table_type, result = datai
63+
else:
64+
assert len(datai) == 3
65+
# grid_point_weight
66+
table_type, key, obj = datai
67+
baseline_dict = getattr(model_baseline, table_type)
68+
if table_type == 'grid_point_weight' and key not in baseline_dict:
69+
#log.warning('no grid_point_weight')
70+
continue
71+
baseline_obj = baseline_dict[key]
72+
assert obj == baseline_obj, obj - baseline_obj
73+
continue
74+
75+
baseline_result = model_baseline.get_result(table_type)
76+
for subcase_id, resulti in result.items():
77+
if subcase_id in baseline_result:
78+
baseline_resulti = baseline_result[subcase_id]
79+
else:
80+
if table_type == 'eigenvectors' and subcase_id in model_baseline.displacements:
81+
baseline_resulti = model_baseline.displacements[subcase_id]
82+
elif subcase_id not in baseline_result:
83+
is_passed = False
84+
log.info(f'**{table_type} {subcase_id} is missing')
85+
continue
86+
else:
87+
raise RuntimeError('asdf')
88+
#baseline_resulti = baseline_result[subcase_id]
89+
90+
if hasattr(resulti, 'node_layer'):
91+
assert np.array_equal(baseline_resulti.node_layer, resulti.node_layer)
92+
if hasattr(resulti, 'element_node'):
93+
assert np.array_equal(baseline_resulti.element_node, resulti.element_node)
94+
if hasattr(resulti, 'element'):
95+
assert np.array_equal(baseline_resulti.element, resulti.element)
96+
if hasattr(resulti, 'node_gridtype'):
97+
assert np.array_equal(baseline_resulti.node_gridtype, resulti.node_gridtype)
98+
is_passedi = np.allclose(baseline_resulti.data, resulti.data,
99+
rtol=rtol, atol=atol, equal_nan=True)
100+
if not is_passedi:
101+
is_passed = False
102+
log.info(f'**{table_type}')
103+
return is_passed
104+
105+
def process_op2s(op2_filenames,
106+
convert_op2_to_excel=True,
107+
convert_op2_to_csv=True):
108+
from pyNastran.op2.op2 import read_op2
109+
from pyNastran.f06.csv_writer import write_csv
110+
build_dataframe = convert_op2_to_excel
111+
112+
for op2_filename in op2_filenames:
113+
if not os.path.exists(op2_filename):
114+
print(f'*{op2_filename}')
115+
continue
116+
base = os.path.splitext(op2_filename)[0]
117+
excel_filename = base + '.xlsx'
118+
csv_filename = base + '.csv'
119+
try:
120+
model = read_op2(op2_filename, build_dataframe=build_dataframe, debug=False)
121+
except Exception as e:
122+
print(f'***{op2_filename}')
123+
continue
124+
125+
if convert_op2_to_excel:
126+
op2_to_excel(model, excel_filename)
127+
128+
if convert_op2_to_csv:
129+
write_csv(model, csv_filename, is_exponent_format=True)
130+
131+
def get_op2_results(model):
132+
log = model.log
133+
for table_type in model.get_table_types():
134+
if table_type in {'psds'}:
135+
continue
136+
result = model.get_result(table_type)
137+
if result is None or result == {}:
138+
continue
139+
if table_type in {'grid_point_weight'}:
140+
for key, weight in model.grid_point_weight.items():
141+
yield table_type, key, weight
142+
#log.warning(f'skipping {table_type}')
143+
continue
144+
yield table_type, result
145+
146+
def op2_to_excel(model, excel_filename) -> None:
147+
sheet_names = []
148+
pd_results = []
149+
for table_type, result in get_op2_results(model):
150+
#for table_type in model.get_table_types():
151+
#if table_type in {'psds'}:
152+
#continue
153+
#result = model.get_result(table_type)
154+
#if result is None or result == {}:
155+
#continue
156+
#if table_type in {'grid_point_weight'}:
157+
#log.warning(f'skipping {table_type}')
158+
#continue
159+
160+
for subcase_id, resulti in result.items():
161+
if isinstance(subcase_id, tuple):
162+
subcase_id = subcase_id[0]
163+
164+
base_sheet_name = resulti.class_name
165+
if base_sheet_name.startswith('Real'):
166+
base_sheet_name = base_sheet_name[4:]
167+
if base_sheet_name.endswith('Array'):
168+
base_sheet_name = base_sheet_name[:-5]
169+
sheet_name = f'S{subcase_id:d}_{base_sheet_name}'
170+
sheet_names.append(sheet_name)
171+
pd_results.append((sheet_name, resulti.dataframe))
172+
if pd_results:
173+
with pd.ExcelWriter(excel_filename) as writer:
174+
for sheet_name, dataframe in pd_results:
175+
dataframe.to_excel(writer, sheet_name=sheet_name)
176+
177+
def run_mystran_jobs(mystran_exe, bdf_filenames, run_mystran=True):
178+
bdf_filename0 = bdf_filenames[0]
179+
run_dirname = Path(os.path.dirname(bdf_filename0))
180+
os.chdir(run_dirname)
181+
182+
op2_filenames = []
183+
f06_filenames = []
184+
assert os.path.exists(mystran_exe), mystran_exe
185+
for bdf_filename in bdf_filenames:
186+
base_dirname_base = os.path.basename(bdf_filename)
187+
base = os.path.splitext(bdf_filename)[0]
188+
op2_filename = base + '.op2'
189+
f06_filename = base + '.f06'
190+
f06_filenames.append(f06_filename)
191+
op2_filenames.append(op2_filename)
192+
args = [mystran_exe, base_dirname_base]
193+
assert os.path.exists(bdf_filename), args
194+
if not os.path.exists(op2_filename) and run_mystran:
195+
FNULL = open(os.devnull, 'w')
196+
return_code = subprocess.call(args, stdout=FNULL, stderr=FNULL)
197+
if return_code:
198+
print(bdf_filename, return_code)
199+
return op2_filenames
200+
201+
def add_plot_to_models(run_dirname, dat_filenames, add_op2_to_models=True):
202+
if add_op2_to_models:
203+
from pyNastran.bdf.bdf import read_bdf
204+
205+
if not os.path.exists(run_dirname):
206+
os.makedirs(run_dirname)
207+
208+
skip_cards = {'EIGR', 'EIGRL', 'PLOAD2', 'SPCADD', 'SPC', 'SPC1', 'LOAD'}
209+
bdf_filenames = []
210+
for dat_filename in dat_filenames:
211+
dat_filename_base = os.path.basename(dat_filename)
212+
bdf_filename_base = os.path.splitext(dat_filename_base)[0] + '.bdf'
213+
bdf_filename = run_dirname / bdf_filename_base
214+
if add_op2_to_models:
215+
model = read_bdf(
216+
dat_filename, validate=True, xref=True,
217+
skip_cards=skip_cards, read_cards=None,
218+
encoding=None, log=None, debug=None, mode='mystran')
219+
add_plot_to_case_control(model)
220+
model.write_bdf(bdf_filename)
221+
elif not os.path.exists(bdf_filename):
222+
bdf_filename = shutil.copyfile(dat_filename, bdf_filename)
223+
bdf_filenames.append(bdf_filename)
224+
return bdf_filenames
225+
226+
def add_plot_to_case_control(model) -> None:
227+
cc = model.case_control_deck
228+
string_keys = {'LABEL', 'SUBTITLE', 'TITLE', }
229+
int_keys = {'METHOD', 'SPC', 'MPC', 'LOAD'}
230+
skip_keys = {'ECHO', 'MEFFMASS', 'MPFACTOR', 'ELDATA', 'TEMPERATURE(LOAD)', 'TEMPERATURE(BOTH)', }
231+
keys_to_process = {'DISPLACEMENT', 'OLOAD', 'SPCFORCES', 'MPCFORCES',
232+
'STRESS', 'STRAIN', 'FORCE', 'GPFORCE'}
233+
for subcase_id, subcase in cc.subcases.items():
234+
keys_to_update = []
235+
for key in subcase.params:
236+
if key in skip_keys or key in string_keys or key in int_keys:
237+
continue
238+
if key.startswith('SET '):
239+
continue
240+
if key in keys_to_process:
241+
keys_to_update.append(key)
242+
continue
243+
print(f'{key} is not supported')
244+
#assert key in keys_to_process, key
245+
for key in keys_to_update:
246+
value, options, res_type = subcase.params[key]
247+
if 'PLOT' not in options:
248+
options.append('PLOT')
249+
if 'PRINT' not in options:
250+
options.append('PRINT')
251+
subcase.params[key] = (value, options, res_type)
252+
253+
def main():
254+
base_dirname = Path(r'C:\mystran_bkp')
255+
add_op2_to_models = True
256+
convert_op2_to_csv = False
257+
convert_op2_to_excel = True
258+
run_mystran = True
259+
260+
reference_dirname = base_dirname / 'Benchmark_Main_Package_12_29_2023'
261+
input_dirname = reference_dirname / 'DAT' / 'Orig'
262+
#run_dirname = reference_dirname / 'run_'
263+
#mystran_exe = reference_dirname / 'MYSTRAN' / 'mystran-15.1.4.exe'
264+
265+
dat_filenames = get_files_of_type(str(input_dirname), extension='.DAT')
266+
267+
assert os.path.exists(input_dirname), input_dirname
268+
baseline_rev = '15.0'
269+
#revs = ['12.2', '15.0', '15.1', '15.1.1', '15.1.2', '15.1.3', '15.1.4']
270+
revs = ['15.0', '15.1.1'] # failed
271+
#revs = ['15.0', '15.1.4'] # failed
272+
revs = ['15.0', '15.9'] # failed
273+
#revs = ['15.9'] # dev
274+
bdf_filenames_by_rev = {}
275+
op2_filenames_by_rev = {}
276+
for rev in revs:
277+
mystran_exe = reference_dirname / 'MYSTRAN' / f'mystran-{rev}.exe'
278+
run_dirname = reference_dirname / f'run_{rev}'
279+
bdf_filenames = add_plot_to_models(run_dirname, dat_filenames, add_op2_to_models=add_op2_to_models)
280+
op2_filenames = run_mystran_jobs(mystran_exe, bdf_filenames, run_mystran=run_mystran)
281+
bdf_filenames_by_rev[rev] = bdf_filenames
282+
op2_filenames_by_rev[rev] = op2_filenames
283+
#process_op2s(op2_filenames,
284+
#convert_op2_to_excel=convert_op2_to_excel,
285+
#convert_op2_to_csv=convert_op2_to_csv)
286+
#for rev in revs:
287+
288+
baseline_op2_filenames = op2_filenames_by_rev[baseline_rev]
289+
for rev in revs:
290+
if rev == baseline_rev:
291+
continue
292+
op2_filenames = op2_filenames_by_rev[rev]
293+
process_op2s_compare(baseline_op2_filenames,
294+
op2_filenames,
295+
convert_op2_to_excel=True)
296+
297+
#for rev in revs:
298+
#baseline_run_dirname = reference_dirname / f'run_{baseline_rev}'
299+
300+
301+
if __name__ == '__main__':
302+
main()

0 commit comments

Comments
 (0)