pyvale 2025.4.0__py3-none-any.whl → 2025.5.1__py3-none-any.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 +78 -64
- pyvale/analyticmeshgen.py +102 -0
- pyvale/{core/analyticsimdatafactory.py → analyticsimdatafactory.py} +44 -16
- pyvale/analyticsimdatagenerator.py +323 -0
- pyvale/blendercalibrationdata.py +15 -0
- pyvale/blenderlightdata.py +26 -0
- pyvale/blendermaterialdata.py +15 -0
- pyvale/blenderrenderdata.py +30 -0
- pyvale/blenderscene.py +488 -0
- pyvale/blendertools.py +420 -0
- pyvale/{core/camera.py → camera.py} +15 -15
- pyvale/{core/cameradata.py → cameradata.py} +27 -22
- pyvale/{core/cameradata2d.py → cameradata2d.py} +8 -6
- pyvale/camerastereo.py +217 -0
- pyvale/{core/cameratools.py → cameratools.py} +220 -26
- pyvale/{core/cython → cython}/rastercyth.py +11 -7
- pyvale/data/__init__.py +5 -7
- pyvale/data/cal_target.tiff +0 -0
- pyvale/data/case00_HEX20_out.e +0 -0
- pyvale/data/case00_HEX27_out.e +0 -0
- pyvale/data/case00_HEX8_out.e +0 -0
- pyvale/data/case00_TET10_out.e +0 -0
- pyvale/data/case00_TET14_out.e +0 -0
- pyvale/data/case00_TET4_out.e +0 -0
- pyvale/{core/dataset.py → dataset.py} +91 -16
- pyvale/{core/errorcalculator.py → errorcalculator.py} +13 -16
- pyvale/{core/errordriftcalc.py → errordriftcalc.py} +14 -14
- pyvale/{core/errorintegrator.py → errorintegrator.py} +25 -28
- pyvale/{core/errorrand.py → errorrand.py} +39 -46
- pyvale/errorsyscalib.py +134 -0
- pyvale/{core/errorsysdep.py → errorsysdep.py} +25 -29
- pyvale/{core/errorsysfield.py → errorsysfield.py} +59 -52
- pyvale/{core/errorsysindep.py → errorsysindep.py} +85 -182
- pyvale/examples/__init__.py +5 -7
- pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +131 -0
- pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +158 -0
- pyvale/examples/basics/ex1_3_customsens_therm3d.py +216 -0
- pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +153 -0
- pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +168 -0
- pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +133 -0
- pyvale/examples/basics/ex1_7_spatavg_therm2d.py +123 -0
- pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +112 -0
- pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +111 -0
- pyvale/examples/basics/ex2_3_sensangle_disp2d.py +139 -0
- pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +196 -0
- pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +109 -0
- pyvale/examples/basics/ex3_1_basictensors_strain2d.py +114 -0
- pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +111 -0
- pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +182 -0
- pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +171 -0
- pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +252 -0
- pyvale/examples/{analyticdatagen → genanalyticdata}/ex1_1_scalarvisualisation.py +6 -9
- pyvale/examples/{analyticdatagen → genanalyticdata}/ex1_2_scalarcasebuild.py +8 -11
- pyvale/examples/{analyticdatagen → genanalyticdata}/ex2_1_analyticsensors.py +9 -12
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +8 -15
- pyvale/examples/renderblender/ex1_1_blenderscene.py +121 -0
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +119 -0
- pyvale/examples/renderblender/ex2_1_stereoscene.py +128 -0
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +131 -0
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +120 -0
- pyvale/examples/{rasterisation → renderrasterisation}/ex_rastenp.py +6 -7
- pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_oneframe.py +5 -7
- pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_static_cypara.py +6 -13
- pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_static_pypara.py +9 -12
- pyvale/examples/{ex1_4_thermal2d.py → visualisation/ex1_1_plot_traces.py} +33 -20
- pyvale/examples/{features/ex_animation_tools_3dmonoblock.py → visualisation/ex2_1_animate_sim.py} +37 -31
- pyvale/experimentsimulator.py +175 -0
- pyvale/{core/field.py → field.py} +6 -14
- pyvale/fieldconverter.py +351 -0
- pyvale/{core/fieldsampler.py → fieldsampler.py} +9 -10
- pyvale/{core/fieldscalar.py → fieldscalar.py} +17 -18
- pyvale/{core/fieldtensor.py → fieldtensor.py} +23 -26
- pyvale/{core/fieldtransform.py → fieldtransform.py} +9 -5
- pyvale/{core/fieldvector.py → fieldvector.py} +14 -16
- pyvale/{core/generatorsrandom.py → generatorsrandom.py} +29 -52
- pyvale/{core/imagedef2d.py → imagedef2d.py} +11 -8
- pyvale/{core/integratorfactory.py → integratorfactory.py} +12 -13
- pyvale/{core/integratorquadrature.py → integratorquadrature.py} +57 -32
- pyvale/integratorrectangle.py +165 -0
- pyvale/{core/integratorspatial.py → integratorspatial.py} +9 -10
- pyvale/{core/integratortype.py → integratortype.py} +7 -8
- pyvale/output.py +17 -0
- pyvale/pyvaleexceptions.py +11 -0
- pyvale/{core/raster.py → raster.py} +8 -8
- pyvale/{core/rastercy.py → rastercy.py} +11 -10
- pyvale/{core/rasternp.py → rasternp.py} +12 -13
- pyvale/{core/rendermesh.py → rendermesh.py} +10 -19
- pyvale/{core/sensorarray.py → sensorarray.py} +7 -8
- pyvale/{core/sensorarrayfactory.py → sensorarrayfactory.py} +64 -78
- pyvale/{core/sensorarraypoint.py → sensorarraypoint.py} +39 -41
- pyvale/{core/sensordata.py → sensordata.py} +7 -8
- pyvale/sensordescriptor.py +213 -0
- pyvale/{core/sensortools.py → sensortools.py} +8 -9
- pyvale/simcases/case00_HEX20.i +5 -5
- pyvale/simcases/case00_HEX27.i +5 -5
- pyvale/simcases/case00_HEX8.i +242 -0
- pyvale/simcases/case00_TET10.i +2 -2
- pyvale/simcases/case00_TET14.i +2 -2
- pyvale/simcases/case00_TET4.i +242 -0
- pyvale/simcases/run_1case.py +1 -1
- pyvale/simtools.py +67 -0
- pyvale/visualexpplotter.py +191 -0
- pyvale/{core/visualimagedef.py → visualimagedef.py} +13 -10
- pyvale/{core/visualimages.py → visualimages.py} +10 -9
- pyvale/visualopts.py +493 -0
- pyvale/{core/visualsimanimator.py → visualsimanimator.py} +47 -19
- pyvale/visualsimsensors.py +318 -0
- pyvale/visualtools.py +136 -0
- pyvale/visualtraceplotter.py +142 -0
- {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/METADATA +17 -14
- pyvale-2025.5.1.dist-info/RECORD +172 -0
- {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/WHEEL +1 -1
- pyvale/core/__init__.py +0 -7
- pyvale/core/analyticmeshgen.py +0 -59
- pyvale/core/analyticsimdatagenerator.py +0 -160
- pyvale/core/cython/rastercyth.c +0 -32267
- pyvale/core/experimentsimulator.py +0 -99
- pyvale/core/fieldconverter.py +0 -154
- pyvale/core/integratorrectangle.py +0 -88
- pyvale/core/optimcheckfuncs.py +0 -153
- pyvale/core/sensordescriptor.py +0 -101
- pyvale/core/visualexpplotter.py +0 -151
- pyvale/core/visualopts.py +0 -180
- pyvale/core/visualsimplotter.py +0 -182
- pyvale/core/visualtools.py +0 -81
- pyvale/core/visualtraceplotter.py +0 -256
- pyvale/examples/analyticdatagen/__init__.py +0 -7
- pyvale/examples/ex1_1_thermal2d.py +0 -89
- pyvale/examples/ex1_2_thermal2d.py +0 -111
- pyvale/examples/ex1_3_thermal2d.py +0 -113
- pyvale/examples/ex1_5_thermal2d.py +0 -105
- pyvale/examples/ex2_1_thermal3d .py +0 -87
- pyvale/examples/ex2_2_thermal3d.py +0 -51
- pyvale/examples/ex2_3_thermal3d.py +0 -109
- pyvale/examples/ex3_1_displacement2d.py +0 -47
- pyvale/examples/ex3_2_displacement2d.py +0 -79
- pyvale/examples/ex3_3_displacement2d.py +0 -104
- pyvale/examples/ex3_4_displacement2d.py +0 -105
- pyvale/examples/ex4_1_strain2d.py +0 -57
- pyvale/examples/ex4_2_strain2d.py +0 -79
- pyvale/examples/ex4_3_strain2d.py +0 -100
- pyvale/examples/ex5_1_multiphysics2d.py +0 -78
- pyvale/examples/ex6_1_multiphysics2d_expsim.py +0 -118
- pyvale/examples/ex6_2_multiphysics3d_expsim.py +0 -158
- pyvale/examples/features/__init__.py +0 -7
- pyvale/examples/features/ex_area_avg.py +0 -89
- pyvale/examples/features/ex_calibration_error.py +0 -108
- pyvale/examples/features/ex_chain_field_errs.py +0 -141
- pyvale/examples/features/ex_field_errs.py +0 -78
- pyvale/examples/features/ex_sensor_single_angle_batch.py +0 -110
- pyvale-2025.4.0.dist-info/RECORD +0 -157
- {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/licenses/LICENSE +0 -0
- {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Copyright (C) 2025 The Computer Aided Validation Team
|
|
8
|
-
================================================================================
|
|
9
|
-
'''
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
10
7
|
import matplotlib.pyplot as plt
|
|
11
8
|
import numpy as np
|
|
12
9
|
import pyvale
|
|
@@ -19,7 +16,7 @@ def main() -> None:
|
|
|
19
16
|
field_key = 'scalar'
|
|
20
17
|
t_field = pyvale.FieldScalar(sim_data,
|
|
21
18
|
field_key=field_key,
|
|
22
|
-
|
|
19
|
+
elem_dims=2)
|
|
23
20
|
|
|
24
21
|
n_sens = (4,1,1)
|
|
25
22
|
x_lims = (0.0,10.0)
|
|
@@ -47,9 +44,9 @@ def main() -> None:
|
|
|
47
44
|
error_chain = []
|
|
48
45
|
if errors_on['indep_sys']:
|
|
49
46
|
error_chain.append(pyvale.ErrSysOffset(offset=-5.0))
|
|
50
|
-
error_chain.append(pyvale.
|
|
47
|
+
error_chain.append(pyvale.ErrSysUnif(low=-5.0,
|
|
51
48
|
high=5.0))
|
|
52
|
-
gen_norm = pyvale.
|
|
49
|
+
gen_norm = pyvale.GenNormal(std=1.0)
|
|
53
50
|
|
|
54
51
|
if errors_on['rand']:
|
|
55
52
|
error_chain.append(pyvale.ErrRandNormPercent(std_percent=1.0))
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
4
6
|
|
|
5
|
-
License: MIT
|
|
6
|
-
Copyright (C) 2025 The Computer Aided Validation Team
|
|
7
|
-
================================================================================
|
|
8
|
-
"""
|
|
9
7
|
|
|
10
8
|
from pathlib import Path
|
|
11
9
|
import numpy as np
|
|
@@ -14,8 +12,6 @@ import pyvale as pyv
|
|
|
14
12
|
|
|
15
13
|
|
|
16
14
|
def main() -> None:
|
|
17
|
-
#---------------------------------------------------------------------------
|
|
18
|
-
# LOAD FILES
|
|
19
15
|
sim_path = pyv.DataSet.mechanical_2d_path()
|
|
20
16
|
sim_data = mh.ExodusReader(sim_path).read_all_sim_data()
|
|
21
17
|
|
|
@@ -37,8 +33,7 @@ def main() -> None:
|
|
|
37
33
|
print(f"{disp_y.shape=}")
|
|
38
34
|
print(80*"-")
|
|
39
35
|
|
|
40
|
-
|
|
41
|
-
# INPUT DATA
|
|
36
|
+
|
|
42
37
|
cam_data = pyv.CameraData2D(pixels_count=np.array((1040,1540)),
|
|
43
38
|
leng_per_px=0.1e-3,
|
|
44
39
|
bits=8,
|
|
@@ -49,8 +44,7 @@ def main() -> None:
|
|
|
49
44
|
add_static_ref=True)
|
|
50
45
|
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
# PRE-PROCESS IMAGES
|
|
47
|
+
|
|
54
48
|
(upsampled_image,
|
|
55
49
|
image_mask,
|
|
56
50
|
image_input,
|
|
@@ -68,8 +62,7 @@ def main() -> None:
|
|
|
68
62
|
disp = np.array((disp_x[:,ff],disp_y[:,ff])).T
|
|
69
63
|
print(f"{disp.shape=}")
|
|
70
64
|
|
|
71
|
-
|
|
72
|
-
# DEFORM IMAGES AND SAVE
|
|
65
|
+
|
|
73
66
|
pyv.ImageDef2D.deform_images_to_disk(cam_data,
|
|
74
67
|
upsampled_image,
|
|
75
68
|
coords,
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from scipy.spatial.transform import Rotation
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import pyvale
|
|
11
|
+
import mooseherder as mh
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
data_path = pyvale.DataSet.render_mechanical_3d_path()
|
|
15
|
+
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
16
|
+
|
|
17
|
+
disp_comps = ("disp_x","disp_y", "disp_z")
|
|
18
|
+
|
|
19
|
+
# Scale m -> mm
|
|
20
|
+
# NOTE: All lengths are to be specified in mm
|
|
21
|
+
sim_data = pyvale.scale_length_units(sim_data,disp_comps,1000.0)
|
|
22
|
+
|
|
23
|
+
render_mesh = pyvale.create_render_mesh(sim_data,
|
|
24
|
+
("disp_y","disp_x"),
|
|
25
|
+
sim_spat_dim=3,
|
|
26
|
+
field_disp_keys=disp_comps)
|
|
27
|
+
|
|
28
|
+
# Set the save path
|
|
29
|
+
# --------------------------------------------------------------------------
|
|
30
|
+
# All the files saved will be saved to a subfolder within this specified
|
|
31
|
+
# base directory.
|
|
32
|
+
# This base directory can be specified by:
|
|
33
|
+
base_dir = Path.cwd()
|
|
34
|
+
# If no base directory is specified, it will be set as your home directory
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Creating the scene
|
|
38
|
+
# --------------------------------------------------------------------------
|
|
39
|
+
scene = pyvale.BlenderScene()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# It should be noted that the mesh will be centred to allow for the cameras
|
|
43
|
+
# to be centred on the mesh.
|
|
44
|
+
part = scene.add_part(render_mesh, sim_spat_dim=3)
|
|
45
|
+
# Set the part location
|
|
46
|
+
part_location = np.array([0, 0, 0])
|
|
47
|
+
pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
|
|
48
|
+
# Set part rotation
|
|
49
|
+
part_rotation = Rotation.from_euler("xyz", [0, 0, 0])
|
|
50
|
+
pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
|
|
51
|
+
|
|
52
|
+
# Add the camera
|
|
53
|
+
cam_data = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
|
|
54
|
+
pixels_size=np.array([0.00345, 0.00345]),
|
|
55
|
+
pos_world=(0, 0, 400),
|
|
56
|
+
rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
|
|
57
|
+
roi_cent_world=(0, 0, 0),
|
|
58
|
+
focal_length=15.0)
|
|
59
|
+
camera = scene.add_camera(cam_data)
|
|
60
|
+
|
|
61
|
+
# The camera can be moved and rotated this:
|
|
62
|
+
camera.location = (0, 0, 410)
|
|
63
|
+
camera.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# Add the light
|
|
67
|
+
light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
|
|
68
|
+
pos_world=(0, 0, 400),
|
|
69
|
+
rot_world=Rotation.from_euler("xyz",
|
|
70
|
+
[0, 0, 0]),
|
|
71
|
+
energy=1)
|
|
72
|
+
light = scene.add_light(light_data)
|
|
73
|
+
|
|
74
|
+
# The light can also be moved and rotated:
|
|
75
|
+
light.location = (0, 0, 410)
|
|
76
|
+
light.rotation_euler = (0, 0, 0)
|
|
77
|
+
|
|
78
|
+
# Apply the speckle pattern
|
|
79
|
+
material_data = pyvale.BlenderMaterialData()
|
|
80
|
+
speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
|
|
81
|
+
# NOTE: If you wish to use a bigger camera, you will need to generate a
|
|
82
|
+
# bigger speckle pattern generator
|
|
83
|
+
|
|
84
|
+
mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data)
|
|
85
|
+
scene.add_speckle(part=part,
|
|
86
|
+
speckle_path=speckle_path,
|
|
87
|
+
mat_data=material_data,
|
|
88
|
+
mm_px_resolution=mm_px_resolution)
|
|
89
|
+
|
|
90
|
+
# Rendering image
|
|
91
|
+
# --------------------------------------------------------------------------
|
|
92
|
+
# Set this to True to render image of the current scene
|
|
93
|
+
render_opts = True
|
|
94
|
+
if render_opts:
|
|
95
|
+
# NOTE: If no save directory is specified, this is where the images will
|
|
96
|
+
# be saved
|
|
97
|
+
render_data = pyvale.RenderData(cam_data=cam_data,
|
|
98
|
+
base_dir=base_dir,
|
|
99
|
+
threads=8)
|
|
100
|
+
# NOTE: The number of threads used to render the images is set within
|
|
101
|
+
# RenderData, it is defaulted to 4 threads
|
|
102
|
+
|
|
103
|
+
scene.render_single_image(stage_image=False,
|
|
104
|
+
render_data=render_data)
|
|
105
|
+
# NOTE: If bounce_image is set to True, the image will be saved to disk,
|
|
106
|
+
# converted to an array, deleted and the image array will be returned.
|
|
107
|
+
|
|
108
|
+
print()
|
|
109
|
+
print(80*"-")
|
|
110
|
+
print("Save directory of the image:", (render_data.base_dir / "blenderimages"))
|
|
111
|
+
print(80*"-")
|
|
112
|
+
print()
|
|
113
|
+
|
|
114
|
+
# Save Blender file
|
|
115
|
+
# --------------------------------------------------------------------------
|
|
116
|
+
# The file that will be saved is a Blender project file. This can be opened
|
|
117
|
+
# with the Blender GUI to view the scene.
|
|
118
|
+
pyvale.BlenderTools.save_blender_file(base_dir)
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__":
|
|
121
|
+
main()
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from scipy.spatial.transform import Rotation
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import pyvale
|
|
11
|
+
import mooseherder as mh
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
data_path = pyvale.DataSet.render_mechanical_3d_path()
|
|
15
|
+
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
16
|
+
|
|
17
|
+
disp_comps = ("disp_x","disp_y", "disp_z")
|
|
18
|
+
|
|
19
|
+
# Scale m -> mm
|
|
20
|
+
sim_data = pyvale.scale_length_units(sim_data,disp_comps,1000.0)
|
|
21
|
+
|
|
22
|
+
render_mesh = pyvale.create_render_mesh(sim_data,
|
|
23
|
+
("disp_y","disp_x"),
|
|
24
|
+
sim_spat_dim=3,
|
|
25
|
+
field_disp_keys=disp_comps)
|
|
26
|
+
|
|
27
|
+
# Set the save path
|
|
28
|
+
# --------------------------------------------------------------------------
|
|
29
|
+
# All the files saved will be saved to a subfolder within this specified
|
|
30
|
+
# base directory.
|
|
31
|
+
# This base directory can be specified by:
|
|
32
|
+
base_dir = Path.cwd()
|
|
33
|
+
# If no base directory is specified, it will be set as your home directory
|
|
34
|
+
|
|
35
|
+
# Creating the scene
|
|
36
|
+
# --------------------------------------------------------------------------
|
|
37
|
+
scene = pyvale.BlenderScene()
|
|
38
|
+
|
|
39
|
+
# It should be noted that the mesh will be centred to allow for the cameras
|
|
40
|
+
# to be centred on the mesh.
|
|
41
|
+
part = scene.add_part(render_mesh, sim_spat_dim=3)
|
|
42
|
+
# Set the part location
|
|
43
|
+
part_location = np.array([0, 0, 0])
|
|
44
|
+
pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
|
|
45
|
+
# Set part rotation
|
|
46
|
+
part_rotation = Rotation.from_euler("xyz", [0, 0, 0])
|
|
47
|
+
pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
|
|
48
|
+
|
|
49
|
+
# Add the camera
|
|
50
|
+
cam_data = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
|
|
51
|
+
pixels_size=np.array([0.00345, 0.00345]),
|
|
52
|
+
pos_world=(0, 0, 400),
|
|
53
|
+
rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
|
|
54
|
+
roi_cent_world=(0, 0, 0),
|
|
55
|
+
focal_length=15.0)
|
|
56
|
+
camera = scene.add_camera(cam_data)
|
|
57
|
+
|
|
58
|
+
# The camera can be moved and rotated this:
|
|
59
|
+
camera.location = (0, 0, 410)
|
|
60
|
+
camera.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
|
|
61
|
+
|
|
62
|
+
# Add the light
|
|
63
|
+
light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
|
|
64
|
+
pos_world=(0, 0, 400),
|
|
65
|
+
rot_world=Rotation.from_euler("xyz",
|
|
66
|
+
[0, 0, 0]),
|
|
67
|
+
energy=1)
|
|
68
|
+
light = scene.add_light(light_data)
|
|
69
|
+
|
|
70
|
+
# The light can also be moved and rotated:
|
|
71
|
+
light.location = (0, 0, 410)
|
|
72
|
+
light.rotation_euler = (0, 0, 0)
|
|
73
|
+
|
|
74
|
+
# Apply the speckle pattern
|
|
75
|
+
material_data = pyvale.BlenderMaterialData()
|
|
76
|
+
speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
|
|
77
|
+
# NOTE: If you wish to use a bigger camera, you will need to generate a
|
|
78
|
+
# bigger speckle pattern generator
|
|
79
|
+
mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data)
|
|
80
|
+
scene.add_speckle(part=part,
|
|
81
|
+
speckle_path=speckle_path,
|
|
82
|
+
mat_data=material_data,
|
|
83
|
+
mm_px_resolution=mm_px_resolution)
|
|
84
|
+
|
|
85
|
+
# Deform and render images
|
|
86
|
+
# --------------------------------------------------------------------------
|
|
87
|
+
# Set this to True to render image of the deforming part
|
|
88
|
+
render_opts = True
|
|
89
|
+
if render_opts:
|
|
90
|
+
# NOTE: If no save directory is specified, this is where the images will
|
|
91
|
+
# be saved
|
|
92
|
+
render_data = pyvale.RenderData(cam_data=cam_data,
|
|
93
|
+
base_dir=base_dir,
|
|
94
|
+
threads=8)
|
|
95
|
+
# NOTE: The number of threads used to render the images is set within
|
|
96
|
+
# RenderData, it is defaulted to 4 threads
|
|
97
|
+
|
|
98
|
+
scene.render_deformed_images(render_mesh,
|
|
99
|
+
sim_spat_dim=3,
|
|
100
|
+
render_data=render_data,
|
|
101
|
+
part=part,
|
|
102
|
+
stage_image=False)
|
|
103
|
+
# NOTE: If bounce_image is set to True, the image will be saved to disk,
|
|
104
|
+
# converted to an array, deleted and the image array will be returned.
|
|
105
|
+
|
|
106
|
+
print()
|
|
107
|
+
print(80*"-")
|
|
108
|
+
print("Save directory of the image:", render_data.base_dir)
|
|
109
|
+
print(80*"-")
|
|
110
|
+
print()
|
|
111
|
+
|
|
112
|
+
# Save Blender file
|
|
113
|
+
# --------------------------------------------------------------------------
|
|
114
|
+
# The file that will be saved is a Blender project file. This can be opened
|
|
115
|
+
# with the Blender GUI to view the scene.
|
|
116
|
+
pyvale.BlenderTools.save_blender_file(base_dir)
|
|
117
|
+
|
|
118
|
+
if __name__ == "__main__":
|
|
119
|
+
main()
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from scipy.spatial.transform import Rotation
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import pyvale
|
|
11
|
+
import mooseherder as mh
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
data_path = pyvale.DataSet.render_mechanical_3d_path()
|
|
15
|
+
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
16
|
+
|
|
17
|
+
disp_comps = ("disp_x","disp_y", "disp_z")
|
|
18
|
+
|
|
19
|
+
# Scale m -> mm
|
|
20
|
+
# NOTE: All lengths are to be specified in mm
|
|
21
|
+
sim_data = pyvale.scale_length_units(sim_data,disp_comps,1000.0)
|
|
22
|
+
|
|
23
|
+
render_mesh = pyvale.create_render_mesh(sim_data,
|
|
24
|
+
("disp_y","disp_x"),
|
|
25
|
+
sim_spat_dim=3,
|
|
26
|
+
field_disp_keys=disp_comps)
|
|
27
|
+
|
|
28
|
+
# Set the save path
|
|
29
|
+
# --------------------------------------------------------------------------
|
|
30
|
+
# All the files saved will be saved to a subfolder within this specified
|
|
31
|
+
# base directory.
|
|
32
|
+
# This base directory can be specified by:
|
|
33
|
+
base_dir = Path.cwd()
|
|
34
|
+
# If no base directory is specified, it will be set as your home directory
|
|
35
|
+
|
|
36
|
+
# Creating the scene
|
|
37
|
+
# --------------------------------------------------------------------------
|
|
38
|
+
scene = pyvale.BlenderScene()
|
|
39
|
+
|
|
40
|
+
part = scene.add_part(render_mesh, sim_spat_dim=3)
|
|
41
|
+
# Set the part location
|
|
42
|
+
part_location = np.array([0, 0, 0])
|
|
43
|
+
pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
|
|
44
|
+
# Set part rotation
|
|
45
|
+
part_rotation = Rotation.from_euler("xyz", [0, 0, 0])
|
|
46
|
+
pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
|
|
47
|
+
|
|
48
|
+
# Add the stereo camera system
|
|
49
|
+
cam_data_0 = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
|
|
50
|
+
pixels_size=np.array([0.00345, 0.00345]),
|
|
51
|
+
pos_world=np.array([0, 0, 400]),
|
|
52
|
+
rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
|
|
53
|
+
roi_cent_world=(0, 0, 0),
|
|
54
|
+
focal_length=15.0)
|
|
55
|
+
# Set this to "symmetric" to get a symmetric stereo system or set this to
|
|
56
|
+
# "faceon" to get a face-on stereo system
|
|
57
|
+
stereo_setup = "faceon"
|
|
58
|
+
if stereo_setup == "symmetric":
|
|
59
|
+
stereo_system = pyvale.CameraTools.symmetric_stereo_cameras(
|
|
60
|
+
cam_data_0=cam_data_0,
|
|
61
|
+
stereo_angle=15.0)
|
|
62
|
+
if stereo_setup == "faceon":
|
|
63
|
+
stereo_system = pyvale.CameraTools.faceon_stereo_cameras(
|
|
64
|
+
cam_data_0=cam_data_0,
|
|
65
|
+
stereo_angle=15.0)
|
|
66
|
+
|
|
67
|
+
cam0, cam1 = scene.add_stereo_system(stereo_system)
|
|
68
|
+
|
|
69
|
+
# Generate calibration file
|
|
70
|
+
stereo_system.save_calibration(base_dir)
|
|
71
|
+
|
|
72
|
+
# Add the light
|
|
73
|
+
light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
|
|
74
|
+
pos_world=(0, 0, 400),
|
|
75
|
+
rot_world=Rotation.from_euler("xyz",
|
|
76
|
+
[0, 0, 0]),
|
|
77
|
+
energy=1)
|
|
78
|
+
light = scene.add_light(light_data)
|
|
79
|
+
|
|
80
|
+
# The light can also be moved and rotated:
|
|
81
|
+
light.location = (0, 0, 410)
|
|
82
|
+
light.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
|
|
83
|
+
|
|
84
|
+
# Apply the speckle pattern
|
|
85
|
+
material_data = pyvale.BlenderMaterialData()
|
|
86
|
+
speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
|
|
87
|
+
# NOTE: If you wish to use a bigger camera, you will need to generate a
|
|
88
|
+
# bigger speckle pattern generator
|
|
89
|
+
|
|
90
|
+
mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data_0)
|
|
91
|
+
scene.add_speckle(part=part,
|
|
92
|
+
speckle_path=speckle_path,
|
|
93
|
+
mat_data=material_data,
|
|
94
|
+
mm_px_resolution=mm_px_resolution)
|
|
95
|
+
|
|
96
|
+
# Rendering image
|
|
97
|
+
# --------------------------------------------------------------------------
|
|
98
|
+
# Set this to True to render image of the current scene
|
|
99
|
+
render_opts = True
|
|
100
|
+
if render_opts:
|
|
101
|
+
# NOTE: If no save directory is specified, this is where the images will
|
|
102
|
+
# be saved
|
|
103
|
+
render_data = pyvale.RenderData(cam_data=(stereo_system.cam_data_0,
|
|
104
|
+
stereo_system.cam_data_1),
|
|
105
|
+
base_dir=base_dir,
|
|
106
|
+
threads=8)
|
|
107
|
+
# NOTE: The number of threads used to render the images is set within
|
|
108
|
+
# RenderData, it is defaulted to 4 threads
|
|
109
|
+
|
|
110
|
+
scene.render_single_image(stage_image=False,
|
|
111
|
+
render_data=render_data)
|
|
112
|
+
# NOTE: If bounce_image is set to True, the image will be saved to disk,
|
|
113
|
+
# converted to an array, deleted and the image array will be returned.
|
|
114
|
+
|
|
115
|
+
print()
|
|
116
|
+
print(80*"-")
|
|
117
|
+
print("Save directory of the image:", (render_data.base_dir / "blenderimages"))
|
|
118
|
+
print(80*"-")
|
|
119
|
+
print()
|
|
120
|
+
|
|
121
|
+
# Save Blender file
|
|
122
|
+
# --------------------------------------------------------------------------
|
|
123
|
+
# The file that will be saved is a Blender project file. This can be opened
|
|
124
|
+
# with the Blender GUI to view the scene.
|
|
125
|
+
pyvale.BlenderTools.save_blender_file(base_dir=base_dir)
|
|
126
|
+
|
|
127
|
+
if __name__ == "__main__":
|
|
128
|
+
main()
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from scipy.spatial.transform import Rotation
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import pyvale
|
|
11
|
+
import mooseherder as mh
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
data_path = pyvale.DataSet.render_mechanical_3d_path()
|
|
15
|
+
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
16
|
+
|
|
17
|
+
disp_comps = ("disp_x","disp_y", "disp_z")
|
|
18
|
+
|
|
19
|
+
# Scale m -> mm
|
|
20
|
+
# NOTE: All lengths are to be specified in mm
|
|
21
|
+
sim_data = pyvale.scale_length_units(sim_data,disp_comps,1000.0)
|
|
22
|
+
|
|
23
|
+
render_mesh = pyvale.create_render_mesh(sim_data,
|
|
24
|
+
("disp_y","disp_x"),
|
|
25
|
+
sim_spat_dim=3,
|
|
26
|
+
field_disp_keys=disp_comps)
|
|
27
|
+
|
|
28
|
+
# Set the save path
|
|
29
|
+
# --------------------------------------------------------------------------
|
|
30
|
+
# All the files saved will be saved to a subfolder within this specified
|
|
31
|
+
# base directory.
|
|
32
|
+
# This base directory can be specified by:
|
|
33
|
+
base_dir = Path.cwd()
|
|
34
|
+
# If no base directory is specified, it will be set as your home directory
|
|
35
|
+
|
|
36
|
+
# Creating the scene
|
|
37
|
+
# --------------------------------------------------------------------------
|
|
38
|
+
scene = pyvale.BlenderScene()
|
|
39
|
+
|
|
40
|
+
part = scene.add_part(render_mesh, sim_spat_dim=3)
|
|
41
|
+
# Set the part location
|
|
42
|
+
part_location = np.array([0, 0, 0])
|
|
43
|
+
pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
|
|
44
|
+
# Set part rotation
|
|
45
|
+
part_rotation = Rotation.from_euler("xyz", [0, 0, 0])
|
|
46
|
+
pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
|
|
47
|
+
|
|
48
|
+
# Add the stereo camera system
|
|
49
|
+
cam_data_0 = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
|
|
50
|
+
pixels_size=np.array([0.00345, 0.00345]),
|
|
51
|
+
pos_world=np.array([0, 0, 400]),
|
|
52
|
+
rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
|
|
53
|
+
roi_cent_world=(0, 0, 0),
|
|
54
|
+
focal_length=15.0)
|
|
55
|
+
# Set this to "symmetric" to get a symmetric stereo system or set this to
|
|
56
|
+
# "faceon" to get a face-on stereo system
|
|
57
|
+
stereo_setup = "faceon"
|
|
58
|
+
if stereo_setup == "symmetric":
|
|
59
|
+
stereo_system = pyvale.CameraTools.symmetric_stereo_cameras(
|
|
60
|
+
cam_data_0=cam_data_0,
|
|
61
|
+
stereo_angle=15.0)
|
|
62
|
+
if stereo_setup == "faceon":
|
|
63
|
+
stereo_system = pyvale.CameraTools.faceon_stereo_cameras(
|
|
64
|
+
cam_data_0=cam_data_0,
|
|
65
|
+
stereo_angle=15.0)
|
|
66
|
+
|
|
67
|
+
cam0, cam1 = scene.add_stereo_system(stereo_system)
|
|
68
|
+
|
|
69
|
+
# Generate calibration file
|
|
70
|
+
stereo_system.save_calibration(base_dir)
|
|
71
|
+
|
|
72
|
+
# Add the light
|
|
73
|
+
light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
|
|
74
|
+
pos_world=(0, 0, 400),
|
|
75
|
+
rot_world=Rotation.from_euler("xyz",
|
|
76
|
+
[0, 0, 0]),
|
|
77
|
+
energy=1)
|
|
78
|
+
light = scene.add_light(light_data)
|
|
79
|
+
|
|
80
|
+
# The light can also be moved and rotated:
|
|
81
|
+
light.location = (0, 0, 410)
|
|
82
|
+
light.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
|
|
83
|
+
|
|
84
|
+
# Apply the speckle pattern
|
|
85
|
+
material_data = pyvale.BlenderMaterialData()
|
|
86
|
+
speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
|
|
87
|
+
# NOTE: If you wish to use a bigger camera, you will need to generate a
|
|
88
|
+
# bigger speckle pattern generator
|
|
89
|
+
|
|
90
|
+
mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data_0)
|
|
91
|
+
scene.add_speckle(part=part,
|
|
92
|
+
speckle_path=speckle_path,
|
|
93
|
+
mat_data=material_data,
|
|
94
|
+
mm_px_resolution=mm_px_resolution)
|
|
95
|
+
|
|
96
|
+
# Deform and render images
|
|
97
|
+
# --------------------------------------------------------------------------
|
|
98
|
+
# Set this to True to render image of the deforming part
|
|
99
|
+
render_opts = True
|
|
100
|
+
if render_opts:
|
|
101
|
+
# NOTE: If no save directory is specified, this is where the images will
|
|
102
|
+
# be saved
|
|
103
|
+
render_data = pyvale.RenderData(cam_data=(stereo_system.cam_data_0,
|
|
104
|
+
stereo_system.cam_data_1),
|
|
105
|
+
base_dir=base_dir,
|
|
106
|
+
threads=8)
|
|
107
|
+
# NOTE: The number of threads used to render the images is set within
|
|
108
|
+
# RenderData, it is defaulted to 4 threads
|
|
109
|
+
|
|
110
|
+
scene.render_deformed_images(render_mesh=render_mesh,
|
|
111
|
+
sim_spat_dim=3,
|
|
112
|
+
render_data=render_data,
|
|
113
|
+
part=part,
|
|
114
|
+
stage_image=False)
|
|
115
|
+
# NOTE: If bounce_image is set to True, the image will be saved to disk,
|
|
116
|
+
# converted to an array, deleted and the image array will be returned.
|
|
117
|
+
|
|
118
|
+
print()
|
|
119
|
+
print(80*"-")
|
|
120
|
+
print("Save directory of the image:", (render_data.base_dir / "blenderimages"))
|
|
121
|
+
print(80*"-")
|
|
122
|
+
print()
|
|
123
|
+
|
|
124
|
+
# Save Blender file
|
|
125
|
+
# --------------------------------------------------------------------------
|
|
126
|
+
# The file that will be saved is a Blender project file. This can be opened
|
|
127
|
+
# with the Blender GUI to view the scene.
|
|
128
|
+
pyvale.BlenderTools.save_blender_file(base_dir)
|
|
129
|
+
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
main()
|