Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
conda install -c conda-forge conda-build scikit-build-core numpy anaconda-client conda-libmamba-solver -y
conda config --set solver libmamba
conda build --output-folder conda conda --python ${{matrix.python-version}}
anaconda upload --label main conda/*/*.conda
anaconda upload --label main conda/*/*.tar.bz2

- name: upload artifacts
uses: actions/upload-artifact@v4
Expand Down
21 changes: 8 additions & 13 deletions .github/workflows/linting_and_testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,33 +48,28 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
conda-remove-defaults: "true"

- name: Install dependencies for windows python 3.9 and 3.10
if: ${{ matrix.os == 'windows-latest' && (matrix.python-version == '3.9' || matrix.python-version == '3.10') }}


- name: Install dependencies for windows python 3.10
if: ${{ matrix.os == 'windows-latest' && matrix.python-version == '3.10' }}
run: |
conda run -n test conda info
conda run -n test conda install -c loop3d -c conda-forge "gdal=3.4.3" python=${{ matrix.python-version }} -y
conda run -n test conda install -c loop3d -c conda-forge --file dependencies.txt python=${{ matrix.python-version }} -y
conda run -n test conda install pytest python=${{ matrix.python-version }} -y

- name: Install dependencies for windows python 3.11
if: ${{ matrix.os == 'windows-latest' && matrix.python-version == '3.11' }}
- name: Install dependencies for other environments
if: ${{ matrix.os != 'windows-latest' || matrix.python-version != '3.10' }}
run: |
conda run -n test conda info
conda run -n test conda install -c loop3d -c conda-forge gdal "netcdf4=*=nompi_py311*" python=${{ matrix.python-version }} -y
conda run -n test conda install -c loop3d -c conda-forge gdal python=${{ matrix.python-version }} -y
conda run -n test conda install -c loop3d -c conda-forge --file dependencies.txt python=${{ matrix.python-version }} -y
conda run -n test conda install pytest python=${{ matrix.python-version }} -y

- name: Install dependencies for other environments
if: ${{ !(matrix.os == 'windows-latest' && (matrix.python-version == '3.9' || matrix.python-version == '3.10' || matrix.python-version == '3.11')) }}
run: |
conda run -n test conda info
conda run -n test conda install -c loop3d -c conda-forge python=${{ matrix.python-version }} gdal pytest --file dependencies.txt -y

- name: Install map2loop
run: |
conda run -n test python -m pip install .

- name: Run tests
run: |
conda run -n test pytest -v
conda run -n test pytest
96 changes: 0 additions & 96 deletions map2loop/contact_extractor.py

This file was deleted.

