pyvale 2025.7.1__cp311-cp311-win_amd64.whl → 2025.8.1__cp311-cp311-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyvale might be problematic. Click here for more details.
- pyvale/__init__.py +12 -92
- pyvale/blender/__init__.py +23 -0
- pyvale/{pyvaleexceptions.py → blender/blenderexceptions.py} +0 -3
- pyvale/{blenderlightdata.py → blender/blenderlightdata.py} +3 -3
- pyvale/{blendermaterialdata.py → blender/blendermaterialdata.py} +1 -1
- pyvale/{blenderrenderdata.py → blender/blenderrenderdata.py} +5 -3
- pyvale/{blenderscene.py → blender/blenderscene.py} +33 -30
- pyvale/{blendertools.py → blender/blendertools.py} +14 -10
- pyvale/dataset/__init__.py +7 -0
- pyvale/dataset/dataset.py +443 -0
- pyvale/dic/__init__.py +20 -0
- pyvale/dic/cpp/dicfourier.cpp +36 -4
- pyvale/dic/cpp/dicinterpolator.cpp +56 -1
- pyvale/dic/cpp/dicmain.cpp +24 -19
- pyvale/dic/cpp/dicoptimizer.cpp +6 -1
- pyvale/dic/cpp/dicscanmethod.cpp +32 -32
- pyvale/dic/cpp/dicsignalhandler.cpp +16 -0
- pyvale/dic/cpp/dicstrain.cpp +7 -3
- pyvale/dic/cpp/dicutil.cpp +79 -23
- pyvale/{dic2d.py → dic/dic2d.py} +51 -29
- pyvale/dic/dic2dconv.py +6 -0
- pyvale/dic/dic2dcpp.cp311-win_amd64.pyd +0 -0
- pyvale/{dicchecks.py → dic/dicchecks.py} +28 -16
- pyvale/dic/dicdataimport.py +370 -0
- pyvale/{dicregionofinterest.py → dic/dicregionofinterest.py} +169 -12
- pyvale/{dicresults.py → dic/dicresults.py} +4 -1
- pyvale/{dicstrain.py → dic/dicstrain.py} +9 -9
- pyvale/examples/basics/{ex1_1_basicscalars_therm2d.py → ex1a_basicscalars_therm2d.py} +12 -9
- pyvale/examples/basics/{ex1_2_sensormodel_therm2d.py → ex1b_sensormodel_therm2d.py} +17 -14
- pyvale/examples/basics/{ex1_3_customsens_therm3d.py → ex1c_customsens_therm3d.py} +27 -24
- pyvale/examples/basics/{ex1_4_basicerrors_therm3d.py → ex1d_basicerrors_therm3d.py} +32 -29
- pyvale/examples/basics/{ex1_5_fielderrs_therm3d.py → ex1e_fielderrs_therm3d.py} +19 -15
- pyvale/examples/basics/{ex1_6_caliberrs_therm2d.py → ex1f_caliberrs_therm2d.py} +20 -16
- pyvale/examples/basics/{ex1_7_spatavg_therm2d.py → ex1g_spatavg_therm2d.py} +19 -16
- pyvale/examples/basics/{ex2_1_basicvectors_disp2d.py → ex2a_basicvectors_disp2d.py} +13 -10
- pyvale/examples/basics/{ex2_2_vectorsens_disp2d.py → ex2b_vectorsens_disp2d.py} +19 -15
- pyvale/examples/basics/{ex2_3_sensangle_disp2d.py → ex2c_sensangle_disp2d.py} +21 -18
- pyvale/examples/basics/{ex2_4_chainfielderrs_disp2d.py → ex2d_chainfielderrs_disp2d.py} +31 -29
- pyvale/examples/basics/{ex2_5_vectorfields3d_disp3d.py → ex2e_vectorfields3d_disp3d.py} +21 -18
- pyvale/examples/basics/{ex3_1_basictensors_strain2d.py → ex3a_basictensors_strain2d.py} +16 -14
- pyvale/examples/basics/{ex3_2_tensorsens2d_strain2d.py → ex3b_tensorsens2d_strain2d.py} +17 -14
- pyvale/examples/basics/{ex3_3_tensorsens3d_strain3d.py → ex3c_tensorsens3d_strain3d.py} +25 -22
- pyvale/examples/basics/{ex4_1_expsim2d_thermmech2d.py → ex4a_expsim2d_thermmech2d.py} +17 -14
- pyvale/examples/basics/{ex4_2_expsim3d_thermmech3d.py → ex4b_expsim3d_thermmech3d.py} +37 -34
- pyvale/examples/basics/ex5_nomesh.py +24 -0
- pyvale/examples/dic/ex1_2_blenderdeformed.py +174 -0
- pyvale/examples/dic/ex1_region_of_interest.py +6 -3
- pyvale/examples/dic/ex2_plate_with_hole.py +21 -18
- pyvale/examples/dic/ex3_plate_with_hole_strain.py +8 -6
- pyvale/examples/dic/ex4_dic_blender.py +17 -15
- pyvale/examples/dic/ex5_dic_challenge.py +19 -14
- pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +16 -10
- pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +3 -3
- pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +29 -23
- pyvale/examples/genanalyticdata/ex2_2_analyticsensors_nomesh.py +67 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +12 -9
- pyvale/examples/mooseherder/ex0_create_moose_config.py +65 -0
- pyvale/examples/mooseherder/ex1a_modify_moose_input.py +71 -0
- pyvale/examples/mooseherder/ex1b_modify_gmsh_input.py +69 -0
- pyvale/examples/mooseherder/ex2a_run_moose_once.py +80 -0
- pyvale/examples/mooseherder/ex2b_run_gmsh_once.py +64 -0
- pyvale/examples/mooseherder/ex2c_run_both_once.py +114 -0
- pyvale/examples/mooseherder/ex3_run_moose_seq_para.py +157 -0
- pyvale/examples/mooseherder/ex4_run_gmsh-moose_seq_para.py +176 -0
- pyvale/examples/mooseherder/ex5_run_moose_paramulti.py +136 -0
- pyvale/examples/mooseherder/ex6_read_moose_exodus.py +163 -0
- pyvale/examples/mooseherder/ex7a_read_moose_herd_results.py +153 -0
- pyvale/examples/mooseherder/ex7b_read_multi_herd_results.py +116 -0
- pyvale/examples/mooseherder/ex7c_read_multi_gmshmoose_results.py +127 -0
- pyvale/examples/mooseherder/ex7d_readconfig_multi_gmshmoose_results.py +143 -0
- pyvale/examples/mooseherder/ex8_read_existing_sweep_output.py +72 -0
- pyvale/examples/renderblender/ex1_1_blenderscene.py +24 -20
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +22 -18
- pyvale/examples/renderblender/ex2_1_stereoscene.py +36 -29
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +26 -20
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +24 -17
- pyvale/examples/renderrasterisation/ex_rastenp.py +14 -12
- pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +14 -15
- pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +13 -11
- pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +13 -11
- pyvale/mooseherder/__init__.py +32 -0
- pyvale/mooseherder/directorymanager.py +416 -0
- pyvale/mooseherder/exodusreader.py +763 -0
- pyvale/mooseherder/gmshrunner.py +163 -0
- pyvale/mooseherder/inputmodifier.py +236 -0
- pyvale/mooseherder/mooseconfig.py +226 -0
- pyvale/mooseherder/mooseherd.py +527 -0
- pyvale/mooseherder/mooserunner.py +303 -0
- pyvale/mooseherder/outputreader.py +22 -0
- pyvale/mooseherder/simdata.py +92 -0
- pyvale/mooseherder/simrunner.py +31 -0
- pyvale/mooseherder/sweepreader.py +356 -0
- pyvale/mooseherder/sweeptools.py +76 -0
- pyvale/sensorsim/__init__.py +82 -0
- pyvale/{camera.py → sensorsim/camera.py} +7 -7
- pyvale/{camerasensor.py → sensorsim/camerasensor.py} +7 -7
- pyvale/{camerastereo.py → sensorsim/camerastereo.py} +2 -2
- pyvale/{cameratools.py → sensorsim/cameratools.py} +4 -4
- pyvale/{cython → sensorsim/cython}/rastercyth.c +596 -596
- pyvale/{cython → sensorsim/cython}/rastercyth.cp311-win_amd64.pyd +0 -0
- pyvale/{cython → sensorsim/cython}/rastercyth.py +16 -17
- pyvale/{errorcalculator.py → sensorsim/errorcalculator.py} +1 -1
- pyvale/{errorintegrator.py → sensorsim/errorintegrator.py} +2 -2
- pyvale/{errorrand.py → sensorsim/errorrand.py} +4 -4
- pyvale/{errorsyscalib.py → sensorsim/errorsyscalib.py} +2 -2
- pyvale/{errorsysdep.py → sensorsim/errorsysdep.py} +2 -2
- pyvale/{errorsysfield.py → sensorsim/errorsysfield.py} +8 -8
- pyvale/{errorsysindep.py → sensorsim/errorsysindep.py} +3 -3
- pyvale/sensorsim/exceptions.py +8 -0
- pyvale/{experimentsimulator.py → sensorsim/experimentsimulator.py} +23 -3
- pyvale/{field.py → sensorsim/field.py} +1 -1
- pyvale/{fieldconverter.py → sensorsim/fieldconverter.py} +72 -19
- pyvale/sensorsim/fieldinterp.py +37 -0
- pyvale/sensorsim/fieldinterpmesh.py +124 -0
- pyvale/sensorsim/fieldinterppoints.py +55 -0
- pyvale/{fieldsampler.py → sensorsim/fieldsampler.py} +4 -4
- pyvale/{fieldscalar.py → sensorsim/fieldscalar.py} +28 -24
- pyvale/{fieldtensor.py → sensorsim/fieldtensor.py} +33 -31
- pyvale/{fieldvector.py → sensorsim/fieldvector.py} +33 -31
- pyvale/{imagedef2d.py → sensorsim/imagedef2d.py} +9 -5
- pyvale/{integratorfactory.py → sensorsim/integratorfactory.py} +6 -6
- pyvale/{integratorquadrature.py → sensorsim/integratorquadrature.py} +3 -3
- pyvale/{integratorrectangle.py → sensorsim/integratorrectangle.py} +3 -3
- pyvale/{integratorspatial.py → sensorsim/integratorspatial.py} +1 -1
- pyvale/{rastercy.py → sensorsim/rastercy.py} +5 -5
- pyvale/{rasternp.py → sensorsim/rasternp.py} +9 -9
- pyvale/{rasteropts.py → sensorsim/rasteropts.py} +1 -1
- pyvale/{renderer.py → sensorsim/renderer.py} +1 -1
- pyvale/{rendermesh.py → sensorsim/rendermesh.py} +5 -5
- pyvale/{renderscene.py → sensorsim/renderscene.py} +2 -2
- pyvale/{sensorarray.py → sensorsim/sensorarray.py} +1 -1
- pyvale/{sensorarrayfactory.py → sensorsim/sensorarrayfactory.py} +12 -12
- pyvale/{sensorarraypoint.py → sensorsim/sensorarraypoint.py} +10 -8
- pyvale/{sensordata.py → sensorsim/sensordata.py} +1 -1
- pyvale/{sensortools.py → sensorsim/sensortools.py} +2 -20
- pyvale/sensorsim/simtools.py +174 -0
- pyvale/{visualexpplotter.py → sensorsim/visualexpplotter.py} +3 -3
- pyvale/{visualimages.py → sensorsim/visualimages.py} +2 -2
- pyvale/{visualsimanimator.py → sensorsim/visualsimanimator.py} +4 -4
- pyvale/{visualsimplotter.py → sensorsim/visualsimplotter.py} +5 -5
- pyvale/{visualsimsensors.py → sensorsim/visualsimsensors.py} +12 -12
- pyvale/{visualtools.py → sensorsim/visualtools.py} +1 -1
- pyvale/{visualtraceplotter.py → sensorsim/visualtraceplotter.py} +2 -2
- pyvale/simcases/case17.geo +3 -0
- pyvale/simcases/case17.i +4 -4
- pyvale/simcases/run_1case.py +1 -9
- pyvale/simcases/run_all_cases.py +1 -1
- pyvale/simcases/run_build_case.py +1 -1
- pyvale/simcases/run_example_cases.py +1 -1
- pyvale/verif/__init__.py +12 -0
- pyvale/{analyticsimdatafactory.py → verif/analyticsimdatafactory.py} +2 -2
- pyvale/{analyticsimdatagenerator.py → verif/analyticsimdatagenerator.py} +2 -2
- pyvale/verif/psens.py +125 -0
- pyvale/verif/psensconst.py +18 -0
- pyvale/verif/psensmech.py +227 -0
- pyvale/verif/psensmultiphys.py +187 -0
- pyvale/verif/psensscalar.py +347 -0
- pyvale/verif/psenstensor.py +123 -0
- pyvale/verif/psensvector.py +116 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/METADATA +6 -7
- pyvale-2025.8.1.dist-info/RECORD +260 -0
- pyvale/dataset.py +0 -415
- pyvale/dic2dcpp.cp311-win_amd64.pyd +0 -0
- pyvale/dicdataimport.py +0 -247
- pyvale/simtools.py +0 -67
- pyvale-2025.7.1.dist-info/RECORD +0 -211
- /pyvale/{blendercalibrationdata.py → blender/blendercalibrationdata.py} +0 -0
- /pyvale/{dicspecklegenerator.py → dic/dicspecklegenerator.py} +0 -0
- /pyvale/{dicspecklequality.py → dic/dicspecklequality.py} +0 -0
- /pyvale/{dicstrainresults.py → dic/dicstrainresults.py} +0 -0
- /pyvale/{cameradata.py → sensorsim/cameradata.py} +0 -0
- /pyvale/{cameradata2d.py → sensorsim/cameradata2d.py} +0 -0
- /pyvale/{errordriftcalc.py → sensorsim/errordriftcalc.py} +0 -0
- /pyvale/{fieldtransform.py → sensorsim/fieldtransform.py} +0 -0
- /pyvale/{generatorsrandom.py → sensorsim/generatorsrandom.py} +0 -0
- /pyvale/{imagetools.py → sensorsim/imagetools.py} +0 -0
- /pyvale/{integratortype.py → sensorsim/integratortype.py} +0 -0
- /pyvale/{output.py → sensorsim/output.py} +0 -0
- /pyvale/{raster.py → sensorsim/raster.py} +0 -0
- /pyvale/{sensordescriptor.py → sensorsim/sensordescriptor.py} +0 -0
- /pyvale/{visualimagedef.py → sensorsim/visualimagedef.py} +0 -0
- /pyvale/{visualopts.py → sensorsim/visualopts.py} +0 -0
- /pyvale/{analyticmeshgen.py → verif/analyticmeshgen.py} +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/WHEEL +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/licenses/LICENSE +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from pyvale.mooseherder.simrunner import SimRunner
|
|
10
|
+
from pyvale.mooseherder.mooseconfig import MooseConfig
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MooseRunner(SimRunner):
|
|
14
|
+
"""Used to run MOOSE models (*.i) from python."""
|
|
15
|
+
def __init__(self, config: MooseConfig):
|
|
16
|
+
"""Constructor for MOOSE runner taking a MooseConfig object
|
|
17
|
+
that contains the paths to the main MOOSE install, the MOOSE app and
|
|
18
|
+
the MOOSE app name. Sets default parallelisation options to 1 MPI task
|
|
19
|
+
and 1 thread. Sets environment variables required for MPI setup.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
config : MooseConfig
|
|
25
|
+
moose configuration object containing the required paths and app
|
|
26
|
+
name to construct the command string.
|
|
27
|
+
"""
|
|
28
|
+
self._config = config.get_config()
|
|
29
|
+
|
|
30
|
+
self._n_threads = 1
|
|
31
|
+
self._n_tasks = 1
|
|
32
|
+
self._redirect_stdout = True
|
|
33
|
+
self._arg_list = list('')
|
|
34
|
+
self._input_path = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def set_env_vars(self) -> None:
|
|
38
|
+
"""Sets environment variables for calling MOOSE with MPI."""
|
|
39
|
+
os.environ['CC'] = 'mpicc'
|
|
40
|
+
os.environ['CXX'] = 'mpicxx'
|
|
41
|
+
os.environ['F90'] = 'mpif90'
|
|
42
|
+
os.environ['F77'] = 'mpif77'
|
|
43
|
+
os.environ['FC'] = 'mpif90'
|
|
44
|
+
os.environ['MOOSE_DIR'] = str(self._config['main_path'])
|
|
45
|
+
if not str(self._config['app_path']) in os.environ["PATH"]:
|
|
46
|
+
os.environ["PATH"] = os.environ["PATH"] + ':' + str(self._config['app_path'])
|
|
47
|
+
|
|
48
|
+
def set_threads(self, n_threads: int) -> None:
|
|
49
|
+
"""Sets the number of threads asked of MOOSE on the command line.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
n_threads : int
|
|
54
|
+
Number of threads.
|
|
55
|
+
"""
|
|
56
|
+
# Need to make sure number is sensible based on cpu
|
|
57
|
+
if n_threads <= 0:
|
|
58
|
+
n_threads = 1
|
|
59
|
+
elif os.cpu_count() is None:
|
|
60
|
+
n_threads = 1
|
|
61
|
+
elif n_threads > os.cpu_count(): # type: ignore
|
|
62
|
+
n_threads = os.cpu_count() # type: ignore
|
|
63
|
+
|
|
64
|
+
self._n_threads = int(n_threads)
|
|
65
|
+
|
|
66
|
+
def set_tasks(self, n_tasks: int) -> None:
|
|
67
|
+
"""Sets the number of MPI tasks asked of MOOSE on the command line.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
n_tasks : int
|
|
72
|
+
Number of mpi tasks.
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
# Need to make sure is sensible based on cpu
|
|
79
|
+
if n_tasks <= 0:
|
|
80
|
+
n_tasks = 1
|
|
81
|
+
elif os.cpu_count() is None:
|
|
82
|
+
n_tasks = 1
|
|
83
|
+
elif n_tasks > os.cpu_count(): # type: ignore
|
|
84
|
+
n_tasks = os.cpu_count() # type: ignore
|
|
85
|
+
|
|
86
|
+
self._n_tasks = int(n_tasks)
|
|
87
|
+
|
|
88
|
+
def set_stdout(self, redirect_flag: bool = True) -> None:
|
|
89
|
+
"""Sets MOOSE to redirect output (True) to file instead of console (False).
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
redirect_flag : bool
|
|
94
|
+
True = output to stdout file, False
|
|
95
|
+
= output to console. Defaults to True.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
|
|
100
|
+
"""
|
|
101
|
+
self._redirect_stdout = redirect_flag
|
|
102
|
+
|
|
103
|
+
def set_run_opts(self, n_tasks: int = 1,
|
|
104
|
+
n_threads: int = 1,
|
|
105
|
+
redirect_out: bool = True) -> None:
|
|
106
|
+
"""Sets all options for MOOSE run parallelisation and output.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
n_tasks : int
|
|
111
|
+
Number of mpi tasks for MOOSE run.
|
|
112
|
+
Defaults to 1.
|
|
113
|
+
n_threads : int
|
|
114
|
+
Number of threads for MOOSE run.
|
|
115
|
+
Defaults to 1.
|
|
116
|
+
redirect : bool
|
|
117
|
+
Redirect MOOSE output from console to
|
|
118
|
+
file (True). Defaults to False.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
self.set_threads(n_threads)
|
|
125
|
+
self.set_tasks(n_tasks)
|
|
126
|
+
self.set_stdout(redirect_out)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_input_file(self) -> Path | None:
|
|
130
|
+
"""get_input_file
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
Path | None
|
|
138
|
+
full path to the input file or None if not specified.
|
|
139
|
+
|
|
140
|
+
"""
|
|
141
|
+
return self._input_path
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def set_input_file(self, input_path: Path) -> None:
|
|
145
|
+
"""Sets the path to the MOOSE input file and checks it exists.
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
input_file : Path
|
|
150
|
+
full path and name of *.i MOOSE input script.
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
|
|
155
|
+
Raises
|
|
156
|
+
------
|
|
157
|
+
FileNotFoundError
|
|
158
|
+
the MOOSE input script doesn't exist
|
|
159
|
+
|
|
160
|
+
"""
|
|
161
|
+
if not input_path.is_file():
|
|
162
|
+
raise FileNotFoundError("Input file does not exist.")
|
|
163
|
+
|
|
164
|
+
self._input_path = input_path
|
|
165
|
+
self.assemble_arg_list()
|
|
166
|
+
|
|
167
|
+
def get_input_dir(self) -> Path | None:
|
|
168
|
+
"""Gets the path to the directory for the specified input file.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
|
|
173
|
+
Returns
|
|
174
|
+
-------
|
|
175
|
+
Path
|
|
176
|
+
path to input file directory, if no input file is specified
|
|
177
|
+
returns None.
|
|
178
|
+
|
|
179
|
+
"""
|
|
180
|
+
if self._input_path is None:
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
return self._input_path.parent # type: ignore
|
|
184
|
+
|
|
185
|
+
def get_input_tag(self) -> str:
|
|
186
|
+
"""Gets the input file name string without the path or the .i
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
str
|
|
194
|
+
input file string, if no input file is specified returns an
|
|
195
|
+
empty string.
|
|
196
|
+
|
|
197
|
+
"""
|
|
198
|
+
if self._input_path is None:
|
|
199
|
+
return ""
|
|
200
|
+
|
|
201
|
+
return self._input_path.stem # type: ignore
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def get_output_path(self) -> Path | None:
|
|
205
|
+
"""Gets the file and path for the output exodus file based
|
|
206
|
+
on the specified input file. Includes '_out.e'.
|
|
207
|
+
|
|
208
|
+
Parameters
|
|
209
|
+
----------
|
|
210
|
+
|
|
211
|
+
Returns
|
|
212
|
+
-------
|
|
213
|
+
Path
|
|
214
|
+
output exodus file name with path, returns an empty None
|
|
215
|
+
if no input file is specified.
|
|
216
|
+
|
|
217
|
+
"""
|
|
218
|
+
if self._input_path is None:
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
return self._input_path.parent / (self._input_path.stem +'_out.e')
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def get_arg_list(self) -> list[str]:
|
|
225
|
+
"""Run string getter.
|
|
226
|
+
|
|
227
|
+
Parameters
|
|
228
|
+
----------
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
str
|
|
233
|
+
command line string to run MOOSE.
|
|
234
|
+
|
|
235
|
+
"""
|
|
236
|
+
return self._arg_list
|
|
237
|
+
|
|
238
|
+
def assemble_arg_list(self, input_file = None) -> list[str]:
|
|
239
|
+
"""Assmebles the command line string to run MOOSE based on current
|
|
240
|
+
options.
|
|
241
|
+
|
|
242
|
+
Parameters
|
|
243
|
+
----------
|
|
244
|
+
input_file : str
|
|
245
|
+
Full path to MOOSE input file, if not
|
|
246
|
+
empty updates the input file. Defaults to "".
|
|
247
|
+
|
|
248
|
+
Returns
|
|
249
|
+
-------
|
|
250
|
+
str
|
|
251
|
+
command line string that will be used by the runner when run
|
|
252
|
+
is called.
|
|
253
|
+
|
|
254
|
+
"""
|
|
255
|
+
if input_file is not None:
|
|
256
|
+
self.set_input_file(input_file)
|
|
257
|
+
|
|
258
|
+
if self._input_path is None:
|
|
259
|
+
raise RuntimeError('No input file specified, set one using set_input_file or by passing on into this function.')
|
|
260
|
+
|
|
261
|
+
arg_list = []
|
|
262
|
+
if self._n_tasks > 1:
|
|
263
|
+
arg_list = ['mpirun','-np',str(self._n_tasks)]
|
|
264
|
+
|
|
265
|
+
arg_list = arg_list + [str(self._config['app_name']) \
|
|
266
|
+
,f'--n-threads={self._n_threads}','-i' \
|
|
267
|
+
,str(self._input_path.name)]
|
|
268
|
+
|
|
269
|
+
if self._redirect_stdout:
|
|
270
|
+
arg_list = arg_list + ['--redirect-stdout']
|
|
271
|
+
|
|
272
|
+
self._arg_list = arg_list
|
|
273
|
+
|
|
274
|
+
return self._arg_list
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def run(self, input_file = None) -> None:
|
|
278
|
+
"""Runs MOOSE based on current options by passing run string to
|
|
279
|
+
subprocess shell.
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
282
|
+
----------
|
|
283
|
+
input_file : Path
|
|
284
|
+
Full path to MOOSE input file, if not
|
|
285
|
+
empty updates the input file. Defaults to None.
|
|
286
|
+
|
|
287
|
+
Returns
|
|
288
|
+
-------
|
|
289
|
+
|
|
290
|
+
"""
|
|
291
|
+
if input_file is not None:
|
|
292
|
+
self.set_input_file(input_file)
|
|
293
|
+
|
|
294
|
+
if self._input_path is None:
|
|
295
|
+
raise RuntimeError("Set input path before calling run.")
|
|
296
|
+
|
|
297
|
+
self.set_env_vars()
|
|
298
|
+
|
|
299
|
+
self.assemble_arg_list()
|
|
300
|
+
subprocess.run(self._arg_list,
|
|
301
|
+
shell=False,
|
|
302
|
+
cwd=str(self._input_path.parent),
|
|
303
|
+
check=False)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from pyvale.mooseherder.simdata import SimData, SimReadConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class OutputReader(ABC):
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def __init__(self, output_file: Path) -> None:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def read_sim_data(self, read_config: SimReadConfig) -> SimData:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def read_all_sim_data(self) -> SimData:
|
|
22
|
+
pass
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class SimData:
|
|
13
|
+
"""Data class for simulation output. Allows for structured meshes with
|
|
14
|
+
connectivity tables or for point clouds."""
|
|
15
|
+
|
|
16
|
+
num_spat_dims: int = 3
|
|
17
|
+
""" Number of spatial dimensions in the simulation, required to determine
|
|
18
|
+
element types given that all coords are padded to [x,y,z]. Allows for 2D and
|
|
19
|
+
1D simulations using any combination of the [x,y,z] axes.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
time: np.ndarray | None = None
|
|
23
|
+
""" Vector of time steps with dimensions [t]. Defaults to None.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
coords: np.ndarray | None = None
|
|
27
|
+
""" Array of nodal coordinates in N by 3 where N is the number of nodes
|
|
28
|
+
columns are [x,y,z] coordinates and rows are the nth node. Defaults to
|
|
29
|
+
None.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
connect: dict[str,np.ndarray] | None = None
|
|
33
|
+
""" Element connectivity table:
|
|
34
|
+
key = "connectX" where X is the subdomain e.g. connect1
|
|
35
|
+
Element table given as E by n_e rows where E is the number of elements
|
|
36
|
+
in the given subdomain. n_e is the number of nodes per element.
|
|
37
|
+
Defaults to None.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
side_sets: dict[tuple[str,str],np.ndarray] | None = None
|
|
41
|
+
""" Sidesets by name and associated node and element numbers.
|
|
42
|
+
key = (name, "node" or "elem") e.g. ("bottom","node") will return node
|
|
43
|
+
numbers associated with associated with sideset called "bottom" as a
|
|
44
|
+
numpy array with n_s entries where n_s is the number of nodes in the
|
|
45
|
+
sideset.
|
|
46
|
+
Defaults to None.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
node_vars: dict[str,np.ndarray] | None = None
|
|
50
|
+
""" Nodal variable by name.
|
|
51
|
+
key = "name" e.g. "disp_x" or "temp"
|
|
52
|
+
Gives the nodal variable as a numpy array, N by t where N is the number
|
|
53
|
+
of nodes and t is the number of time steps. Note that element variables
|
|
54
|
+
can be stored as nodal depending on output options or material output
|
|
55
|
+
order selected.
|
|
56
|
+
Defaults to None.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
elem_vars: dict[tuple[str,int],np.ndarray] | None = None
|
|
60
|
+
""" Element variables by name and block.
|
|
61
|
+
key = (name, block num)
|
|
62
|
+
Gives the element variable as a numpy array, E by t where E is the
|
|
63
|
+
number of elements and t is the number of time steps. Note that element
|
|
64
|
+
variables might exist as nodal variables only depending on output
|
|
65
|
+
options and specified material output order.
|
|
66
|
+
Defaults to None.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
glob_vars: dict[str,np.ndarray] | None = None
|
|
70
|
+
""" Global variables by name. Global variable include postprocessors and
|
|
71
|
+
extracted reactions at boundaries.
|
|
72
|
+
key = name (as specified in input file post-processor), e.g. "react_y"
|
|
73
|
+
Gives a numpy array with t entries corresponding to the number of time
|
|
74
|
+
steps in the simulation.
|
|
75
|
+
Defaults to None.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
@dataclass(slots=True)
|
|
79
|
+
class SimReadConfig:
|
|
80
|
+
"""Used to specify names of variables to be read into the SimData class.
|
|
81
|
+
This class allows the user to only extract the required variables by
|
|
82
|
+
name.
|
|
83
|
+
"""
|
|
84
|
+
time: bool = True
|
|
85
|
+
coords: bool = True
|
|
86
|
+
connect: bool = True
|
|
87
|
+
sidesets: np.ndarray | None = None
|
|
88
|
+
node_vars: np.ndarray | None = None
|
|
89
|
+
elem_vars: list[tuple[str,int]] | None = None
|
|
90
|
+
glob_vars: np.ndarray | None = None
|
|
91
|
+
time_inds: np.ndarray | None = None
|
|
92
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
class SimRunner(ABC):
|
|
11
|
+
"""SimRunner: ABC for the moosherd simulation chain. A simulation has an
|
|
12
|
+
input file which can be get or set. The simulation can then be run with the
|
|
13
|
+
given input files and then the path to the simulation output file can be
|
|
14
|
+
retrieved.
|
|
15
|
+
"""
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def get_input_file(self) -> Path | None:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def set_input_file(self, input_path: Path) -> None:
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def run(self, input_file: Path | None = None) -> None:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def get_output_path(self) -> Path | None:
|
|
30
|
+
pass
|
|
31
|
+
|