pyvale 2025.7.1__cp311-cp311-musllinux_1_2_i686.whl → 2025.8.1__cp311-cp311-musllinux_1_2_i686.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyvale might be problematic. Click here for more details.
- pyvale/__init__.py +12 -92
- pyvale/blender/__init__.py +23 -0
- pyvale/{pyvaleexceptions.py → blender/blenderexceptions.py} +0 -3
- pyvale/{blenderlightdata.py → blender/blenderlightdata.py} +3 -3
- pyvale/{blendermaterialdata.py → blender/blendermaterialdata.py} +1 -1
- pyvale/{blenderrenderdata.py → blender/blenderrenderdata.py} +5 -3
- pyvale/{blenderscene.py → blender/blenderscene.py} +33 -30
- pyvale/{blendertools.py → blender/blendertools.py} +14 -10
- pyvale/dataset/__init__.py +7 -0
- pyvale/dataset/dataset.py +443 -0
- pyvale/dic/__init__.py +20 -0
- pyvale/dic/cpp/dicfourier.cpp +36 -4
- pyvale/dic/cpp/dicinterpolator.cpp +56 -1
- pyvale/dic/cpp/dicmain.cpp +24 -19
- pyvale/dic/cpp/dicoptimizer.cpp +6 -1
- pyvale/dic/cpp/dicscanmethod.cpp +32 -32
- pyvale/dic/cpp/dicsignalhandler.cpp +16 -0
- pyvale/dic/cpp/dicstrain.cpp +7 -3
- pyvale/dic/cpp/dicutil.cpp +79 -23
- pyvale/{dic2d.py → dic/dic2d.py} +51 -29
- pyvale/dic/dic2dconv.py +6 -0
- pyvale/{dic2dcpp.cpython-311-i386-linux-musl.so → dic/dic2dcpp.cpython-311-i386-linux-musl.so} +0 -0
- pyvale/{dicchecks.py → dic/dicchecks.py} +28 -16
- pyvale/dic/dicdataimport.py +370 -0
- pyvale/{dicregionofinterest.py → dic/dicregionofinterest.py} +169 -12
- pyvale/{dicresults.py → dic/dicresults.py} +4 -1
- pyvale/{dicstrain.py → dic/dicstrain.py} +9 -9
- pyvale/examples/basics/{ex1_1_basicscalars_therm2d.py → ex1a_basicscalars_therm2d.py} +12 -9
- pyvale/examples/basics/{ex1_2_sensormodel_therm2d.py → ex1b_sensormodel_therm2d.py} +17 -14
- pyvale/examples/basics/{ex1_3_customsens_therm3d.py → ex1c_customsens_therm3d.py} +27 -24
- pyvale/examples/basics/{ex1_4_basicerrors_therm3d.py → ex1d_basicerrors_therm3d.py} +32 -29
- pyvale/examples/basics/{ex1_5_fielderrs_therm3d.py → ex1e_fielderrs_therm3d.py} +19 -15
- pyvale/examples/basics/{ex1_6_caliberrs_therm2d.py → ex1f_caliberrs_therm2d.py} +20 -16
- pyvale/examples/basics/{ex1_7_spatavg_therm2d.py → ex1g_spatavg_therm2d.py} +19 -16
- pyvale/examples/basics/{ex2_1_basicvectors_disp2d.py → ex2a_basicvectors_disp2d.py} +13 -10
- pyvale/examples/basics/{ex2_2_vectorsens_disp2d.py → ex2b_vectorsens_disp2d.py} +19 -15
- pyvale/examples/basics/{ex2_3_sensangle_disp2d.py → ex2c_sensangle_disp2d.py} +21 -18
- pyvale/examples/basics/{ex2_4_chainfielderrs_disp2d.py → ex2d_chainfielderrs_disp2d.py} +31 -29
- pyvale/examples/basics/{ex2_5_vectorfields3d_disp3d.py → ex2e_vectorfields3d_disp3d.py} +21 -18
- pyvale/examples/basics/{ex3_1_basictensors_strain2d.py → ex3a_basictensors_strain2d.py} +16 -14
- pyvale/examples/basics/{ex3_2_tensorsens2d_strain2d.py → ex3b_tensorsens2d_strain2d.py} +17 -14
- pyvale/examples/basics/{ex3_3_tensorsens3d_strain3d.py → ex3c_tensorsens3d_strain3d.py} +25 -22
- pyvale/examples/basics/{ex4_1_expsim2d_thermmech2d.py → ex4a_expsim2d_thermmech2d.py} +17 -14
- pyvale/examples/basics/{ex4_2_expsim3d_thermmech3d.py → ex4b_expsim3d_thermmech3d.py} +37 -34
- pyvale/examples/basics/ex5_nomesh.py +24 -0
- pyvale/examples/dic/ex1_2_blenderdeformed.py +174 -0
- pyvale/examples/dic/ex1_region_of_interest.py +6 -3
- pyvale/examples/dic/ex2_plate_with_hole.py +21 -18
- pyvale/examples/dic/ex3_plate_with_hole_strain.py +8 -6
- pyvale/examples/dic/ex4_dic_blender.py +17 -15
- pyvale/examples/dic/ex5_dic_challenge.py +19 -14
- pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +16 -10
- pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +3 -3
- pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +29 -23
- pyvale/examples/genanalyticdata/ex2_2_analyticsensors_nomesh.py +67 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +12 -9
- pyvale/examples/mooseherder/ex0_create_moose_config.py +65 -0
- pyvale/examples/mooseherder/ex1a_modify_moose_input.py +71 -0
- pyvale/examples/mooseherder/ex1b_modify_gmsh_input.py +69 -0
- pyvale/examples/mooseherder/ex2a_run_moose_once.py +80 -0
- pyvale/examples/mooseherder/ex2b_run_gmsh_once.py +64 -0
- pyvale/examples/mooseherder/ex2c_run_both_once.py +114 -0
- pyvale/examples/mooseherder/ex3_run_moose_seq_para.py +157 -0
- pyvale/examples/mooseherder/ex4_run_gmsh-moose_seq_para.py +176 -0
- pyvale/examples/mooseherder/ex5_run_moose_paramulti.py +136 -0
- pyvale/examples/mooseherder/ex6_read_moose_exodus.py +163 -0
- pyvale/examples/mooseherder/ex7a_read_moose_herd_results.py +153 -0
- pyvale/examples/mooseherder/ex7b_read_multi_herd_results.py +116 -0
- pyvale/examples/mooseherder/ex7c_read_multi_gmshmoose_results.py +127 -0
- pyvale/examples/mooseherder/ex7d_readconfig_multi_gmshmoose_results.py +143 -0
- pyvale/examples/mooseherder/ex8_read_existing_sweep_output.py +72 -0
- pyvale/examples/renderblender/ex1_1_blenderscene.py +24 -20
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +22 -18
- pyvale/examples/renderblender/ex2_1_stereoscene.py +36 -29
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +26 -20
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +24 -17
- pyvale/examples/renderrasterisation/ex_rastenp.py +14 -12
- pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +14 -15
- pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +13 -11
- pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +13 -11
- pyvale/mooseherder/__init__.py +32 -0
- pyvale/mooseherder/directorymanager.py +416 -0
- pyvale/mooseherder/exodusreader.py +763 -0
- pyvale/mooseherder/gmshrunner.py +163 -0
- pyvale/mooseherder/inputmodifier.py +236 -0
- pyvale/mooseherder/mooseconfig.py +226 -0
- pyvale/mooseherder/mooseherd.py +527 -0
- pyvale/mooseherder/mooserunner.py +303 -0
- pyvale/mooseherder/outputreader.py +22 -0
- pyvale/mooseherder/simdata.py +92 -0
- pyvale/mooseherder/simrunner.py +31 -0
- pyvale/mooseherder/sweepreader.py +356 -0
- pyvale/mooseherder/sweeptools.py +76 -0
- pyvale/sensorsim/__init__.py +82 -0
- pyvale/{camera.py → sensorsim/camera.py} +7 -7
- pyvale/{camerasensor.py → sensorsim/camerasensor.py} +7 -7
- pyvale/{camerastereo.py → sensorsim/camerastereo.py} +2 -2
- pyvale/{cameratools.py → sensorsim/cameratools.py} +4 -4
- pyvale/{cython → sensorsim/cython}/rastercyth.c +596 -596
- pyvale/{cython → sensorsim/cython}/rastercyth.cpython-311-i386-linux-musl.so +0 -0
- pyvale/{cython → sensorsim/cython}/rastercyth.py +16 -17
- pyvale/{errorcalculator.py → sensorsim/errorcalculator.py} +1 -1
- pyvale/{errorintegrator.py → sensorsim/errorintegrator.py} +2 -2
- pyvale/{errorrand.py → sensorsim/errorrand.py} +4 -4
- pyvale/{errorsyscalib.py → sensorsim/errorsyscalib.py} +2 -2
- pyvale/{errorsysdep.py → sensorsim/errorsysdep.py} +2 -2
- pyvale/{errorsysfield.py → sensorsim/errorsysfield.py} +8 -8
- pyvale/{errorsysindep.py → sensorsim/errorsysindep.py} +3 -3
- pyvale/sensorsim/exceptions.py +8 -0
- pyvale/{experimentsimulator.py → sensorsim/experimentsimulator.py} +23 -3
- pyvale/{field.py → sensorsim/field.py} +1 -1
- pyvale/{fieldconverter.py → sensorsim/fieldconverter.py} +72 -19
- pyvale/sensorsim/fieldinterp.py +37 -0
- pyvale/sensorsim/fieldinterpmesh.py +124 -0
- pyvale/sensorsim/fieldinterppoints.py +55 -0
- pyvale/{fieldsampler.py → sensorsim/fieldsampler.py} +4 -4
- pyvale/{fieldscalar.py → sensorsim/fieldscalar.py} +28 -24
- pyvale/{fieldtensor.py → sensorsim/fieldtensor.py} +33 -31
- pyvale/{fieldvector.py → sensorsim/fieldvector.py} +33 -31
- pyvale/{imagedef2d.py → sensorsim/imagedef2d.py} +9 -5
- pyvale/{integratorfactory.py → sensorsim/integratorfactory.py} +6 -6
- pyvale/{integratorquadrature.py → sensorsim/integratorquadrature.py} +3 -3
- pyvale/{integratorrectangle.py → sensorsim/integratorrectangle.py} +3 -3
- pyvale/{integratorspatial.py → sensorsim/integratorspatial.py} +1 -1
- pyvale/{rastercy.py → sensorsim/rastercy.py} +5 -5
- pyvale/{rasternp.py → sensorsim/rasternp.py} +9 -9
- pyvale/{rasteropts.py → sensorsim/rasteropts.py} +1 -1
- pyvale/{renderer.py → sensorsim/renderer.py} +1 -1
- pyvale/{rendermesh.py → sensorsim/rendermesh.py} +5 -5
- pyvale/{renderscene.py → sensorsim/renderscene.py} +2 -2
- pyvale/{sensorarray.py → sensorsim/sensorarray.py} +1 -1
- pyvale/{sensorarrayfactory.py → sensorsim/sensorarrayfactory.py} +12 -12
- pyvale/{sensorarraypoint.py → sensorsim/sensorarraypoint.py} +10 -8
- pyvale/{sensordata.py → sensorsim/sensordata.py} +1 -1
- pyvale/{sensortools.py → sensorsim/sensortools.py} +2 -20
- pyvale/sensorsim/simtools.py +174 -0
- pyvale/{visualexpplotter.py → sensorsim/visualexpplotter.py} +3 -3
- pyvale/{visualimages.py → sensorsim/visualimages.py} +2 -2
- pyvale/{visualsimanimator.py → sensorsim/visualsimanimator.py} +4 -4
- pyvale/{visualsimplotter.py → sensorsim/visualsimplotter.py} +5 -5
- pyvale/{visualsimsensors.py → sensorsim/visualsimsensors.py} +12 -12
- pyvale/{visualtools.py → sensorsim/visualtools.py} +1 -1
- pyvale/{visualtraceplotter.py → sensorsim/visualtraceplotter.py} +2 -2
- pyvale/simcases/case17.geo +3 -0
- pyvale/simcases/case17.i +4 -4
- pyvale/simcases/run_1case.py +1 -9
- pyvale/simcases/run_all_cases.py +1 -1
- pyvale/simcases/run_build_case.py +1 -1
- pyvale/simcases/run_example_cases.py +1 -1
- pyvale/verif/__init__.py +12 -0
- pyvale/{analyticsimdatafactory.py → verif/analyticsimdatafactory.py} +2 -2
- pyvale/{analyticsimdatagenerator.py → verif/analyticsimdatagenerator.py} +2 -2
- pyvale/verif/psens.py +125 -0
- pyvale/verif/psensconst.py +18 -0
- pyvale/verif/psensmech.py +227 -0
- pyvale/verif/psensmultiphys.py +187 -0
- pyvale/verif/psensscalar.py +347 -0
- pyvale/verif/psenstensor.py +123 -0
- pyvale/verif/psensvector.py +116 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/METADATA +6 -7
- pyvale-2025.8.1.dist-info/RECORD +263 -0
- pyvale/dataset.py +0 -415
- pyvale/dicdataimport.py +0 -247
- pyvale/simtools.py +0 -67
- pyvale-2025.7.1.dist-info/RECORD +0 -214
- /pyvale/{blendercalibrationdata.py → blender/blendercalibrationdata.py} +0 -0
- /pyvale/{dicspecklegenerator.py → dic/dicspecklegenerator.py} +0 -0
- /pyvale/{dicspecklequality.py → dic/dicspecklequality.py} +0 -0
- /pyvale/{dicstrainresults.py → dic/dicstrainresults.py} +0 -0
- /pyvale/{cameradata.py → sensorsim/cameradata.py} +0 -0
- /pyvale/{cameradata2d.py → sensorsim/cameradata2d.py} +0 -0
- /pyvale/{errordriftcalc.py → sensorsim/errordriftcalc.py} +0 -0
- /pyvale/{fieldtransform.py → sensorsim/fieldtransform.py} +0 -0
- /pyvale/{generatorsrandom.py → sensorsim/generatorsrandom.py} +0 -0
- /pyvale/{imagetools.py → sensorsim/imagetools.py} +0 -0
- /pyvale/{integratortype.py → sensorsim/integratortype.py} +0 -0
- /pyvale/{output.py → sensorsim/output.py} +0 -0
- /pyvale/{raster.py → sensorsim/raster.py} +0 -0
- /pyvale/{sensordescriptor.py → sensorsim/sensordescriptor.py} +0 -0
- /pyvale/{visualimagedef.py → sensorsim/visualimagedef.py} +0 -0
- /pyvale/{visualopts.py → sensorsim/visualopts.py} +0 -0
- /pyvale/{analyticmeshgen.py → verif/analyticmeshgen.py} +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/WHEEL +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/licenses/LICENSE +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/top_level.txt +0 -0
|
@@ -15,7 +15,7 @@ import yaml
|
|
|
15
15
|
import os
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
|
-
class
|
|
18
|
+
class RegionOfInterest:
|
|
19
19
|
"""
|
|
20
20
|
A class for interactively selecting and manipulating ROI of an image before passing to the DIC engine.
|
|
21
21
|
|
|
@@ -84,6 +84,7 @@ class DICRegionOfInterest:
|
|
|
84
84
|
self.height = None
|
|
85
85
|
self.width = None
|
|
86
86
|
self.subset_size = None
|
|
87
|
+
self.coord_label = None
|
|
87
88
|
|
|
88
89
|
def interactive_selection(self, subset_size):
|
|
89
90
|
"""
|
|
@@ -117,6 +118,8 @@ class DICRegionOfInterest:
|
|
|
117
118
|
|
|
118
119
|
# Create graphics widget
|
|
119
120
|
self.graphics_widget = pg.GraphicsLayoutWidget()
|
|
121
|
+
|
|
122
|
+
|
|
120
123
|
|
|
121
124
|
main_layout.addLayout(sidebar)
|
|
122
125
|
main_layout.addWidget(self.graphics_widget)
|
|
@@ -165,7 +168,27 @@ class DICRegionOfInterest:
|
|
|
165
168
|
self.buttons['undo_prev'].setEnabled(False)
|
|
166
169
|
self.buttons['redo_prev'].setEnabled(False)
|
|
167
170
|
|
|
171
|
+
self.coord_label = QtWidgets.QLabel("(-, -)")
|
|
172
|
+
self.coord_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight)
|
|
173
|
+
|
|
174
|
+
# Set fixed width to handle largest expected value comfortably
|
|
175
|
+
self.coord_label.setMinimumWidth(350)
|
|
176
|
+
self.coord_label.setMaximumWidth(350)
|
|
177
|
+
|
|
178
|
+
self.coord_label.setStyleSheet("""
|
|
179
|
+
QLabel {
|
|
180
|
+
background-color: rgba(0, 0, 0, 150);
|
|
181
|
+
color: white;
|
|
182
|
+
padding: 5px;
|
|
183
|
+
border-radius: 3px;
|
|
184
|
+
font-family: monospace;
|
|
185
|
+
font-size: 12px;
|
|
186
|
+
}
|
|
187
|
+
""")
|
|
188
|
+
|
|
168
189
|
sidebar.addStretch()
|
|
190
|
+
sidebar.addWidget(self.coord_label)
|
|
191
|
+
|
|
169
192
|
return sidebar
|
|
170
193
|
|
|
171
194
|
def _setup_graphics(self):
|
|
@@ -222,6 +245,24 @@ class DICRegionOfInterest:
|
|
|
222
245
|
self.buttons[btn_id].clicked.connect(handler)
|
|
223
246
|
|
|
224
247
|
self.main_view.scene().sigMouseClicked.connect(self._mouse_clicked)
|
|
248
|
+
self.main_view.scene().sigMouseMoved.connect(self._mouse_moved)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _mouse_moved(self, pos):
|
|
252
|
+
"""Handle mouse movement to update coordinate display."""
|
|
253
|
+
if self.main_view.sceneBoundingRect().contains(pos):
|
|
254
|
+
mouse_point = self.main_view.mapSceneToView(pos)
|
|
255
|
+
# Convert from graphics coordinates to image coordinates
|
|
256
|
+
img_x = int(round(mouse_point.x()))
|
|
257
|
+
img_y = int(round(self.width - mouse_point.y()))
|
|
258
|
+
|
|
259
|
+
# Clamp coordinates to image bounds
|
|
260
|
+
img_x = max(0, min(img_x, self.height - 1))
|
|
261
|
+
img_y = max(0, min(img_y, self.width - 1))
|
|
262
|
+
|
|
263
|
+
self.coord_label.setText(f"({img_x}, {img_y})")
|
|
264
|
+
else:
|
|
265
|
+
self.coord_label.setText("(-, -)")
|
|
225
266
|
|
|
226
267
|
def _start_drawing_mode(self, mode):
|
|
227
268
|
"""Start drawing mode for specified shape type."""
|
|
@@ -536,7 +577,7 @@ class DICRegionOfInterest:
|
|
|
536
577
|
self._update_button_states()
|
|
537
578
|
|
|
538
579
|
def _save_interactive_roi(self):
|
|
539
|
-
"""Save the current ROI to a YAML file."""
|
|
580
|
+
"""Save the current ROI to a YAML file. This only works with the interactive GUI."""
|
|
540
581
|
filename, _ = QtWidgets.QFileDialog.getSaveFileName(self.main_window, 'Save ROI', 'roi_interactive.yaml', filter='YAML Files (*.yaml)')
|
|
541
582
|
|
|
542
583
|
if filename:
|
|
@@ -566,7 +607,7 @@ class DICRegionOfInterest:
|
|
|
566
607
|
yaml.dump(serialized, f, sort_keys=False)
|
|
567
608
|
|
|
568
609
|
def _open_interactive_roi(self):
|
|
569
|
-
"""Open ROI from a YAML file."""
|
|
610
|
+
"""Open ROI from a YAML file. This only works with the interactive GUI."""
|
|
570
611
|
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
|
|
571
612
|
self.main_window, 'Open ROI', filter='YAML Files (*.yaml)'
|
|
572
613
|
)
|
|
@@ -586,6 +627,7 @@ class DICRegionOfInterest:
|
|
|
586
627
|
if entry.get('type') == 'SeedROI':
|
|
587
628
|
# Restore the seed ROI
|
|
588
629
|
x, y = entry['pos']
|
|
630
|
+
y = self.width-y
|
|
589
631
|
size = entry.get('size', [10, 10]) # fallback default
|
|
590
632
|
self.seed_roi = pg.RectROI(
|
|
591
633
|
[x, y], size,
|
|
@@ -671,13 +713,13 @@ class DICRegionOfInterest:
|
|
|
671
713
|
def _finalize_selection(self):
|
|
672
714
|
"""Process the final mask and seed location."""
|
|
673
715
|
self.mask = np.flipud(self.temp_mask.T)
|
|
674
|
-
|
|
716
|
+
|
|
675
717
|
if hasattr(self, 'seed_roi'):
|
|
676
718
|
pos = self.seed_roi.pos()
|
|
677
719
|
x = int(np.floor(pos.x()))
|
|
678
720
|
y = int(np.floor(self.width - pos.y()))
|
|
679
721
|
self.seed = [x, y]
|
|
680
|
-
|
|
722
|
+
|
|
681
723
|
if not self.mask[y, x]:
|
|
682
724
|
raise ValueError(f"Seed location [{x}, {y}] is not within the mask")
|
|
683
725
|
print(f"Final seed location: [{x}, {y}]")
|
|
@@ -833,6 +875,111 @@ class DICRegionOfInterest:
|
|
|
833
875
|
self.__roi_selected = True
|
|
834
876
|
|
|
835
877
|
|
|
878
|
+
def save_yaml(self, filename: str | Path) -> None:
|
|
879
|
+
"""
|
|
880
|
+
Save the current ROI to a YAML file. This only works with the after having run the interactive GUI.
|
|
881
|
+
|
|
882
|
+
Parameters
|
|
883
|
+
----------
|
|
884
|
+
filename : str or pathlib.Path
|
|
885
|
+
Filename of the YAML file to save the ROI data.
|
|
886
|
+
|
|
887
|
+
Raises
|
|
888
|
+
------
|
|
889
|
+
ValueError
|
|
890
|
+
If no ROI has been selected.
|
|
891
|
+
"""
|
|
892
|
+
|
|
893
|
+
if filename:
|
|
894
|
+
|
|
895
|
+
# Ensure extension is added if user doesn't include it
|
|
896
|
+
if filename and not filename.endswith('.yaml'):
|
|
897
|
+
filename += '.yaml'
|
|
898
|
+
|
|
899
|
+
print("Saving to file:", filename)
|
|
900
|
+
serialized = [
|
|
901
|
+
self._get_roi_data(roi, add)
|
|
902
|
+
for roi, add in zip(self.roi_list, self.add_list)
|
|
903
|
+
]
|
|
904
|
+
|
|
905
|
+
# add ROI to serialized data
|
|
906
|
+
if hasattr(self, 'seed_roi'):
|
|
907
|
+
self._finalize_selection()
|
|
908
|
+
seed_data = {
|
|
909
|
+
'type': 'SeedROI',
|
|
910
|
+
'pos': [self.seed[0], self.seed[1]],
|
|
911
|
+
'size': [self.subset_size, self.subset_size],
|
|
912
|
+
'add': True
|
|
913
|
+
}
|
|
914
|
+
serialized.append(seed_data)
|
|
915
|
+
|
|
916
|
+
with open(filename, 'w') as f:
|
|
917
|
+
yaml.dump(serialized, f, sort_keys=False)
|
|
918
|
+
|
|
919
|
+
def read_yaml(self, filename: str | Path) -> None:
|
|
920
|
+
"""
|
|
921
|
+
Load the ROI from a YAML file and restore the state of the GUI.
|
|
922
|
+
This method will clear existing ROIs and restore the state from the YAML file.
|
|
923
|
+
|
|
924
|
+
Parameters
|
|
925
|
+
----------
|
|
926
|
+
filename : str or pathlib.Path
|
|
927
|
+
Path to the YAML file containing the ROI data.
|
|
928
|
+
|
|
929
|
+
Raises
|
|
930
|
+
------
|
|
931
|
+
FileNotFoundError
|
|
932
|
+
If the specified file does not exist.
|
|
933
|
+
ValueError
|
|
934
|
+
If the loaded data is not a valid ROI format.
|
|
935
|
+
"""
|
|
936
|
+
|
|
937
|
+
# need to create a temp qapplication so I can import the ROI.
|
|
938
|
+
self.__roi_selected = True
|
|
939
|
+
|
|
940
|
+
# Initialize GUI
|
|
941
|
+
self._setup_gui()
|
|
942
|
+
self._setup_graphics()
|
|
943
|
+
self._connect_signals()
|
|
944
|
+
|
|
945
|
+
if filename:
|
|
946
|
+
with open(filename, 'r') as f:
|
|
947
|
+
data = yaml.safe_load(f)
|
|
948
|
+
|
|
949
|
+
self.roi_list = []
|
|
950
|
+
self.add_list = []
|
|
951
|
+
|
|
952
|
+
self.seed_roi = None # Clear existing seed
|
|
953
|
+
|
|
954
|
+
for entry in data:
|
|
955
|
+
if entry.get('type') == 'SeedROI':
|
|
956
|
+
# Restore the seed ROI
|
|
957
|
+
x, y = entry['pos']
|
|
958
|
+
y = self.width-y
|
|
959
|
+
size = entry.get('size', [10, 10]) # fallback default
|
|
960
|
+
self.seed_roi = pg.RectROI(
|
|
961
|
+
[x, y], size,
|
|
962
|
+
pen=pg.mkPen('b', width=3),
|
|
963
|
+
hoverPen=pg.mkPen('y', width=3),
|
|
964
|
+
handlePen='#0000',
|
|
965
|
+
handleHoverPen='#0000'
|
|
966
|
+
)
|
|
967
|
+
self.main_view.addItem(self.seed_roi)
|
|
968
|
+
|
|
969
|
+
else:
|
|
970
|
+
# Restore standard ROI
|
|
971
|
+
roi = self._create_roi_from_data(entry)
|
|
972
|
+
self.roi_list.append(roi)
|
|
973
|
+
self.add_list.append(entry['add'])
|
|
974
|
+
self.main_view.addItem(roi)
|
|
975
|
+
roi.sigRegionChanged.connect(self._redraw_fill_layer)
|
|
976
|
+
|
|
977
|
+
self._redraw_fill_layer()
|
|
978
|
+
self._update_button_states()
|
|
979
|
+
self._finalize_selection()
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
|
|
836
983
|
def show_image(self) -> None:
|
|
837
984
|
"""
|
|
838
985
|
Displays the current mask in grayscale.
|
|
@@ -842,20 +989,30 @@ class DICRegionOfInterest:
|
|
|
842
989
|
ValueError: If no ROI is selected.
|
|
843
990
|
"""
|
|
844
991
|
|
|
845
|
-
|
|
846
|
-
if
|
|
847
|
-
|
|
992
|
+
# Convert grayscale image to 3-channel if needed
|
|
993
|
+
if self.ref_image.ndim == 2:
|
|
994
|
+
ref_image_color = cv2.cvtColor(self.ref_image.astype(np.uint8), cv2.COLOR_GRAY2BGR)
|
|
995
|
+
else:
|
|
996
|
+
ref_image_color = self.ref_image
|
|
848
997
|
|
|
849
998
|
# Create a green mask image
|
|
850
|
-
|
|
999
|
+
if self.ref_image.ndim == 3:
|
|
1000
|
+
green_mask = np.zeros_like(self.ref_image)
|
|
1001
|
+
elif self.ref_image.ndim == 2:
|
|
1002
|
+
h, w = self.ref_image.shape
|
|
1003
|
+
green_mask = np.zeros((h, w, 3), dtype=self.ref_image.dtype)
|
|
1004
|
+
else:
|
|
1005
|
+
raise ValueError(f"Unsupported image shape: {self.ref_image.shape}")
|
|
851
1006
|
|
|
852
|
-
|
|
1007
|
+
# Apply the green mask
|
|
1008
|
+
green_mask[self.mask, :] = [0, 255, 0]
|
|
853
1009
|
|
|
854
|
-
# Blend the original image and the mask
|
|
855
|
-
blended =
|
|
1010
|
+
# Blend the original image and the green mask
|
|
1011
|
+
blended = ref_image_color.astype(float) * 0.7 + green_mask.astype(float) * 0.3
|
|
856
1012
|
blended = blended.astype(np.uint8)
|
|
857
1013
|
|
|
858
1014
|
# Display using Matplotlib
|
|
1015
|
+
import matplotlib.pyplot as plt
|
|
859
1016
|
plt.figure()
|
|
860
1017
|
plt.imshow(blended)
|
|
861
1018
|
plt.axis('off')
|
|
@@ -9,7 +9,7 @@ from dataclasses import dataclass
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
11
|
@dataclass(slots=True)
|
|
12
|
-
class
|
|
12
|
+
class Results:
|
|
13
13
|
"""
|
|
14
14
|
Data container for Digital Image Correlation (DIC) analysis results.
|
|
15
15
|
|
|
@@ -38,6 +38,8 @@ class DICResults:
|
|
|
38
38
|
Final `xtol` value from the optimization routine, indicating solution tolerance.
|
|
39
39
|
niter : np.ndarray
|
|
40
40
|
Number of iterations taken to converge for each subset point.
|
|
41
|
+
shape_params : np.ndarray | None
|
|
42
|
+
Optional shape parameters if output during DIC calculation (e.g., affine, rigid).
|
|
41
43
|
filenames : list[str]
|
|
42
44
|
name of DIC result files that have been found
|
|
43
45
|
"""
|
|
@@ -52,4 +54,5 @@ class DICResults:
|
|
|
52
54
|
ftol: np.ndarray
|
|
53
55
|
xtol: np.ndarray
|
|
54
56
|
niter: np.ndarray
|
|
57
|
+
shape_params: np.ndarray
|
|
55
58
|
filenames: list[str]
|
|
@@ -9,13 +9,13 @@ import numpy as np
|
|
|
9
9
|
import glob
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
from pyvale.
|
|
15
|
-
from pyvale.
|
|
16
|
-
from pyvale.
|
|
12
|
+
# pyvale
|
|
13
|
+
import pyvale.dic.dic2dcpp as dic2dcpp
|
|
14
|
+
from pyvale.dic.dicstrainresults import StrainResults
|
|
15
|
+
from pyvale.dic.dicchecks import check_strain_files, check_output_directory
|
|
16
|
+
from pyvale.dic.dicdataimport import data_import
|
|
17
17
|
|
|
18
|
-
def
|
|
18
|
+
def strain_two_dimensional(data: str | Path,
|
|
19
19
|
window_size: int=5,
|
|
20
20
|
window_element: int=4,
|
|
21
21
|
input_binary: bool=False,
|
|
@@ -80,10 +80,10 @@ def strain_2d(data: str | Path,
|
|
|
80
80
|
if window_size % 2 == 0:
|
|
81
81
|
raise ValueError(f"Invalid strain window size: '{window_size}'. Must be an odd number.")
|
|
82
82
|
|
|
83
|
-
filenames =
|
|
83
|
+
filenames = check_strain_files(strain_files=data)
|
|
84
84
|
|
|
85
85
|
# Load data if a file path is given
|
|
86
|
-
results =
|
|
86
|
+
results = data_import(layout="matrix", data=str(data),
|
|
87
87
|
binary=input_binary, delimiter=input_delimiter)
|
|
88
88
|
|
|
89
89
|
# Extract dimensions from the validated object
|
|
@@ -92,7 +92,7 @@ def strain_2d(data: str | Path,
|
|
|
92
92
|
nimg = results.u.shape[0]
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
check_output_directory(str(output_basepath), output_prefix)
|
|
96
96
|
|
|
97
97
|
# assigning c++ struct vals for save config
|
|
98
98
|
strain_save_conf = dic2dcpp.SaveConfig()
|
|
@@ -18,8 +18,11 @@ Test case: Scalar field point sensors (thermocouples) on a 2D thermal simulation
|
|
|
18
18
|
|
|
19
19
|
from pathlib import Path
|
|
20
20
|
import matplotlib.pyplot as plt
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
# Pyvale imports
|
|
23
|
+
import pyvale.sensorsim as sens
|
|
24
|
+
import pyvale.mooseherder as mh
|
|
25
|
+
import pyvale.dataset as dataset
|
|
23
26
|
|
|
24
27
|
#%%
|
|
25
28
|
# Here we load a pre-generated MOOSE finite element simulation dataset that
|
|
@@ -28,13 +31,13 @@ import pyvale as pyv
|
|
|
28
31
|
# to your own MOOSE simulation with exodus output (*.e). Note that the
|
|
29
32
|
# field_key must match the name of your variable in your MOOSE simulation.
|
|
30
33
|
# We use `mooseherder` to load the exodus file into a `SimData` object.
|
|
31
|
-
data_path =
|
|
34
|
+
data_path = dataset.thermal_2d_path()
|
|
32
35
|
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
33
36
|
|
|
34
37
|
#%%
|
|
35
38
|
# Scale to mm to make 3D visualisation scaling easier as pyvista scales
|
|
36
39
|
# everything to unity
|
|
37
|
-
sim_data =
|
|
40
|
+
sim_data = sens.scale_length_units(scale=1000.0,
|
|
38
41
|
sim_data=sim_data,
|
|
39
42
|
disp_comps=None)
|
|
40
43
|
|
|
@@ -46,14 +49,14 @@ n_sens = (3,2,1)
|
|
|
46
49
|
x_lims = (0.0,100.0)
|
|
47
50
|
y_lims = (0.0,50.0)
|
|
48
51
|
z_lims = (0.0,0.0)
|
|
49
|
-
sens_pos =
|
|
52
|
+
sens_pos = sens.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
|
|
50
53
|
|
|
51
54
|
#%%
|
|
52
55
|
# This dataclass contains the parameters to build our sensor array. We can
|
|
53
56
|
# also customise the output frequency, the sensor area and the sensor
|
|
54
57
|
# orientation. For now we will use the defaults which assumes an ideal point
|
|
55
58
|
# sensor sampling at the simulation time steps.
|
|
56
|
-
sens_data =
|
|
59
|
+
sens_data = sens.SensorData(positions=sens_pos)
|
|
57
60
|
|
|
58
61
|
#%%
|
|
59
62
|
# Now that we have our sensor locations we can use the sensor factory to
|
|
@@ -63,7 +66,7 @@ sens_data = pyv.SensorData(positions=sens_pos)
|
|
|
63
66
|
# If you want to remove the simulated errors and just interpolate at the
|
|
64
67
|
# sensor locations then user `.thermocouples_no_errs()`.
|
|
65
68
|
field_key: str = "temperature"
|
|
66
|
-
tc_array =
|
|
69
|
+
tc_array = sens.SensorArrayFactory \
|
|
67
70
|
.thermocouples_basic_errs(sim_data,
|
|
68
71
|
sens_data,
|
|
69
72
|
elem_dims=2,
|
|
@@ -93,7 +96,7 @@ if not output_path.is_dir():
|
|
|
93
96
|
# This creates a pyvista visualisation of the sensor locations on the
|
|
94
97
|
# simulation mesh. The plot will can be shown in interactive mode by calling
|
|
95
98
|
# `pv_plot.show()`.
|
|
96
|
-
pv_plot =
|
|
99
|
+
pv_plot = sens.plot_point_sensors_on_sim(tc_array,field_key)
|
|
97
100
|
|
|
98
101
|
#%%
|
|
99
102
|
# We determined manually by moving camera in interative mode and then
|
|
@@ -125,7 +128,7 @@ print(80*"-"+"\n")
|
|
|
125
128
|
# markers shows the simulated sensor traces. In later examples we will see
|
|
126
129
|
# how to configure this plot but for now we note we that we are returned a
|
|
127
130
|
# matplotlib figure and axes object which allows for further customisation.
|
|
128
|
-
(fig,ax) =
|
|
131
|
+
(fig,ax) = sens.plot_time_traces(tc_array,field_key)
|
|
129
132
|
|
|
130
133
|
#%%
|
|
131
134
|
# We can also save the sensor trace plot as a vector and raster graphic
|
|
@@ -29,8 +29,11 @@ Test case: Scalar field point sensors (thermocouples) on a 2D thermal simulation
|
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
31
|
import matplotlib.pyplot as plt
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
|
|
33
|
+
# Pyvale imports
|
|
34
|
+
import pyvale.sensorsim as sens
|
|
35
|
+
import pyvale.mooseherder as mh
|
|
36
|
+
import pyvale.dataset as dataset
|
|
34
37
|
|
|
35
38
|
|
|
36
39
|
#%%
|
|
@@ -40,14 +43,14 @@ import pyvale as pyv
|
|
|
40
43
|
# Here we load a pre-generated MOOSE finite element simulation dataset that
|
|
41
44
|
# comes packaged with pyvale. The simulation is a 2D rectangular plate with
|
|
42
45
|
# a bi-directional temperature gradient.
|
|
43
|
-
data_path =
|
|
46
|
+
data_path = dataset.thermal_2d_path()
|
|
44
47
|
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
45
48
|
field_key: str = "temperature"
|
|
46
49
|
|
|
47
50
|
#%%
|
|
48
51
|
# Scale to mm to make 3D visualisation scaling easier as pyvista scales
|
|
49
52
|
# everything to unity
|
|
50
|
-
sim_data =
|
|
53
|
+
sim_data = sens.scale_length_units(scale=1000.0,
|
|
51
54
|
sim_data=sim_data,
|
|
52
55
|
disp_comps=None)
|
|
53
56
|
|
|
@@ -59,14 +62,14 @@ n_sens = (4,1,1)
|
|
|
59
62
|
x_lims = (0.0,100.0)
|
|
60
63
|
y_lims = (0.0,50.0)
|
|
61
64
|
z_lims = (0.0,0.0)
|
|
62
|
-
sens_pos =
|
|
65
|
+
sens_pos = sens.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
|
|
63
66
|
|
|
64
67
|
#%%
|
|
65
68
|
# This dataclass contains the parameters to build our sensor array. We can
|
|
66
69
|
# also customise the output frequency, the sensor area and the sensor
|
|
67
70
|
# orientation. For now we will use the defaults which assumes an ideal point
|
|
68
71
|
# sensor sampling at the simulation time steps.
|
|
69
|
-
sens_data =
|
|
72
|
+
sens_data = sens.SensorData(positions=sens_pos)
|
|
70
73
|
|
|
71
74
|
#%%
|
|
72
75
|
# Now that we have our sensor locations we can use the sensor factory to
|
|
@@ -74,7 +77,7 @@ sens_data = pyv.SensorData(positions=sens_pos)
|
|
|
74
77
|
# examples we will see how to customise sensor parameters and errors.
|
|
75
78
|
# This basic thermocouple array includes a 5% systematic and random error -
|
|
76
79
|
# We are specifically using exaggerated errors here for visualisation.
|
|
77
|
-
tc_array =
|
|
80
|
+
tc_array = sens.SensorArrayFactory \
|
|
78
81
|
.thermocouples_basic_errs(sim_data,
|
|
79
82
|
sens_data,
|
|
80
83
|
elem_dims=2,
|
|
@@ -111,16 +114,16 @@ print(80*"-")
|
|
|
111
114
|
print(f"Looking at the last {time_last} virtual measurements for sensor"
|
|
112
115
|
+f" {sens_print}:")
|
|
113
116
|
|
|
114
|
-
|
|
117
|
+
sens.print_measurements(tc_array,sens_print,comp_print,time_print)
|
|
115
118
|
|
|
116
119
|
print(80*"-")
|
|
117
120
|
print("If we call the `calc_measurements()` method then the errors are "
|
|
118
121
|
+ "re-calculated.")
|
|
119
122
|
measurements = tc_array.calc_measurements()
|
|
120
123
|
|
|
121
|
-
|
|
124
|
+
sens.print_measurements(tc_array,sens_print,comp_print,time_print)
|
|
122
125
|
|
|
123
|
-
(fig,ax) =
|
|
126
|
+
(fig,ax) = sens.plot_time_traces(tc_array,field_key)
|
|
124
127
|
ax.set_title("Exp 1: called calc_measurements()")
|
|
125
128
|
|
|
126
129
|
print(80*"-")
|
|
@@ -128,9 +131,9 @@ print("If we call the `get_measurements()` method then the errors are the "
|
|
|
128
131
|
+ "same:")
|
|
129
132
|
measurements = tc_array.get_measurements()
|
|
130
133
|
|
|
131
|
-
|
|
134
|
+
sens.print_measurements(tc_array,sens_print,comp_print,time_print)
|
|
132
135
|
|
|
133
|
-
(fig,ax) =
|
|
136
|
+
(fig,ax) = sens.plot_time_traces(tc_array,field_key)
|
|
134
137
|
ax.set_title("Exp 2: called get_measurements()")
|
|
135
138
|
|
|
136
139
|
print(80*"-")
|
|
@@ -138,9 +141,9 @@ print("If we call the `calc_measurements()` method again we generate / "
|
|
|
138
141
|
"sample new errors:")
|
|
139
142
|
measurements = tc_array.calc_measurements()
|
|
140
143
|
|
|
141
|
-
|
|
144
|
+
sens.print_measurements(tc_array,sens_print,comp_print,time_print)
|
|
142
145
|
|
|
143
|
-
(fig,ax) =
|
|
146
|
+
(fig,ax) = sens.plot_time_traces(tc_array,field_key)
|
|
144
147
|
ax.set_title("Exp 3: called calc_measurements()")
|
|
145
148
|
|
|
146
149
|
print(80*"-")
|
|
@@ -18,8 +18,11 @@ Test case: Scalar field point sensors (thermocouples) on a 3D thermal simulation
|
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
import numpy as np
|
|
20
20
|
import matplotlib.pyplot as plt
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
# Pyvale imports
|
|
23
|
+
import pyvale.mooseherder as mh
|
|
24
|
+
import pyvale.sensorsim as sens
|
|
25
|
+
import pyvale.dataset as dataset
|
|
23
26
|
|
|
24
27
|
#%%
|
|
25
28
|
# To build our custom point sensor array we need to at minimum provide a
|
|
@@ -32,9 +35,9 @@ import pyvale as pyv
|
|
|
32
35
|
# based on the same thermal example we have used in the last two examples so
|
|
33
36
|
# we start by loading our simulation data:
|
|
34
37
|
|
|
35
|
-
data_path =
|
|
38
|
+
data_path = dataset.thermal_3d_path()
|
|
36
39
|
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
37
|
-
sim_data =
|
|
40
|
+
sim_data = sens.scale_length_units(scale=1000.0,
|
|
38
41
|
sim_data=sim_data,
|
|
39
42
|
disp_comps=None)
|
|
40
43
|
|
|
@@ -43,7 +46,7 @@ sim_data = pyv.scale_length_units(scale=1000.0,
|
|
|
43
46
|
# field object to perform interpolation to the sensor locations at the
|
|
44
47
|
# desired sampling times.
|
|
45
48
|
field_key: str = "temperature"
|
|
46
|
-
t_field =
|
|
49
|
+
t_field = sens.FieldScalar(sim_data,
|
|
47
50
|
field_key=field_key,
|
|
48
51
|
elem_dims=3)
|
|
49
52
|
|
|
@@ -56,7 +59,7 @@ n_sens = (1,4,1)
|
|
|
56
59
|
x_lims = (12.5,12.5)
|
|
57
60
|
y_lims = (0.0,33.0)
|
|
58
61
|
z_lims = (0.0,12.0)
|
|
59
|
-
sens_pos =
|
|
62
|
+
sens_pos = sens.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
|
|
60
63
|
|
|
61
64
|
#%%
|
|
62
65
|
# We are also going to specify the times at which we would like to simulate
|
|
@@ -64,8 +67,8 @@ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
|
|
|
64
67
|
# to match the simulation time steps.
|
|
65
68
|
sample_times = np.linspace(0.0,np.max(sim_data.time),50)
|
|
66
69
|
|
|
67
|
-
sensor_data =
|
|
68
|
-
|
|
70
|
+
sensor_data = sens.SensorData(positions=sens_pos,
|
|
71
|
+
sample_times=sample_times)
|
|
69
72
|
|
|
70
73
|
#%%
|
|
71
74
|
# Finally, we can create a `SensorDescriptor` which will be used to label
|
|
@@ -73,20 +76,20 @@ sensor_data = pyv.SensorData(positions=sens_pos,
|
|
|
73
76
|
# examples.
|
|
74
77
|
use_auto_descriptor: str = "blank"
|
|
75
78
|
if use_auto_descriptor == "manual":
|
|
76
|
-
descriptor =
|
|
79
|
+
descriptor = sens.SensorDescriptor(name="Temperature",
|
|
77
80
|
symbol="T",
|
|
78
81
|
units = r"^{\circ}C",
|
|
79
82
|
tag = "TC")
|
|
80
83
|
elif use_auto_descriptor == "factory":
|
|
81
|
-
descriptor =
|
|
84
|
+
descriptor = sens.SensorDescriptorFactory.temperature_descriptor()
|
|
82
85
|
else:
|
|
83
|
-
descriptor =
|
|
86
|
+
descriptor = sens.SensorDescriptor()
|
|
84
87
|
|
|
85
88
|
#%%
|
|
86
89
|
# We can now build our custom point sensor array. This sensor array has no
|
|
87
90
|
# errors so if we call `get_measurements()` or `calc_measurements()` we will
|
|
88
91
|
# be able to extract the simulation truth values at the sensor locations.
|
|
89
|
-
tc_array =
|
|
92
|
+
tc_array = sens.SensorArrayPoint(sensor_data,
|
|
90
93
|
t_field,
|
|
91
94
|
descriptor)
|
|
92
95
|
|
|
@@ -101,7 +104,7 @@ output_path = Path.cwd() / "pyvale-output"
|
|
|
101
104
|
if not output_path.is_dir():
|
|
102
105
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
103
106
|
|
|
104
|
-
pv_plot =
|
|
107
|
+
pv_plot = sens.plot_point_sensors_on_sim(tc_array,field_key)
|
|
105
108
|
|
|
106
109
|
pv_plot.camera_position = [(59.354, 43.428, 69.946),
|
|
107
110
|
(-2.858, 13.189, 4.523),
|
|
@@ -149,8 +152,8 @@ errors_on = {"sys": True,
|
|
|
149
152
|
|
|
150
153
|
error_chain = []
|
|
151
154
|
if errors_on["sys"]:
|
|
152
|
-
error_chain.append(
|
|
153
|
-
error_chain.append(
|
|
155
|
+
error_chain.append(sens.ErrSysOffset(offset=-10.0))
|
|
156
|
+
error_chain.append(sens.ErrSysUnif(low=-10.0,
|
|
154
157
|
high=10.0))
|
|
155
158
|
#%%
|
|
156
159
|
# This random error is generated by sampling from a normal distribution
|
|
@@ -159,8 +162,8 @@ if errors_on["sys"]:
|
|
|
159
162
|
# probability distribution
|
|
160
163
|
|
|
161
164
|
if errors_on["rand"]:
|
|
162
|
-
error_chain.append(
|
|
163
|
-
error_chain.append(
|
|
165
|
+
error_chain.append(sens.ErrRandNorm(std=5.0))
|
|
166
|
+
error_chain.append(sens.ErrRandUnifPercent(low_percent=-5.0,
|
|
164
167
|
high_percent=5.0))
|
|
165
168
|
|
|
166
169
|
#%%
|
|
@@ -171,11 +174,11 @@ if errors_on["rand"]:
|
|
|
171
174
|
# INDEPENDENT.
|
|
172
175
|
|
|
173
176
|
if len(error_chain) > 0:
|
|
174
|
-
err_int_opts =
|
|
175
|
-
error_integrator =
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
err_int_opts = sens.ErrIntOpts()
|
|
178
|
+
error_integrator = sens.ErrIntegrator(error_chain,
|
|
179
|
+
sensor_data,
|
|
180
|
+
tc_array.get_measurement_shape(),
|
|
181
|
+
err_int_opts=err_int_opts)
|
|
179
182
|
tc_array.set_error_integrator(error_integrator)
|
|
180
183
|
|
|
181
184
|
#%%
|
|
@@ -204,11 +207,11 @@ time_print = slice(measurements.shape[2]-time_last,measurements.shape[2])
|
|
|
204
207
|
print(f"These are the last {time_last} virtual measurements of sensor "
|
|
205
208
|
+ f"{sens_print}:")
|
|
206
209
|
|
|
207
|
-
|
|
210
|
+
sens.print_measurements(tc_array,sens_print,comp_print,time_print)
|
|
208
211
|
|
|
209
212
|
print(80*"-")
|
|
210
213
|
|
|
211
|
-
(fig,ax) =
|
|
214
|
+
(fig,ax) = sens.plot_time_traces(tc_array,field_key)
|
|
212
215
|
|
|
213
216
|
save_traces = output_path/"customsensors_ex1_3_sensortraces.png"
|
|
214
217
|
fig.savefig(save_traces, dpi=300, bbox_inches="tight")
|