Skip to content

Commit 2dad8e7

Browse files
fix: use separate thickness table in LPF & add active thickness to project (#157)
* fix: use separate thickness table in LPF * docs: remove unused docstring * fix: min fault length can be int * fix: bug in output of StructuralPoint * fix: add the active_thickness_flag --------- Co-authored-by: AngRodrigues <angela.rodrigues@monash.edu>
1 parent 0d6c5ed commit 2dad8e7

File tree

3 files changed

+70
-54
lines changed

3 files changed

+70
-54
lines changed

map2loop/mapdata.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ def __init__(self, verbose_level: VerboseLevel = VerboseLevel.ALL):
7070
The initialiser for the map data
7171
7272
Args:
73-
tmp_path (str, optional):
74-
The directory for storing temporary files. Defaults to "".
7573
verbose_level (VerboseLevel, optional):
7674
How much console output is sent. Defaults to VerboseLevel.ALL.
7775
"""

map2loop/project.py

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ def __init__(
137137
self.deformation_history = DeformationHistory(project=self)
138138
self.loop_filename = loop_project_filename
139139
self.overwrite_lpf = overwrite_loopprojectfile
140-
140+
self.active_thickness = None
141+
141142
# initialise the dataframes to store data in
142143
self.fault_orientations = pandas.DataFrame(
143144
columns=["ID", "DIPDIR", "DIP", "X", "Y", "Z", "featureId"]
@@ -373,7 +374,7 @@ def get_sampler(self, datatype: Datatype):
373374
return self.samplers[datatype].sampler_label
374375

375376
@beartype.beartype
376-
def set_minimum_fault_length(self, length: float):
377+
def set_minimum_fault_length(self, length: Union[float, int]):
377378
"""
378379
Set the cutoff length for faults to ignore
379380
@@ -395,6 +396,35 @@ def get_minimum_fault_length(self) -> float:
395396
"""
396397
return float(self.map_data.config.fault_config['minimum_fault_length'])
397398

399+
@beartype.beartype
400+
def set_active_thickness(self, thickness_calculator: ThicknessCalculator):
401+
"""
402+
Sets the active_thickness attribute based on the provided thickness_calculator.
403+
Args:
404+
thickness_calculator (object or str): The thickness calculator object or its label.
405+
If an object is provided, it should have a 'thickness_calculator_label' attribute.
406+
Returns:
407+
None
408+
Raises:
409+
ValueError: If the thickness calculator label cannot be determined.
410+
"""
411+
412+
try:
413+
label = thickness_calculator.thickness_calculator_label
414+
except AttributeError:
415+
raise ValueError("The provided thickness calculator object does not have a 'thickness_calculator_label' attribute.")
416+
self.active_thickness = label
417+
418+
@beartype.beartype
419+
def get_active_thickness(self) -> str:
420+
"""
421+
Retrieves the active_thickness attribute.
422+
423+
Returns:
424+
str: The label of the active thickness calculator.
425+
"""
426+
return self.active_thickness
427+
398428
# Processing functions
399429
def sample_map_data(self):
400430
"""
@@ -600,7 +630,9 @@ def calculate_unit_thicknesses(self):
600630
self.stratigraphic_column.stratigraphicUnits[stddev_col_name] = repeated_result[:, 2]
601631

602632
self.thickness_calculator_labels = labels
603-
633+
if self.active_thickness is None:
634+
self.active_thickness = labels[0]
635+
604636
def calculate_fault_orientations(self):
605637
if self.map_data.get_map_data(Datatype.FAULT_ORIENTATION) is not None:
606638
logger.info(f"Calculating fault orientations using {self.fault_orientation.label}")
@@ -703,7 +735,7 @@ def save_into_projectfile(self):
703735
file_exists = False
704736
logger.info(f"\nExisting file '{self.loop_filename}' was successfully deleted.")
705737
except Exception as e:
706-
logger.errow(f"\nFailed to delete existing file '{self.loop_filename}': {e}")
738+
logger.error(f"\nFailed to delete existing file '{self.loop_filename}': {e}")
707739
raise e
708740
else:
709741
logger.error(
@@ -767,51 +799,28 @@ def save_into_projectfile(self):
767799
stratigraphic_data = numpy.zeros(
768800
len(self.stratigraphic_column.stratigraphicUnits), LPF.stratigraphicLayerType
769801
)
802+
stratigraphic_thicknesses = numpy.zeros(
803+
len(self.stratigraphic_column.stratigraphicUnits), LPF.stratigraphicThicknessType)
804+
770805
stratigraphic_data["layerId"] = self.stratigraphic_column.stratigraphicUnits["layerId"]
771806
stratigraphic_data["minAge"] = self.stratigraphic_column.stratigraphicUnits["minAge"]
772807
stratigraphic_data["maxAge"] = self.stratigraphic_column.stratigraphicUnits["maxAge"]
773808
stratigraphic_data["name"] = self.stratigraphic_column.stratigraphicUnits["name"]
774809
stratigraphic_data["group"] = self.stratigraphic_column.stratigraphicUnits["group"]
775810
stratigraphic_data["enabled"] = 1
776811

777-
# Length of the column (number of rows in stratigraphicUnits)
778-
column_len = len(self.stratigraphic_column.stratigraphicUnits)
779-
780-
# Function to retrieve a column if it exists, otherwise return a list of default values
781-
def get_column_or_default(column_name, default_value, length):
782-
return list(
783-
self.stratigraphic_column.stratigraphicUnits.get(
784-
column_name, [default_value] * length
785-
)
786-
)
787-
788-
# Get the current list of thickness calculator labels dynamically
789-
thickness_labels = self.thickness_calculator_labels
790-
791-
# Define a constant for the maximum number of calculators (5 as per your requirement)
792-
MAX_CALCULATORS = 5
793-
794-
# Create lists for mean, median, and stddev values for each calculator dynamically
795-
thickness_mean_list = [
796-
get_column_or_default(f'{label}_mean', 0, column_len) for label in thickness_labels
797-
]
798-
thickness_median_list = [
799-
get_column_or_default(f'{label}_median', 0, column_len) for label in thickness_labels
800-
]
801-
thickness_stddev_list = [
802-
get_column_or_default(f'{label}_stddev', 0, column_len) for label in thickness_labels
803-
]
804-
805-
# Pad with zeros if the number of calculators is less than MAX_CALCULATORS
806-
for _ in range(MAX_CALCULATORS - len(thickness_mean_list)):
807-
thickness_mean_list.append([0] * column_len)
808-
thickness_median_list.append([0] * column_len)
809-
thickness_stddev_list.append([0] * column_len)
810-
811-
# Zip these lists into tuples for each stratigraphic row dynamically, ensuring each tuple has exactly 5 elements
812-
stratigraphic_data["ThicknessMean"] = list(zip(*thickness_mean_list[:MAX_CALCULATORS]))
813-
stratigraphic_data["ThicknessMedian"] = list(zip(*thickness_median_list[:MAX_CALCULATORS]))
814-
stratigraphic_data["ThicknessStdDev"] = list(zip(*thickness_stddev_list[:MAX_CALCULATORS]))
812+
stratigraphic_thicknesses['name']= self.stratigraphic_column.stratigraphicUnits["name"]
813+
814+
# store all of the thickness estimates in a separate table
815+
for i, label in enumerate(self.thickness_calculator_labels):
816+
stratigraphic_thicknesses[f'thickness{i+1}_mean'] = self.stratigraphic_column.stratigraphicUnits.get(f'{label}_mean',0)
817+
stratigraphic_thicknesses[f'thickness{i+1}_median'] = self.stratigraphic_column.stratigraphicUnits.get(f'{label}_median',0)
818+
stratigraphic_thicknesses[f'thickness{i+1}_stddev'] = self.stratigraphic_column.stratigraphicUnits.get(f'{label}_stddev',0)
819+
820+
# store the active thickness calculator as the default thickness
821+
stratigraphic_data["ThicknessMean"] = self.stratigraphic_column.stratigraphicUnits.get(f'{self.active_thickness}_mean',0)
822+
stratigraphic_data["ThicknessMedian"] = self.stratigraphic_column.stratigraphicUnits.get(f'{self.active_thickness}_median',0)
823+
stratigraphic_data["ThicknessStdDev"] = self.stratigraphic_column.stratigraphicUnits.get(f'{self.active_thickness}_stddev',0)
815824

816825
# Assign colours to startigraphic data
817826
stratigraphic_data["colour1Red"] = [
@@ -831,21 +840,28 @@ def get_column_or_default(column_name, default_value, length):
831840
stratigraphic_data["colour2Blue"] = [
832841
int(a * 0.95) for a in stratigraphic_data["colour1Blue"]
833842
]
834-
843+
844+
n_thick_calcs = len(self.thickness_calculator_labels)
835845
# get thickness calculator labels, and fill up with None if empty values up to 5 placeholders
836846
while len(self.thickness_calculator_labels) < 5:
837847
self.thickness_calculator_labels.append("None")
838848

839-
thickness_calculator_labels = [tuple(self.thickness_calculator_labels[:5])]
849+
headers = 'name;'+';'.join([f'{l}_mean;{l}_median;{l}_stddev' for l in self.thickness_calculator_labels[:5]])
850+
headers = headers.split(';') # split into list
840851

841852
# save into LPF
842853
LPF.Set(
843854
self.loop_filename,
844855
"stratigraphicLog",
845856
data=stratigraphic_data,
846-
thickness_calculator_data=thickness_calculator_labels,
847-
verbose=True,
857+
verbose=False,
848858
)
859+
LPF.Set(self.loop_filename,
860+
"stratigraphicThicknesses",
861+
data=stratigraphic_thicknesses,
862+
headers=headers,
863+
ncols=1+3*n_thick_calcs, # index and mean, median, stddev for each thickness calculator
864+
verbose=False)
849865

850866
# Save contacts
851867
contacts_data = numpy.zeros(len(self.map_data.sampled_contacts), LPF.contactObservationType)

map2loop/thickness_calculator.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# internal imports
2-
import scipy.interpolate
32
from .utils import (
43
create_points,
54
rebuild_sampled_basal_contacts,
@@ -13,6 +12,7 @@
1312

1413
# external imports
1514
from abc import ABC, abstractmethod
15+
import scipy.interpolate
1616
import beartype
1717
import numpy
1818
import scipy
@@ -590,10 +590,10 @@ def compute(
590590

591591
output_units = units.copy()
592592
# remove the old thickness column
593-
output_units['ThicknessMedian'] = numpy.empty((len(output_units)))
594-
output_units['ThicknessMean'] = numpy.empty((len(output_units)))
595-
output_units['ThicknessStdDev'] = numpy.empty((len(output_units)))
596-
593+
output_units['ThicknessMedian'] = numpy.full(len(output_units), numpy.nan)
594+
output_units['ThicknessMean'] = numpy.full(len(output_units), numpy.nan)
595+
output_units['ThicknessStdDev'] = numpy.full(len(output_units), numpy.nan)
596+
597597
# find which units have no thickness calculated
598598
names_not_in_result = units[~units['name'].isin(result['unit'])]['name'].to_list()
599599
# assign the thicknesses to the each unit
@@ -602,10 +602,12 @@ def compute(
602602
output_units.loc[idx, 'ThicknessMedian'] = unit['median']
603603
output_units.loc[idx, 'ThicknessMean'] = unit['mean']
604604
output_units.loc[idx, 'ThicknessStdDev'] = unit['std']
605-
605+
606606
output_units["ThicknessMean"] = output_units["ThicknessMean"].fillna(-1)
607607
output_units["ThicknessMedian"] = output_units["ThicknessMedian"].fillna(-1)
608608
output_units["ThicknessStdDev"] = output_units["ThicknessStdDev"].fillna(-1)
609+
610+
609611
# handle the units that have no thickness
610612
for unit in names_not_in_result:
611613
# if no thickness has been calculated for the unit

0 commit comments

Comments
 (0)