pyvale 2025.5.3__cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.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 +89 -0
- pyvale/analyticmeshgen.py +102 -0
- pyvale/analyticsimdatafactory.py +91 -0
- 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/camera.py +146 -0
- pyvale/cameradata.py +69 -0
- pyvale/cameradata2d.py +84 -0
- pyvale/camerastereo.py +217 -0
- pyvale/cameratools.py +522 -0
- pyvale/cython/rastercyth.c +32211 -0
- pyvale/cython/rastercyth.cpython-311-x86_64-linux-gnu.so +0 -0
- pyvale/cython/rastercyth.py +640 -0
- pyvale/data/__init__.py +5 -0
- 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/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/dataset.py +325 -0
- pyvale/errorcalculator.py +109 -0
- pyvale/errordriftcalc.py +146 -0
- pyvale/errorintegrator.py +336 -0
- pyvale/errorrand.py +607 -0
- pyvale/errorsyscalib.py +134 -0
- pyvale/errorsysdep.py +327 -0
- pyvale/errorsysfield.py +414 -0
- pyvale/errorsysindep.py +808 -0
- pyvale/examples/__init__.py +5 -0
- 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/genanalyticdata/ex1_1_scalarvisualisation.py +35 -0
- pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +43 -0
- pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +80 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +79 -0
- 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/renderrasterisation/ex_rastenp.py +153 -0
- pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +218 -0
- pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +187 -0
- pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +190 -0
- pyvale/examples/visualisation/ex1_1_plot_traces.py +102 -0
- pyvale/examples/visualisation/ex2_1_animate_sim.py +89 -0
- pyvale/experimentsimulator.py +175 -0
- pyvale/field.py +128 -0
- pyvale/fieldconverter.py +351 -0
- pyvale/fieldsampler.py +111 -0
- pyvale/fieldscalar.py +166 -0
- pyvale/fieldtensor.py +218 -0
- pyvale/fieldtransform.py +388 -0
- pyvale/fieldvector.py +213 -0
- pyvale/generatorsrandom.py +505 -0
- pyvale/imagedef2d.py +569 -0
- pyvale/integratorfactory.py +240 -0
- pyvale/integratorquadrature.py +217 -0
- pyvale/integratorrectangle.py +165 -0
- pyvale/integratorspatial.py +89 -0
- pyvale/integratortype.py +43 -0
- pyvale/output.py +17 -0
- pyvale/pyvaleexceptions.py +11 -0
- pyvale/raster.py +31 -0
- pyvale/rastercy.py +77 -0
- pyvale/rasternp.py +603 -0
- pyvale/rendermesh.py +147 -0
- pyvale/sensorarray.py +178 -0
- pyvale/sensorarrayfactory.py +196 -0
- pyvale/sensorarraypoint.py +278 -0
- pyvale/sensordata.py +71 -0
- pyvale/sensordescriptor.py +213 -0
- pyvale/sensortools.py +142 -0
- pyvale/simcases/case00_HEX20.i +242 -0
- pyvale/simcases/case00_HEX27.i +242 -0
- pyvale/simcases/case00_HEX8.i +242 -0
- pyvale/simcases/case00_TET10.i +242 -0
- pyvale/simcases/case00_TET14.i +242 -0
- pyvale/simcases/case00_TET4.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/simtools.py +67 -0
- pyvale/visualexpplotter.py +191 -0
- pyvale/visualimagedef.py +74 -0
- pyvale/visualimages.py +76 -0
- pyvale/visualopts.py +493 -0
- pyvale/visualsimanimator.py +111 -0
- pyvale/visualsimsensors.py +318 -0
- pyvale/visualtools.py +136 -0
- pyvale/visualtraceplotter.py +142 -0
- pyvale-2025.5.3.dist-info/METADATA +144 -0
- pyvale-2025.5.3.dist-info/RECORD +175 -0
- pyvale-2025.5.3.dist-info/WHEEL +6 -0
- pyvale-2025.5.3.dist-info/licenses/LICENSE +21 -0
- pyvale-2025.5.3.dist-info/top_level.txt +1 -0
- pyvale.libs/libgomp-a34b3233.so.1.0.0 +0 -0
|
Binary file
|
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
NOTE: this module is a feature under developement.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
import cython
|
|
13
|
+
from cython.parallel import prange, parallel, threadid
|
|
14
|
+
from cython.cimports.libc.math import floor, ceil
|
|
15
|
+
|
|
16
|
+
from pyvale.rendermesh import RenderMeshData
|
|
17
|
+
from pyvale.cameradata import CameraData
|
|
18
|
+
|
|
19
|
+
# NOTE: This module is a feature under developement.
|
|
20
|
+
|
|
21
|
+
@cython.nogil
|
|
22
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
23
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
24
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
25
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
26
|
+
@cython.inline
|
|
27
|
+
@cython.exceptval(check=False)
|
|
28
|
+
def range_len_double(start: cython.double,
|
|
29
|
+
stop: cython.double,
|
|
30
|
+
step: cython.double) -> cython.size_t:
|
|
31
|
+
return int(ceil((stop - start) / step))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@cython.nogil
|
|
35
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
36
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
37
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
38
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
39
|
+
@cython.inline
|
|
40
|
+
@cython.exceptval(check=False)
|
|
41
|
+
def vec_range_int(start: cython.int,
|
|
42
|
+
stop: cython.int,
|
|
43
|
+
step: cython.int,
|
|
44
|
+
vec_buffer: cython.long[:]) -> cython.long[:]:
|
|
45
|
+
|
|
46
|
+
num_vals: cython.size_t = int(ceil((stop - start) / step))
|
|
47
|
+
|
|
48
|
+
vec_buffer[0] = start
|
|
49
|
+
ii: cython.size_t
|
|
50
|
+
for ii in range(1,num_vals):
|
|
51
|
+
vec_buffer[ii] = vec_buffer[ii-1] + step
|
|
52
|
+
|
|
53
|
+
return vec_buffer[0:num_vals]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@cython.nogil
|
|
57
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
58
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
59
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
60
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
61
|
+
@cython.inline
|
|
62
|
+
@cython.exceptval(check=False)
|
|
63
|
+
def vec_max_double(vals: cython.double[:]) -> cython.double:
|
|
64
|
+
|
|
65
|
+
num_vals: cython.size_t = vals.shape[0]
|
|
66
|
+
|
|
67
|
+
ii: cython.size_t = 0
|
|
68
|
+
max_val: cython.double = vals[ii]
|
|
69
|
+
|
|
70
|
+
for ii in range(1,num_vals):
|
|
71
|
+
if vals[ii] > max_val:
|
|
72
|
+
max_val = vals[ii]
|
|
73
|
+
|
|
74
|
+
return max_val
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@cython.nogil
|
|
78
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
79
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
80
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
81
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
82
|
+
@cython.inline
|
|
83
|
+
@cython.exceptval(check=False)
|
|
84
|
+
def vec_min_double(vals: cython.double[:]) -> cython.double:
|
|
85
|
+
|
|
86
|
+
num_vals: cython.size_t = vals.shape[0]
|
|
87
|
+
|
|
88
|
+
ii: cython.size_t = 0
|
|
89
|
+
min_val: cython.double = vals[ii]
|
|
90
|
+
|
|
91
|
+
for ii in range(1,num_vals):
|
|
92
|
+
if vals[ii] < min_val:
|
|
93
|
+
min_val = vals[ii]
|
|
94
|
+
|
|
95
|
+
return min_val
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@cython.nogil
|
|
99
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
100
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
101
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
102
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
103
|
+
@cython.inline
|
|
104
|
+
@cython.exceptval(check=False)
|
|
105
|
+
def vec_dot_double(vec0: cython.double[:], vec1: cython.double[:]
|
|
106
|
+
) -> cython.double:
|
|
107
|
+
vec0_len: cython.size_t = vec0.shape[0]
|
|
108
|
+
vec1_len: cython.size_t = vec1.shape[0]
|
|
109
|
+
if vec0_len != vec1_len:
|
|
110
|
+
return 0.0
|
|
111
|
+
|
|
112
|
+
ii: cython.size_t = 0
|
|
113
|
+
dot: cython.double = 0.0
|
|
114
|
+
for ii in range(vec0_len):
|
|
115
|
+
dot += vec0[ii]*vec1[ii]
|
|
116
|
+
|
|
117
|
+
return dot
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@cython.nogil
|
|
121
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
122
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
123
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
124
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
125
|
+
@cython.inline
|
|
126
|
+
@cython.exceptval(check=False)
|
|
127
|
+
def bound_index_min(min_val: cython.double) -> cython.int:
|
|
128
|
+
min_ind: cython.int = int(floor(min_val))
|
|
129
|
+
if min_ind < 0:
|
|
130
|
+
min_ind = 0
|
|
131
|
+
return min_ind
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@cython.nogil
|
|
135
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
136
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
137
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
138
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
139
|
+
@cython.inline
|
|
140
|
+
@cython.exceptval(check=False)
|
|
141
|
+
def bound_index_max(max_val: cython.double,
|
|
142
|
+
num_pixels: cython.int) -> cython.int:
|
|
143
|
+
max_ind: cython.int = int(ceil(max_val))
|
|
144
|
+
if max_ind > (num_pixels-1):
|
|
145
|
+
max_ind = (num_pixels-1)
|
|
146
|
+
return max_ind
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@cython.nogil
|
|
150
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
151
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
152
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
153
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
154
|
+
@cython.inline
|
|
155
|
+
@cython.exceptval(check=False)
|
|
156
|
+
def mult_mat44_by_vec3(mat44: cython.double[:,:], vec3_in: cython.double[:],
|
|
157
|
+
vec3_out: cython.double[:]) -> cython.double[:]:
|
|
158
|
+
|
|
159
|
+
vec3_out[0] = (mat44[0,0]*vec3_in[0]
|
|
160
|
+
+ mat44[0,1]*vec3_in[1]
|
|
161
|
+
+ mat44[0,2]*vec3_in[2]
|
|
162
|
+
+ mat44[0,3])
|
|
163
|
+
vec3_out[1] = (mat44[1,0]*vec3_in[0]
|
|
164
|
+
+ mat44[1,1]*vec3_in[1]
|
|
165
|
+
+ mat44[1,2]*vec3_in[2]
|
|
166
|
+
+ mat44[1,3])
|
|
167
|
+
vec3_out[2] = (mat44[2,0]*vec3_in[0]
|
|
168
|
+
+ mat44[2,1]*vec3_in[1]
|
|
169
|
+
+ mat44[2,2]*vec3_in[2]
|
|
170
|
+
+ mat44[2,3])
|
|
171
|
+
vec3_out[3] = (mat44[3,0]*vec3_in[0]
|
|
172
|
+
+ mat44[3,1]*vec3_in[1]
|
|
173
|
+
+ mat44[3,2]*vec3_in[2]
|
|
174
|
+
+ mat44[3,3])
|
|
175
|
+
|
|
176
|
+
return vec3_out
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@cython.nogil
|
|
180
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
181
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
182
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
183
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
184
|
+
@cython.exceptval(check=False)
|
|
185
|
+
def world_to_raster_coords(coords_world: cython.double[:],
|
|
186
|
+
world_to_cam_mat: cython.double[:,:],
|
|
187
|
+
image_dist: cython.double,
|
|
188
|
+
image_dims: cython.double[:],
|
|
189
|
+
num_pixels: cython.int[:],
|
|
190
|
+
coords_raster: cython.double[:]
|
|
191
|
+
) -> cython.double[:]:
|
|
192
|
+
xx: cython.size_t = 0
|
|
193
|
+
yy: cython.size_t = 1
|
|
194
|
+
zz: cython.size_t = 2
|
|
195
|
+
ww: cython.size_t = 3
|
|
196
|
+
|
|
197
|
+
coords_raster = mult_mat44_by_vec3(world_to_cam_mat,
|
|
198
|
+
coords_world,
|
|
199
|
+
coords_raster)
|
|
200
|
+
|
|
201
|
+
coords_raster[xx] = coords_raster[xx] / coords_raster[ww]
|
|
202
|
+
coords_raster[yy] = coords_raster[yy] / coords_raster[ww]
|
|
203
|
+
coords_raster[zz] = coords_raster[zz] / coords_raster[ww]
|
|
204
|
+
|
|
205
|
+
coords_raster[xx] = (image_dist * coords_raster[xx]
|
|
206
|
+
/ -coords_raster[zz])
|
|
207
|
+
coords_raster[yy] = (image_dist * coords_raster[yy]
|
|
208
|
+
/ -coords_raster[zz])
|
|
209
|
+
|
|
210
|
+
coords_raster[xx] = 2*coords_raster[xx] / image_dims[xx]
|
|
211
|
+
coords_raster[yy] = 2*coords_raster[yy] / image_dims[yy]
|
|
212
|
+
|
|
213
|
+
coords_raster[xx] = (coords_raster[xx] + 1)/2 * num_pixels[xx]
|
|
214
|
+
coords_raster[yy] = (1-coords_raster[yy])/2 * num_pixels[yy]
|
|
215
|
+
coords_raster[zz] = -coords_raster[zz]
|
|
216
|
+
|
|
217
|
+
return coords_raster
|
|
218
|
+
|
|
219
|
+
@cython.cfunc
|
|
220
|
+
@cython.nogil
|
|
221
|
+
@cython.boundscheck(False)
|
|
222
|
+
@cython.wraparound(False)
|
|
223
|
+
@cython.inline
|
|
224
|
+
@cython.exceptval(check=False)
|
|
225
|
+
def edge_function(vert_0: cython.double[:],
|
|
226
|
+
vert_1: cython.double[:],
|
|
227
|
+
vert_2: cython.double[:]) -> cython.double:
|
|
228
|
+
edge_fun: cython.double = (
|
|
229
|
+
(vert_2[0] - vert_0[0]) * (vert_1[1] - vert_0[1])
|
|
230
|
+
- (vert_2[1] - vert_0[1]) * (vert_1[0] - vert_0[0]))
|
|
231
|
+
return edge_fun
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@cython.cfunc
|
|
235
|
+
@cython.nogil
|
|
236
|
+
@cython.boundscheck(False)
|
|
237
|
+
@cython.wraparound(False)
|
|
238
|
+
@cython.inline
|
|
239
|
+
@cython.exceptval(check=False)
|
|
240
|
+
def edge_function_pt(vert_0: cython.double[:],
|
|
241
|
+
vert_1: cython.double[:],
|
|
242
|
+
vert_2_x: cython.double,
|
|
243
|
+
vert_2_y: cython.double) -> cython.double:
|
|
244
|
+
edge_fun: cython.double = (
|
|
245
|
+
(vert_2_x - vert_0[0]) * (vert_1[1] - vert_0[1])
|
|
246
|
+
- (vert_2_y - vert_0[1]) * (vert_1[0] - vert_0[0]))
|
|
247
|
+
return edge_fun
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@cython.ccall
|
|
251
|
+
@cython.boundscheck(False)
|
|
252
|
+
@cython.wraparound(False)
|
|
253
|
+
@cython.cdivision(True)
|
|
254
|
+
def average_image(image_subpx: cython.double[:,:],
|
|
255
|
+
sub_samp: cython.int,
|
|
256
|
+
) -> cython.double[:,:]:
|
|
257
|
+
|
|
258
|
+
if sub_samp <= 1:
|
|
259
|
+
return np.asarray(image_subpx[:,:])
|
|
260
|
+
|
|
261
|
+
px_num_y: cython.size_t = int(ceil(image_subpx.shape[0]/sub_samp))
|
|
262
|
+
px_num_x: cython.size_t = int(ceil(image_subpx.shape[1]/sub_samp))
|
|
263
|
+
|
|
264
|
+
image_buff_avg_np = np.full((px_num_y,px_num_x),0.0,dtype=np.float64)
|
|
265
|
+
image_buff_avg: cython.double[:,:] = image_buff_avg_np
|
|
266
|
+
|
|
267
|
+
num_subpx_y: cython.size_t = image_subpx.shape[0]
|
|
268
|
+
num_subpx_x: cython.size_t = image_subpx.shape[1]
|
|
269
|
+
subpx_per_px: cython.double = float(sub_samp*sub_samp)
|
|
270
|
+
ss_size: cython.size_t = sub_samp
|
|
271
|
+
|
|
272
|
+
num_px_y: cython.size_t = int(num_subpx_y/sub_samp)
|
|
273
|
+
num_px_x: cython.size_t = int(num_subpx_x/sub_samp)
|
|
274
|
+
|
|
275
|
+
px_sum: cython.double = 0.0
|
|
276
|
+
|
|
277
|
+
ix: cython.size_t = 0
|
|
278
|
+
iy: cython.size_t = 0
|
|
279
|
+
sx: cython.size_t = 0
|
|
280
|
+
sy: cython.size_t = 0
|
|
281
|
+
|
|
282
|
+
for iy in range(num_px_y):
|
|
283
|
+
for ix in range(num_px_x):
|
|
284
|
+
px_sum = 0.0
|
|
285
|
+
for sy in range(ss_size):
|
|
286
|
+
for sx in range(ss_size):
|
|
287
|
+
px_sum += image_subpx[ss_size*iy+sy,ss_size*ix+sx]
|
|
288
|
+
|
|
289
|
+
image_buff_avg[iy,ix] = px_sum / subpx_per_px
|
|
290
|
+
|
|
291
|
+
return image_buff_avg
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
@cython.nogil
|
|
295
|
+
@cython.cfunc
|
|
296
|
+
@cython.boundscheck(False)
|
|
297
|
+
@cython.wraparound(False)
|
|
298
|
+
@cython.cdivision(True)
|
|
299
|
+
@cython.exceptval(check=False)
|
|
300
|
+
def _average_image(image_buff_subpx_in: cython.double[:,:],
|
|
301
|
+
sub_samp: cython.int,
|
|
302
|
+
image_buff_avg_out: cython.double[:,:]
|
|
303
|
+
) -> cython.int:
|
|
304
|
+
|
|
305
|
+
num_subpx_y: cython.size_t = image_buff_subpx_in.shape[0]
|
|
306
|
+
num_subpx_x: cython.size_t = image_buff_subpx_in.shape[1]
|
|
307
|
+
subpx_per_px: cython.double = float(sub_samp*sub_samp)
|
|
308
|
+
ss_size: cython.size_t = sub_samp
|
|
309
|
+
|
|
310
|
+
num_px_y: cython.size_t = int(num_subpx_y/sub_samp)
|
|
311
|
+
num_px_x: cython.size_t = int(num_subpx_x/sub_samp)
|
|
312
|
+
|
|
313
|
+
px_sum: cython.double = 0.0
|
|
314
|
+
|
|
315
|
+
ix: cython.size_t = 0
|
|
316
|
+
iy: cython.size_t = 0
|
|
317
|
+
sx: cython.size_t = 0
|
|
318
|
+
sy: cython.size_t = 0
|
|
319
|
+
|
|
320
|
+
for iy in range(num_px_y):
|
|
321
|
+
for ix in range(num_px_x):
|
|
322
|
+
px_sum = 0.0
|
|
323
|
+
for sy in range(ss_size):
|
|
324
|
+
for sx in range(ss_size):
|
|
325
|
+
px_sum += image_buff_subpx_in[ss_size*iy+sy,ss_size*ix+sx]
|
|
326
|
+
|
|
327
|
+
image_buff_avg_out[iy,ix] = px_sum / subpx_per_px
|
|
328
|
+
|
|
329
|
+
return 0
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
#///////////////////////////////////////////////////////////////////////////////
|
|
333
|
+
@cython.ccall # python+C or cython.cfunc for C only
|
|
334
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
335
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
336
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
337
|
+
def raster_frame(coords: cython.double[:,:],
|
|
338
|
+
connect: cython.size_t[:,:],
|
|
339
|
+
fields_to_render: cython.double[:,:],
|
|
340
|
+
cam_data: CameraData,
|
|
341
|
+
) -> tuple[np.ndarray,np.ndarray,int]:
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
world_to_cam_mat: cython.double[:,:] = cam_data.world_to_cam_mat
|
|
345
|
+
pixels_num: cython.int[:] = cam_data.pixels_num
|
|
346
|
+
image_dims: cython.double[:] = cam_data.image_dims
|
|
347
|
+
image_dist: cython.double = cam_data.image_dist
|
|
348
|
+
sub_samp: cython.int = cam_data.sub_samp
|
|
349
|
+
|
|
350
|
+
nodes_per_elem: cython.size_t = connect.shape[1]
|
|
351
|
+
fields_num: cython.size_t = fields_to_render.shape[1]
|
|
352
|
+
sub_pix_x: cython.int = pixels_num[0]*sub_samp
|
|
353
|
+
sub_pix_y: cython.int = pixels_num[1]*sub_samp
|
|
354
|
+
|
|
355
|
+
#---------------------------------------------------------------------------
|
|
356
|
+
# Final image buffer memory allocation
|
|
357
|
+
image_buff_avg_np = np.full((pixels_num[1],pixels_num[0],fields_num),0.0,dtype=np.float64)
|
|
358
|
+
image_buff_avg: cython.double[:,:,:] = image_buff_avg_np
|
|
359
|
+
|
|
360
|
+
depth_buff_avg_np = np.full((pixels_num[1],pixels_num[0]),0.0,dtype=np.float64)
|
|
361
|
+
depth_buff_avg: cython.double[:,:] = depth_buff_avg_np
|
|
362
|
+
|
|
363
|
+
#---------------------------------------------------------------------------
|
|
364
|
+
# Per-thread scratch memory allocations
|
|
365
|
+
depth_buffer_np = np.full((sub_pix_y,sub_pix_x),1.0e6,dtype=np.float64)
|
|
366
|
+
depth_buff_subpx: cython.double[:,:] = depth_buffer_np
|
|
367
|
+
|
|
368
|
+
image_buffer_np = np.full((sub_pix_y,sub_pix_x,fields_num),0.0,dtype=np.float64)
|
|
369
|
+
image_buff_subpx: cython.double[:,:,:] = image_buffer_np
|
|
370
|
+
|
|
371
|
+
# shape=(nodes_per_elem, coord[X,Y,Z,W])
|
|
372
|
+
nodes_raster_np = np.empty((nodes_per_elem,4),dtype=np.float64)
|
|
373
|
+
nodes_raster_buff: cython.double[:,:] = nodes_raster_np
|
|
374
|
+
|
|
375
|
+
field_raster_np = np.empty((nodes_per_elem,),dtype=np.float64)
|
|
376
|
+
field_raster_buff: cython.double[:] = field_raster_np
|
|
377
|
+
|
|
378
|
+
px_coord_np = np.zeros((nodes_per_elem,),np.float64)
|
|
379
|
+
px_coord_buff: cython.double[:] = px_coord_np
|
|
380
|
+
|
|
381
|
+
weights_np = np.zeros((nodes_per_elem,),np.float64)
|
|
382
|
+
weights_buff: cython.double[:] = weights_np
|
|
383
|
+
#---------------------------------------------------------------------------
|
|
384
|
+
|
|
385
|
+
elems_in_image: cython.size_t = _raster_frame(coords[:,:],
|
|
386
|
+
connect[:,:],
|
|
387
|
+
fields_to_render[:,:],
|
|
388
|
+
world_to_cam_mat[:,:],
|
|
389
|
+
pixels_num[:],
|
|
390
|
+
image_dims[:],
|
|
391
|
+
image_dist,
|
|
392
|
+
sub_samp,
|
|
393
|
+
image_buff_avg[:,:,:],
|
|
394
|
+
depth_buff_avg[:,:],
|
|
395
|
+
image_buff_subpx[:,:,:],
|
|
396
|
+
depth_buff_subpx[:,:],
|
|
397
|
+
nodes_raster_buff[:,:],
|
|
398
|
+
field_raster_buff[:],
|
|
399
|
+
px_coord_buff[:],
|
|
400
|
+
weights_buff[:])
|
|
401
|
+
|
|
402
|
+
return (image_buff_avg_np,depth_buff_avg_np,elems_in_image)
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
#///////////////////////////////////////////////////////////////////////////////
|
|
406
|
+
#@cython.nogil
|
|
407
|
+
@cython.cfunc # python+C or cython.cfunc for C only
|
|
408
|
+
@cython.boundscheck(False) # Turn off array bounds checking
|
|
409
|
+
@cython.wraparound(False) # Turn off negative indexing
|
|
410
|
+
@cython.cdivision(True) # Turn off divide by zero check
|
|
411
|
+
@cython.exceptval(check=False) # Turn off exceptions
|
|
412
|
+
def _raster_frame(coords: cython.double[:,:],
|
|
413
|
+
connect: cython.size_t[:,:],
|
|
414
|
+
fields_to_render: cython.double[:,:],
|
|
415
|
+
world_to_cam_mat: cython.double[:,:],
|
|
416
|
+
num_pixels: cython.int[:],
|
|
417
|
+
image_dims: cython.double[:],
|
|
418
|
+
image_dist: cython.double,
|
|
419
|
+
sub_samp: cython.int,
|
|
420
|
+
# From here these are memory buffers that will be written into
|
|
421
|
+
image_buff_avg: cython.double[:,:,:],
|
|
422
|
+
depth_buff_avg: cython.double[:,:],
|
|
423
|
+
image_buff_subpx: cython.double[:,:,:],
|
|
424
|
+
depth_buff_subpx: cython.double[:,:],
|
|
425
|
+
nodes_raster_buff: cython.double[:,:],
|
|
426
|
+
field_raster_buff: cython.double[:],
|
|
427
|
+
px_coord_buff: cython.double[:],
|
|
428
|
+
weights_buff: cython.double[:],
|
|
429
|
+
) -> cython.size_t:
|
|
430
|
+
"""Rasters a single frame and all associated fields into the image and depth
|
|
431
|
+
buffer provided as inputs to the function. This is a pure cython function
|
|
432
|
+
with the GIL released for parallelisation. All fields (textures) are
|
|
433
|
+
rendered in a sub-loop so that the depth buffer and inside/outside test is
|
|
434
|
+
only performed once for all fields to be rendered.
|
|
435
|
+
|
|
436
|
+
Parameters
|
|
437
|
+
----------
|
|
438
|
+
coords : cython.double[:,:]
|
|
439
|
+
Input. shape=(num_nodes,coords[x,y,z,w])
|
|
440
|
+
connect : cython.size_t[:,:]
|
|
441
|
+
Input. shape=(num_elems,nodes_per_elem)
|
|
442
|
+
fields_to_render : cython.double[:,:]
|
|
443
|
+
Input. shape=(num_nodes,num_fields)
|
|
444
|
+
world_to_cam_mat : cython.double[:,:]
|
|
445
|
+
Input. Homogeneous coordinate transformation matrix from world to camera
|
|
446
|
+
coordinates. shape=(4,4).
|
|
447
|
+
num_pixels : cython.int[:]
|
|
448
|
+
Input. shape=(2 [num_px_x,num_px_y],)
|
|
449
|
+
image_dims : cython.double[:]
|
|
450
|
+
Input. shape=(2 [fov_size_x,fov_size_y],)
|
|
451
|
+
image_dist : cython.double
|
|
452
|
+
Input.
|
|
453
|
+
sub_samp : cython.int
|
|
454
|
+
Number of subsamples per pixel for anti-aliasing.
|
|
455
|
+
image_buff_avg : cython.double[:,:,:]
|
|
456
|
+
Output buffer. shape=(num_px_y,num_px_x,num_fields)
|
|
457
|
+
depth_buff_avg : cython.double[:,:]
|
|
458
|
+
Output buffer. shape=(num_px_y,num_px_x)
|
|
459
|
+
image_buff_subpx : cython.double[:,:,:]
|
|
460
|
+
Processing buffer (output). shape=(num_subpx_y,num_subpx_x,num_fields)
|
|
461
|
+
depth_buff_subpx : cython.double[:,:]
|
|
462
|
+
Processing buffer (output). shape=(num_subpx_y,num_subpx_x)
|
|
463
|
+
nodes_raster_buff : cython.double[:,:]
|
|
464
|
+
Processing buffer (output). shape=(nodes_per_elem, 4 coord[x,y,z,w])
|
|
465
|
+
field_raster_buff : cython.double[:]
|
|
466
|
+
Processing buffer (output). shape=(nodes_per_elem,)
|
|
467
|
+
px_coord_buff : cython.double[:]
|
|
468
|
+
Processing buffer (output). shape=(nodes_per_elem,)
|
|
469
|
+
weights_buff : cython.double[:]
|
|
470
|
+
Processing buffer (output). shape=(nodes_per_elem,)
|
|
471
|
+
|
|
472
|
+
Returns
|
|
473
|
+
-------
|
|
474
|
+
cython.size_t
|
|
475
|
+
Number of rendered elements after backface culling and cropping.
|
|
476
|
+
"""
|
|
477
|
+
|
|
478
|
+
xx: cython.size_t = 0
|
|
479
|
+
yy: cython.size_t = 1
|
|
480
|
+
zz: cython.size_t = 2
|
|
481
|
+
|
|
482
|
+
elem_count: cython.size_t = connect.shape[0]
|
|
483
|
+
nodes_per_elem: cython.size_t = connect.shape[1]
|
|
484
|
+
fields_num: cython.size_t = fields_to_render.shape[1]
|
|
485
|
+
|
|
486
|
+
# tolerance for floating point zero dot product
|
|
487
|
+
tol: cython.double = 1e-12
|
|
488
|
+
|
|
489
|
+
#elem_count: cython.size_t = 1
|
|
490
|
+
elems_in_image: cython.size_t = 0
|
|
491
|
+
|
|
492
|
+
ee: cython.size_t = 0
|
|
493
|
+
nn: cython.size_t = 0
|
|
494
|
+
ii: cython.size_t = 0
|
|
495
|
+
jj: cython.size_t = 0
|
|
496
|
+
ww: cython.size_t = 0
|
|
497
|
+
ff: cython.size_t = 0
|
|
498
|
+
|
|
499
|
+
for ee in range(elem_count):
|
|
500
|
+
|
|
501
|
+
for nn in range(nodes_per_elem):
|
|
502
|
+
# shape=(nodes_per_elem, coord[X,Y,Z,W])
|
|
503
|
+
nodes_raster_buff[nn,:] = world_to_raster_coords(coords[connect[ee,nn],:],
|
|
504
|
+
world_to_cam_mat,
|
|
505
|
+
image_dist,
|
|
506
|
+
image_dims,
|
|
507
|
+
num_pixels,
|
|
508
|
+
nodes_raster_buff[nn,:])
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
elem_area: cython.double = edge_function(nodes_raster_buff[0,:],
|
|
512
|
+
nodes_raster_buff[1,:],
|
|
513
|
+
nodes_raster_buff[2,:])
|
|
514
|
+
|
|
515
|
+
if elem_area < -tol: # Backface culling
|
|
516
|
+
continue
|
|
517
|
+
|
|
518
|
+
print(f"{nodes_raster_buff[0,0]},{nodes_raster_buff[0,1]},{nodes_raster_buff[0,2]}")
|
|
519
|
+
print(f"{nodes_raster_buff[1,0]},{nodes_raster_buff[1,1]},{nodes_raster_buff[1,2]}")
|
|
520
|
+
print(f"{nodes_raster_buff[2,0]},{nodes_raster_buff[2,1]},{nodes_raster_buff[2,2]}")
|
|
521
|
+
print(f"{ee} ELEM AREA : {elem_area}")
|
|
522
|
+
print()
|
|
523
|
+
|
|
524
|
+
x_min: cython.double = vec_min_double(nodes_raster_buff[:,xx])
|
|
525
|
+
x_max: cython.double = vec_max_double(nodes_raster_buff[:,xx])
|
|
526
|
+
|
|
527
|
+
if ((x_min > num_pixels[xx]-1) or (x_max < 0)): # x crop
|
|
528
|
+
continue
|
|
529
|
+
|
|
530
|
+
y_min: cython.double = vec_min_double(nodes_raster_buff[:,yy])
|
|
531
|
+
y_max: cython.double = vec_max_double(nodes_raster_buff[:,yy])
|
|
532
|
+
|
|
533
|
+
if ((y_min > num_pixels[yy]-1) or (y_max < 0)): # y crop
|
|
534
|
+
continue
|
|
535
|
+
|
|
536
|
+
elems_in_image += 1
|
|
537
|
+
|
|
538
|
+
xi_min: cython.size_t = bound_index_min(x_min)
|
|
539
|
+
xi_max: cython.size_t = bound_index_max(x_max,num_pixels[xx])
|
|
540
|
+
yi_min: cython.size_t = bound_index_min(y_min)
|
|
541
|
+
yi_max: cython.size_t = bound_index_max(y_max,num_pixels[yy])
|
|
542
|
+
|
|
543
|
+
for nn in range(nodes_per_elem):
|
|
544
|
+
nodes_raster_buff[nn,zz] = 1/nodes_raster_buff[nn,zz]
|
|
545
|
+
|
|
546
|
+
num_bound_x: cython.size_t = range_len_double(float(xi_min),
|
|
547
|
+
float(xi_max),
|
|
548
|
+
1.0/float(sub_samp))
|
|
549
|
+
num_bound_y: cython.size_t = range_len_double(float(yi_min),
|
|
550
|
+
float(yi_max),
|
|
551
|
+
1.0/float(sub_samp))
|
|
552
|
+
|
|
553
|
+
bound_coord_x: cython.double = float(xi_min) + 1.0/(2.0*float(sub_samp))
|
|
554
|
+
bound_coord_y: cython.double = float(yi_min) + 1.0/(2.0*float(sub_samp))
|
|
555
|
+
coord_step: cython.double = 1.0/float(sub_samp)
|
|
556
|
+
bound_ind_x: cython.size_t = sub_samp*xi_min
|
|
557
|
+
bound_ind_y: cython.size_t = sub_samp*yi_min
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
for jj in range(num_bound_y):
|
|
561
|
+
|
|
562
|
+
bound_coord_x = float(xi_min) + 1.0/(2.0*float(sub_samp))
|
|
563
|
+
bound_ind_x: cython.size_t = sub_samp*xi_min
|
|
564
|
+
|
|
565
|
+
for ii in range(num_bound_x):
|
|
566
|
+
|
|
567
|
+
px_coord_buff[xx] = bound_coord_x
|
|
568
|
+
px_coord_buff[yy] = bound_coord_y
|
|
569
|
+
|
|
570
|
+
# Check the edge functions for each edge one at a time, as soon
|
|
571
|
+
# as one is outside we don't need to do anymore work
|
|
572
|
+
weights_buff[0] = edge_function(nodes_raster_buff[1,:],
|
|
573
|
+
nodes_raster_buff[2,:],
|
|
574
|
+
px_coord_buff)
|
|
575
|
+
if (weights_buff[0] < -tol):
|
|
576
|
+
bound_coord_x += coord_step
|
|
577
|
+
bound_ind_x += 1
|
|
578
|
+
continue
|
|
579
|
+
|
|
580
|
+
weights_buff[1] = edge_function(nodes_raster_buff[2,:],
|
|
581
|
+
nodes_raster_buff[0,:],
|
|
582
|
+
px_coord_buff)
|
|
583
|
+
if (weights_buff[1] < -tol):
|
|
584
|
+
bound_coord_x += coord_step
|
|
585
|
+
bound_ind_x += 1
|
|
586
|
+
continue
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
weights_buff[2] = edge_function(nodes_raster_buff[0,:],
|
|
590
|
+
nodes_raster_buff[1,:],
|
|
591
|
+
px_coord_buff)
|
|
592
|
+
if (weights_buff[2] < -tol):
|
|
593
|
+
bound_coord_x += coord_step
|
|
594
|
+
bound_ind_x += 1
|
|
595
|
+
continue
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
for ww in range(nodes_per_elem):
|
|
599
|
+
weights_buff[ww] = weights_buff[ww] / elem_area
|
|
600
|
+
|
|
601
|
+
weight_dot_nodes: cython.double = vec_dot_double(
|
|
602
|
+
weights_buff,
|
|
603
|
+
nodes_raster_buff[:,zz])
|
|
604
|
+
|
|
605
|
+
# Check the depth buffer, if the element is behind move on
|
|
606
|
+
px_coord_z: cython.double = 1/weight_dot_nodes
|
|
607
|
+
if px_coord_z >= depth_buff_subpx[bound_ind_y,bound_ind_x]:
|
|
608
|
+
continue
|
|
609
|
+
|
|
610
|
+
# We only need one depth buffer for all fields
|
|
611
|
+
depth_buff_subpx[bound_ind_y,bound_ind_x] = px_coord_z
|
|
612
|
+
|
|
613
|
+
for ff in range(fields_num):
|
|
614
|
+
for nn in range(nodes_per_elem):
|
|
615
|
+
|
|
616
|
+
field_raster_buff[nn] = (fields_to_render[connect[ee,nn],ff]
|
|
617
|
+
*nodes_raster_buff[nn,zz])
|
|
618
|
+
|
|
619
|
+
px_field: cython.double = (vec_dot_double(field_raster_buff,
|
|
620
|
+
weights_buff)
|
|
621
|
+
*px_coord_z)
|
|
622
|
+
|
|
623
|
+
image_buff_subpx[bound_ind_y,bound_ind_x,ff] = px_field
|
|
624
|
+
|
|
625
|
+
# end for(x) - increment the x coords
|
|
626
|
+
bound_coord_x += coord_step
|
|
627
|
+
bound_ind_x += 1
|
|
628
|
+
|
|
629
|
+
# end for(y) - increment the y coords
|
|
630
|
+
bound_coord_y += coord_step
|
|
631
|
+
bound_ind_y += 1
|
|
632
|
+
|
|
633
|
+
_average_image(depth_buff_subpx,sub_samp,depth_buff_avg)
|
|
634
|
+
|
|
635
|
+
for ff in range(fields_num):
|
|
636
|
+
_average_image(image_buff_subpx[:,:,ff],
|
|
637
|
+
sub_samp,
|
|
638
|
+
image_buff_avg[:,:,ff])
|
|
639
|
+
|
|
640
|
+
return elems_in_image
|
pyvale/data/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#===============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
#===============================================================================
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
pyvale/data/case13_out.e
ADDED
|
Binary file
|
pyvale/data/case16_out.e
ADDED
|
Binary file
|
pyvale/data/case17_out.e
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
pyvale/data/case25_out.e
ADDED
|
Binary file
|
pyvale/data/case26_out.e
ADDED
|
Binary file
|
|
Binary file
|