11 changes: 4 additions & 7 deletions map2loop/data_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,13 +471,11 @@ def check_keys(d: dict, parent_key=""):
"fault": {
"structtype_column", "fault_text", "dip_null_value",
"dipdir_flag", "dipdir_column", "dip_column", "orientation_type",
"dipestimate_column", "dipestimate_text","displacement_column",
"displacement_text", "name_column","objectid_column", "featureid_column", "minimum_fault_length",
"fault_length_column", "fault_length_text", "ignore_fault_codes",
"dipestimate_column", "dipestimate_text", "name_column",
"objectid_column", "minimum_fault_length", "ignore_fault_codes",
},
"fold": {
"structtype_column", "fold_text", "axial_plane_dipdir_column",
"axial_plane_dip_column","tightness_column", "description_column",
"structtype_column", "fold_text", "description_column",
"synform_text", "foldname_column","objectid_column",
},
}
Expand Down Expand Up @@ -855,7 +853,6 @@ def validate_structtype_column(
if text_keys:
for text_key, config_key in text_keys.items():
text_value = config.get(config_key, None)
text_pattern = '|'.join(text_value) if text_value else None
if text_value:
if not isinstance(text_value, str):
error_msg = (
Expand All @@ -865,7 +862,7 @@ def validate_structtype_column(
logger.error(error_msg)
return (True, error_msg)

if not geodata[structtype_column].str.contains(text_pattern, case=False, regex=True, na=False).any():
if not geodata[structtype_column].str.contains(text_value, na=False).any():
if text_key == "synform_text":
warning_msg = (
f"Datatype {datatype_name.upper()}: The '{text_key}' value '{text_value}' is not found in column '{structtype_column}'. "
Expand Down
70 changes: 31 additions & 39 deletions map2loop/topology.py → map2loop/map2model_wrapper.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
from typing import Optional
# internal imports
from .m2l_enums import VerboseLevel
from .contact_extractor import ContactExtractor

# external imports
import geopandas
import pandas
import numpy
import geopandas as gpd
import pandas as pd
import numpy as np

from .logging import getLogger

logger = getLogger(__name__)


class Topology:
class Map2ModelWrapper:
"""
Topology calculator for units and faults relationships
A wrapper around map2model functionality

Attributes
----------
sorted_units: None or list
the stratigraphic column
map2model's estimate of the stratigraphic column
fault_fault_relationships: None or pandas.DataFrame
data frame of fault to fault relationships with columns ["Fault1", "Fault2", "Type", "Angle"]
unit_fault_relationships: None or pandas.DataFrame
Expand All @@ -34,9 +32,7 @@ class Topology:
"""

def __init__(
self, geology_data: geopandas.GeoDataFrame,
fault_data: Optional[geopandas.GeoDataFrame] = None,
verbose_level: VerboseLevel = VerboseLevel.NONE
self, map_data, *, verbose_level: VerboseLevel = VerboseLevel.NONE
):
"""
The initialiser for the map2model wrapper
Expand All @@ -51,8 +47,7 @@ def __init__(
self._fault_fault_relationships = None
self._unit_fault_relationships = None
self._unit_unit_relationships = None
self.geology_data = geology_data
self.fault_data = fault_data
self.map_data = map_data
self.verbose_level = verbose_level
self.buffer_radius = 500

Expand All @@ -79,13 +74,13 @@ def unit_unit_relationships(self):

def reset(self):
"""
Reset before the next run
Reset the wrapper to before the map2model process
"""
logger.info("Resetting topology calculator")
logger.info("Resetting map2model wrapper")
self.sorted_units = None
self._fault_fault_relationships = None
self._unit_fault_relationships = None
self._unit_unit_relationships = None
self.fault_fault_relationships = None
self.unit_fault_relationships = None
self.unit_unit_relationships = None

def get_sorted_units(self):
"""
Expand Down Expand Up @@ -129,23 +124,23 @@ def get_unit_unit_relationships(self):

def _calculate_fault_fault_relationships(self):

faults = self.fault_data.copy()
faults = self.map_data.FAULT.copy()
# reset index so that we can index the adjacency matrix with the index
faults.reset_index(inplace=True)
buffers = faults.buffer(self.buffer_radius)
# create the adjacency matrix
intersection = geopandas.sjoin(
geopandas.GeoDataFrame(geometry=buffers), geopandas.GeoDataFrame(geometry=faults["geometry"])
intersection = gpd.sjoin(
gpd.GeoDataFrame(geometry=buffers), gpd.GeoDataFrame(geometry=faults["geometry"])
)
intersection["index_left"] = intersection.index
intersection.reset_index(inplace=True)

adjacency_matrix = numpy.zeros((faults.shape[0], faults.shape[0]), dtype=bool)
adjacency_matrix = np.zeros((faults.shape[0], faults.shape[0]), dtype=bool)
adjacency_matrix[
intersection.loc[:, "index_left"], intersection.loc[:, "index_right"]
] = True
f1, f2 = numpy.where(numpy.tril(adjacency_matrix, k=-1))
df = pandas.DataFrame(
f1, f2 = np.where(np.tril(adjacency_matrix, k=-1))
df = pd.DataFrame(
{'Fault1': faults.loc[f1, 'ID'].to_list(), 'Fault2': faults.loc[f2, 'ID'].to_list()}
)
df['Angle'] = 60 # make it big to prevent LS from making splays
Expand All @@ -156,29 +151,26 @@ def _calculate_fault_unit_relationships(self):
"""Calculate unit/fault relationships using geopandas sjoin.
This will return
"""
units = self.geology_data["UNITNAME"].unique()
faults = self.fault_data.copy().reset_index().drop(columns=['index'])
adjacency_matrix = numpy.zeros((len(units), faults.shape[0]), dtype=bool)
units = self.map_data.GEOLOGY["UNITNAME"].unique()
faults = self.map_data.FAULT.copy().reset_index().drop(columns=['index'])
adjacency_matrix = np.zeros((len(units), faults.shape[0]), dtype=bool)
for i, u in enumerate(units):
unit = self.geology_data[self.geology_data["UNITNAME"] == u]
intersection = geopandas.sjoin(
geopandas.GeoDataFrame(geometry=faults["geometry"]),
geopandas.GeoDataFrame(geometry=unit["geometry"]),
unit = self.map_data.GEOLOGY[self.map_data.GEOLOGY["UNITNAME"] == u]
intersection = gpd.sjoin(
gpd.GeoDataFrame(geometry=faults["geometry"]),
gpd.GeoDataFrame(geometry=unit["geometry"]),
)
intersection["index_left"] = intersection.index
intersection.reset_index(inplace=True)
adjacency_matrix[i, intersection.loc[:, "index_left"]] = True
u, f = numpy.where(adjacency_matrix)
df = pandas.DataFrame({"Unit": units[u].tolist(), "Fault": faults.loc[f, "ID"].to_list()})
u, f = np.where(adjacency_matrix)
df = pd.DataFrame({"Unit": units[u].tolist(), "Fault": faults.loc[f, "ID"].to_list()})
self._unit_fault_relationships = df

def _calculate_unit_unit_relationships(self):
extractor = ContactExtractor(
self.geology_data,
self.fault_data,
)
contacts = extractor.extract_all_contacts()
self._unit_unit_relationships = contacts.copy().drop(
if self.map_data.contacts is None:
self.map_data.extract_all_contacts()
self._unit_unit_relationships = self.map_data.contacts.copy().drop(
columns=['length', 'geometry']
)
return self._unit_unit_relationships
Expand Down
Loading
Loading