LoopStructural 1.6.17__py3-none-any.whl → 1.6.18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of LoopStructural might be problematic. Click here for more details.

@@ -560,14 +560,14 @@ class GeologicalModel:
560
560
  DeprecationWarning(
561
561
  "set_stratigraphic_column is deprecated, use model.stratigraphic_column.add_units instead"
562
562
  )
563
- for g in stratigraphic_column.keys():
563
+ for i, g in enumerate(stratigraphic_column.keys()):
564
564
  for u in stratigraphic_column[g].keys():
565
565
  thickness = 0
566
566
  if "min" in stratigraphic_column[g][u] and "max" in stratigraphic_column[g][u]:
567
567
  min_val = stratigraphic_column[g][u]["min"]
568
568
  max_val = stratigraphic_column[g][u].get("max", None)
569
569
  thickness = max_val - min_val if max_val is not None else None
570
- logger.warning(
570
+ logger.info(
571
571
  f"""
572
572
  model.stratigraphic_column.add_unit({u},
573
573
  colour={stratigraphic_column[g][u].get("colour", None)},
@@ -578,9 +578,11 @@ class GeologicalModel:
578
578
  colour=stratigraphic_column[g][u].get("colour", None),
579
579
  thickness=thickness,
580
580
  )
581
+
581
582
  self.stratigraphic_column.add_unconformity(
582
583
  name=''.join([g, 'unconformity']),
583
584
  )
585
+ self.stratigraphic_column.group_mapping[f'Group_{i+1}'] = g
584
586
 
585
587
  def create_and_add_foliation(
586
588
  self,
@@ -1520,7 +1522,7 @@ class GeologicalModel:
1520
1522
  if feature_id >= 0:
1521
1523
  vals = self.features[feature_id].evaluate_value(xyz)
1522
1524
  for u in g.units:
1523
- strat_id[np.logical_and(vals < u.max, vals > u.min)] = s_id
1525
+ strat_id[np.logical_and(vals < u.max(), vals > u.min())] = s_id
1524
1526
  s_id += 1
1525
1527
  if feature_id == -1:
1526
1528
  logger.error(f"Model does not contain {g.name}")
@@ -1725,16 +1727,8 @@ class GeologicalModel:
1725
1727
  ids : list
1726
1728
  list of unique stratigraphic ids, featurename, unit name and min and max scalar values
1727
1729
  """
1728
- ids = []
1729
- if self.stratigraphic_column is None:
1730
- logger.warning('No stratigraphic column defined')
1731
- return ids
1732
- for group in self.stratigraphic_column.keys():
1733
- if group == "faults":
1734
- continue
1735
- for name, series in self.stratigraphic_column[group].items():
1736
- ids.append([series["id"], group, name, series['min'], series['max']])
1737
- return ids
1730
+ return self.stratigraphic_column.get_stratigraphic_ids()
1731
+
1738
1732
 
1739
1733
  def get_fault_surfaces(self, faults: List[str] = []):
1740
1734
  surfaces = []
@@ -39,24 +39,59 @@ class StratigraphicColumnElement:
39
39
  self.uuid = uuid
40
40
 
41
41
 
42
- class StratigraphicUnit(StratigraphicColumnElement):
42
+ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUnit']):
43
43
  """
44
44
  A class to represent a stratigraphic unit.
45
45
  """
46
46
 
47
- def __init__(self, *, uuid=None, name=None, colour=None, thickness=None, data=None):
47
+ def __init__(self, *, uuid=None, name=None, colour=None, thickness=None, data=None, id=None):
48
48
  """
49
49
  Initializes the StratigraphicUnit with a name and an optional description.
50
50
  """
51
- super().__init__(uuid)
51
+ StratigraphicColumnElement.__init__(self, uuid)
52
+ Observable.__init__(self)
52
53
  self.name = name
53
54
  if colour is None:
54
55
  colour = rng.random(3)
55
56
  self.colour = colour
56
- self.thickness = thickness
57
+ self._thickness = thickness
57
58
  self.data = data
58
59
  self.element_type = StratigraphicColumnElementType.UNIT
59
-
60
+ self._id = id
61
+ self.min_value = None # Minimum scalar field value for the unit
62
+ self.max_value = None # Maximum scalar field value for the unit
63
+ @property
64
+ def id(self):
65
+ return self._id
66
+ @property
67
+ def thickness(self):
68
+ return self._thickness
69
+ @thickness.setter
70
+ def thickness(self, value):
71
+ """
72
+ Sets the thickness of the unit.
73
+ """
74
+ self._thickness = value
75
+ self.notify('unit/thickness_updated', unit=self)
76
+ @id.setter
77
+ def id(self, value):
78
+ """
79
+ Sets the ID of the unit.
80
+ """
81
+ if not isinstance(value, int):
82
+ raise TypeError("ID must be an integer")
83
+ self._id = value
84
+ self.notify('unit/id_updated', unit=self)
85
+ def min(self):
86
+ """
87
+ Returns the minimum value of the unit.
88
+ """
89
+ return self.min_value if self.min_value is not None else 0
90
+ def max(self):
91
+ """
92
+ Returns the maximum value of the unit.
93
+ """
94
+ return self.max_value if self.max_value is not None else np.inf
60
95
  def to_dict(self):
61
96
  """
62
97
  Converts the stratigraphic unit to a dictionary representation.
@@ -164,20 +199,37 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
164
199
  Initializes the StratigraphicColumn with a name and a list of layers.
165
200
  """
166
201
  super().__init__()
167
- self.order = [StratigraphicUnit(name='Basement', colour='grey', thickness=np.inf),StratigraphicUnconformity(name='Base Unconformity', unconformity_type=UnconformityType.ERODE)]
202
+ self.order = []
203
+ self.add_basement()
168
204
  self.group_mapping = {}
169
- def clear(self,basement=True):
205
+
206
+ def get_new_id(self):
207
+ """
208
+ Generates a new unique ID for a stratigraphic unit.
209
+ """
210
+ if not self.order:
211
+ return 0
212
+ return max([u.id for u in self.order if isinstance(u, StratigraphicUnit)], default=0) + 1
213
+ def add_basement(self):
214
+ self.add_unit(name='Basement', colour='grey', thickness=np.inf)
215
+ self.add_unconformity(
216
+ name='Base Unconformity', unconformity_type=UnconformityType.ERODE
217
+ )
218
+ def clear(self, basement=True):
170
219
  """
171
220
  Clears the stratigraphic column, removing all elements.
172
221
  """
173
222
  if basement:
174
- self.order = [StratigraphicUnit(name='Basement', colour='grey', thickness=np.inf),StratigraphicUnconformity(name='Base Unconformity', unconformity_type=UnconformityType.ERODE)]
223
+ self.add_basement()
224
+
175
225
  else:
176
226
  self.order = []
177
227
  self.group_mapping = {}
178
228
  self.notify('column_cleared')
179
- def add_unit(self, name,*, colour=None, thickness=None, where='top'):
180
- unit = StratigraphicUnit(name=name, colour=colour, thickness=thickness)
229
+ def add_unit(self, name,*, colour=None, thickness=None, where='top',id=None):
230
+ if id is None:
231
+ id = self.get_new_id()
232
+ unit = StratigraphicUnit(name=name, colour=colour, thickness=thickness, id=id)
181
233
 
182
234
  if where == 'top':
183
235
  self.order.append(unit)
@@ -185,7 +237,9 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
185
237
  self.order.insert(0, unit)
186
238
  else:
187
239
  raise ValueError("Invalid 'where' argument. Use 'top' or 'bottom'.")
240
+ unit.attach(self.update_unit_values,'unit/*')
188
241
  self.notify('unit_added', unit=unit)
242
+ self.update_unit_values() # Update min and max values after adding a unit
189
243
  return unit
190
244
 
191
245
  def remove_unit(self, uuid):
@@ -197,7 +251,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
197
251
  del self.order[i]
198
252
  self.notify('unit_removed', uuid=uuid)
199
253
  return True
200
-
254
+
201
255
  return False
202
256
 
203
257
  def add_unconformity(self, name, *, unconformity_type=UnconformityType.ERODE, where='top' ):
@@ -249,7 +303,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
249
303
  if element.uuid == uuid:
250
304
  return element
251
305
  raise KeyError(f"No element found with uuid: {uuid}")
252
-
306
+
253
307
  def get_group_for_unit_name(self, unit_name:str) -> Optional[StratigraphicGroup]:
254
308
  """
255
309
  Retrieves the group for a given unit name.
@@ -300,7 +354,15 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
300
354
  if group:
301
355
  groups.append(group)
302
356
  return groups
357
+ def get_stratigraphic_ids(self) -> List[List[str]]:
358
+ ids = []
359
+ for group in self.get_groups():
360
+ if group == "faults":
361
+ continue
303
362
 
363
+ for unit in group.units:
364
+ ids.append([unit.id, group, unit.name, unit.min(), unit.max()])
365
+ return ids
304
366
  def get_unitname_groups(self):
305
367
  groups = self.get_groups()
306
368
  groups_list = []
@@ -309,7 +371,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
309
371
  group = [u.name for u in g.units if isinstance(u, StratigraphicUnit)]
310
372
  groups_list.append(group)
311
373
  return groups_list
312
-
374
+
313
375
  def get_group_unit_pairs(self) -> List[Tuple[str,str]]:
314
376
  """
315
377
  Returns a list of tuples containing group names and unit names.
@@ -341,6 +403,20 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
341
403
  self.__getitem__(uuid) for uuid in new_order if self.__getitem__(uuid) is not None
342
404
  ]
343
405
  self.notify('order_updated', new_order=self.order)
406
+ self.update_unit_values() # Update min and max values after updating the order
407
+ def update_unit_values(self, *, observable: Optional["Observable"] = None, event: Optional[str]= None):
408
+ """
409
+ Updates the min and max values for each unit based on their position in the column.
410
+ """
411
+ # If the event is not 'unit/*', skip the update
412
+ if event is not None and event != 'unit/*':
413
+ return
414
+ cumulative_thickness = 0
415
+ for element in self.order:
416
+ if isinstance(element, StratigraphicUnit):
417
+ element.min_value = cumulative_thickness
418
+ element.max_value = cumulative_thickness + (element.thickness or 0)
419
+ cumulative_thickness = element.max_value
344
420
 
345
421
  def update_element(self, unit_data: Dict):
346
422
  """
@@ -360,6 +436,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
360
436
  unit_data.get('unconformity_type', element.unconformity_type.value)
361
437
  )
362
438
  self.notify('element_updated', element=element)
439
+ self.update_unit_values() # Update min and max values after updating an element
363
440
 
364
441
  def __str__(self):
365
442
  """
@@ -189,6 +189,9 @@ class SVariogram:
189
189
  # find the extrema of the average curve
190
190
  res = find_peaks_and_troughs(np.array(averagex), np.array(averagey))
191
191
  px2, py2 = res
192
+ logger.info(f"Found {len(px2)} peaks and troughs in the s-variogram")
193
+ for i in range(len(px2)):
194
+ logger.info(f"Peak {i}: {px2[i]} {py2[i]}")
192
195
  wl1 = 0.0
193
196
  wl1py = 0.0
194
197
  for i in range(len(px)):
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Callable
4
4
  from contextlib import contextmanager
5
- from typing import Any, Generic, Protocol, TypeAlias, TypeVar, runtime_checkable
5
+ from typing import Any, Generic, Protocol, TypeVar, runtime_checkable
6
6
  import threading
7
7
  import weakref
8
8
 
@@ -17,7 +17,7 @@ class Observer(Protocol):
17
17
  """Receive a notification."""
18
18
 
19
19
 
20
- Callback: TypeAlias = Callable[["Observable", str, Any], None]
20
+ Callback = Callable[["Observable", str, Any], None]
21
21
  T = TypeVar("T", bound="Observable")
22
22
 
23
23
 
LoopStructural/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.6.17"
1
+ __version__ = "1.6.18"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: LoopStructural
3
- Version: 1.6.17
3
+ Version: 1.6.18
4
4
  Summary: 3D geological modelling
5
5
  Author-email: Lachlan Grose <lachlan.grose@monash.edu>
6
6
  License: MIT
@@ -1,5 +1,5 @@
1
1
  LoopStructural/__init__.py,sha256=ZS5J2TI2OuhRE0o3EXmPbbjrvh1-Vy9RFwL7Hc1YBow,2079
2
- LoopStructural/version.py,sha256=RFX1x9AQ2Z9aP2gCXAUVtaLq0UOmist-rpJN8M8jz9I,23
2
+ LoopStructural/version.py,sha256=4Zzb1p1N54zNXVm2h5jVUlkFjge9TszzpDGANK9ZNPM,23
3
3
  LoopStructural/datasets/__init__.py,sha256=ylb7fzJU_DyQ73LlwQos7VamqkDSGITbbnoKg7KAOmE,677
4
4
  LoopStructural/datasets/_base.py,sha256=FB_D5ybBYHoaNbycdkpZcRffzjrrL1xp9X0k-pyob9Y,7618
5
5
  LoopStructural/datasets/_example_models.py,sha256=Zg33IeUyh4C-lC0DRMLqCDP2IrX8L-gNV1WxJwBGjzM,113
@@ -72,8 +72,8 @@ LoopStructural/interpolators/supports/_support_factory.py,sha256=XNAxnr-JS3KEhds
72
72
  LoopStructural/modelling/__init__.py,sha256=a-bq2gDhyUlcky5l9kl_IP3ExMdohkgYjQz2V8madQE,902
73
73
  LoopStructural/modelling/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
74
  LoopStructural/modelling/core/fault_topology.py,sha256=bChp5dnfc-4GJRENWxB14mEW_13uBMh5ZYRKbLdjweE,11195
75
- LoopStructural/modelling/core/geological_model.py,sha256=23ZQF2Xvs-PeRdrxt-IqrkVaMDWud_JjW00ok2tKs2k,65850
76
- LoopStructural/modelling/core/stratigraphic_column.py,sha256=GB93W607LY3d_NE75lzwBWrV34YhHN_troCXWuUMBk8,18070
75
+ LoopStructural/modelling/core/geological_model.py,sha256=f6bkpXdKxr72OozUb1vdoosLcjzMIht8VNgNlONluVA,65570
76
+ LoopStructural/modelling/core/stratigraphic_column.py,sha256=fmT51wInY3kei7Ya01cd5P5hcnhY5TkLBLJJwkUd_lE,20807
77
77
  LoopStructural/modelling/features/__init__.py,sha256=Vf-qd5EDBtJ1DpuXXyCcw2-wf6LWPRW5wzxDEO3vOc8,939
78
78
  LoopStructural/modelling/features/_analytical_feature.py,sha256=U_g86LgQhYY2359rdsDqpvziYwqrWkc5EdvhJARiUWo,3597
79
79
  LoopStructural/modelling/features/_base_geological_feature.py,sha256=kGyrbb8nNzfi-M8WSrVMEQYKtxThdcBxaji5HKXtAqw,13483
@@ -98,7 +98,7 @@ LoopStructural/modelling/features/fold/__init__.py,sha256=pOv20yQvshZozvmO_YFw2E
98
98
  LoopStructural/modelling/features/fold/_fold.py,sha256=bPnnLUSiF4uoMRg8aHoOSTPRgaM0JyLoRQPu5_A-J3w,5448
99
99
  LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py,sha256=CXLbFRQ3CrTMAcHmfdbKcmSvvLs9_6TLe0Wqi1pK2tg,892
100
100
  LoopStructural/modelling/features/fold/_foldframe.py,sha256=Rgf5aofN0OVDTZ2pzqLzAGlJUO2rnNm3aFvLSnH77yo,7669
101
- LoopStructural/modelling/features/fold/_svariogram.py,sha256=uzGaKZ5HGh8xZcsGGg68GUKVjkd5udLy7-4lh0NQc2Y,7765
101
+ LoopStructural/modelling/features/fold/_svariogram.py,sha256=uLeBWZahEmystf8mpPJH_zKxp7hPyPJh0H5ROZO0pZs,7933
102
102
  LoopStructural/modelling/features/fold/fold_function/__init__.py,sha256=VqMjabsBd5GnPnDMXeKwXqtd0te2iXnvHxpf6jCC9YU,830
103
103
  LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py,sha256=5Bu_5xjyu4KL7thZ4fsh938Ep3Oyh5TL7_rfz_13Qng,8047
104
104
  LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py,sha256=Cjb6Pt6cdRoH3WGqFyJ2rHxnMe6SKvzRayA6hTuwZA8,4069
@@ -129,13 +129,13 @@ LoopStructural/utils/json_encoder.py,sha256=5YNouf1TlhjEqOYgthd07MRXc0JLgxern-ny
129
129
  LoopStructural/utils/linalg.py,sha256=tBXyu6NXcG2AcPuzUMnkVI4ncZWtE_MPHGj2PLXRwfY,123
130
130
  LoopStructural/utils/logging.py,sha256=dIUWEsS2lT4G1dsf4ZYXknTR7eQkrgvGA4b_E0vMIRU,2402
131
131
  LoopStructural/utils/maths.py,sha256=KaLj9RHsxdaSkEHm4t0JEzykhiuETAV14KpjL6lknWY,10374
132
- LoopStructural/utils/observer.py,sha256=BjoL2-DydNWF1QDfFNd7TQIlRbKus_JNBfqX2ZFDAek,5327
132
+ LoopStructural/utils/observer.py,sha256=etHF2zhDWbrKAaIKAktdVLosD696o_B0P9rH3G5IzV0,5305
133
133
  LoopStructural/utils/regions.py,sha256=SjCC40GI7_n03G4mlcmvyrBgJFbxnvB3leBzXWco37o,3891
134
134
  LoopStructural/utils/typing.py,sha256=29uVSTZdzXXH-jdlaYyBWZ1gQ2-nlZ2-XoVgG_PXNFY,157
135
135
  LoopStructural/utils/utils.py,sha256=2Z4zVE6G752-SPmM29zebk82bROJxEwi_YiiJjcVED4,2438
136
136
  LoopStructural/visualisation/__init__.py,sha256=5BDgKor8-ae6DrS7IZybJ3Wq_pTnCchxuY4EgzA7v1M,318
137
- loopstructural-1.6.17.dist-info/licenses/LICENSE,sha256=ZqGeNFOgmYevj7Ld7Q-kR4lAxWXuBRUdUmPC6XM_py8,1071
138
- loopstructural-1.6.17.dist-info/METADATA,sha256=Io5NikqqA3SupAKqkEtWRytgor6JPn9c5nV8L0FzQLw,6453
139
- loopstructural-1.6.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
140
- loopstructural-1.6.17.dist-info/top_level.txt,sha256=QtQErKzYHfg6ddxTQ1NyaTxXBVM6qAqrM_vxEPyXZLg,15
141
- loopstructural-1.6.17.dist-info/RECORD,,
137
+ loopstructural-1.6.18.dist-info/licenses/LICENSE,sha256=ZqGeNFOgmYevj7Ld7Q-kR4lAxWXuBRUdUmPC6XM_py8,1071
138
+ loopstructural-1.6.18.dist-info/METADATA,sha256=Ps1KAvAFlPgR11P0nbTfYrMlcPS6bX3OewD1UKRXEnU,6453
139
+ loopstructural-1.6.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
140
+ loopstructural-1.6.18.dist-info/top_level.txt,sha256=QtQErKzYHfg6ddxTQ1NyaTxXBVM6qAqrM_vxEPyXZLg,15
141
+ loopstructural-1.6.18.dist-info/RECORD,,