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.

Files changed (176) hide show
  1. pyvale/__init__.py +12 -92
  2. pyvale/blender/__init__.py +23 -0
  3. pyvale/{pyvaleexceptions.py → blender/blenderexceptions.py} +0 -3
  4. pyvale/{blenderlightdata.py → blender/blenderlightdata.py} +3 -3
  5. pyvale/{blendermaterialdata.py → blender/blendermaterialdata.py} +1 -1
  6. pyvale/{blenderrenderdata.py → blender/blenderrenderdata.py} +5 -3
  7. pyvale/{blenderscene.py → blender/blenderscene.py} +33 -30
  8. pyvale/{blendertools.py → blender/blendertools.py} +14 -10
  9. pyvale/dataset/__init__.py +7 -0
  10. pyvale/dataset/dataset.py +443 -0
  11. pyvale/dic/__init__.py +20 -0
  12. pyvale/{dic2d.py → dic/dic2d.py} +31 -36
  13. pyvale/dic/dic2dconv.py +6 -0
  14. pyvale/{dic2dcpp.cpython-311-darwin.so → dic/dic2dcpp.cpython-311-darwin.so} +0 -0
  15. pyvale/{dicdataimport.py → dic/dicdataimport.py} +8 -8
  16. pyvale/{dicregionofinterest.py → dic/dicregionofinterest.py} +1 -1
  17. pyvale/{dicresults.py → dic/dicresults.py} +1 -1
  18. pyvale/{dicstrain.py → dic/dicstrain.py} +9 -9
  19. pyvale/examples/basics/{ex1_1_basicscalars_therm2d.py → ex1a_basicscalars_therm2d.py} +12 -9
  20. pyvale/examples/basics/{ex1_2_sensormodel_therm2d.py → ex1b_sensormodel_therm2d.py} +17 -14
  21. pyvale/examples/basics/{ex1_3_customsens_therm3d.py → ex1c_customsens_therm3d.py} +27 -24
  22. pyvale/examples/basics/{ex1_4_basicerrors_therm3d.py → ex1d_basicerrors_therm3d.py} +32 -29
  23. pyvale/examples/basics/{ex1_5_fielderrs_therm3d.py → ex1e_fielderrs_therm3d.py} +19 -15
  24. pyvale/examples/basics/{ex1_6_caliberrs_therm2d.py → ex1f_caliberrs_therm2d.py} +20 -16
  25. pyvale/examples/basics/{ex1_7_spatavg_therm2d.py → ex1g_spatavg_therm2d.py} +19 -16
  26. pyvale/examples/basics/{ex2_1_basicvectors_disp2d.py → ex2a_basicvectors_disp2d.py} +13 -10
  27. pyvale/examples/basics/{ex2_2_vectorsens_disp2d.py → ex2b_vectorsens_disp2d.py} +19 -15
  28. pyvale/examples/basics/{ex2_3_sensangle_disp2d.py → ex2c_sensangle_disp2d.py} +21 -18
  29. pyvale/examples/basics/{ex2_4_chainfielderrs_disp2d.py → ex2d_chainfielderrs_disp2d.py} +31 -29
  30. pyvale/examples/basics/{ex2_5_vectorfields3d_disp3d.py → ex2e_vectorfields3d_disp3d.py} +21 -18
  31. pyvale/examples/basics/{ex3_1_basictensors_strain2d.py → ex3a_basictensors_strain2d.py} +16 -14
  32. pyvale/examples/basics/{ex3_2_tensorsens2d_strain2d.py → ex3b_tensorsens2d_strain2d.py} +17 -14
  33. pyvale/examples/basics/{ex3_3_tensorsens3d_strain3d.py → ex3c_tensorsens3d_strain3d.py} +25 -22
  34. pyvale/examples/basics/{ex4_1_expsim2d_thermmech2d.py → ex4a_expsim2d_thermmech2d.py} +17 -14
  35. pyvale/examples/basics/{ex4_2_expsim3d_thermmech3d.py → ex4b_expsim3d_thermmech3d.py} +37 -34
  36. pyvale/examples/basics/ex5_nomesh.py +24 -0
  37. pyvale/examples/dic/ex1_2_blenderdeformed.py +174 -0
  38. pyvale/examples/dic/ex1_region_of_interest.py +6 -3
  39. pyvale/examples/dic/ex2_plate_with_hole.py +21 -18
  40. pyvale/examples/dic/ex3_plate_with_hole_strain.py +8 -6
  41. pyvale/examples/dic/ex4_dic_blender.py +17 -15
  42. pyvale/examples/dic/ex5_dic_challenge.py +19 -14
  43. pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +16 -10
  44. pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +3 -3
  45. pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +29 -23
  46. pyvale/examples/genanalyticdata/ex2_2_analyticsensors_nomesh.py +67 -0
  47. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +12 -9
  48. pyvale/examples/mooseherder/ex0_create_moose_config.py +65 -0
  49. pyvale/examples/mooseherder/ex1a_modify_moose_input.py +71 -0
  50. pyvale/examples/mooseherder/ex1b_modify_gmsh_input.py +69 -0
  51. pyvale/examples/mooseherder/ex2a_run_moose_once.py +80 -0
  52. pyvale/examples/mooseherder/ex2b_run_gmsh_once.py +64 -0
  53. pyvale/examples/mooseherder/ex2c_run_both_once.py +114 -0
  54. pyvale/examples/mooseherder/ex3_run_moose_seq_para.py +157 -0
  55. pyvale/examples/mooseherder/ex4_run_gmsh-moose_seq_para.py +176 -0
  56. pyvale/examples/mooseherder/ex5_run_moose_paramulti.py +136 -0
  57. pyvale/examples/mooseherder/ex6_read_moose_exodus.py +163 -0
  58. pyvale/examples/mooseherder/ex7a_read_moose_herd_results.py +153 -0
  59. pyvale/examples/mooseherder/ex7b_read_multi_herd_results.py +116 -0
  60. pyvale/examples/mooseherder/ex7c_read_multi_gmshmoose_results.py +127 -0
  61. pyvale/examples/mooseherder/ex7d_readconfig_multi_gmshmoose_results.py +143 -0
  62. pyvale/examples/mooseherder/ex8_read_existing_sweep_output.py +72 -0
  63. pyvale/examples/renderblender/ex1_1_blenderscene.py +24 -20
  64. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +22 -18
  65. pyvale/examples/renderblender/ex2_1_stereoscene.py +36 -29
  66. pyvale/examples/renderblender/ex2_2_stereodeformed.py +26 -20
  67. pyvale/examples/renderblender/ex3_1_blendercalibration.py +24 -17
  68. pyvale/examples/renderrasterisation/ex_rastenp.py +14 -12
  69. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +14 -15
  70. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +13 -11
  71. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +13 -11
  72. pyvale/mooseherder/__init__.py +32 -0
  73. pyvale/mooseherder/directorymanager.py +416 -0
  74. pyvale/mooseherder/exodusreader.py +763 -0
  75. pyvale/mooseherder/gmshrunner.py +163 -0
  76. pyvale/mooseherder/inputmodifier.py +236 -0
  77. pyvale/mooseherder/mooseconfig.py +226 -0
  78. pyvale/mooseherder/mooseherd.py +527 -0
  79. pyvale/mooseherder/mooserunner.py +303 -0
  80. pyvale/mooseherder/outputreader.py +22 -0
  81. pyvale/mooseherder/simdata.py +92 -0
  82. pyvale/mooseherder/simrunner.py +31 -0
  83. pyvale/mooseherder/sweepreader.py +356 -0
  84. pyvale/mooseherder/sweeptools.py +76 -0
  85. pyvale/sensorsim/__init__.py +82 -0
  86. pyvale/{camera.py → sensorsim/camera.py} +7 -7
  87. pyvale/{camerasensor.py → sensorsim/camerasensor.py} +7 -7
  88. pyvale/{camerastereo.py → sensorsim/camerastereo.py} +2 -2
  89. pyvale/{cameratools.py → sensorsim/cameratools.py} +4 -4
  90. pyvale/{cython → sensorsim/cython}/rastercyth.c +596 -596
  91. pyvale/{cython → sensorsim/cython}/rastercyth.cpython-311-darwin.so +0 -0
  92. pyvale/{cython → sensorsim/cython}/rastercyth.py +16 -17
  93. pyvale/{errorcalculator.py → sensorsim/errorcalculator.py} +1 -1
  94. pyvale/{errorintegrator.py → sensorsim/errorintegrator.py} +2 -2
  95. pyvale/{errorrand.py → sensorsim/errorrand.py} +4 -4
  96. pyvale/{errorsyscalib.py → sensorsim/errorsyscalib.py} +2 -2
  97. pyvale/{errorsysdep.py → sensorsim/errorsysdep.py} +2 -2
  98. pyvale/{errorsysfield.py → sensorsim/errorsysfield.py} +8 -8
  99. pyvale/{errorsysindep.py → sensorsim/errorsysindep.py} +3 -3
  100. pyvale/sensorsim/exceptions.py +8 -0
  101. pyvale/{experimentsimulator.py → sensorsim/experimentsimulator.py} +23 -3
  102. pyvale/{field.py → sensorsim/field.py} +1 -1
  103. pyvale/{fieldconverter.py → sensorsim/fieldconverter.py} +72 -19
  104. pyvale/sensorsim/fieldinterp.py +37 -0
  105. pyvale/sensorsim/fieldinterpmesh.py +124 -0
  106. pyvale/sensorsim/fieldinterppoints.py +55 -0
  107. pyvale/{fieldsampler.py → sensorsim/fieldsampler.py} +4 -4
  108. pyvale/{fieldscalar.py → sensorsim/fieldscalar.py} +28 -24
  109. pyvale/{fieldtensor.py → sensorsim/fieldtensor.py} +33 -31
  110. pyvale/{fieldvector.py → sensorsim/fieldvector.py} +33 -31
  111. pyvale/{imagedef2d.py → sensorsim/imagedef2d.py} +9 -5
  112. pyvale/{integratorfactory.py → sensorsim/integratorfactory.py} +6 -6
  113. pyvale/{integratorquadrature.py → sensorsim/integratorquadrature.py} +3 -3
  114. pyvale/{integratorrectangle.py → sensorsim/integratorrectangle.py} +3 -3
  115. pyvale/{integratorspatial.py → sensorsim/integratorspatial.py} +1 -1
  116. pyvale/{rastercy.py → sensorsim/rastercy.py} +5 -5
  117. pyvale/{rasternp.py → sensorsim/rasternp.py} +9 -9
  118. pyvale/{rasteropts.py → sensorsim/rasteropts.py} +1 -1
  119. pyvale/{renderer.py → sensorsim/renderer.py} +1 -1
  120. pyvale/{rendermesh.py → sensorsim/rendermesh.py} +5 -5
  121. pyvale/{renderscene.py → sensorsim/renderscene.py} +2 -2
  122. pyvale/{sensorarray.py → sensorsim/sensorarray.py} +1 -1
  123. pyvale/{sensorarrayfactory.py → sensorsim/sensorarrayfactory.py} +12 -12
  124. pyvale/{sensorarraypoint.py → sensorsim/sensorarraypoint.py} +10 -8
  125. pyvale/{sensordata.py → sensorsim/sensordata.py} +1 -1
  126. pyvale/{sensortools.py → sensorsim/sensortools.py} +2 -20
  127. pyvale/sensorsim/simtools.py +174 -0
  128. pyvale/{visualexpplotter.py → sensorsim/visualexpplotter.py} +3 -3
  129. pyvale/{visualimages.py → sensorsim/visualimages.py} +2 -2
  130. pyvale/{visualsimanimator.py → sensorsim/visualsimanimator.py} +4 -4
  131. pyvale/{visualsimplotter.py → sensorsim/visualsimplotter.py} +5 -5
  132. pyvale/{visualsimsensors.py → sensorsim/visualsimsensors.py} +12 -12
  133. pyvale/{visualtools.py → sensorsim/visualtools.py} +1 -1
  134. pyvale/{visualtraceplotter.py → sensorsim/visualtraceplotter.py} +2 -2
  135. pyvale/simcases/case17.geo +3 -0
  136. pyvale/simcases/case17.i +4 -4
  137. pyvale/simcases/run_1case.py +1 -9
  138. pyvale/simcases/run_all_cases.py +1 -1
  139. pyvale/simcases/run_build_case.py +1 -1
  140. pyvale/simcases/run_example_cases.py +1 -1
  141. pyvale/verif/__init__.py +12 -0
  142. pyvale/{analyticsimdatafactory.py → verif/analyticsimdatafactory.py} +2 -2
  143. pyvale/{analyticsimdatagenerator.py → verif/analyticsimdatagenerator.py} +2 -2
  144. pyvale/verif/psens.py +125 -0
  145. pyvale/verif/psensconst.py +18 -0
  146. pyvale/verif/psensmech.py +227 -0
  147. pyvale/verif/psensmultiphys.py +187 -0
  148. pyvale/verif/psensscalar.py +347 -0
  149. pyvale/verif/psenstensor.py +123 -0
  150. pyvale/verif/psensvector.py +116 -0
  151. {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/METADATA +6 -7
  152. pyvale-2025.8.1.dist-info/RECORD +262 -0
  153. pyvale/dataset.py +0 -415
  154. pyvale/simtools.py +0 -67
  155. pyvale-2025.7.2.dist-info/RECORD +0 -214
  156. /pyvale/{blendercalibrationdata.py → blender/blendercalibrationdata.py} +0 -0
  157. /pyvale/{dicchecks.py → dic/dicchecks.py} +0 -0
  158. /pyvale/{dicspecklegenerator.py → dic/dicspecklegenerator.py} +0 -0
  159. /pyvale/{dicspecklequality.py → dic/dicspecklequality.py} +0 -0
  160. /pyvale/{dicstrainresults.py → dic/dicstrainresults.py} +0 -0
  161. /pyvale/{cameradata.py → sensorsim/cameradata.py} +0 -0
  162. /pyvale/{cameradata2d.py → sensorsim/cameradata2d.py} +0 -0
  163. /pyvale/{errordriftcalc.py → sensorsim/errordriftcalc.py} +0 -0
  164. /pyvale/{fieldtransform.py → sensorsim/fieldtransform.py} +0 -0
  165. /pyvale/{generatorsrandom.py → sensorsim/generatorsrandom.py} +0 -0
  166. /pyvale/{imagetools.py → sensorsim/imagetools.py} +0 -0
  167. /pyvale/{integratortype.py → sensorsim/integratortype.py} +0 -0
  168. /pyvale/{output.py → sensorsim/output.py} +0 -0
  169. /pyvale/{raster.py → sensorsim/raster.py} +0 -0
  170. /pyvale/{sensordescriptor.py → sensorsim/sensordescriptor.py} +0 -0
  171. /pyvale/{visualimagedef.py → sensorsim/visualimagedef.py} +0 -0
  172. /pyvale/{visualopts.py → sensorsim/visualopts.py} +0 -0
  173. /pyvale/{analyticmeshgen.py → verif/analyticmeshgen.py} +0 -0
  174. {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/WHEEL +0 -0
  175. {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/licenses/LICENSE +0 -0
  176. {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,116 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ """
8
+ Read parameter sweep results for a MOOSE simulation
9
+ ================================================================================
10
+
11
+ In this example we read the all the simulation results from multiple calls to
12
+ her workflow manager and verify that we correctly read all of the simulation
13
+ outputs.
14
+
15
+ **Installing moose**: To run this example you will need to have installed moose
16
+ on your system. As moose supports unix operating systems windows users will need
17
+ to use windows subsystem for linux (WSL). We use the proteus moose build which
18
+ can be found here: https://github.com/aurora-multiphysics/proteus. Build scripts
19
+ for common linux distributions can be found in the 'scripts' directory of the
20
+ repo. You can also create your own moose build using instructions here:
21
+ https://mooseframework.inl.gov/.
22
+
23
+ We start by importing what we need for this example.
24
+ """
25
+
26
+ import time
27
+ from pathlib import Path
28
+ import numpy as np
29
+
30
+ #pyvale imports
31
+ import pyvale.dataset as dataset
32
+ from pyvale.mooseherder import (MooseHerd,
33
+ MooseRunner,
34
+ MooseConfig,
35
+ InputModifier,
36
+ DirectoryManager,
37
+ SweepReader,
38
+ sweep_param_grid)
39
+
40
+
41
+ #%%
42
+ # The first part of this example is the same as our previous example called:
43
+ # 'Using multiple calls to run parallel sweeps'. For a detailed explanation of
44
+ # the code below head to that example. For now we use this to generate multiple
45
+ # sets of outputs and then use a sweep reader to read this all in below.
46
+
47
+ moose_input = dataset.element_case_input_path(dataset.EElemTest.HEX20)
48
+ moose_modifier = InputModifier(moose_input,'#','')
49
+
50
+ config = {'main_path': Path.home()/ 'moose',
51
+ 'app_path': Path.home() / 'proteus',
52
+ 'app_name': 'proteus-opt'}
53
+ moose_config = MooseConfig(config)
54
+
55
+ moose_runner = MooseRunner(moose_config)
56
+ moose_runner.set_run_opts(n_tasks = 1,
57
+ n_threads = 2,
58
+ redirect_out = True)
59
+
60
+ num_para_sims: int = 4
61
+ dir_manager = DirectoryManager(n_dirs=num_para_sims)
62
+ herd = MooseHerd([moose_runner],[moose_modifier],dir_manager)
63
+ herd.set_num_para_sims(n_para=num_para_sims)
64
+
65
+ output_path = Path.cwd() / "pyvale-output"
66
+ if not output_path.is_dir():
67
+ output_path.mkdir(parents=True, exist_ok=True)
68
+
69
+ dir_manager.set_base_dir(output_path)
70
+ dir_manager.reset_dirs()
71
+
72
+ moose_params = {"nElemX": (2,3),
73
+ "lengX": np.array([10e-3,15e-3]),
74
+ "PRatio":(0.3,)}
75
+ params = [moose_params,]
76
+ sweep_params = sweep_param_grid(params)
77
+
78
+ print("\nParameter sweep variables by simulation:")
79
+ for ii,pp in enumerate(sweep_params):
80
+ print(f"Sim: {ii}, Params [moose,]: {pp}")
81
+
82
+ num_para_runs: int = 3
83
+ if __name__ == '__main__':
84
+ sweep_times = np.zeros((num_para_runs,),dtype=np.float64)
85
+ for rr in range(num_para_runs):
86
+ herd.run_para(sweep_params)
87
+ sweep_times[rr] = herd.get_sweep_time()
88
+
89
+ print()
90
+ for ii,ss in enumerate(sweep_times):
91
+ print(f"Sweep {ii} took: {ss:.3f}seconds")
92
+ print()
93
+
94
+ #%%
95
+ # Here we will just read all the results sequentially and verify that we have
96
+ # the number of simulation results we expect for the multiple calls above.
97
+ # Looking at our parameter sweep we have 4 unique combination of variables and
98
+ # we ran this 3 times so we expect to have a total of 12 simulation results in
99
+ # our outer list which we print below. Note that our inner list still has a
100
+ # single ``SimData`` object as we only have a single moose simulation in our
101
+ # simulation chain.
102
+ sweep_reader = SweepReader(dir_manager)
103
+ start_time = time.perf_counter()
104
+ sweep_results_seq = sweep_reader.read_sequential()
105
+ read_time_seq = time.perf_counter() - start_time
106
+
107
+ print("Outer list = unique simulation chain:")
108
+ print(f" {len(sweep_results_seq)=}")
109
+ print("Inner list = particular simulation tool in the chain:")
110
+ print(f" {len(sweep_results_seq[0])=}")
111
+ print("'SimData' object for the particular simulation tool:")
112
+ print(f" {type(sweep_results_seq[0][0])=}")
113
+ print()
114
+
115
+ print(f'Read time (sequential) = {read_time_seq:.6f} seconds')
116
+
@@ -0,0 +1,127 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ """
8
+ Read parameter sweep results for a Gmsh and MOOSE simulation
9
+ ================================================================================
10
+
11
+ In this example we will read the results from a sweep that includes gmsh and
12
+ moose in the simulation chain. A key difference here in the results output is
13
+ that gmsh does not create output we want to read so the inner list of our
14
+ results list of lists will have 'None' in its 0 index and then the ``SimData``
15
+ data object from our moose simulation in the 1 index.
16
+
17
+ **Installing moose**: To run this example you will need to have installed moose
18
+ on your system. As moose supports unix operating systems windows users will need
19
+ to use windows subsystem for linux (WSL). We use the proteus moose build which
20
+ can be found here: https://github.com/aurora-multiphysics/proteus. Build scripts
21
+ for common linux distributions can be found in the 'scripts' directory of the
22
+ repo. You can also create your own moose build using instructions here:
23
+ https://mooseframework.inl.gov/.
24
+
25
+ **Installing gmsh**: For this example you will need to have a gmsh executable
26
+ which can be downloaded and installed from here: https://gmsh.info/#Download
27
+
28
+ We start by importing what we need for this example.
29
+ """
30
+
31
+ import time
32
+ from pathlib import Path
33
+ import numpy as np
34
+
35
+ #pyvale imports
36
+ import pyvale.dataset as dataset
37
+ from pyvale.mooseherder import (MooseHerd,
38
+ MooseRunner,
39
+ GmshRunner,
40
+ MooseConfig,
41
+ InputModifier,
42
+ DirectoryManager,
43
+ SweepReader,
44
+ sweep_param_grid)
45
+
46
+ #%%
47
+ # The first part of this example is the same as the previous example we have
48
+ # seen running a parallel parameter sweep for gmsh+moose using the herd workflow
49
+ # manager. If you are not familiar with the code below go back to the example
50
+ # entitled 'Running a parameter sweep of a Gmsh and MOOSE simulation'.
51
+ # Otherwise you can skip down to the next code block where we will read the
52
+ # output of the sweep and compare it to what we have seen previously.
53
+ sim_case: int = 17
54
+
55
+ gmsh_input = dataset.sim_case_gmsh_file_path(case_num=sim_case)
56
+ gmsh_modifier = InputModifier(gmsh_input,"//",";")
57
+
58
+ gmsh_runner = GmshRunner(gmsh_path=(Path.home() / "gmsh/bin/gmsh"))
59
+ gmsh_runner.set_input_file(gmsh_input)
60
+
61
+ moose_input = dataset.sim_case_input_file_path(case_num=sim_case)
62
+ moose_modifier = InputModifier(moose_input,"#","")
63
+
64
+ moose_config = MooseConfig({'main_path': Path.home()/ 'moose',
65
+ 'app_path': Path.home() / 'proteus',
66
+ 'app_name': 'proteus-opt'})
67
+ moose_runner = MooseRunner(moose_config)
68
+ moose_runner.set_run_opts(n_tasks = 1,
69
+ n_threads = 2,
70
+ redirect_out = True)
71
+
72
+ num_para_sims: int = 4
73
+ dir_manager = DirectoryManager(n_dirs=num_para_sims)
74
+ herd = MooseHerd([gmsh_runner,moose_runner],
75
+ [gmsh_modifier,moose_modifier],
76
+ dir_manager,
77
+ num_para_sims)
78
+
79
+ output_path = Path.cwd() / "pyvale-output"
80
+ if not output_path.is_dir():
81
+ output_path.mkdir(parents=True, exist_ok=True)
82
+
83
+ dir_manager.set_base_dir(output_path)
84
+ dir_manager.reset_dirs()
85
+
86
+ gmsh_params = {"plate_width": np.array([150e-3,100e-3]),
87
+ "plate_height": ("plate_width + 100e-3",
88
+ "plate_width + 50e-3")}
89
+ moose_params = None
90
+ sweep_params = sweep_param_grid([gmsh_params,moose_params])
91
+
92
+ if __name__ == "__main__":
93
+ herd.run_para(sweep_params)
94
+ time_run_para = herd.get_sweep_time()
95
+
96
+
97
+ print(f'Sweep run time (para) = {time_run_para:.3f} seconds\n')
98
+
99
+ #%%
100
+ # We now pass the directory manager we used for the sweep to our sweep reader
101
+ # and then we read in the sweep results sequentially. As we have seen before
102
+ # our sweep results are given as a list of lists where the outer list is the
103
+ # unique simulation chain in our parameter sweep and the inner list corresponds
104
+ # to each simulation tool in the chain. In this case we have gmsh and moose so
105
+ # our inner list should have a length of 2.
106
+
107
+ sweep_reader = SweepReader(dir_manager,num_para_read=4)
108
+
109
+ start_time = time.perf_counter()
110
+ sweep_results_seq = sweep_reader.read_sequential()
111
+ read_time_seq = time.perf_counter() - start_time
112
+
113
+ print(f'Read time sequential = {read_time_seq:.6f} seconds\n')
114
+
115
+ print("Outer list = unique simulation chain:")
116
+ print(f" {len(sweep_results_seq)=}")
117
+ print("Inner list = particular simulation tool in the chain:")
118
+ print(f" {len(sweep_results_seq[0])=}")
119
+ print()
120
+
121
+ #%%
122
+ # As gmsh does not have any simulation output we can read as a ``SimData``
123
+ # object we see that our inner sweep results list has 'None' in the position
124
+ # corresponding to gmsh (the 0 index). We also see we have our moose output as
125
+ # a ``SimData`` object at the 1 index of the inner list.
126
+ print(f"{type(sweep_results_seq[0][0])=}")
127
+ print(f"{type(sweep_results_seq[0][1])=}")
@@ -0,0 +1,143 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ """
8
+ Using read config to extract specific variables from a sweep
9
+ ================================================================================
10
+
11
+ In this example we are going to use a read configuration object to control what
12
+ variables are read from our simulation output. This is useful for when we might
13
+ only want to read a subset of the simulation data for post-processing. For
14
+ example a post processor like 'max_temp' from 'glob_vars' without reading in the
15
+ full temperature field. This can help save memory when reading in data from
16
+ large sweeps.
17
+
18
+ **Installing moose**: To run this example you will need to have installed moose
19
+ on your system. As moose supports unix operating systems windows users will need
20
+ to use windows subsystem for linux (WSL). We use the proteus moose build which
21
+ can be found here: https://github.com/aurora-multiphysics/proteus. Build scripts
22
+ for common linux distributions can be found in the 'scripts' directory of the
23
+ repo. You can also create your own moose build using instructions here:
24
+ https://mooseframework.inl.gov/.
25
+
26
+ We start by importing what we need for this example.
27
+ """
28
+
29
+ import time
30
+ from pathlib import Path
31
+ import numpy as np
32
+
33
+ #pyvale imports
34
+ import pyvale.dataset as dataset
35
+ from pyvale.mooseherder import (MooseHerd,
36
+ MooseRunner,
37
+ MooseConfig,
38
+ InputModifier,
39
+ DirectoryManager,
40
+ ExodusReader,
41
+ SweepReader,
42
+ sweep_param_grid)
43
+
44
+ #%%
45
+ # The first part of this example is the same as our previous example called:
46
+ # 'Using multiple calls to run parallel sweeps'. For a detailed explanation of
47
+ # the code below head to that example. For now we use this to generate multiple
48
+ # sets of outputs and then use a sweep reader to read this all in below.
49
+
50
+ moose_input = dataset.element_case_input_path(dataset.EElemTest.HEX20)
51
+ moose_modifier = InputModifier(moose_input,'#','')
52
+
53
+ config = {'main_path': Path.home()/ 'moose',
54
+ 'app_path': Path.home() / 'proteus',
55
+ 'app_name': 'proteus-opt'}
56
+ moose_config = MooseConfig(config)
57
+
58
+ moose_runner = MooseRunner(moose_config)
59
+ moose_runner.set_run_opts(n_tasks = 1,
60
+ n_threads = 2,
61
+ redirect_out = True)
62
+
63
+ num_para_sims: int = 4
64
+ dir_manager = DirectoryManager(n_dirs=num_para_sims)
65
+ herd = MooseHerd([moose_runner],[moose_modifier],dir_manager)
66
+ herd.set_num_para_sims(n_para=num_para_sims)
67
+
68
+ output_path = Path.cwd() / "pyvale-output"
69
+ if not output_path.is_dir():
70
+ output_path.mkdir(parents=True, exist_ok=True)
71
+
72
+ dir_manager.set_base_dir(output_path)
73
+ dir_manager.reset_dirs()
74
+
75
+ moose_params = {"nElemX": (2,3),
76
+ "lengX": np.array([10e-3,15e-3]),
77
+ "PRatio":(0.3,)}
78
+ params = [moose_params,]
79
+ sweep_params = sweep_param_grid(params)
80
+
81
+ print("\nParameter sweep variables by simulation:")
82
+ for ii,pp in enumerate(sweep_params):
83
+ print(f"Sim: {ii}, Params [moose,]: {pp}")
84
+
85
+ num_para_runs: int = 3
86
+ if __name__ == '__main__':
87
+ sweep_times = np.zeros((num_para_runs,),dtype=np.float64)
88
+ for rr in range(num_para_runs):
89
+ herd.run_para(sweep_params)
90
+ sweep_times[rr] = herd.get_sweep_time()
91
+
92
+ print()
93
+ for ii,ss in enumerate(sweep_times):
94
+ print(f"Sweep {ii} took: {ss:.3f}seconds")
95
+ print()
96
+
97
+
98
+ #%%
99
+ # Now we create a sweep reader as we have done before and we will use this to
100
+ # read the json keys containing the paths to all the output files. The output
101
+ # file paths have the same list of lists structure we get when we read the
102
+ # sweep data where the outer list corresponds to the unique simulation chain and
103
+ # the inner list corresponds to position of the specific simulation tool in the
104
+ # chain.
105
+ #
106
+
107
+ sweep_reader = SweepReader(dir_manager,num_para_read=4)
108
+ output_file_paths = sweep_reader.read_all_output_file_keys()
109
+
110
+
111
+ #%%
112
+ # When we used a read configuration with our exodus reader previously we saw
113
+ # that it can be simpler to get the read configuration that covers everything
114
+ # in our file and then edit it to extract what we want. Here we are use our
115
+ # exodus reader to extract the read configuration fo the first simulation.
116
+ # We also get the original sim data so we can compare to the case when we use
117
+ # a read configuration to control what we read.
118
+ #
119
+ # Now we want to edit the read configuration so that we only read every second
120
+ # time step from our simulation output files. We do this by getting the
121
+ # original time steps with our exodus reader and then using this to change the
122
+ # ``time_inds`` field of our read configuration to extract every second step.
123
+ exodus_reader = ExodusReader(output_file_paths[0][0])
124
+ sim_data_orig = exodus_reader.read_all_sim_data()
125
+
126
+ read_config = exodus_reader.get_read_config()
127
+ sim_time = exodus_reader.get_time()
128
+ read_config.time_inds = np.arange(0,sim_time.shape[0],2)
129
+
130
+ #%%
131
+ # Now we read the sweep results using our read configuration and then check
132
+ # extracted simulation data object to see that we have every second time step.
133
+ sweep_results_seq = sweep_reader.read_sequential(read_config=read_config)
134
+
135
+ print("Comparison of time steps extracted:")
136
+ print()
137
+ print(f"{sim_data_orig.time.shape=}")
138
+ print(f"{sweep_results_seq[0][0].time.shape=}")
139
+ print()
140
+ print(f"{sim_data_orig.node_vars['disp_x'].shape=}")
141
+ print(f"{sweep_results_seq[0][0].node_vars['disp_x'].shape=}")
142
+ print()
143
+
@@ -0,0 +1,72 @@
1
+ # =============================================================================="ctrl+p"
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ """
8
+ Reading results from a pre-run parameter sweep
9
+ ================================================================================
10
+
11
+ In this example we will read in the output of a parameter sweep performed by the
12
+ 'herd' workflow manager specifically showing how we can read a sweep if we don't
13
+ have the original directory manager.
14
+
15
+ **NOTE**: this example assumes you have run one of the previous examples using
16
+ the herd workflow manager and that there is a series of output simulation
17
+ working directories in the pyvale-output directory. If not please run the
18
+ example called 'Running a parameter sweep of a MOOSE simulation' first.
19
+
20
+ We start by importing what we need for this example.
21
+ """
22
+ import time
23
+ from pprint import pprint
24
+ from pathlib import Path
25
+ from pyvale.mooseherder import DirectoryManager
26
+ from pyvale.mooseherder import SweepReader
27
+
28
+ #%%
29
+ # First we create a directory manager and pass it our standard pyvale output
30
+ # directory where our simulation sweep output is. The number of directories here
31
+ # is not critical as long as it is equal to or larger than the number of working
32
+ # directories you used when you ran your sweep it will find all simulation
33
+ # outputs that exist in the working directories.
34
+ output_base_path = Path.cwd() / "pyvale-output"
35
+ dir_manager = DirectoryManager(n_dirs=4)
36
+ dir_manager.set_base_dir(output_base_path)
37
+
38
+ #%%
39
+ # We now pass the directory manager into a sweep reader setting the option to
40
+ # read our sweep output in parallel. Note that for small output files reading
41
+ # the output in parallel will probably be slower than reading sequentially so
42
+ # make sure you test the reader for your particular case.
43
+ #
44
+ # We then use the reader extract the list of list of output file paths and the
45
+ # combinations of variables that were used for this parameter sweep.
46
+ sweep_reader = SweepReader(dir_manager,num_para_read=4)
47
+
48
+ output_files = sweep_reader.read_all_output_file_keys()
49
+ sweep_variables = sweep_reader.read_all_sweep_var_files()
50
+
51
+ print('Output files in json keys:')
52
+ pprint(sweep_reader.read_all_output_file_keys())
53
+ print()
54
+
55
+ print('Parameter sweep variables found:')
56
+ pprint(sweep_reader.read_all_sweep_var_files())
57
+ print()
58
+
59
+ #%%
60
+ # Now we use our sweep reader to read in the existing sweep results. We can also
61
+ # use a read configuration here if we want to filter out specific parts of the
62
+ # simulation output but for now we will read all of the data.
63
+
64
+ if __name__ == '__main__':
65
+ start_time = time.perf_counter()
66
+ sweep_data = sweep_reader.read_results_para()
67
+ read_time_para = time.perf_counter() - start_time
68
+
69
+ print("-"*80)
70
+ print(f'Number of simulations outputs read: {len(sweep_data):d}')
71
+ print(f'Read time parallel = {read_time_para:.6f} seconds')
72
+ print("-"*80)
@@ -5,7 +5,7 @@
5
5
  # ==============================================================================
6
6
 
7
7
  """
8
- Blender example: Creating a scene with 2D DIC
8
+ Creating a scene with 2D DIC
9
9
  ---------------------------------------------
10
10
 
11
11
  This example takes you through creating a scene and adding all the necessary
@@ -18,8 +18,12 @@ Test case: mechanical analysis of a plate with a hole loaded in tension.
18
18
  import numpy as np
19
19
  from scipy.spatial.transform import Rotation
20
20
  from pathlib import Path
21
- import pyvale
22
- import mooseherder as mh
21
+
22
+ #pyvale modules
23
+ import pyvale.sensorsim as sens
24
+ import pyvale.dataset as dataset
25
+ import pyvale.blender as blender
26
+ import pyvale.mooseherder as mh
23
27
 
24
28
  # %%
25
29
  # Here we load in a pre-generated MOOSE finite element simulation dataset that
@@ -29,7 +33,7 @@ import mooseherder as mh
29
33
  # format (*.e). `mooseherder` is then used to convert the simulation output
30
34
  # into a `SimData` object.
31
35
 
32
- data_path = pyvale.DataSet.render_mechanical_3d_path()
36
+ data_path = dataset.render_mechanical_3d_path()
33
37
  sim_data = mh.ExodusReader(data_path).read_all_sim_data()
34
38
 
35
39
  # %%
@@ -40,11 +44,11 @@ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
40
44
  # The `disp_comps` are the expected direction of displacement. Since this is a
41
45
  # 3D deformation test case, displacement is expected in the x, y and z directions.
42
46
  disp_comps = ("disp_x","disp_y", "disp_z")
43
- sim_data = pyvale.scale_length_units(scale=1000.0,
47
+ sim_data = sens.scale_length_units(scale=1000.0,
44
48
  sim_data=sim_data,
45
49
  disp_comps=disp_comps)
46
50
 
47
- render_mesh = pyvale.create_render_mesh(sim_data,
51
+ render_mesh = sens.create_render_mesh(sim_data,
48
52
  ("disp_y","disp_x"),
49
53
  sim_spat_dim=3,
50
54
  field_disp_keys=disp_comps)
@@ -64,10 +68,10 @@ base_dir = Path.cwd()
64
68
  # In order to create a DIC setup in Blender, first a scene must be created.
65
69
  # A scene is a holding space for all of your objects (e.g. camera(s), light(s)
66
70
  # and sample(s)).
67
- # A scene is initialised using the `BlenderScene` class. All the subsequent
71
+ # A scene is initialised using the `blender.Scene` class. All the subsequent
68
72
  # objects and actions necessary are then methods of this class.
69
73
 
70
- scene = pyvale.BlenderScene()
74
+ scene = blender.Scene()
71
75
 
72
76
  # %%
73
77
  # The next thing that can be added to the scene is a sample.
@@ -79,10 +83,10 @@ scene = pyvale.BlenderScene()
79
83
  part = scene.add_part(render_mesh, sim_spat_dim=3)
80
84
  # Set the part location
81
85
  part_location = np.array([0, 0, 0])
82
- pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
86
+ blender.Tools.move_blender_obj(part=part, pos_world=part_location)
83
87
  # Set part rotation
84
88
  part_rotation = Rotation.from_euler("xyz", [0, 0, 0], degrees=True)
85
- pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
89
+ blender.Tools.rotate_blender_obj(part=part, rot_world=part_rotation)
86
90
 
87
91
  # %%
88
92
  # A camera can then be added to the scene.
@@ -91,7 +95,7 @@ pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
91
95
  # This camera can then be added to the Blender scene.
92
96
  # The camera can also be moved and rotated.
93
97
 
94
- cam_data = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
98
+ cam_data = sens.CameraData(pixels_num=np.array([1540, 1040]),
95
99
  pixels_size=np.array([0.00345, 0.00345]),
96
100
  pos_world=(0, 0, 400),
97
101
  rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
@@ -106,10 +110,10 @@ camera.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
106
110
  # Blender offers different light types: Point, Sun, Spot and Area.
107
111
  # The light can also be moved and rotated like the camera.
108
112
 
109
- light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
110
- pos_world=(0, 0, 400),
111
- rot_world=Rotation.from_euler("xyz",
112
- [0, 0, 0]),
113
+ light_data = blender.LightData(type=blender.LightType.POINT,
114
+ pos_world=(0, 0, 400),
115
+ rot_world=Rotation.from_euler("xyz",
116
+ [0, 0, 0]),
113
117
  energy=1)
114
118
  light = scene.add_light(light_data)
115
119
  light.location = (0, 0, 410)
@@ -126,10 +130,10 @@ light.rotation_euler = (0, 0, 0)
126
130
  # It should be noted that for a bigger camera or sample you may need to generate
127
131
  # a larger speckle pattern.
128
132
 
129
- material_data = pyvale.BlenderMaterialData()
130
- speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
133
+ material_data = blender.MaterialData()
134
+ speckle_path = dataset.dic_pattern_5mpx_path()
131
135
 
132
- mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data)
136
+ mm_px_resolution = sens.CameraTools.calculate_mm_px_resolution(cam_data)
133
137
  scene.add_speckle(part=part,
134
138
  speckle_path=speckle_path,
135
139
  mat_data=material_data,
@@ -142,7 +146,7 @@ scene.add_speckle(part=part,
142
146
  # Firstly, all the rendering parameters must be set, including parameters such as
143
147
  # the number of threads to use.
144
148
 
145
- render_data = pyvale.RenderData(cam_data=cam_data,
149
+ render_data = blender.RenderData(cam_data=cam_data,
146
150
  base_dir=base_dir,
147
151
  threads=8)
148
152
 
@@ -164,5 +168,5 @@ print("Save directory of the image:", (render_data.base_dir / "blenderimages"))
164
168
  # There is also the option to save the scene as a Blender project file.
165
169
  # This file can be opened with the Blender GUI to view the scene.
166
170
 
167
- pyvale.BlenderTools.save_blender_file(base_dir)
171
+ blender.Tools.save_blender_file(base_dir)
168
172