pyvale 2025.7.2__cp311-cp311-macosx_14_0_arm64.whl → 2025.8.1__cp311-cp311-macosx_14_0_arm64.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/{dic2d.py → dic/dic2d.py} +31 -36
- pyvale/dic/dic2dconv.py +6 -0
- pyvale/{dic2dcpp.cpython-311-darwin.so → dic/dic2dcpp.cpython-311-darwin.so} +0 -0
- pyvale/{dicdataimport.py → dic/dicdataimport.py} +8 -8
- pyvale/{dicregionofinterest.py → dic/dicregionofinterest.py} +1 -1
- pyvale/{dicresults.py → dic/dicresults.py} +1 -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.cpython-311-darwin.so +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.2.dist-info → pyvale-2025.8.1.dist-info}/METADATA +6 -7
- pyvale-2025.8.1.dist-info/RECORD +262 -0
- pyvale/dataset.py +0 -415
- pyvale/simtools.py +0 -67
- pyvale-2025.7.2.dist-info/RECORD +0 -214
- /pyvale/{blendercalibrationdata.py → blender/blendercalibrationdata.py} +0 -0
- /pyvale/{dicchecks.py → dic/dicchecks.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.2.dist-info → pyvale-2025.8.1.dist-info}/WHEEL +0 -0
- {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/licenses/LICENSE +0 -0
- {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,527 @@
|
|
|
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 time
|
|
8
|
+
import multiprocessing as mp
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from multiprocessing.pool import Pool
|
|
11
|
+
|
|
12
|
+
from pyvale.mooseherder.directorymanager import DirectoryManager
|
|
13
|
+
from pyvale.mooseherder.simrunner import SimRunner
|
|
14
|
+
from pyvale.mooseherder.inputmodifier import InputModifier
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MooseHerdError(Exception):
|
|
18
|
+
"""MooseHerdError: custom error class for flagging errors with the moose
|
|
19
|
+
herd.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
class MooseHerd:
|
|
23
|
+
"""MooseHerd class that can run parametric sweeps of simulation chains in
|
|
24
|
+
parallel with configurable parallelisation options. Takes a list of
|
|
25
|
+
SimRunner objects and a corresponding list of InputModifiers to insert the
|
|
26
|
+
variables into the input scripts for the SimRunners. When calling run_* the
|
|
27
|
+
herd will first call all InputModifiers in the specified order and then
|
|
28
|
+
call run on all the SimRunners in order. Uses the DirectoryManager class to
|
|
29
|
+
create/clear and log the directories in which each parallel worker is
|
|
30
|
+
creating input files and running simulations.
|
|
31
|
+
"""
|
|
32
|
+
def __init__(self, sim_runners: list[SimRunner],
|
|
33
|
+
input_mods: list[InputModifier],
|
|
34
|
+
dir_manager: DirectoryManager,
|
|
35
|
+
num_para_sims: int = 1) -> None:
|
|
36
|
+
"""__init__
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
sim_runners (list[SimRunner]): list of objects that inherit from
|
|
40
|
+
the SimRunner ABC in the order they need to be run. The mesh
|
|
41
|
+
needs to be created before runnning moose so a common chain
|
|
42
|
+
would be [GmshRunner,MooseRunner].
|
|
43
|
+
input_mods (list[InputModifier]): list of InputModifiers to create
|
|
44
|
+
the required input scripts for the SimRunners.
|
|
45
|
+
dir_manager (DirectoryManager): used to control how many and
|
|
46
|
+
which directories are used to run the simulations.
|
|
47
|
+
"""
|
|
48
|
+
self._runners = sim_runners
|
|
49
|
+
self._modifiers = input_mods
|
|
50
|
+
self._dir_manager = dir_manager
|
|
51
|
+
|
|
52
|
+
self._n_para_sims = num_para_sims
|
|
53
|
+
|
|
54
|
+
self._input_names = [f'sim-{ii+1}' for ii,_ in enumerate(sim_runners)]
|
|
55
|
+
|
|
56
|
+
self._keep_all = True
|
|
57
|
+
|
|
58
|
+
self._var_sweep = list([])
|
|
59
|
+
|
|
60
|
+
self._sweep_iter = 0
|
|
61
|
+
self._sweep_run_time = -1.0
|
|
62
|
+
|
|
63
|
+
self._sim_iter = 0
|
|
64
|
+
self._iter_run_time = -1.0
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def set_input_copy_names(self, input_names: list[str] | None = None) -> None:
|
|
68
|
+
"""set_input_copy_name: sets the name that will be used when copying
|
|
69
|
+
input files to the working directories for the sweep. The defualt name
|
|
70
|
+
is 'sim-i' so the first combination of variables in the simulation chain
|
|
71
|
+
will be called 'sim-1-1'.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
input_names : list[str] | None
|
|
76
|
+
List of name prefixes to be used for the simulation files. Defaults
|
|
77
|
+
to None.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
|
|
82
|
+
Raises
|
|
83
|
+
------
|
|
84
|
+
MooseHerdError
|
|
85
|
+
The lengths of the sim runner list and the input
|
|
86
|
+
modifier lists are not the same.
|
|
87
|
+
|
|
88
|
+
"""
|
|
89
|
+
if input_names is None:
|
|
90
|
+
self._input_names = [f'sim-{ii+1}' for ii,_ in enumerate(self._runners)]
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
if len(input_names) != len(self._runners):
|
|
94
|
+
raise MooseHerdError(f'The length of the input names ({len(input_names)})'
|
|
95
|
+
'must match the length of the sim runners ' +
|
|
96
|
+
f'and input modifiers ({len(self._runners)})')
|
|
97
|
+
|
|
98
|
+
self._input_names = input_names
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def set_keep_flag(self, keep_all: bool = True) -> None:
|
|
102
|
+
"""set_keep_flag: flag used for allowing multiple calls to run_para or
|
|
103
|
+
run_seq to keep everything or to overwrite with every call to run_*.
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
keep_all : bool
|
|
108
|
+
True = keep all inputs and outputs with
|
|
109
|
+
multiple calls to run_*. False = overwrite inputs and outputs
|
|
110
|
+
with multiple calls to run_*. Defaults to True.
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
self._keep_all = keep_all
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def set_num_para_sims(self, n_para: int = 1) -> None:
|
|
120
|
+
"""set_num_para_sims: sets the number of simulation chains to run in
|
|
121
|
+
parallel. Limits the number
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
n_para : int
|
|
126
|
+
Number of parallel simulation to run. Defaults to 1.
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
|
|
131
|
+
"""
|
|
132
|
+
n_para = int(n_para)
|
|
133
|
+
n_cpus = os.cpu_count()
|
|
134
|
+
|
|
135
|
+
if n_cpus is None:
|
|
136
|
+
pass
|
|
137
|
+
elif n_para <= 0:
|
|
138
|
+
n_para = 1
|
|
139
|
+
elif n_para > n_cpus:
|
|
140
|
+
n_para = n_cpus
|
|
141
|
+
|
|
142
|
+
if self._n_para_sims != n_para:
|
|
143
|
+
self._n_para_sims = n_para
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_sim_iter(self) -> int:
|
|
147
|
+
"""get_sim_iter: returns the current simulation iteration corresponding
|
|
148
|
+
to the combination of variables being analysed. This number will
|
|
149
|
+
accumulate with multiple calls to run_* is keep_all=true.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
|
|
154
|
+
Returns
|
|
155
|
+
-------
|
|
156
|
+
int
|
|
157
|
+
current simulation iteration number.
|
|
158
|
+
|
|
159
|
+
"""
|
|
160
|
+
return self._sim_iter
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def get_sweep_iter(self) -> int:
|
|
164
|
+
"""get_sweep_iter: gets the current sweep iteration. The sweep
|
|
165
|
+
iteration is incremented with every call to run_* if keep_all = true.
|
|
166
|
+
If keep_all = false then sweep_iter is held at 1.
|
|
167
|
+
|
|
168
|
+
Parameters
|
|
169
|
+
----------
|
|
170
|
+
|
|
171
|
+
Returns
|
|
172
|
+
-------
|
|
173
|
+
int
|
|
174
|
+
current sweep iteration number.
|
|
175
|
+
|
|
176
|
+
"""
|
|
177
|
+
return self._sweep_iter
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def reset_iter_counts(self) -> None:
|
|
181
|
+
"""reset_iter_counts: resets the simulation iteration and the sweep
|
|
182
|
+
iteration counters to zero.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
|
|
187
|
+
Returns
|
|
188
|
+
-------
|
|
189
|
+
|
|
190
|
+
"""
|
|
191
|
+
self._sim_iter = 0
|
|
192
|
+
self._sweep_iter = 0
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _get_process_name(self) -> str:
|
|
196
|
+
"""_get_process_name: only here for monkey patching with pytest.
|
|
197
|
+
|
|
198
|
+
Parameters
|
|
199
|
+
----------
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
str
|
|
204
|
+
the process name string.
|
|
205
|
+
|
|
206
|
+
"""
|
|
207
|
+
return mp.current_process().name
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _get_worker_num(self) -> str:
|
|
211
|
+
"""_get_worker_num: helper function to get the worker number for the
|
|
212
|
+
current sub-process.
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
str
|
|
220
|
+
number string taken from the process name. If this is the main
|
|
221
|
+
process returns '1'.
|
|
222
|
+
|
|
223
|
+
"""
|
|
224
|
+
name = self._get_process_name()
|
|
225
|
+
|
|
226
|
+
if name == 'MainProcess':
|
|
227
|
+
worker_num = '1'
|
|
228
|
+
else:
|
|
229
|
+
worker_num = name.split('-',1)[1]
|
|
230
|
+
|
|
231
|
+
if int(worker_num) > self._n_para_sims:
|
|
232
|
+
worker_num = str((int(worker_num) % self._n_para_sims)+1)
|
|
233
|
+
|
|
234
|
+
return worker_num
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _get_run_num(self, sim_iter: int, worker_num: str) -> str:
|
|
238
|
+
"""_get_run_num: helper function to get the run directory number string
|
|
239
|
+
|
|
240
|
+
Parameters
|
|
241
|
+
----------
|
|
242
|
+
sim_iter : int
|
|
243
|
+
the current simulation iteration.
|
|
244
|
+
worker_num : str
|
|
245
|
+
the worker number extracted from the current
|
|
246
|
+
process number as a string.
|
|
247
|
+
|
|
248
|
+
Returns
|
|
249
|
+
-------
|
|
250
|
+
str
|
|
251
|
+
the string specifying the run directory number for this
|
|
252
|
+
simulation iteration.
|
|
253
|
+
|
|
254
|
+
"""
|
|
255
|
+
if self._keep_all:
|
|
256
|
+
run_num = str(sim_iter+1)
|
|
257
|
+
else:
|
|
258
|
+
run_num = worker_num
|
|
259
|
+
|
|
260
|
+
return run_num
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _mod_input(self,
|
|
264
|
+
modifier: InputModifier,
|
|
265
|
+
mod_vars: dict | None,
|
|
266
|
+
save_file: Path) -> None:
|
|
267
|
+
"""_mod_input: helper function that uses the input modifier to write
|
|
268
|
+
new variables to the input file and save it to the specified path.
|
|
269
|
+
|
|
270
|
+
Parameters
|
|
271
|
+
----------
|
|
272
|
+
modifier : InputModifier
|
|
273
|
+
input modifier for the specified type of
|
|
274
|
+
input file.
|
|
275
|
+
mod_vars : dict | None
|
|
276
|
+
dictionary of variables to write to the
|
|
277
|
+
input file, if None just copy the input file.
|
|
278
|
+
save_file : Path
|
|
279
|
+
path with file name and extension to output the
|
|
280
|
+
modified input file.
|
|
281
|
+
|
|
282
|
+
Returns
|
|
283
|
+
-------
|
|
284
|
+
|
|
285
|
+
"""
|
|
286
|
+
if mod_vars is not None:
|
|
287
|
+
modifier.update_vars(mod_vars)
|
|
288
|
+
modifier.write_file(save_file)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _run(self, runner: SimRunner, run_file: Path) -> Path | None:
|
|
292
|
+
"""_run: helper function to call the SimRunner and get the path to the
|
|
293
|
+
output file.
|
|
294
|
+
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
runner : SimRunner
|
|
298
|
+
for running the simulation, must be a class
|
|
299
|
+
that implements the SimRunner ABC.
|
|
300
|
+
run_file : Path
|
|
301
|
+
path to the input file to run with SimRunner.
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
Returns
|
|
305
|
+
-------
|
|
306
|
+
Path | None
|
|
307
|
+
Path to the output or None
|
|
308
|
+
|
|
309
|
+
"""
|
|
310
|
+
runner.run(run_file)
|
|
311
|
+
return runner.get_output_path()
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def run_once(self, sim_iter: int, var_list: list[dict | None]
|
|
315
|
+
) -> list[Path | None]:
|
|
316
|
+
"""run_once: runs a specific simulation chain with the given variable
|
|
317
|
+
list once and returns a list of paths to the output files. Used by
|
|
318
|
+
run_seq and run_para for parallelisation.
|
|
319
|
+
|
|
320
|
+
Parameters
|
|
321
|
+
----------
|
|
322
|
+
sim_iter : int
|
|
323
|
+
current simulation iteration which is the index of
|
|
324
|
+
the var_list from the var_sweep.
|
|
325
|
+
var_list : list[dict | None]
|
|
326
|
+
list of dictionaries that contain
|
|
327
|
+
the variables that will be run for this iteration.
|
|
328
|
+
|
|
329
|
+
Returns
|
|
330
|
+
-------
|
|
331
|
+
list[Path | None]
|
|
332
|
+
list of paths to the simulation output. If there
|
|
333
|
+
is no useful output from the runner in the simulation chain it
|
|
334
|
+
returns None in the list.
|
|
335
|
+
|
|
336
|
+
"""
|
|
337
|
+
iter_start_time = time.perf_counter()
|
|
338
|
+
|
|
339
|
+
worker_num = self._get_worker_num()
|
|
340
|
+
run_dir = self._dir_manager.get_run_dir(int(worker_num)-1)
|
|
341
|
+
run_num = self._get_run_num(sim_iter,worker_num)
|
|
342
|
+
|
|
343
|
+
run_files = list([])
|
|
344
|
+
for ii,mm in enumerate(self._modifiers):
|
|
345
|
+
ext = mm.get_input_file().suffix
|
|
346
|
+
run_files.append(run_dir / (self._input_names[ii] +'-'+run_num+ext))
|
|
347
|
+
self._mod_input(mm,var_list[ii],run_files[ii])
|
|
348
|
+
|
|
349
|
+
output_list = list([])
|
|
350
|
+
for ii,rr in enumerate(self._runners):
|
|
351
|
+
output_list.append(self._run(rr,run_files[ii]))
|
|
352
|
+
|
|
353
|
+
self._iter_run_time = time.perf_counter() - iter_start_time
|
|
354
|
+
|
|
355
|
+
return output_list
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _start_sweep(self, var_sweep: list[list[dict | None]]) -> float:
|
|
359
|
+
"""_start_sweep: helper function used at the start of a variable sweep
|
|
360
|
+
in either run_seq or run_para. Sets the var_sweep attribute, deals with
|
|
361
|
+
the management of directories and starts the performance counter.
|
|
362
|
+
|
|
363
|
+
Parameters
|
|
364
|
+
----------
|
|
365
|
+
var_sweep : list[list[dict | None]]
|
|
366
|
+
as passed to run_seq/para.
|
|
367
|
+
|
|
368
|
+
Returns
|
|
369
|
+
-------
|
|
370
|
+
float
|
|
371
|
+
performance timer start value.
|
|
372
|
+
|
|
373
|
+
"""
|
|
374
|
+
self._var_sweep = var_sweep
|
|
375
|
+
|
|
376
|
+
if not self._keep_all:
|
|
377
|
+
self.reset_iter_counts()
|
|
378
|
+
self._dir_manager.clear_dirs()
|
|
379
|
+
self._dir_manager.create_dirs()
|
|
380
|
+
|
|
381
|
+
return time.perf_counter()
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def _end_sweep(self, start_sweep_time: float,
|
|
385
|
+
output_files: list[list[Path | None]]) -> None:
|
|
386
|
+
"""_end_sweep: helper function called at the end of runseq/para.
|
|
387
|
+
Reacords the sweep run time. Increments the iteration counters. and
|
|
388
|
+
writes the output key and sweep variables to the first workers
|
|
389
|
+
directory.
|
|
390
|
+
|
|
391
|
+
Parameters
|
|
392
|
+
----------
|
|
393
|
+
start_sweep_time : float
|
|
394
|
+
the sweep start time taken from the
|
|
395
|
+
_start_sweep() function.
|
|
396
|
+
output_files : list[list[Path]]
|
|
397
|
+
list of list of paths to the
|
|
398
|
+
simulation chain output files.
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
Returns
|
|
402
|
+
-------
|
|
403
|
+
|
|
404
|
+
"""
|
|
405
|
+
self._sweep_run_time = time.perf_counter() - start_sweep_time
|
|
406
|
+
|
|
407
|
+
self._sweep_iter += 1
|
|
408
|
+
self._sim_iter += len(self._var_sweep)
|
|
409
|
+
|
|
410
|
+
self._dir_manager.set_output_paths(output_files)
|
|
411
|
+
self._dir_manager.write_output_key(self._sweep_iter)
|
|
412
|
+
self._dir_manager.write_sweep_vars(self._var_sweep,self._sweep_iter)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def run_sequential(self, var_sweep: list[list[dict | None]]
|
|
416
|
+
) -> list[list[Path | None]]:
|
|
417
|
+
"""run_sequential: runs the variable sweep given in var_sweep
|
|
418
|
+
sequentially and returns the paths to the simulation outputs.
|
|
419
|
+
|
|
420
|
+
Parameters
|
|
421
|
+
----------
|
|
422
|
+
var_sweep : list[list[dict | None]]
|
|
423
|
+
outer list is the simulation
|
|
424
|
+
iteration, inner list is the position in the simulation chain
|
|
425
|
+
that the variable dictionary corresponds to. The dictionary
|
|
426
|
+
contains the variables that will be inserted into the input
|
|
427
|
+
file before calling run on the SimRunner. If None instead of
|
|
428
|
+
a dictionary then the input file is copied with no modification
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
Returns
|
|
432
|
+
-------
|
|
433
|
+
list[list[Path | None]]
|
|
434
|
+
outer list is the simulation iteration and
|
|
435
|
+
the inner list corresponds to the position of the SimRunner in
|
|
436
|
+
the cimulation chain. Gives the path to the simulation output
|
|
437
|
+
or None if no useful output is produced.
|
|
438
|
+
|
|
439
|
+
"""
|
|
440
|
+
start_sweep_time = self._start_sweep(var_sweep)
|
|
441
|
+
|
|
442
|
+
output_files = list([])
|
|
443
|
+
|
|
444
|
+
ii = self._sim_iter
|
|
445
|
+
for vv in var_sweep:
|
|
446
|
+
output_files.append(self.run_once(ii,vv))
|
|
447
|
+
ii += 1
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
self._end_sweep(start_sweep_time,output_files)
|
|
451
|
+
|
|
452
|
+
return output_files
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def run_para(self, var_sweep: list[list[dict | None]]
|
|
456
|
+
) -> list[list[Path | None]]:
|
|
457
|
+
"""run_para: runs the variable sweep with the simulation chain in
|
|
458
|
+
parallel.
|
|
459
|
+
|
|
460
|
+
Parameters
|
|
461
|
+
----------
|
|
462
|
+
var_sweep : list[list[dict | None]]
|
|
463
|
+
outer list is the simulation
|
|
464
|
+
iteration, inner list is the position in the simulation chain
|
|
465
|
+
that the variable dictionary corresponds to. The dictionary
|
|
466
|
+
contains the variables that will be inserted into the input
|
|
467
|
+
file before calling run on the SimRunner. If None instead of
|
|
468
|
+
a dictionary then the input file is copied with no modification
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
Returns
|
|
472
|
+
-------
|
|
473
|
+
list[list[Path | None]]
|
|
474
|
+
outer list is the simulation iteration and
|
|
475
|
+
the inner list corresponds to the position of the SimRunner in
|
|
476
|
+
the cimulation chain. Gives the path to the simulation output
|
|
477
|
+
or None if no useful output is produced.
|
|
478
|
+
|
|
479
|
+
"""
|
|
480
|
+
sweep_start_time = self._start_sweep(var_sweep)
|
|
481
|
+
|
|
482
|
+
with Pool(self._n_para_sims) as pool:
|
|
483
|
+
processes = list([])
|
|
484
|
+
|
|
485
|
+
ii = self._sim_iter
|
|
486
|
+
for vv in var_sweep:
|
|
487
|
+
processes.append(pool.apply_async(self.run_once, args=(ii,vv)))
|
|
488
|
+
ii += 1
|
|
489
|
+
|
|
490
|
+
output_files = [pp.get() for pp in processes]
|
|
491
|
+
|
|
492
|
+
self._end_sweep(sweep_start_time, output_files)
|
|
493
|
+
|
|
494
|
+
return output_files
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def get_sweep_time(self) -> float:
|
|
498
|
+
"""get_sweep_time
|
|
499
|
+
|
|
500
|
+
Parameters
|
|
501
|
+
----------
|
|
502
|
+
|
|
503
|
+
Returns
|
|
504
|
+
-------
|
|
505
|
+
float
|
|
506
|
+
the time taken for the variable sweep to run based on the
|
|
507
|
+
performance counter.
|
|
508
|
+
|
|
509
|
+
"""
|
|
510
|
+
return self._sweep_run_time
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
def get_iter_time(self) -> float:
|
|
514
|
+
"""get_iter_time
|
|
515
|
+
|
|
516
|
+
Returns
|
|
517
|
+
float: the time taken for the current simulation iteration to run.
|
|
518
|
+
|
|
519
|
+
Parameters
|
|
520
|
+
----------
|
|
521
|
+
|
|
522
|
+
Returns
|
|
523
|
+
-------
|
|
524
|
+
|
|
525
|
+
"""
|
|
526
|
+
return self._iter_run_time
|
|
527
|
+
|