Skip to content

Commit 26399b2

Browse files
Processing/processing tools basal contacts test (#21)
* input files * fix: change stratigraphic column QgsProcessingParameterFeatureSink description parameter to string * feat add formation column mapping and validation for strat column * tester.yml * input file * test_basal_contacts * fix import in test_basal_contacts.py * fix strati_column in test_basal_contacts * removed duplicated input files
1 parent b74bc79 commit 26399b2

2 files changed

Lines changed: 143 additions & 4 deletions

File tree

m2l/processing/algorithms/extract_basal_contacts.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
7878
)
7979
)
8080

81+
self.addParameter(
82+
QgsProcessingParameterField(
83+
'FORMATION_FIELD',
84+
'Formation Field',
85+
parentLayerParameterName=self.INPUT_GEOLOGY,
86+
type=QgsProcessingParameterField.String,
87+
defaultValue='formation',
88+
optional=True
89+
)
90+
)
91+
8192
self.addParameter(
8293
QgsProcessingParameterFeatureSource(
8394
self.INPUT_FAULTS,
@@ -127,7 +138,14 @@ def processAlgorithm(
127138
geology = self.parameterAsVectorLayer(parameters, self.INPUT_GEOLOGY, context)
128139
faults = self.parameterAsVectorLayer(parameters, self.INPUT_FAULTS, context)
129140
strati_column = self.parameterAsMatrix(parameters, self.INPUT_STRATI_COLUMN, context)
130-
ignore_units = self.parameterAsMatrix(parameters, self.INPUT_IGNORE_UNITS, context)
141+
ignore_units = self.parameterAsMatrix(parameters, self.INPUT_IGNORE_UNITS, context)
142+
143+
if not strati_column or all(isinstance(unit, str) and not unit.strip() for unit in strati_column):
144+
raise QgsProcessingException("no stratigraphic column found")
145+
146+
if not ignore_units or all(isinstance(unit, str) and not unit.strip() for unit in ignore_units):
147+
feedback.pushInfo("no units to ignore specified")
148+
131149
# if strati_column and strati_column.strip():
132150
# strati_column = [unit.strip() for unit in strati_column.split(',')]
133151
# Save stratigraphic column settings
@@ -138,10 +156,15 @@ def processAlgorithm(
138156
ignore_settings.setValue("m2l/ignore_units", ignore_units)
139157

140158
unit_name_field = self.parameterAsString(parameters, 'UNIT_NAME_FIELD', context)
159+
formation_field = self.parameterAsString(parameters, 'FORMATION_FIELD', context)
141160

142161
geology = qgsLayerToGeoDataFrame(geology)
143-
mask = ~geology['Formation'].astype(str).str.strip().isin(ignore_units)
144-
geology = geology[mask].reset_index(drop=True)
162+
if formation_field and formation_field in geology.columns:
163+
mask = ~geology[formation_field].astype(str).str.strip().isin(ignore_units)
164+
geology = geology[mask].reset_index(drop=True)
165+
feedback.pushInfo(f"filtered by formation field: {formation_field}")
166+
else:
167+
feedback.pushInfo(f"no formation field found: {formation_field}")
145168

146169
faults = qgsLayerToGeoDataFrame(faults) if faults else None
147170
if unit_name_field != 'UNITNAME' and unit_name_field in geology.columns:
@@ -154,7 +177,7 @@ def processAlgorithm(
154177
feedback.pushInfo("Exporting Basal Contacts Layer...")
155178
basal_contacts = GeoDataFrameToQgsLayer(
156179
self,
157-
contact_extractor.basal_contacts,
180+
basal_contacts,
158181
parameters=parameters,
159182
context=context,
160183
output_key=self.OUTPUT,

tests/qgis/test_basal_contacts.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import unittest
2+
from pathlib import Path
3+
from qgis.core import QgsVectorLayer, QgsProcessingContext, QgsProcessingFeedback, QgsMessageLog, Qgis, QgsApplication
4+
from qgis.testing import start_app
5+
from m2l.processing.algorithms.extract_basal_contacts import BasalContactsAlgorithm
6+
from m2l.processing.provider import Map2LoopProvider
7+
8+
class TestBasalContacts(unittest.TestCase):
9+
10+
@classmethod
11+
def setUpClass(cls):
12+
cls.qgs = start_app()
13+
14+
cls.provider = Map2LoopProvider()
15+
QgsApplication.processingRegistry().addProvider(cls.provider)
16+
17+
def setUp(self):
18+
self.test_dir = Path(__file__).parent
19+
self.input_dir = self.test_dir / "input"
20+
21+
self.geology_file = self.input_dir / "geol_clip_no_gaps.shp"
22+
self.faults_file = self.input_dir / "faults_clip.shp"
23+
24+
self.assertTrue(self.geology_file.exists(), f"geology not found: {self.geology_file}")
25+
26+
if not self.faults_file.exists():
27+
QgsMessageLog.logMessage(f"faults not found: {self.faults_file}, will run test without faults", "TestBasalContacts", Qgis.Warning)
28+
29+
def test_basal_contacts_extraction(self):
30+
31+
geology_layer = QgsVectorLayer(str(self.geology_file), "geology", "ogr")
32+
33+
self.assertTrue(geology_layer.isValid(), "geology layer should be valid")
34+
self.assertGreater(geology_layer.featureCount(), 0, "geology layer should have features")
35+
36+
faults_layer = None
37+
if self.faults_file.exists():
38+
faults_layer = QgsVectorLayer(str(self.faults_file), "faults", "ogr")
39+
self.assertTrue(faults_layer.isValid(), "faults layer should be valid")
40+
self.assertGreater(faults_layer.featureCount(), 0, "faults layer should have features")
41+
QgsMessageLog.logMessage(f"faults layer: {faults_layer.featureCount()} features", "TestBasalContacts", Qgis.Critical)
42+
43+
QgsMessageLog.logMessage(f"geology layer: {geology_layer.featureCount()} features", "TestBasalContacts", Qgis.Critical)
44+
45+
strati_column = [
46+
"Turee Creek Group",
47+
"Boolgeeda Iron Formation",
48+
"Woongarra Rhyolite",
49+
"Weeli Wolli Formation",
50+
"Brockman Iron Formation",
51+
"Mount McRae Shale and Mount Sylvia Formation",
52+
"Wittenoom Formation",
53+
"Marra Mamba Iron Formation",
54+
"Jeerinah Formation",
55+
"Bunjinah Formation",
56+
"Pyradie Formation",
57+
"Fortescue Group",
58+
"Hardey Formation",
59+
"Boongal Formation",
60+
"Mount Roe Basalt",
61+
"Rocklea Inlier greenstones",
62+
"Rocklea Inlier metagranitic unit"
63+
]
64+
65+
algorithm = BasalContactsAlgorithm()
66+
algorithm.initAlgorithm()
67+
68+
parameters = {
69+
'GEOLOGY': geology_layer,
70+
'UNIT_NAME_FIELD': 'unitname',
71+
'FORMATION_FIELD': 'formation',
72+
'FAULTS': faults_layer,
73+
'STRATIGRAPHIC_COLUMN': strati_column,
74+
'IGNORE_UNITS': [],
75+
'BASAL_CONTACTS': 'memory:basal_contacts'
76+
}
77+
78+
context = QgsProcessingContext()
79+
feedback = QgsProcessingFeedback()
80+
81+
try:
82+
QgsMessageLog.logMessage("Starting basal contacts algorithm...", "TestBasalContacts", Qgis.Critical)
83+
84+
result = algorithm.processAlgorithm(parameters, context, feedback)
85+
86+
QgsMessageLog.logMessage(f"Result: {result}", "TestBasalContacts", Qgis.Critical)
87+
88+
self.assertIsNotNone(result, "result should not be None")
89+
self.assertIn('BASAL_CONTACTS', result, "Result should contain BASAL_CONTACTS key")
90+
91+
basal_contacts_layer = context.takeResultLayer(result['BASAL_CONTACTS'])
92+
self.assertIsNotNone(basal_contacts_layer, "basal contacts layer should not be None")
93+
self.assertTrue(basal_contacts_layer.isValid(), "basal contacts layer should be valid")
94+
self.assertGreater(basal_contacts_layer.featureCount(), 0, "basal contacts layer should have features")
95+
96+
QgsMessageLog.logMessage(f"Generated {basal_contacts_layer.featureCount()} basal contacts",
97+
"TestBasalContacts", Qgis.Critical)
98+
99+
QgsMessageLog.logMessage("Basal contacts test completed successfully!", "TestBasalContacts", Qgis.Critical)
100+
101+
except Exception as e:
102+
QgsMessageLog.logMessage(f"Basal contacts test error: {str(e)}", "TestBasalContacts", Qgis.Critical)
103+
QgsMessageLog.logMessage(f"Error type: {type(e).__name__}", "TestBasalContacts", Qgis.Critical)
104+
import traceback
105+
QgsMessageLog.logMessage(f"Full traceback:\n{traceback.format_exc()}", "TestBasalContacts", Qgis.Critical)
106+
raise
107+
108+
finally:
109+
QgsMessageLog.logMessage("=" * 50, "TestBasalContacts", Qgis.Critical)
110+
111+
@classmethod
112+
def tearDownClass(cls):
113+
QgsApplication.processingRegistry().removeProvider(cls.provider)
114+
115+
if __name__ == '__main__':
116+
unittest.main()

0 commit comments

Comments
 (0)