pyvale 2025.4.0__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 +75 -0
- pyvale/core/__init__.py +7 -0
- pyvale/core/analyticmeshgen.py +59 -0
- pyvale/core/analyticsimdatafactory.py +63 -0
- pyvale/core/analyticsimdatagenerator.py +160 -0
- pyvale/core/camera.py +146 -0
- pyvale/core/cameradata.py +64 -0
- pyvale/core/cameradata2d.py +82 -0
- pyvale/core/cameratools.py +328 -0
- pyvale/core/cython/rastercyth.c +32267 -0
- pyvale/core/cython/rastercyth.py +636 -0
- pyvale/core/dataset.py +250 -0
- pyvale/core/errorcalculator.py +112 -0
- pyvale/core/errordriftcalc.py +146 -0
- pyvale/core/errorintegrator.py +339 -0
- pyvale/core/errorrand.py +614 -0
- pyvale/core/errorsysdep.py +331 -0
- pyvale/core/errorsysfield.py +407 -0
- pyvale/core/errorsysindep.py +905 -0
- pyvale/core/experimentsimulator.py +99 -0
- pyvale/core/field.py +136 -0
- pyvale/core/fieldconverter.py +154 -0
- pyvale/core/fieldsampler.py +112 -0
- pyvale/core/fieldscalar.py +167 -0
- pyvale/core/fieldtensor.py +221 -0
- pyvale/core/fieldtransform.py +384 -0
- pyvale/core/fieldvector.py +215 -0
- pyvale/core/generatorsrandom.py +528 -0
- pyvale/core/imagedef2d.py +566 -0
- pyvale/core/integratorfactory.py +241 -0
- pyvale/core/integratorquadrature.py +192 -0
- pyvale/core/integratorrectangle.py +88 -0
- pyvale/core/integratorspatial.py +90 -0
- pyvale/core/integratortype.py +44 -0
- pyvale/core/optimcheckfuncs.py +153 -0
- pyvale/core/raster.py +31 -0
- pyvale/core/rastercy.py +76 -0
- pyvale/core/rasternp.py +604 -0
- pyvale/core/rendermesh.py +156 -0
- pyvale/core/sensorarray.py +179 -0
- pyvale/core/sensorarrayfactory.py +210 -0
- pyvale/core/sensorarraypoint.py +280 -0
- pyvale/core/sensordata.py +72 -0
- pyvale/core/sensordescriptor.py +101 -0
- pyvale/core/sensortools.py +143 -0
- pyvale/core/visualexpplotter.py +151 -0
- pyvale/core/visualimagedef.py +71 -0
- pyvale/core/visualimages.py +75 -0
- pyvale/core/visualopts.py +180 -0
- pyvale/core/visualsimanimator.py +83 -0
- pyvale/core/visualsimplotter.py +182 -0
- pyvale/core/visualtools.py +81 -0
- pyvale/core/visualtraceplotter.py +256 -0
- pyvale/data/__init__.py +7 -0
- pyvale/data/case13_out.e +0 -0
- pyvale/data/case16_out.e +0 -0
- pyvale/data/case17_out.e +0 -0
- pyvale/data/case18_1_out.e +0 -0
- pyvale/data/case18_2_out.e +0 -0
- pyvale/data/case18_3_out.e +0 -0
- pyvale/data/case25_out.e +0 -0
- pyvale/data/case26_out.e +0 -0
- pyvale/data/optspeckle_2464x2056px_spec5px_8bit_gblur1px.tiff +0 -0
- pyvale/examples/__init__.py +7 -0
- pyvale/examples/analyticdatagen/__init__.py +7 -0
- pyvale/examples/analyticdatagen/ex1_1_scalarvisualisation.py +38 -0
- pyvale/examples/analyticdatagen/ex1_2_scalarcasebuild.py +46 -0
- pyvale/examples/analyticdatagen/ex2_1_analyticsensors.py +83 -0
- pyvale/examples/ex1_1_thermal2d.py +89 -0
- pyvale/examples/ex1_2_thermal2d.py +111 -0
- pyvale/examples/ex1_3_thermal2d.py +113 -0
- pyvale/examples/ex1_4_thermal2d.py +89 -0
- pyvale/examples/ex1_5_thermal2d.py +105 -0
- pyvale/examples/ex2_1_thermal3d .py +87 -0
- pyvale/examples/ex2_2_thermal3d.py +51 -0
- pyvale/examples/ex2_3_thermal3d.py +109 -0
- pyvale/examples/ex3_1_displacement2d.py +47 -0
- pyvale/examples/ex3_2_displacement2d.py +79 -0
- pyvale/examples/ex3_3_displacement2d.py +104 -0
- pyvale/examples/ex3_4_displacement2d.py +105 -0
- pyvale/examples/ex4_1_strain2d.py +57 -0
- pyvale/examples/ex4_2_strain2d.py +79 -0
- pyvale/examples/ex4_3_strain2d.py +100 -0
- pyvale/examples/ex5_1_multiphysics2d.py +78 -0
- pyvale/examples/ex6_1_multiphysics2d_expsim.py +118 -0
- pyvale/examples/ex6_2_multiphysics3d_expsim.py +158 -0
- pyvale/examples/features/__init__.py +7 -0
- pyvale/examples/features/ex_animation_tools_3dmonoblock.py +83 -0
- pyvale/examples/features/ex_area_avg.py +89 -0
- pyvale/examples/features/ex_calibration_error.py +108 -0
- pyvale/examples/features/ex_chain_field_errs.py +141 -0
- pyvale/examples/features/ex_field_errs.py +78 -0
- pyvale/examples/features/ex_sensor_single_angle_batch.py +110 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +86 -0
- pyvale/examples/rasterisation/ex_rastenp.py +154 -0
- pyvale/examples/rasterisation/ex_rastercyth_oneframe.py +220 -0
- pyvale/examples/rasterisation/ex_rastercyth_static_cypara.py +194 -0
- pyvale/examples/rasterisation/ex_rastercyth_static_pypara.py +193 -0
- pyvale/simcases/case00_HEX20.i +242 -0
- pyvale/simcases/case00_HEX27.i +242 -0
- pyvale/simcases/case00_TET10.i +242 -0
- pyvale/simcases/case00_TET14.i +242 -0
- pyvale/simcases/case01.i +101 -0
- pyvale/simcases/case02.i +156 -0
- pyvale/simcases/case03.i +136 -0
- pyvale/simcases/case04.i +181 -0
- pyvale/simcases/case05.i +234 -0
- pyvale/simcases/case06.i +305 -0
- pyvale/simcases/case07.geo +135 -0
- pyvale/simcases/case07.i +87 -0
- pyvale/simcases/case08.geo +144 -0
- pyvale/simcases/case08.i +153 -0
- pyvale/simcases/case09.geo +204 -0
- pyvale/simcases/case09.i +87 -0
- pyvale/simcases/case10.geo +204 -0
- pyvale/simcases/case10.i +257 -0
- pyvale/simcases/case11.geo +337 -0
- pyvale/simcases/case11.i +147 -0
- pyvale/simcases/case12.geo +388 -0
- pyvale/simcases/case12.i +329 -0
- pyvale/simcases/case13.i +140 -0
- pyvale/simcases/case14.i +159 -0
- pyvale/simcases/case15.geo +337 -0
- pyvale/simcases/case15.i +150 -0
- pyvale/simcases/case16.geo +391 -0
- pyvale/simcases/case16.i +357 -0
- pyvale/simcases/case17.geo +135 -0
- pyvale/simcases/case17.i +144 -0
- pyvale/simcases/case18.i +254 -0
- pyvale/simcases/case18_1.i +254 -0
- pyvale/simcases/case18_2.i +254 -0
- pyvale/simcases/case18_3.i +254 -0
- pyvale/simcases/case19.geo +252 -0
- pyvale/simcases/case19.i +99 -0
- pyvale/simcases/case20.geo +252 -0
- pyvale/simcases/case20.i +250 -0
- pyvale/simcases/case21.geo +74 -0
- pyvale/simcases/case21.i +155 -0
- pyvale/simcases/case22.geo +82 -0
- pyvale/simcases/case22.i +140 -0
- pyvale/simcases/case23.geo +164 -0
- pyvale/simcases/case23.i +140 -0
- pyvale/simcases/case24.geo +79 -0
- pyvale/simcases/case24.i +123 -0
- pyvale/simcases/case25.geo +82 -0
- pyvale/simcases/case25.i +140 -0
- pyvale/simcases/case26.geo +166 -0
- pyvale/simcases/case26.i +140 -0
- pyvale/simcases/run_1case.py +61 -0
- pyvale/simcases/run_all_cases.py +69 -0
- pyvale/simcases/run_build_case.py +64 -0
- pyvale/simcases/run_example_cases.py +69 -0
- pyvale-2025.4.0.dist-info/METADATA +140 -0
- pyvale-2025.4.0.dist-info/RECORD +157 -0
- pyvale-2025.4.0.dist-info/WHEEL +5 -0
- pyvale-2025.4.0.dist-info/licenses/LICENSE +21 -0
- pyvale-2025.4.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""
|
|
2
|
+
================================================================================
|
|
3
|
+
pyvale: the python validation engine
|
|
4
|
+
License: MIT
|
|
5
|
+
Copyright (C) 2025 The Computer Aided Validation Team
|
|
6
|
+
================================================================================
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import time
|
|
10
|
+
import numpy as np
|
|
11
|
+
from scipy.spatial.transform import Rotation
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
import mooseherder as mh
|
|
14
|
+
import pyvale as pyv
|
|
15
|
+
import imagebenchmarks as ib
|
|
16
|
+
|
|
17
|
+
def main() -> None:
|
|
18
|
+
"""pyvale example: rasterisation field renderer
|
|
19
|
+
----------------------------------------------------------------------------
|
|
20
|
+
- TODO
|
|
21
|
+
"""
|
|
22
|
+
print()
|
|
23
|
+
print(80*"=")
|
|
24
|
+
print("RASTER CYTHON FILE (should be *.so on Linux):")
|
|
25
|
+
print(pyv.rastercyth.__file__)
|
|
26
|
+
print(80*"=")
|
|
27
|
+
print()
|
|
28
|
+
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
benchmark = True
|
|
32
|
+
if not benchmark:
|
|
33
|
+
|
|
34
|
+
# This a path to an exodus *.e output file from MOOSE, this can be
|
|
35
|
+
# replaced with a path to your own simulation file
|
|
36
|
+
#sim_path = Path.home()/"pyvale"/"src"/"pyvale"/"simcases"/"case26_out.e"
|
|
37
|
+
|
|
38
|
+
sim_path = pyv.DataSet.render_simple_block_path()
|
|
39
|
+
sim_path = pyv.DataSet.render_mechanical_3d_path()
|
|
40
|
+
sim_data = mh.ExodusReader(sim_path).read_all_sim_data()
|
|
41
|
+
|
|
42
|
+
disp_comps = ("disp_x","disp_y","disp_z")
|
|
43
|
+
|
|
44
|
+
# Scale m -> mm
|
|
45
|
+
sim_data = pyv.scale_length_units(sim_data,disp_comps,1000.0)
|
|
46
|
+
|
|
47
|
+
print()
|
|
48
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_x']))=}")
|
|
49
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_y']))=}")
|
|
50
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_z']))=}")
|
|
51
|
+
print()
|
|
52
|
+
|
|
53
|
+
# Extracts the surface mesh from a full 3d simulation for rendering
|
|
54
|
+
render_mesh = pyv.create_render_mesh(sim_data,
|
|
55
|
+
("disp_y","disp_x","disp_z"),
|
|
56
|
+
sim_spat_dim=3,
|
|
57
|
+
field_disp_keys=disp_comps)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
pixel_num = np.array((960,1280),dtype=np.int32)
|
|
64
|
+
pixel_size = np.array((5.3e-3,5.3e-3),dtype=np.float64)
|
|
65
|
+
focal_leng: float = 50.0
|
|
66
|
+
cam_rot = Rotation.from_euler("ZYX",(0.0,-30.0,-10.0),degrees=True)
|
|
67
|
+
fov_scale_factor: float = 1.1
|
|
68
|
+
|
|
69
|
+
(roi_pos_world,
|
|
70
|
+
cam_pos_world) = pyv.CameraTools.pos_fill_frame_from_rotation(
|
|
71
|
+
coords_world=render_mesh.coords,
|
|
72
|
+
pixel_num=pixel_num,
|
|
73
|
+
pixel_size=pixel_size,
|
|
74
|
+
focal_leng=focal_leng,
|
|
75
|
+
cam_rot=cam_rot,
|
|
76
|
+
frame_fill=fov_scale_factor,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
cam_data = pyv.CameraData(
|
|
80
|
+
pixels_num=pixel_num,
|
|
81
|
+
pixels_size=pixel_size,
|
|
82
|
+
pos_world=cam_pos_world,
|
|
83
|
+
rot_world=cam_rot,
|
|
84
|
+
roi_cent_world=roi_pos_world,
|
|
85
|
+
focal_length=focal_leng,
|
|
86
|
+
sub_samp=2,
|
|
87
|
+
back_face_removal=True,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
else:
|
|
91
|
+
case_ind = 0
|
|
92
|
+
(case_ident,render_mesh,cam_data) = ib.load_benchmark_by_index(case_ind)
|
|
93
|
+
print(80*"=")
|
|
94
|
+
print("BENCHMARK IDENTIFIER:")
|
|
95
|
+
print(f"{case_ident}")
|
|
96
|
+
print(80*"=")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
print()
|
|
100
|
+
print(80*"-")
|
|
101
|
+
print("MESH DATA:")
|
|
102
|
+
print(80*"-")
|
|
103
|
+
print("connectivity.shape=(num_elems,num_nodes_per_elem)")
|
|
104
|
+
print(f"{render_mesh.connectivity.shape=}")
|
|
105
|
+
print()
|
|
106
|
+
print("coords.shape=(num_nodes,coord[x,y,z])")
|
|
107
|
+
print(f"{render_mesh.coords.shape=}")
|
|
108
|
+
print()
|
|
109
|
+
print("fields.shape=(num_coords,num_time_steps,num_components)")
|
|
110
|
+
print(f"{render_mesh.fields_render.shape=}")
|
|
111
|
+
if render_mesh.fields_disp is not None:
|
|
112
|
+
print(f"{render_mesh.fields_disp.shape=}")
|
|
113
|
+
print(80*"-")
|
|
114
|
+
print()
|
|
115
|
+
|
|
116
|
+
print(80*"-")
|
|
117
|
+
print("CAMERA DATA:")
|
|
118
|
+
print(80*"-")
|
|
119
|
+
print(f"{cam_data.image_dist=}")
|
|
120
|
+
print(f"{cam_data.roi_cent_world=}")
|
|
121
|
+
print(f"{cam_data.pos_world=}")
|
|
122
|
+
print()
|
|
123
|
+
print("World to camera matrix:")
|
|
124
|
+
print(cam_data.world_to_cam_mat)
|
|
125
|
+
print(80*"-")
|
|
126
|
+
print()
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
print(80*"-")
|
|
130
|
+
total_frames = render_mesh.fields_render.shape[1]*render_mesh.fields_render.shape[2]
|
|
131
|
+
print(f"Time steps to render: {render_mesh.fields_render.shape[1]}")
|
|
132
|
+
print(f"Fields to render: {render_mesh.fields_render.shape[2]}")
|
|
133
|
+
print(f"Total frames to render: {total_frames}")
|
|
134
|
+
print(80*"-")
|
|
135
|
+
|
|
136
|
+
print(80*"=")
|
|
137
|
+
print("RASTER ELEMENT LOOP START")
|
|
138
|
+
print(80*"=")
|
|
139
|
+
|
|
140
|
+
num_loops = 1
|
|
141
|
+
|
|
142
|
+
loop_times = np.zeros((num_loops,),dtype=np.float64)
|
|
143
|
+
|
|
144
|
+
frame = -1
|
|
145
|
+
fields_render = render_mesh.fields_render[:,frame,:]
|
|
146
|
+
total_frames = fields_render.shape[1]
|
|
147
|
+
|
|
148
|
+
print()
|
|
149
|
+
print("Running raster loop.")
|
|
150
|
+
for nn in range(num_loops):
|
|
151
|
+
print(f"Running loop {nn}")
|
|
152
|
+
loop_start = time.perf_counter()
|
|
153
|
+
|
|
154
|
+
(image_buffer,
|
|
155
|
+
depth_buffer,
|
|
156
|
+
elems_in_image) = pyv.rastercyth.raster_frame(
|
|
157
|
+
render_mesh.coords,
|
|
158
|
+
render_mesh.connectivity,
|
|
159
|
+
fields_render,
|
|
160
|
+
cam_data)
|
|
161
|
+
|
|
162
|
+
loop_times[nn] = time.perf_counter() - loop_start
|
|
163
|
+
|
|
164
|
+
print()
|
|
165
|
+
print(80*"=")
|
|
166
|
+
print("PERFORMANCE TIMERS")
|
|
167
|
+
print(f"Elements in image = {elems_in_image}")
|
|
168
|
+
print(f"Image buffer shape = {image_buffer.shape}")
|
|
169
|
+
print(f"Avg. total render time = {np.mean(loop_times):.4f} seconds")
|
|
170
|
+
print(f"Avg. render time per frame = {(np.mean(loop_times)/total_frames):.4f} seconds")
|
|
171
|
+
print(80*"=")
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
#===========================================================================
|
|
175
|
+
# PLOTTING
|
|
176
|
+
plot_on = True
|
|
177
|
+
plot_field = 0
|
|
178
|
+
|
|
179
|
+
# depth_to_plot = np.copy(np.asarray(depth_buffer[:,:,plot_frame]))
|
|
180
|
+
# depth_to_plot[depth_buffer[:,:,plot_frame] > 10*cam_data.image_dist] = np.nan
|
|
181
|
+
# image_to_plot = np.copy(np.asarray(image_buffer[:,:,plot_frame,plot_field]))
|
|
182
|
+
# image_to_plot[depth_buffer[:,:,plot_frame] > 10*cam_data.image_dist] = np.nan
|
|
183
|
+
|
|
184
|
+
if plot_on:
|
|
185
|
+
plot_opts = pyv.PlotOptsGeneral()
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
(fig, ax) = plt.subplots(figsize=plot_opts.single_fig_size_square,
|
|
189
|
+
layout='constrained')
|
|
190
|
+
fig.set_dpi(plot_opts.resolution)
|
|
191
|
+
cset = plt.imshow(depth_buffer[:,:],
|
|
192
|
+
cmap=plt.get_cmap(plot_opts.cmap_seq))
|
|
193
|
+
#origin='lower')
|
|
194
|
+
ax.set_aspect('equal','box')
|
|
195
|
+
fig.colorbar(cset)
|
|
196
|
+
ax.set_title(f"Depth buffer",fontsize=plot_opts.font_head_size)
|
|
197
|
+
ax.set_xlabel(r"x ($px$)",
|
|
198
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
199
|
+
ax.set_ylabel(r"y ($px$)",
|
|
200
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
201
|
+
|
|
202
|
+
(fig, ax) = plt.subplots(figsize=plot_opts.single_fig_size_square,
|
|
203
|
+
layout='constrained')
|
|
204
|
+
fig.set_dpi(plot_opts.resolution)
|
|
205
|
+
cset = plt.imshow(image_buffer[:,:,plot_field],
|
|
206
|
+
cmap=plt.get_cmap(plot_opts.cmap_seq))
|
|
207
|
+
#origin='lower')
|
|
208
|
+
ax.set_aspect('equal','box')
|
|
209
|
+
fig.colorbar(cset)
|
|
210
|
+
ax.set_title(f"Field Image",fontsize=plot_opts.font_head_size)
|
|
211
|
+
ax.set_xlabel(r"x ($px$)",
|
|
212
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
213
|
+
ax.set_ylabel(r"y ($px$)",
|
|
214
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
215
|
+
|
|
216
|
+
plt.show()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
if __name__ == "__main__":
|
|
220
|
+
main()
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""
|
|
2
|
+
================================================================================
|
|
3
|
+
pyvale: the python validation engine
|
|
4
|
+
License: MIT
|
|
5
|
+
Copyright (C) 2025 The Computer Aided Validation Team
|
|
6
|
+
================================================================================
|
|
7
|
+
"""
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import time
|
|
10
|
+
import numpy as np
|
|
11
|
+
from scipy.spatial.transform import Rotation
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
import mooseherder as mh
|
|
14
|
+
import pyvale as pyv
|
|
15
|
+
|
|
16
|
+
def main() -> None:
|
|
17
|
+
"""pyvale example: rasterisation field renderer
|
|
18
|
+
----------------------------------------------------------------------------
|
|
19
|
+
- TODO
|
|
20
|
+
"""
|
|
21
|
+
print()
|
|
22
|
+
print(80*"=")
|
|
23
|
+
print("RASTER CYTHON FILE (should be *.so on Linux):")
|
|
24
|
+
print(pyv.rastercyth.__file__)
|
|
25
|
+
print(80*"=")
|
|
26
|
+
print()
|
|
27
|
+
|
|
28
|
+
# This a path to an exodus *.e output file from MOOSE, this can be
|
|
29
|
+
# replaced with a path to your own simulation file
|
|
30
|
+
sim_path = pyv.DataSet.render_mechanical_3d_path()
|
|
31
|
+
#sim_path = pyv.DataSet.render_simple_block_path()
|
|
32
|
+
#sim_path = Path.home()/"pyvale"/"src"/"pyvale"/"simcases"/"case26_out.e"
|
|
33
|
+
sim_data = mh.ExodusReader(sim_path).read_all_sim_data()
|
|
34
|
+
|
|
35
|
+
disp_comps = ("disp_x","disp_y","disp_z")
|
|
36
|
+
|
|
37
|
+
# Scale m -> mm
|
|
38
|
+
sim_data = pyv.scale_length_units(sim_data,disp_comps,1000.0)
|
|
39
|
+
|
|
40
|
+
print()
|
|
41
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_x']))=}")
|
|
42
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_y']))=}")
|
|
43
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_z']))=}")
|
|
44
|
+
print()
|
|
45
|
+
|
|
46
|
+
# Extracts the surface mesh from a full 3d simulation for rendering
|
|
47
|
+
render_mesh = pyv.create_render_mesh(sim_data,
|
|
48
|
+
("disp_y","disp_x"),
|
|
49
|
+
sim_spat_dim=3,
|
|
50
|
+
field_disp_keys=disp_comps)
|
|
51
|
+
|
|
52
|
+
print()
|
|
53
|
+
print(80*"-")
|
|
54
|
+
print("MESH DATA:")
|
|
55
|
+
print(80*"-")
|
|
56
|
+
print("connectivity.shape=(num_elems,num_nodes_per_elem)")
|
|
57
|
+
print(f"{render_mesh.connectivity.shape=}")
|
|
58
|
+
print()
|
|
59
|
+
print("coords.shape=(num_nodes,coord[x,y,z])")
|
|
60
|
+
print(f"{render_mesh.coords.shape=}")
|
|
61
|
+
print()
|
|
62
|
+
print("fields.shape=(num_coords,num_time_steps,num_components)")
|
|
63
|
+
print(f"{render_mesh.fields_render.shape=}")
|
|
64
|
+
if render_mesh.fields_disp is not None:
|
|
65
|
+
print(f"{render_mesh.fields_disp.shape=}")
|
|
66
|
+
print(80*"-")
|
|
67
|
+
print()
|
|
68
|
+
|
|
69
|
+
pixel_num = np.array((960,1280),dtype=np.int32)
|
|
70
|
+
pixel_size = np.array((5.3e-3,5.3e-3),dtype=np.float64)
|
|
71
|
+
focal_leng: float = 50.0
|
|
72
|
+
cam_rot = Rotation.from_euler("zyx",(0.0,-30.0,-10.0),degrees=True)
|
|
73
|
+
fov_scale_factor: float = 1.1
|
|
74
|
+
|
|
75
|
+
(roi_pos_world,
|
|
76
|
+
cam_pos_world) = pyv.CameraTools.pos_fill_frame_from_rotation(
|
|
77
|
+
coords_world=render_mesh.coords,
|
|
78
|
+
pixel_num=pixel_num,
|
|
79
|
+
pixel_size=pixel_size,
|
|
80
|
+
focal_leng=focal_leng,
|
|
81
|
+
cam_rot=cam_rot,
|
|
82
|
+
frame_fill=fov_scale_factor,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
cam_data = pyv.CameraData(
|
|
86
|
+
pixels_num=pixel_num,
|
|
87
|
+
pixels_size=pixel_size,
|
|
88
|
+
pos_world=cam_pos_world,
|
|
89
|
+
rot_world=cam_rot,
|
|
90
|
+
roi_cent_world=roi_pos_world,
|
|
91
|
+
focal_length=focal_leng,
|
|
92
|
+
sub_samp=2,
|
|
93
|
+
back_face_removal=True,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
print(80*"-")
|
|
97
|
+
print("CAMERA DATA:")
|
|
98
|
+
print(80*"-")
|
|
99
|
+
print(f"{cam_data.image_dist=}")
|
|
100
|
+
print(f"{cam_data.roi_cent_world=}")
|
|
101
|
+
print(f"{cam_data.pos_world=}")
|
|
102
|
+
print()
|
|
103
|
+
print("World to camera matrix:")
|
|
104
|
+
print(cam_data.world_to_cam_mat)
|
|
105
|
+
print(80*"-")
|
|
106
|
+
print()
|
|
107
|
+
|
|
108
|
+
print(80*"-")
|
|
109
|
+
total_frames = render_mesh.fields_render.shape[1]*render_mesh.fields_render.shape[2]
|
|
110
|
+
print(f"Time steps to render: {render_mesh.fields_render.shape[1]}")
|
|
111
|
+
print(f"Fields to render: {render_mesh.fields_render.shape[2]}")
|
|
112
|
+
print(f"Total frames to render: {total_frames}")
|
|
113
|
+
print(80*"-")
|
|
114
|
+
|
|
115
|
+
print(80*"=")
|
|
116
|
+
print("RASTER ELEMENT LOOP START")
|
|
117
|
+
print(80*"=")
|
|
118
|
+
|
|
119
|
+
num_loops = 1
|
|
120
|
+
loop_times = np.zeros((num_loops,),dtype=np.float64)
|
|
121
|
+
|
|
122
|
+
print()
|
|
123
|
+
print("Running raster loop.")
|
|
124
|
+
for nn in range(num_loops):
|
|
125
|
+
print(f"Running loop {nn}")
|
|
126
|
+
loop_start = time.perf_counter()
|
|
127
|
+
|
|
128
|
+
(image_buffer,
|
|
129
|
+
depth_buffer,
|
|
130
|
+
elems_in_image) = pyv.rastercyth.raster_static_mesh(
|
|
131
|
+
render_mesh,
|
|
132
|
+
cam_data,
|
|
133
|
+
0)
|
|
134
|
+
|
|
135
|
+
loop_times[nn] = time.perf_counter() - loop_start
|
|
136
|
+
|
|
137
|
+
print()
|
|
138
|
+
print(80*"=")
|
|
139
|
+
print("PERFORMANCE TIMERS")
|
|
140
|
+
print(f"Elements in image = {elems_in_image}")
|
|
141
|
+
print(f"Image buffer shape = {image_buffer.shape}")
|
|
142
|
+
print(f"Avg. total render time = {np.mean(loop_times):.4f} seconds")
|
|
143
|
+
print(f"Avg. render time per frame = {(np.mean(loop_times)/total_frames):.4f} seconds")
|
|
144
|
+
print(80*"=")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
#===========================================================================
|
|
148
|
+
# PLOTTING
|
|
149
|
+
plot_on = True
|
|
150
|
+
plot_frames = (1,)#range(3)
|
|
151
|
+
plot_field = 0
|
|
152
|
+
|
|
153
|
+
# depth_to_plot = np.copy(np.asarray(depth_buffer[:,:,plot_frame]))
|
|
154
|
+
# depth_to_plot[depth_buffer[:,:,plot_frame] > 10*cam_data.image_dist] = np.nan
|
|
155
|
+
# image_to_plot = np.copy(np.asarray(image_buffer[:,:,plot_frame,plot_field]))
|
|
156
|
+
# image_to_plot[depth_buffer[:,:,plot_frame] > 10*cam_data.image_dist] = np.nan
|
|
157
|
+
|
|
158
|
+
if plot_on:
|
|
159
|
+
plot_opts = pyv.PlotOptsGeneral()
|
|
160
|
+
|
|
161
|
+
for ff in plot_frames:
|
|
162
|
+
(fig, ax) = plt.subplots(figsize=plot_opts.single_fig_size_square,
|
|
163
|
+
layout='constrained')
|
|
164
|
+
fig.set_dpi(plot_opts.resolution)
|
|
165
|
+
cset = plt.imshow(depth_buffer[:,:,ff],
|
|
166
|
+
cmap=plt.get_cmap(plot_opts.cmap_seq))
|
|
167
|
+
#origin='lower')
|
|
168
|
+
ax.set_aspect('equal','box')
|
|
169
|
+
fig.colorbar(cset)
|
|
170
|
+
ax.set_title(f"Depth buffer: {ff}",fontsize=plot_opts.font_head_size)
|
|
171
|
+
ax.set_xlabel(r"x ($px$)",
|
|
172
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
173
|
+
ax.set_ylabel(r"y ($px$)",
|
|
174
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
175
|
+
|
|
176
|
+
(fig, ax) = plt.subplots(figsize=plot_opts.single_fig_size_square,
|
|
177
|
+
layout='constrained')
|
|
178
|
+
fig.set_dpi(plot_opts.resolution)
|
|
179
|
+
cset = plt.imshow(image_buffer[:,:,ff,plot_field],
|
|
180
|
+
cmap=plt.get_cmap(plot_opts.cmap_seq))
|
|
181
|
+
#origin='lower')
|
|
182
|
+
ax.set_aspect('equal','box')
|
|
183
|
+
fig.colorbar(cset)
|
|
184
|
+
ax.set_title(f"Field Image: {ff}",fontsize=plot_opts.font_head_size)
|
|
185
|
+
ax.set_xlabel(r"x ($px$)",
|
|
186
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
187
|
+
ax.set_ylabel(r"y ($px$)",
|
|
188
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
189
|
+
|
|
190
|
+
plt.show()
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
if __name__ == "__main__":
|
|
194
|
+
main()
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""
|
|
2
|
+
================================================================================
|
|
3
|
+
pyvale: the python validation engine
|
|
4
|
+
License: MIT
|
|
5
|
+
Copyright (C) 2025 The Computer Aided Validation Team
|
|
6
|
+
================================================================================
|
|
7
|
+
"""
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import time
|
|
10
|
+
import numpy as np
|
|
11
|
+
from scipy.spatial.transform import Rotation
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
import mooseherder as mh
|
|
14
|
+
import pyvale as pyv
|
|
15
|
+
|
|
16
|
+
def main() -> None:
|
|
17
|
+
"""pyvale example: rasterisation field renderer
|
|
18
|
+
----------------------------------------------------------------------------
|
|
19
|
+
- TODO
|
|
20
|
+
"""
|
|
21
|
+
print()
|
|
22
|
+
print(80*"=")
|
|
23
|
+
print("RASTER CYTHON FILE (should be *.so on Linux):")
|
|
24
|
+
print(pyv.rastercyth.__file__)
|
|
25
|
+
print(80*"=")
|
|
26
|
+
print()
|
|
27
|
+
|
|
28
|
+
# This a path to an exodus *.e output file from MOOSE, this can be
|
|
29
|
+
# replaced with a path to your own simulation file
|
|
30
|
+
sim_path = pyv.DataSet.render_mechanical_3d_path()
|
|
31
|
+
#sim_path = pyv.DataSet.render_simple_block_path()
|
|
32
|
+
#sim_path = Path.home()/"pyvale"/"src"/"pyvale"/"simcases"/"case26_out.e"
|
|
33
|
+
sim_data = mh.ExodusReader(sim_path).read_all_sim_data()
|
|
34
|
+
|
|
35
|
+
disp_comps = ("disp_x","disp_y","disp_z")
|
|
36
|
+
|
|
37
|
+
# Scale m -> mm
|
|
38
|
+
sim_data = pyv.scale_length_units(sim_data,disp_comps,1000.0)
|
|
39
|
+
|
|
40
|
+
print()
|
|
41
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_x']))=}")
|
|
42
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_y']))=}")
|
|
43
|
+
print(f"{np.max(np.abs(sim_data.node_vars['disp_z']))=}")
|
|
44
|
+
print()
|
|
45
|
+
|
|
46
|
+
# Extracts the surface mesh from a full 3d simulation for rendering
|
|
47
|
+
render_mesh = pyv.create_render_mesh(sim_data,
|
|
48
|
+
("disp_y","disp_x"),
|
|
49
|
+
sim_spat_dim=3,
|
|
50
|
+
field_disp_keys=disp_comps)
|
|
51
|
+
|
|
52
|
+
print()
|
|
53
|
+
print(80*"-")
|
|
54
|
+
print("MESH DATA:")
|
|
55
|
+
print(80*"-")
|
|
56
|
+
print("connectivity.shape=(num_elems,num_nodes_per_elem)")
|
|
57
|
+
print(f"{render_mesh.connectivity.shape=}")
|
|
58
|
+
print()
|
|
59
|
+
print("coords.shape=(num_nodes,coord[x,y,z])")
|
|
60
|
+
print(f"{render_mesh.coords.shape=}")
|
|
61
|
+
print()
|
|
62
|
+
print("fields.shape=(num_coords,num_time_steps,num_components)")
|
|
63
|
+
print(f"{render_mesh.fields_render.shape=}")
|
|
64
|
+
if render_mesh.fields_disp is not None:
|
|
65
|
+
print(f"{render_mesh.fields_disp.shape=}")
|
|
66
|
+
print(80*"-")
|
|
67
|
+
print()
|
|
68
|
+
|
|
69
|
+
pixel_num = np.array((960,1280),dtype=np.int32)
|
|
70
|
+
pixel_size = np.array((5.3e-3,5.3e-3),dtype=np.float64)
|
|
71
|
+
focal_leng: float = 50.0
|
|
72
|
+
cam_rot = Rotation.from_euler("zyx",(0.0,-30.0,-10.0),degrees=True)
|
|
73
|
+
fov_scale_factor: float = 1.1
|
|
74
|
+
|
|
75
|
+
(roi_pos_world,
|
|
76
|
+
cam_pos_world) = pyv.CameraTools.pos_fill_frame_from_rotation(
|
|
77
|
+
coords_world=render_mesh.coords,
|
|
78
|
+
pixel_num=pixel_num,
|
|
79
|
+
pixel_size=pixel_size,
|
|
80
|
+
focal_leng=focal_leng,
|
|
81
|
+
cam_rot=cam_rot,
|
|
82
|
+
frame_fill=fov_scale_factor,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
cam_data = pyv.CameraData(
|
|
86
|
+
pixels_num=pixel_num,
|
|
87
|
+
pixels_size=pixel_size,
|
|
88
|
+
pos_world=cam_pos_world,
|
|
89
|
+
rot_world=cam_rot,
|
|
90
|
+
roi_cent_world=roi_pos_world,
|
|
91
|
+
focal_length=focal_leng,
|
|
92
|
+
sub_samp=2,
|
|
93
|
+
back_face_removal=True,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
print(80*"-")
|
|
97
|
+
print("CAMERA DATA:")
|
|
98
|
+
print(80*"-")
|
|
99
|
+
print(f"{cam_data.image_dist=}")
|
|
100
|
+
print(f"{cam_data.roi_cent_world=}")
|
|
101
|
+
print(f"{cam_data.pos_world=}")
|
|
102
|
+
print()
|
|
103
|
+
print("World to camera matrix:")
|
|
104
|
+
print(cam_data.world_to_cam_mat)
|
|
105
|
+
print(80*"-")
|
|
106
|
+
print()
|
|
107
|
+
|
|
108
|
+
print(80*"-")
|
|
109
|
+
total_frames = render_mesh.fields_render.shape[1]*render_mesh.fields_render.shape[2]
|
|
110
|
+
print(f"Time steps to render: {render_mesh.fields_render.shape[1]}")
|
|
111
|
+
print(f"Fields to render: {render_mesh.fields_render.shape[2]}")
|
|
112
|
+
print(f"Total frames to render: {total_frames}")
|
|
113
|
+
print(80*"-")
|
|
114
|
+
|
|
115
|
+
print(80*"=")
|
|
116
|
+
print("RASTER ELEMENT LOOP START")
|
|
117
|
+
print(80*"=")
|
|
118
|
+
|
|
119
|
+
num_loops = 1
|
|
120
|
+
loop_times = np.zeros((num_loops,),dtype=np.float64)
|
|
121
|
+
|
|
122
|
+
print()
|
|
123
|
+
print("Running raster loop.")
|
|
124
|
+
for nn in range(num_loops):
|
|
125
|
+
print(f"Running loop {nn}")
|
|
126
|
+
loop_start = time.perf_counter()
|
|
127
|
+
|
|
128
|
+
(image_buffer,
|
|
129
|
+
depth_buffer,
|
|
130
|
+
elems_in_images) = pyv.RasterCY.raster_static_mesh(cam_data,
|
|
131
|
+
render_mesh,
|
|
132
|
+
16)
|
|
133
|
+
|
|
134
|
+
loop_times[nn] = time.perf_counter() - loop_start
|
|
135
|
+
|
|
136
|
+
print()
|
|
137
|
+
print(80*"=")
|
|
138
|
+
print("PERFORMANCE TIMERS")
|
|
139
|
+
print(f"Elements in image = {elems_in_images}")
|
|
140
|
+
print(f"Image buffer shape = {image_buffer.shape}")
|
|
141
|
+
print(f"Avg. total render time = {np.mean(loop_times):.4f} seconds")
|
|
142
|
+
print(f"Avg. render time per frame = {(np.mean(loop_times)/total_frames):.4f} seconds")
|
|
143
|
+
print(80*"=")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
#===========================================================================
|
|
147
|
+
# PLOTTING
|
|
148
|
+
plot_on = False
|
|
149
|
+
plot_frames = (-1,)#range(3)
|
|
150
|
+
plot_field = 0
|
|
151
|
+
|
|
152
|
+
# depth_to_plot = np.copy(np.asarray(depth_buffer[:,:,plot_frame]))
|
|
153
|
+
# depth_to_plot[depth_buffer[:,:,plot_frame] > 10*cam_data.image_dist] = np.nan
|
|
154
|
+
# image_to_plot = np.copy(np.asarray(image_buffer[:,:,plot_frame,plot_field]))
|
|
155
|
+
# image_to_plot[depth_buffer[:,:,plot_frame] > 10*cam_data.image_dist] = np.nan
|
|
156
|
+
|
|
157
|
+
if plot_on:
|
|
158
|
+
plot_opts = pyv.PlotOptsGeneral()
|
|
159
|
+
|
|
160
|
+
for ff in plot_frames:
|
|
161
|
+
(fig, ax) = plt.subplots(figsize=plot_opts.single_fig_size_square,
|
|
162
|
+
layout='constrained')
|
|
163
|
+
fig.set_dpi(plot_opts.resolution)
|
|
164
|
+
cset = plt.imshow(depth_buffer[:,:,ff],
|
|
165
|
+
cmap=plt.get_cmap(plot_opts.cmap_seq))
|
|
166
|
+
#origin='lower')
|
|
167
|
+
ax.set_aspect('equal','box')
|
|
168
|
+
fig.colorbar(cset)
|
|
169
|
+
ax.set_title(f"Depth buffer: {ff}",fontsize=plot_opts.font_head_size)
|
|
170
|
+
ax.set_xlabel(r"x ($px$)",
|
|
171
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
172
|
+
ax.set_ylabel(r"y ($px$)",
|
|
173
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
174
|
+
|
|
175
|
+
(fig, ax) = plt.subplots(figsize=plot_opts.single_fig_size_square,
|
|
176
|
+
layout='constrained')
|
|
177
|
+
fig.set_dpi(plot_opts.resolution)
|
|
178
|
+
cset = plt.imshow(image_buffer[:,:,ff,plot_field],
|
|
179
|
+
cmap=plt.get_cmap(plot_opts.cmap_seq))
|
|
180
|
+
#origin='lower')
|
|
181
|
+
ax.set_aspect('equal','box')
|
|
182
|
+
fig.colorbar(cset)
|
|
183
|
+
ax.set_title(f"Field Image: {ff}",fontsize=plot_opts.font_head_size)
|
|
184
|
+
ax.set_xlabel(r"x ($px$)",
|
|
185
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
186
|
+
ax.set_ylabel(r"y ($px$)",
|
|
187
|
+
fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
|
|
188
|
+
|
|
189
|
+
plt.show()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if __name__ == "__main__":
|
|
193
|
+
main()
|