Skip to content

Commit

Permalink
Merge branch 'v3.2' of https://github.com/Loop3D/map2loop into fix--i…
Browse files Browse the repository at this point in the history
…ssue-133
  • Loading branch information
AngRodrigues committed Dec 12, 2024
2 parents 61936f9 + 7bf14b1 commit 34d3ee2
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 89 deletions.
1 change: 1 addition & 0 deletions .github/workflows/CD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ jobs:
- name: Installing dependencies
shell: bash -l {0}
run: |
conda install -c conda-forge conda-build anaconda-client conda-verify -y
conda install -c loop3d -c conda-forge --file dependencies.txt -y
pip uninstall loopprojectfile -y
Expand Down
133 changes: 65 additions & 68 deletions map2loop/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,19 @@ def to_dict(self):
}

@beartype.beartype
def update_from_dictionary(self, dictionary: dict, lower: bool = False):
def update_from_dictionary(self, dictionary: dict, lower: bool = True):
"""
Update the config dictionary from a provided dict
Args:
dictionary (dict): The dictionary to update from
"""
# make sure dictionary doesn't contain legacy keys
self.check_for_legacy_keys(dictionary)

# make sure it has the minimum requirements
self.validate_config_dictionary(dictionary)

if "structure" in dictionary:
self.structure_config.update(dictionary["structure"])
for key in dictionary["structure"].keys():
Expand All @@ -108,6 +114,7 @@ def update_from_dictionary(self, dictionary: dict, lower: bool = False):
f"Config dictionary structure segment contained {key} which is not used"
)
dictionary.pop("structure")

if "geology" in dictionary:
self.geology_config.update(dictionary["geology"])
for key in dictionary["geology"].keys():
Expand Down Expand Up @@ -135,82 +142,19 @@ def update_from_dictionary(self, dictionary: dict, lower: bool = False):
if len(dictionary):
logger.warning(f"Unused keys from config format {list(dictionary.keys())}")

@beartype.beartype
def update_from_legacy_file(self, file_map: dict, lower: bool = False):
"""
Update the config dictionary from the provided old version dictionary
Args:
file_map (dict): The old version dictionary to update from
"""

code_mapping = {
"otype": (self.structure_config, "orientation_type"),
"dd": (self.structure_config, "dipdir_column"),
"d": (self.structure_config, "dip_column"),
"sf": (self.structure_config, "description_column"),
"bedding": (self.structure_config, "bedding_text"),
"bo": (self.structure_config, "overturned_column"),
"btype": (self.structure_config, "overturned_text"),
"gi": (self.structure_config, "objectid_column"),
"c": (self.geology_config, "unitname_column"),
"u": (self.geology_config, "alt_unitname_column"),
"g": (self.geology_config, "group_column"),
"g2": (self.geology_config, "supergroup_column"),
"ds": (self.geology_config, "description_column"),
"min": (self.geology_config, "minage_column"),
"max": (self.geology_config, "maxage_column"),
"r1": (self.geology_config, "rocktype_column"),
"r2": (self.geology_config, "alt_rocktype_column"),
"sill": (self.geology_config, "sill_text"),
"intrusive": (self.geology_config, "intrusive_text"),
"volcanic": (self.geology_config, "volcanic_text"),
"f": (self.fault_config, "structtype_column"),
"fault": (self.fault_config, "fault_text"),
"fdipnull": (self.fault_config, "dip_null_value"),
"fdipdip_flag": (self.fault_config, "dipdir_flag"),
"fdipdir": (self.fault_config, "dipdir_column"),
"fdip": (self.fault_config, "dip_column"),
"fdipest": (self.fault_config, "dipestimate_column"),
"fdipest_vals": (self.fault_config, "dipestimate_text"),
"n": (self.fault_config, "name_column"),
"ff": (self.fold_config, "structtype_column"),
"fold": (self.fold_config, "fold_text"),
"t": (self.fold_config, "description_column"),
"syn": (self.fold_config, "synform_text"),
}
for code in code_mapping:
if code in file_map:
if lower is True:
file_map[code] = str(file_map[code]).lower()
code_mapping[code][0][code_mapping[code][1]] = file_map[code]
file_map.pop(code)

if "o" in file_map:
self.structure_config["objectid_column"] = file_map["o"]
self.fault_config["objectid_column"] = file_map["o"]
self.fold_config["objectid_column"] = file_map["o"]
file_map.pop("o")

