wolfhece 2.2.28__py3-none-any.whl → 2.2.29__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.
- wolfhece/PyConfig.py +27 -3
- wolfhece/PyDraw.py +192 -20
- wolfhece/PyVertexvectors.py +155 -21
- wolfhece/PyWMS.py +6 -3
- wolfhece/__init__.py +27 -0
- wolfhece/acceptability/acceptability.py +25 -20
- wolfhece/acceptability/acceptability_gui.py +150 -92
- wolfhece/acceptability/func.py +169 -82
- wolfhece/apps/version.py +1 -1
- wolfhece/irm_qdf.py +71 -7
- wolfhece/lb7208_ntv2/__init__.py +0 -0
- wolfhece/lb7208_ntv2/be_ign_README.txt +36 -0
- wolfhece/lb7208_ntv2/be_ign_bd72lb72_etrs89lb08.tif +0 -0
- wolfhece/lb7208_ntv2/be_ign_hBG18.tif +0 -0
- wolfhece/mesh2d/gpu_2d.py +11 -2
- wolfhece/report/compare_arrays.py +268 -58
- wolfhece/report/simplesimgpu.py +25 -6
- wolfhece/scenario/config_manager.py +243 -7
- wolfhece/ui/wolf_multiselection_collapsiblepane.py +153 -1
- wolfhece/wolf_array.py +67 -62
- wolfhece/wolf_texture.py +4 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/METADATA +1 -1
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/RECORD +26 -22
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/WHEEL +0 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
# be_ign_README.txt
|
2
|
+
|
3
|
+
The files in this section result from the conversion of datasets originating
|
4
|
+
from [IGN Belgium](http://www.ngi.be)
|
5
|
+
|
6
|
+
## Included grids
|
7
|
+
|
8
|
+
### Belgium: BD72 -> ETRS89
|
9
|
+
|
10
|
+
Grid transformation from Belgium Datum 72 to ETRS89 in Belgium.
|
11
|
+
|
12
|
+
*Source*: [IGN](http://www.ngi.be/Common/Lambert2008/NTv2.zip)
|
13
|
+
*Format*: GeoTIFF converted from NTv2
|
14
|
+
*License*: [Creative Commons Attribution 4.0](https://creativecommons.org/licenses/by/4.0/)
|
15
|
+
*Credit*: (c)2014-2016 Grid created by Nicolas SIMON.
|
16
|
+
|
17
|
+
It provides an accuracy better than 5mm in 99.6% of validation points and a
|
18
|
+
worst case of 1.3 cm outside the border.
|
19
|
+
Recommended to transform from Belgian Lambert 72 (EPSG:31370) to Belgian Lambert 2008 (EPSG:3812)
|
20
|
+
Documentation in French: (http://www.ngi.be/FR/FR2-1-7.shtm)
|
21
|
+
Documentation in Dutch: (http://www.ngi.be/NL/NL2-1-7.shtm)
|
22
|
+
|
23
|
+
* be_ign_bd72lb72_etrs89lb08.tif
|
24
|
+
|
25
|
+
### Belgium vertical grid:
|
26
|
+
|
27
|
+
*Source*: [IGN](https://www.ngi.be/website/wp-content/uploads/2020/07/hBG18_fr.zip)
|
28
|
+
*Format*: GeoTIFF converted from 'XYZ ASCII Grid'
|
29
|
+
*License*: [Creative Commons Attribution 4.0](https://creativecommons.org/licenses/by/4.0/)
|
30
|
+
*Credit*: C. Slobbe, R. Klees, H.H. Farahani, L. Huisman, B. Alberts, P. Voet, F. De Doncker (2018). The Belgian hybrid quasi-geoid: hBG18. V. 1.0. GFZ Data Services. http://doi.org/10.5880/isg.2018.003
|
31
|
+
*Horizontal CRS*: EPSG:4937 (ETRS89)
|
32
|
+
|
33
|
+
Vertical transformation for Geoid model hGB18. Used to make the transitions
|
34
|
+
from heights in vertical CRS (EPSG:5710 - Ostend height) to heights above the ellipsoid in ETRS89 (EPSG:4937).
|
35
|
+
|
36
|
+
* be_ign_hBG18.tif
|
Binary file
|
Binary file
|
wolfhece/mesh2d/gpu_2d.py
CHANGED
@@ -88,8 +88,17 @@ class Sim_2D_GPU():
|
|
88
88
|
self.magnetic_grid:header_wolf = None
|
89
89
|
|
90
90
|
if (self.dir /'parameters.json').exists():
|
91
|
-
|
92
|
-
|
91
|
+
try:
|
92
|
+
self._sim = SimpleSimulation.load(self.dir)
|
93
|
+
except Exception as e:
|
94
|
+
logging.error(_("Error loading simulation from directory {dir}: {error}").format(dir=self.dir, error=str(e)))
|
95
|
+
logging.error(_("Please check your files and try again."))
|
96
|
+
return
|
97
|
+
|
98
|
+
try:
|
99
|
+
self.infiltration = infiltration_GPU(self)
|
100
|
+
except Exception as e:
|
101
|
+
logging.error(_("Error initializing infiltration GPU: {error}").format(error=str(e)))
|
93
102
|
|
94
103
|
# Fine arrays with type
|
95
104
|
self.files_array={'Characteristics':[
|
@@ -4,13 +4,17 @@ import numpy.ma as ma
|
|
4
4
|
from pathlib import Path
|
5
5
|
import matplotlib.pyplot as plt
|
6
6
|
from enum import Enum
|
7
|
-
from scipy.ndimage import label, sum_labels
|
7
|
+
from scipy.ndimage import label, sum_labels, find_objects
|
8
8
|
import pymupdf as pdf
|
9
|
+
import wx
|
10
|
+
from tqdm import tqdm
|
11
|
+
from matplotlib import use, get_backend
|
9
12
|
|
10
13
|
from .common import A4_rect, rect_cm, list_to_html, list_to_html_aligned, get_rect_from_text
|
11
14
|
from .common import inches2cm, pts2cm, cm2pts, cm2inches, DefaultLayoutA4, NamedTemporaryFile, pt2inches, TemporaryDirectory
|
12
15
|
from ..wolf_array import WolfArray, header_wolf, vector, zone, Zones, wolfvertex as wv, wolfpalette
|
13
16
|
from ..PyTranslate import _
|
17
|
+
from .pdf import PDFViewer
|
14
18
|
|
15
19
|
class ArrayDifferenceLayout(DefaultLayoutA4):
|
16
20
|
"""
|
@@ -98,8 +102,16 @@ class ArrayDifference():
|
|
98
102
|
|
99
103
|
self._background = 'IGN'
|
100
104
|
|
105
|
+
self._contour = None
|
106
|
+
self._external_border = None
|
107
|
+
|
101
108
|
@property
|
102
109
|
def contour(self) -> vector:
|
110
|
+
""" Get the contour of the difference part. """
|
111
|
+
|
112
|
+
if self._contour is not None and isinstance(self._contour, vector):
|
113
|
+
return self._contour
|
114
|
+
|
103
115
|
ret = self.reference.suxsuy_contour(abs=True)
|
104
116
|
ret = ret[2]
|
105
117
|
|
@@ -111,8 +123,11 @@ class ArrayDifference():
|
|
111
123
|
@property
|
112
124
|
def external_border(self) -> vector:
|
113
125
|
"""
|
114
|
-
Get the bounds of the
|
126
|
+
Get the bounds of the difference part.
|
115
127
|
"""
|
128
|
+
if self._external_border is not None and isinstance(self._external_border, vector):
|
129
|
+
return self._external_border
|
130
|
+
|
116
131
|
ret = vector(name=_("External border"))
|
117
132
|
(xmin, xmax), (ymin, ymax) = self.reference.get_bounds()
|
118
133
|
ret.add_vertex(wv(xmin, ymin))
|
@@ -194,6 +209,13 @@ class ArrayDifference():
|
|
194
209
|
Walonmap= True,
|
195
210
|
cat = 'IMAGERIE/ORTHO_2022_ETE',
|
196
211
|
)
|
212
|
+
else:
|
213
|
+
self.reference.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
214
|
+
first_mask_data=False, with_legend=False,
|
215
|
+
update_palette= False,
|
216
|
+
Walonmap= False,
|
217
|
+
)
|
218
|
+
|
197
219
|
|
198
220
|
self.reference.array.mask[:,:] = old_mask
|
199
221
|
|
@@ -225,11 +247,23 @@ class ArrayDifference():
|
|
225
247
|
new = WolfArray(srcheader=h)
|
226
248
|
new.array.mask[:,:] = True
|
227
249
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
250
|
+
if self._background.upper() == 'IGN' or self._background.upper() == 'NGI':
|
251
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
252
|
+
first_mask_data=False, with_legend=False,
|
253
|
+
update_palette= False,
|
254
|
+
IGN= True,
|
255
|
+
cat = 'orthoimage_coverage')
|
256
|
+
elif self._background.upper() == 'WALONMAP':
|
257
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
258
|
+
first_mask_data=False, with_legend=False,
|
259
|
+
update_palette= False,
|
260
|
+
Walonmap= True,
|
261
|
+
cat = 'IMAGERIE/ORTHO_2022_ETE')
|
262
|
+
else:
|
263
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
264
|
+
first_mask_data=False, with_legend=False,
|
265
|
+
update_palette= False,
|
266
|
+
Walonmap= False)
|
233
267
|
|
234
268
|
self.external_border.plot_matplotlib(ax=ax)
|
235
269
|
|
@@ -295,7 +329,8 @@ class ArrayDifference():
|
|
295
329
|
|
296
330
|
fig, ax = figax
|
297
331
|
|
298
|
-
|
332
|
+
data = self.reference.array.compressed()
|
333
|
+
ax.hist(data, bins = min(100, int(len(data)/4)), density=density, alpha = alpha, **kwargs)
|
299
334
|
# ax.set_xlabel("Value")
|
300
335
|
# ax.set_ylabel("Frequency")
|
301
336
|
return fig, ax
|
@@ -309,7 +344,8 @@ class ArrayDifference():
|
|
309
344
|
|
310
345
|
fig, ax = figax
|
311
346
|
|
312
|
-
|
347
|
+
data = self.to_compare.array.compressed()
|
348
|
+
ax.hist(data, bins= min(100, int(len(data)/4)), density=density, alpha = alpha, **kwargs)
|
313
349
|
# ax.set_xlabel("Value")
|
314
350
|
# ax.set_ylabel("Frequency")
|
315
351
|
return fig, ax
|
@@ -349,7 +385,7 @@ class ArrayDifference():
|
|
349
385
|
fig, ax = figax
|
350
386
|
|
351
387
|
difference_data = self.difference.array.compressed()
|
352
|
-
ax.hist(difference_data, density=density, alpha=alpha, **kwargs)
|
388
|
+
ax.hist(difference_data, bins= min(100, int(len(difference_data)/4)), density=density, alpha=alpha, **kwargs)
|
353
389
|
|
354
390
|
# ax.set_xlabel("Value")
|
355
391
|
# ax.set_ylabel("Frequency")
|
@@ -396,7 +432,6 @@ class ArrayDifference():
|
|
396
432
|
if 'Histogram' in key:
|
397
433
|
fig.tight_layout()
|
398
434
|
|
399
|
-
|
400
435
|
# convert canvas to PNG and insert it into the PDF
|
401
436
|
temp_file = NamedTemporaryFile(delete=False, suffix='.png')
|
402
437
|
fig.savefig(temp_file, format='png', bbox_inches='tight', dpi=self._dpi)
|
@@ -419,6 +454,7 @@ class ArrayDifference():
|
|
419
454
|
def create_report(self, output_file: str | Path = None) -> Path:
|
420
455
|
""" Create a page report for the array difference. """
|
421
456
|
|
457
|
+
from time import sleep
|
422
458
|
if output_file is None:
|
423
459
|
output_file = Path(f"array_difference_{self.index}.pdf")
|
424
460
|
|
@@ -429,6 +465,7 @@ class ArrayDifference():
|
|
429
465
|
layout.create_report()
|
430
466
|
self._complete_report(layout)
|
431
467
|
layout.save_report(output_file)
|
468
|
+
sleep(0.2) # Ensure the file is saved before returning
|
432
469
|
|
433
470
|
return output_file
|
434
471
|
|
@@ -459,6 +496,10 @@ class CompareArrays:
|
|
459
496
|
|
460
497
|
self.difference_parts:dict[int, ArrayDifference] = {}
|
461
498
|
|
499
|
+
self._pdf_path = None
|
500
|
+
|
501
|
+
self._background = 'IGN'
|
502
|
+
|
462
503
|
@property
|
463
504
|
def difference(self) -> WolfArray:
|
464
505
|
|
@@ -467,6 +508,24 @@ class CompareArrays:
|
|
467
508
|
|
468
509
|
return self.array_to_compare - self.array_reference
|
469
510
|
|
511
|
+
def get_zones(self):
|
512
|
+
"""
|
513
|
+
Get a Zones object containing the differences.
|
514
|
+
"""
|
515
|
+
|
516
|
+
ret_zones = Zones()
|
517
|
+
exterior = zone(name=_("External border"))
|
518
|
+
contours = zone(name=_("Contours"))
|
519
|
+
|
520
|
+
ret_zones.add_zone(exterior, forceparent=True)
|
521
|
+
ret_zones.add_zone(contours, forceparent=True)
|
522
|
+
|
523
|
+
for diff in self.difference_parts.values():
|
524
|
+
exterior.add_vector(diff.external_border, forceparent=True)
|
525
|
+
contours.add_vector(diff.contour, forceparent=True)
|
526
|
+
|
527
|
+
return ret_zones
|
528
|
+
|
470
529
|
def plot_position(self, figax:tuple[plt.Figure, plt.Axes]=None) -> tuple[plt.Figure, plt.Axes]:
|
471
530
|
"""
|
472
531
|
Plot the reference array with a background.
|
@@ -487,14 +546,27 @@ class CompareArrays:
|
|
487
546
|
new = WolfArray(srcheader=h)
|
488
547
|
new.array.mask[:,:] = True
|
489
548
|
|
549
|
+
if self._background.upper() == 'IGN' or self._background.upper() == 'NGI':
|
490
550
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
551
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
552
|
+
first_mask_data=False, with_legend=False,
|
553
|
+
update_palette= False,
|
554
|
+
IGN= True,
|
555
|
+
cat = 'orthoimage_coverage',
|
556
|
+
)
|
557
|
+
elif self._background.upper() == 'WALONMAP':
|
558
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
559
|
+
first_mask_data=False, with_legend=False,
|
560
|
+
update_palette= False,
|
561
|
+
Walonmap= True,
|
562
|
+
cat = 'IMAGERIE/ORTHO_2022_ETE',
|
563
|
+
)
|
564
|
+
else:
|
565
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
566
|
+
first_mask_data=False, with_legend=False,
|
567
|
+
update_palette= False,
|
568
|
+
Walonmap= False,
|
569
|
+
)
|
498
570
|
return fig, ax
|
499
571
|
|
500
572
|
def plot_cartoweb(self, figax:tuple[plt.Figure, plt.Axes]=None) -> tuple[plt.Figure, plt.Axes]:
|
@@ -517,14 +589,20 @@ class CompareArrays:
|
|
517
589
|
new = WolfArray(srcheader=h)
|
518
590
|
new.array.mask[:,:] = True
|
519
591
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
592
|
+
if self._background.upper() == 'IGN' or self._background.upper() == 'NGI':
|
593
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
594
|
+
first_mask_data=False, with_legend=False,
|
595
|
+
update_palette= False,
|
596
|
+
Cartoweb= True,
|
597
|
+
cat = 'overlay',
|
598
|
+
)
|
599
|
+
else:
|
600
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
601
|
+
first_mask_data=False, with_legend=False,
|
602
|
+
update_palette= False,
|
603
|
+
Cartoweb= False,
|
604
|
+
cat = 'overlay',
|
605
|
+
)
|
528
606
|
return fig, ax
|
529
607
|
|
530
608
|
def plot_topo_grey(self, figax:tuple[plt.Figure, plt.Axes]=None) -> tuple[plt.Figure, plt.Axes]:
|
@@ -547,14 +625,20 @@ class CompareArrays:
|
|
547
625
|
new = WolfArray(srcheader=h)
|
548
626
|
new.array.mask[:,:] = True
|
549
627
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
628
|
+
if self._background.upper() == 'IGN' or self._background.upper() == 'NGI':
|
629
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
630
|
+
first_mask_data=False, with_legend=False,
|
631
|
+
update_palette= False,
|
632
|
+
Cartoweb= True,
|
633
|
+
cat = 'topo_grey',
|
634
|
+
)
|
635
|
+
else:
|
636
|
+
new.plot_matplotlib(figax=figax, figsize = self.default_size_arrays,
|
637
|
+
first_mask_data=False, with_legend=False,
|
638
|
+
update_palette= False,
|
639
|
+
Cartoweb= False,
|
640
|
+
cat = 'topo_grey',
|
641
|
+
)
|
558
642
|
return fig, ax
|
559
643
|
|
560
644
|
def plot_reference(self, figax:tuple[plt.Figure, plt.Axes]=None) -> tuple[plt.Figure, plt.Axes]:
|
@@ -568,7 +652,7 @@ class CompareArrays:
|
|
568
652
|
|
569
653
|
self.array_reference.plot_matplotlib(figax=figax, figsize = self.default_size_arrays, first_mask_data=False, with_legend=True, update_palette= False)
|
570
654
|
|
571
|
-
for diff in self.difference_parts.values():
|
655
|
+
for diff in tqdm(self.difference_parts.values(), desc="Plotting external borders"):
|
572
656
|
diff.external_border.plot_matplotlib(ax=ax)
|
573
657
|
|
574
658
|
return fig, ax
|
@@ -584,7 +668,7 @@ class CompareArrays:
|
|
584
668
|
|
585
669
|
self.array_to_compare.plot_matplotlib(figax=figax, figsize = self.default_size_arrays, first_mask_data=False, with_legend=True, update_palette= False)
|
586
670
|
|
587
|
-
for diff in self.difference_parts.values():
|
671
|
+
for diff in tqdm(self.difference_parts.values(), desc="Plotting contours"):
|
588
672
|
diff.contour.plot_matplotlib(ax=ax)
|
589
673
|
|
590
674
|
return fig, ax
|
@@ -606,11 +690,22 @@ class CompareArrays:
|
|
606
690
|
diff.plot_matplotlib(figax=figax, figsize = self.default_size_arrays, first_mask_data=False, with_legend=True, update_palette= False)
|
607
691
|
return fig, ax
|
608
692
|
|
609
|
-
def localize_differences(self, threshold: float = 0.0
|
693
|
+
def localize_differences(self, threshold: float = 0.0,
|
694
|
+
ignored_patche_area:float = 1.) -> np.ndarray:
|
695
|
+
""" Localize the differences between the two arrays and label them.
|
696
|
+
|
697
|
+
:param threshold: The threshold value to consider a difference significant.
|
698
|
+
:param ignored_patche_area: The area of patches to ignore (in m²).
|
699
|
+
"""
|
700
|
+
|
701
|
+
assert threshold >= 0, "Threshold must be a non-negative value."
|
610
702
|
|
611
703
|
labeled_array = self.difference.array.data.copy()
|
612
704
|
labeled_array[self.array_reference.array.mask] = 0
|
613
705
|
|
706
|
+
# apply threshold
|
707
|
+
labeled_array[np.abs(labeled_array) < threshold] = 0
|
708
|
+
|
614
709
|
self.labeled_array, self.num_features = label(labeled_array)
|
615
710
|
|
616
711
|
self.nb_cells = []
|
@@ -620,13 +715,29 @@ class CompareArrays:
|
|
620
715
|
|
621
716
|
self.nb_cells.sort(key=lambda x: x[0], reverse=True)
|
622
717
|
|
718
|
+
# find features where nb_cells is lower than ignored_patche_area / (dx * dy)
|
719
|
+
ignored_patche_cells = int(ignored_patche_area / (self.array_reference.dx * self.array_reference.dy))
|
720
|
+
self.last_features = self.num_features
|
721
|
+
for idx, (nb_cell, idx_feature) in enumerate(self.nb_cells):
|
722
|
+
if nb_cell <= ignored_patche_cells:
|
723
|
+
self.last_features = idx
|
724
|
+
break
|
725
|
+
|
726
|
+
all_slices = find_objects(self.labeled_array)
|
727
|
+
|
728
|
+
logging.info(f"Total number of features found: {self.last_features}")
|
729
|
+
|
623
730
|
# find xmin, ymin, xmax, ymax for each feature
|
624
|
-
for idx_feature in range(1, self.num_features
|
625
|
-
mask = self.labeled_array == idx_feature
|
626
|
-
|
731
|
+
for idx_feature, slices in tqdm(zip(range(1, self.num_features+1), all_slices), desc="Processing features", unit="feature"):
|
732
|
+
mask = self.labeled_array[slices] == idx_feature
|
733
|
+
nb_in_patch = np.count_nonzero(mask)
|
734
|
+
|
735
|
+
if nb_in_patch <= ignored_patche_cells:
|
736
|
+
logging.debug(f"Feature {idx_feature} has too few cells ({np.count_nonzero(mask)}) and will be ignored.")
|
737
|
+
continue
|
627
738
|
|
628
|
-
imin, imax =
|
629
|
-
jmin, jmax =
|
739
|
+
imin, imax = slices[0].start, slices[0].stop - 1
|
740
|
+
jmin, jmax = slices[1].start, slices[1].stop - 1
|
630
741
|
|
631
742
|
imin = int(max(imin - 1, 0))
|
632
743
|
imax = int(min(imax + 1, self.labeled_array.shape[0] - 1))
|
@@ -635,17 +746,25 @@ class CompareArrays:
|
|
635
746
|
|
636
747
|
ref_crop = self.array_reference.crop(imin, jmin, imax-imin+1, jmax-jmin+1)
|
637
748
|
to_compare_crop = self.array_to_compare.crop(imin, jmin, imax-imin+1, jmax-jmin+1)
|
749
|
+
label_crop = self.labeled_array[imin:imax+1, jmin:jmax+1].copy()
|
638
750
|
|
639
|
-
ref_crop.array.mask[:,:] = ~mask[imin:imax+1, jmin:jmax+1]
|
640
|
-
ref_crop.set_nullvalue_in_mask()
|
641
751
|
|
642
|
-
to_compare_crop.array.mask[:,:] =
|
752
|
+
to_compare_crop.array.mask[:,:] = ref_crop.array.mask[:,:] = self.labeled_array[imin:imax+1, jmin:jmax+1] != idx_feature
|
753
|
+
|
754
|
+
ref_crop.set_nullvalue_in_mask()
|
643
755
|
to_compare_crop.set_nullvalue_in_mask()
|
756
|
+
label_crop[label_crop != idx_feature] = 0
|
644
757
|
|
645
|
-
ref_crop.
|
646
|
-
to_compare_crop.nbnotnull =
|
758
|
+
ref_crop.nbnotnull = nb_in_patch
|
759
|
+
to_compare_crop.nbnotnull = nb_in_patch
|
647
760
|
|
648
|
-
self.difference_parts[idx_feature] = ArrayDifference(ref_crop, to_compare_crop, idx_feature,
|
761
|
+
self.difference_parts[idx_feature] = ArrayDifference(ref_crop, to_compare_crop, idx_feature, label_crop)
|
762
|
+
|
763
|
+
assert self.last_features == len(self.difference_parts), \
|
764
|
+
f"Last feature index {self.last_features} does not match the number of differences found"
|
765
|
+
|
766
|
+
self.num_features = self.last_features
|
767
|
+
logging.info(f"Number of features after filtering: {self.num_features}")
|
649
768
|
|
650
769
|
return self.labeled_array
|
651
770
|
|
@@ -721,9 +840,10 @@ class CompareArrays:
|
|
721
840
|
surf = self.array_reference.dx * self.array_reference.dy
|
722
841
|
|
723
842
|
# Extract the number of cells for each feature
|
724
|
-
nb_cells = [item[0] * surf for item in self.nb_cells]
|
843
|
+
nb_cells = [item[0] * surf for item in self.nb_cells[:self.last_features]]
|
725
844
|
|
726
|
-
|
845
|
+
if len(nb_cells) > 0:
|
846
|
+
ax.hist(nb_cells, bins= min(100, int(len(nb_cells)/4)), density=density, alpha=alpha, **kwargs)
|
727
847
|
|
728
848
|
ax.set_title(_("Histogram of surface in each feature [m²]"))
|
729
849
|
|
@@ -748,13 +868,22 @@ class CompareArrays:
|
|
748
868
|
|
749
869
|
fig, ax = figax
|
750
870
|
|
751
|
-
# Calculate the difference between the two arrays
|
752
|
-
diff = self.difference
|
871
|
+
# # Calculate the difference between the two arrays
|
872
|
+
# diff = self.difference
|
753
873
|
|
754
|
-
volumes =
|
874
|
+
volumes = []
|
875
|
+
for idx in tqdm(self.nb_cells[:self.last_features], desc="Calculating volumes"):
|
876
|
+
# Get the feature index
|
877
|
+
feature_index = idx[1]
|
878
|
+
part = self.difference_parts[feature_index]
|
879
|
+
# Create a mask for the feature
|
880
|
+
mask = part.label == feature_index
|
881
|
+
# Calculate the volume for this feature
|
882
|
+
volumes.append(np.ma.sum(part.difference.array[mask]) * self.array_reference.dx * self.array_reference.dy)
|
755
883
|
|
756
884
|
# Create a histogram of the differences
|
757
|
-
|
885
|
+
if len(volumes) > 0:
|
886
|
+
ax.hist(volumes, bins= min(100, int(len(volumes)/4)), density=density, alpha=alpha, **kwargs)
|
758
887
|
|
759
888
|
ax.set_title(_("Histogram of net volumes [m³]"))
|
760
889
|
|
@@ -809,7 +938,9 @@ class CompareArrays:
|
|
809
938
|
|
810
939
|
|
811
940
|
|
812
|
-
def create_report(self, output_file: str | Path = None,
|
941
|
+
def create_report(self, output_file: str | Path = None,
|
942
|
+
append_all_differences: bool = True,
|
943
|
+
nb_max_differences:int = -1) -> None:
|
813
944
|
""" Create a page report for the array comparison. """
|
814
945
|
|
815
946
|
if output_file is None:
|
@@ -822,6 +953,14 @@ class CompareArrays:
|
|
822
953
|
layout.create_report()
|
823
954
|
self._complete_report(layout)
|
824
955
|
|
956
|
+
if nb_max_differences < 0:
|
957
|
+
nb_max_differences = len(self.difference_parts)
|
958
|
+
elif nb_max_differences > len(self.difference_parts):
|
959
|
+
logging.warning(f"Requested {nb_max_differences} differences, but only {len(self.difference_parts)} are available. Using all available differences.")
|
960
|
+
elif nb_max_differences < len(self.difference_parts):
|
961
|
+
logging.info(f"Limiting to {nb_max_differences} differences.")
|
962
|
+
|
963
|
+
features_to_treat = [feature[1] for feature in self.nb_cells[:nb_max_differences]]
|
825
964
|
|
826
965
|
with TemporaryDirectory() as temp_dir:
|
827
966
|
|
@@ -833,12 +972,83 @@ class CompareArrays:
|
|
833
972
|
|
834
973
|
if append_all_differences:
|
835
974
|
# Add each difference report to the main layout
|
836
|
-
all_pdfs.extend([
|
975
|
+
all_pdfs.extend([self.difference_parts[idx].create_report(Path(temp_dir) / f"array_difference_{idx}.pdf") for idx in tqdm(features_to_treat, desc="Creating individual difference reports")])
|
837
976
|
|
838
|
-
for pdf_file in all_pdfs:
|
977
|
+
for pdf_file in tqdm(all_pdfs, desc="Compiling PDFs"):
|
839
978
|
layout._doc.insert_file(pdf_file)
|
840
979
|
|
841
980
|
# create a TOC
|
842
981
|
layout._doc.set_toc(layout._doc.get_toc())
|
843
982
|
|
844
|
-
layout.save_report(output_file)
|
983
|
+
layout.save_report(output_file)
|
984
|
+
self._pdf_path = output_file
|
985
|
+
|
986
|
+
@property
|
987
|
+
def pdf_path(self) -> Path:
|
988
|
+
""" Return the path to the generated PDF report. """
|
989
|
+
if hasattr(self, '_pdf_path'):
|
990
|
+
return self._pdf_path
|
991
|
+
else:
|
992
|
+
raise AttributeError("PDF path not set. Please create the report first.")
|
993
|
+
|
994
|
+
class CompareArrays_wx(PDFViewer):
|
995
|
+
|
996
|
+
def __init__(self, reference: WolfArray | str | Path,
|
997
|
+
to_compare: WolfArray | str | Path,
|
998
|
+
ignored_patche_area:float = 2.0,
|
999
|
+
nb_max_patches:int = 10,
|
1000
|
+
threshold: float = 0.01,
|
1001
|
+
dpi=200, **kwargs):
|
1002
|
+
""" Initialize the Simple Simulation GPU Report Viewer for comparison """
|
1003
|
+
|
1004
|
+
super(CompareArrays_wx, self).__init__(None, **kwargs)
|
1005
|
+
|
1006
|
+
use('agg')
|
1007
|
+
|
1008
|
+
if isinstance(reference, WolfArray) and isinstance(to_compare, WolfArray):
|
1009
|
+
if np.any(reference.array.mask != to_compare.array.mask):
|
1010
|
+
logging.warning("The masks of the two arrays are not identical. This may lead to unexpected results.")
|
1011
|
+
dlg = wx.MessageDialog(self,
|
1012
|
+
_("The masks of the two arrays are not identical.\nThis may lead to unexpected results.\n\nWe will use the reference mask for the comparison."),
|
1013
|
+
_("Warning"),
|
1014
|
+
wx.OK | wx.ICON_WARNING)
|
1015
|
+
dlg.ShowModal()
|
1016
|
+
dlg.Destroy()
|
1017
|
+
to_compare = WolfArray(mold=to_compare)
|
1018
|
+
to_compare.array.mask[:,:] = reference.array.mask[:,:]
|
1019
|
+
|
1020
|
+
self._report = CompareArrays(reference, to_compare)
|
1021
|
+
|
1022
|
+
self._report._dpi = dpi
|
1023
|
+
self._report.localize_differences(threshold=threshold,
|
1024
|
+
ignored_patche_area=ignored_patche_area)
|
1025
|
+
self._report.create_report(nb_max_differences=nb_max_patches)
|
1026
|
+
|
1027
|
+
# Load the PDF into the viewer
|
1028
|
+
if self._report.pdf_path is None:
|
1029
|
+
logging.error("No report created. Cannot load PDF.")
|
1030
|
+
return
|
1031
|
+
|
1032
|
+
self.load_pdf(self._report.pdf_path)
|
1033
|
+
self.viewer.SetZoom(-1) # Fit to width
|
1034
|
+
|
1035
|
+
# Set the title of the frame
|
1036
|
+
self.SetTitle("Simple Simulation GPU Comparison Report")
|
1037
|
+
|
1038
|
+
self.Bind(wx.EVT_CLOSE, self.on_close)
|
1039
|
+
|
1040
|
+
use('wxagg')
|
1041
|
+
|
1042
|
+
def on_close(self, event):
|
1043
|
+
""" Handle the close event to clean up resources """
|
1044
|
+
self.viewer.pdfdoc.pdfdoc.close()
|
1045
|
+
self.Destroy()
|
1046
|
+
|
1047
|
+
def get_zones(self) -> Zones:
|
1048
|
+
"""
|
1049
|
+
Get the zones from the report.
|
1050
|
+
"""
|
1051
|
+
ret = self._report.get_zones()
|
1052
|
+
ret.prep_listogl()
|
1053
|
+
|
1054
|
+
return ret
|