if len(file_map) > 0:
logger.warning(f"Unused keys from legacy format {list(file_map.keys())}")

@beartype.beartype
def update_from_file(
self, filename: Union[pathlib.Path, str], legacy_format: bool = False, lower: bool = False
self, filename: Union[pathlib.Path, str], lower: bool = False
):
"""
Update the config dictionary from the provided json filename or url
Args:
filename (Union[pathlib.Path, str]): Filename or URL of the JSON config file
legacy_format (bool, optional): Whether the JSON is an old version. Defaults to False.
lower (bool, optional): convert keys to lowercase. Defaults to False.
"""
if legacy_format:
func = self.update_from_legacy_file
else:
func = self.update_from_dictionary
func = self.update_from_dictionary

try:
filename = str(filename)
Expand Down Expand Up @@ -269,7 +213,60 @@ def update_from_file(
err_string += "Please check the file is accessible online and then\n"
else:
err_string += "Please check the file exists and is accessible then\n"
if not legacy_format:
err_string += "Also check if this is a legacy config file and add clut_file_legacy=True to the Project function\n"
err_string += "Check the contents for mismatched quotes or brackets!"
raise Exception(err_string)

@beartype.beartype
def validate_config_dictionary(self, config_dict: dict) -> None:
"""
Validate the structure and keys of the configuration dictionary.
Args:
config_dict (dict): The config dictionary to validate.
Raises:
ValueError: If the dictionary does not meet the minimum requirements for ma2p2loop.
"""
required_keys = {
"structure": {"dipdir_column", "dip_column"},
"geology": {"unitname_column", "alt_unitname_column"},
}

for section, keys in required_keys.items():
if section not in config_dict:
logger.error(f"Missing required section '{section}' in config dictionary.")
raise ValueError(f"Missing required section '{section}' in config dictionary.")

for key in keys:
if key not in config_dict[section]:
logger.error(
f"Missing required key '{key}' for '{section}' section of the config dictionary."
)
raise ValueError(
f"Missing required key '{key}' for '{section}' section of the config dictionary."
)

@beartype.beartype
def check_for_legacy_keys(self, config_dict: dict) -> None:

legacy_keys = {
"otype", "dd", "d", "sf", "bedding", "bo", "btype", "gi", "c", "u",
"g", "g2", "ds", "min", "max", "r1", "r2", "sill", "intrusive", "volcanic",
"f", "fdipnull", "fdipdip_flag", "fdipdir", "fdip", "fdipest",
"fdipest_vals", "n", "ff", "t", "syn"
}

# Recursively search for keys in the dictionary
def check_keys(d: dict, parent_key=""):
for key, value in d.items():
if key in legacy_keys:
logger.error(
f"Legacy key found in config - '{key}' at '{parent_key + key}'. Please use the new config format. Use map2loop.utils.update_from_legacy_file to convert between the formats if needed"
)
raise ValueError(
f"Legacy key found in config - '{key}' at '{parent_key + key}'. Please use the new config format. Use map2loop.utils.update_from_legacy_file to convert between the formats if needed"
)
if isinstance(value, dict):
check_keys(value, parent_key=f"{parent_key}{key}.")

check_keys(config_dict)
13 changes: 7 additions & 6 deletions map2loop/mapdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,20 +257,21 @@ def get_filename(self, datatype: Datatype):

@beartype.beartype
def set_config_filename(
self, filename: Union[pathlib.Path, str], legacy_format: bool = False, lower: bool = False
self, filename: Union[pathlib.Path, str], lower: bool = False
):
"""
Set the config filename and update the config structure
Args:
filename (str):
The filename of the config file
legacy_format (bool, optional):
Whether the file is in m2lv2 form. Defaults to False.
lower (bool, optional):
Flag to convert the config file to lowercase. Defaults to False.
"""
logger.info('Setting config filename to {filename}')
self.config_filename = filename
self.config.update_from_file(filename, legacy_format=legacy_format, lower=lower)

self.config.update_from_file(filename, lower=lower)

logger.info(f"Config is: {self.config.to_dict()}")

def get_config_filename(self):
Expand Down Expand Up @@ -409,7 +410,7 @@ def set_filenames_from_australian_state(self, state: str):

else:
self.set_config_filename(
AustraliaStateUrls.aus_config_urls[state], legacy_format=False, lower=lower
AustraliaStateUrls.aus_config_urls[state], lower=lower
)
self.set_colour_filename(AustraliaStateUrls.aus_clut_urls[state])
else:
Expand Down
32 changes: 22 additions & 10 deletions map2loop/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ def __init__(
config_filename: Union[pathlib.Path, str] = "",
config_dictionary: dict = {},
clut_filename: Union[pathlib.Path, str] = "",
clut_file_legacy: bool = False,
save_pre_checked_map_data: bool = False,
loop_project_filename: str = "",
overwrite_loopprojectfile: bool = False,
Expand Down Expand Up @@ -109,8 +108,6 @@ def __init__(
A dictionary version of the configuration file. Defaults to {}.
clut_filename (str, optional):
The filename of the colour look up table to use. Defaults to "".
clut_file_legacy (bool, optional):
A flag to indicate if the clut file is in the legacy format. Defaults to False.
save_pre_checked_map_data (bool, optional):
A flag to save all map data to file before use. Defaults to False.
loop_project_filename (str, optional):
Expand Down Expand Up @@ -148,6 +145,7 @@ def __init__(
self.fold_samples = pandas.DataFrame(columns=["ID", "X", "Y", "Z", "featureId"])
self.geology_samples = pandas.DataFrame(columns=["ID", "X", "Y", "Z", "featureId"])


# Check for alternate config filenames in kwargs
if "metadata_filename" in kwargs and config_filename == "":
config_filename = kwargs["metadata_filename"]
Expand Down Expand Up @@ -204,19 +202,18 @@ def __init__(
self.map_data.set_filename(Datatype.DTM, dtm_filename)
if fault_orientation_filename != "":
self.map_data.set_filename(Datatype.FAULT_ORIENTATION, fault_orientation_filename)

if config_filename != "":
if clut_file_legacy:
logger.warning(
"DEPRECATION: Legacy files are deprecated and their use will be removed in v3.2"
)

self.map_data.set_config_filename(config_filename, legacy_format=clut_file_legacy)
self.map_data.set_config_filename(config_filename)

if config_dictionary != {}:
self.map_data.config.update_from_dictionary(config_dictionary)

if clut_filename != "":
self.map_data.set_colour_filename(clut_filename)



# Load all data (both shape and raster)
self.map_data.load_all_map_data()

Expand Down Expand Up @@ -357,6 +354,21 @@ def set_sampler(self, datatype: Datatype, sampler: Sampler):
sampler (Sampler):
The sampler to use
"""
allowed_samplers = {
Datatype.STRUCTURE: SamplerDecimator,
Datatype.GEOLOGY: SamplerSpacing,
Datatype.FAULT: SamplerSpacing,
Datatype.FOLD: SamplerSpacing,
Datatype.DTM: SamplerSpacing,
}

# Check for wrong sampler
if datatype in allowed_samplers:
allowed_sampler_type = allowed_samplers[datatype]
if not isinstance(sampler, allowed_sampler_type):
raise ValueError(
f"Got wrong argument for this datatype: {type(sampler).__name__}, please use {allowed_sampler_type.__name__} instead"
)
## does the enum print the number or the label?
logger.info(f"Setting sampler for {datatype} to {sampler.sampler_label}")
self.samplers[datatype] = sampler
Expand Down
2 changes: 1 addition & 1 deletion map2loop/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pandas
import shapely
import numpy
from typing import Optional
from typing import Optional, Union


class Sampler(ABC):
Expand Down
6 changes: 3 additions & 3 deletions map2loop/sorter.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ def sort(

class SorterUseHint(SorterUseNetworkX):
def __init__(self):
print(
"SorterUseHint is deprecated and will be removed in map2loop v3.2. Use SorterUseNetworkX instead"
logger.info(
"SorterUseHint is deprecated in v3.2. Use SorterUseNetworkX instead"
)
super().__init__()

Expand Down Expand Up @@ -158,7 +158,7 @@ def sort(
logger.info("Calling age based sorter")
sorted_units = units.copy()
if "minAge" in units.columns and "maxAge" in units.columns:
print(sorted_units["minAge"], sorted_units["maxAge"])
# print(sorted_units["minAge"], sorted_units["maxAge"])
sorted_units["meanAge"] = sorted_units.apply(
lambda row: (row["minAge"] + row["maxAge"]) / 2.0, axis=1
)
Expand Down
Loading

0 comments on commit 34d3ee2

Please sign in to comment.