From b60e460799443b7258d8a33f8522f4ae4a297ddf Mon Sep 17 00:00:00 2001 From: leon-wagner Date: Mon, 11 Nov 2024 10:48:58 +0100 Subject: [PATCH] added DFAPath algorithm as 'Experimental' --- avaframeConnector_commonFunc.py | 29 ++++ avaframeConnector_provider.py | 2 + pb_tool.cfg | 3 +- runComputeDFAPath_algorithm.py | 243 ++++++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 runComputeDFAPath_algorithm.py diff --git a/avaframeConnector_commonFunc.py b/avaframeConnector_commonFunc.py index 45e1fe8..407a108 100644 --- a/avaframeConnector_commonFunc.py +++ b/avaframeConnector_commonFunc.py @@ -143,6 +143,35 @@ def getAlphaBetaResults(targetDir, useSmallAva=False): else: return "None" +def getDFAPathResults(targetDir): + '''Get results from path generation + + Parameters + ----------- + targetDir: pathlib path + to avalanche directory + Returns + ------- + DFAPathResults : massAvgPath and splitPoint + ''' + from qgis.core import (QgsVectorLayer) + avaDir = pathlib.Path(str(targetDir)) + pathDir = avaDir / 'Outputs' / 'DFAPath' + allDFAPathLayers = [] + + # Collect all path shapefiles + for file in pathDir.glob('massAvgPath*.shp'): + pathLayer = QgsVectorLayer(str(file), f"Mass Average Path - {file.stem}", "ogr") + if pathLayer.isValid(): + allDFAPathLayers.append(pathLayer) + + # Collect all split point shapefiles + for file in pathDir.glob('splitPointParabolicFit*.shp'): + splitPointLayer = QgsVectorLayer(str(file), f"Split Point - {file.stem}", "ogr") + if splitPointLayer.isValid(): + allDFAPathLayers.append(splitPointLayer) + + return allDFAPathLayers def getAna4ProbAnaResults(targetDir): """Get results of ana4PropAna diff --git a/avaframeConnector_provider.py b/avaframeConnector_provider.py index 3b9d3de..c24474d 100644 --- a/avaframeConnector_provider.py +++ b/avaframeConnector_provider.py @@ -89,6 +89,7 @@ def find_python(): from .avaframeConnector_algorithm import AvaFrameConnectorAlgorithm from .layerRename_algorithm import layerRenameAlgorithm from .getVersion_algorithm import getVersionAlgorithm +from .runComputeDFAPath_algorithm import runComputeDFAPathAlgorithm from .runCom1DFA_algorithm import runCom1DFAAlgorithm from .runCom2AB_algorithm import runCom2ABAlgorithm from .runCom5SnowSlide_algorithm import runCom5SnowSlideAlgorithm @@ -123,6 +124,7 @@ def loadAlgorithms(self): """ self.addAlgorithm(AvaFrameConnectorAlgorithm()) self.addAlgorithm(layerRenameAlgorithm()) + self.addAlgorithm(runComputeDFAPathAlgorithm()) self.addAlgorithm(runCom1DFAAlgorithm()) self.addAlgorithm(runCom2ABAlgorithm()) self.addAlgorithm(runCom5SnowSlideAlgorithm()) diff --git a/pb_tool.cfg b/pb_tool.cfg index 75b383b..02dbb00 100644 --- a/pb_tool.cfg +++ b/pb_tool.cfg @@ -52,7 +52,8 @@ python_files: __init__.py avaframeConnector.py avaframeConnector_provider.py avaframeConnector_algorithm.py layerRename_algorithm.py getVersion_algorithm.py - update_algorithm.py + update_algorithm.py + runComputeDFAPath_algorithm.py runCom1DFA_algorithm.py runCom2AB_algorithm.py runAna4ProbAna_algorithm.py diff --git a/runComputeDFAPath_algorithm.py b/runComputeDFAPath_algorithm.py new file mode 100644 index 0000000..8548e4c --- /dev/null +++ b/runComputeDFAPath_algorithm.py @@ -0,0 +1,243 @@ +# -*- coding: utf-8 -*- + +""" +/*************************************************************************** + AvaFrameRunComputeDFAPath + A QGIS plugin + Connects to AvaFrame + Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ + ------------------- + begin : 2021-08-26 + copyright : (C) 2021 by AvaFrame Team + email : felix@avaframe.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +""" + +__author__ = 'AvaFrame Team' +__date__ = '2022' +__copyright__ = '(C) 2022 by AvaFrame Team' + +# This will get replaced with a git SHA1 when you do a git archive + +__revision__ = '$Format:%H$' + +import subprocess + +from qgis.PyQt.QtCore import QCoreApplication +from qgis.core import (QgsProcessing, + QgsProcessingException, + QgsProcessingAlgorithm, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterFolderDestination, + QgsProcessingOutputVectorLayer, + QgsProcessingParameterBoolean, + QgsProcessingOutputMultipleLayers + ) + + +class runComputeDFAPathAlgorithm(QgsProcessingAlgorithm): + """ + This is the AvaFrame Connection, i.e. the part running with QGis. For this + connector to work, more installation is needed. See instructions at docs.avaframe.org + """ + + DEM = 'DEM' + REL = 'REL' + RUNDFA = 'RUNDFA' + FOLDEST = 'FOLDEST' + OUTPUT = 'OUTPUT' + OUTPPR = 'OUTPPR' + + def initAlgorithm(self, config): + """ + Here we define the inputs and output of the algorithm, along + with some other properties. + """ + + self.addParameter(QgsProcessingParameterRasterLayer( + self.DEM, + self.tr("DEM layer"))) + + self.addParameter(QgsProcessingParameterMultipleLayers( + self.REL, + self.tr('Release layer(s)'), + layerType=QgsProcessing.TypeVectorAnyGeometry + )) + + self.addParameter(QgsProcessingParameterBoolean( + self.RUNDFA, + self.tr('Run dense flow (com1DFA)'), + optional=True, + defaultValue=True + )) + + self.addParameter(QgsProcessingParameterFolderDestination( + self.FOLDEST, + self.tr('Destination folder') + )) + + self.addOutput(QgsProcessingOutputVectorLayer( + self.OUTPUT, + self.tr("Output layer"), + QgsProcessing.TypeVectorAnyGeometry)) + + self.addOutput(QgsProcessingOutputMultipleLayers( + self.OUTPPR, + )) + + def flags(self): + return super().flags() + # return super().flags() | QgsProcessingAlgorithm.FlagNoThreading + + def processAlgorithm(self, parameters, context, feedback): + """ + Here is where the processing itself takes place. + """ + + import avaframe.version as gv + from . import avaframeConnector_commonFunc as cF + + feedback.pushInfo('AvaFrame Version: ' + gv.getVersion()) + + # targetADDTONAME = self.parameterAsString(parameters, self.ADDTONAME, context) + targetADDTONAME = '' + + sourceDEM = self.parameterAsRasterLayer(parameters, self.DEM, context) + if sourceDEM is None: + raise QgsProcessingException(self.invalidSourceError(parameters, self.DEM)) + + # Release files + allREL = self.parameterAsLayerList(parameters, self.REL, context) + if allREL is None: + raise QgsProcessingException(self.invalidSourceError(parameters, self.REL)) + + relDict = {} + if allREL: + relDict = {lyr.source(): lyr for lyr in allREL} + + #runDFA bool + sourceRUNDFA = self.parameterAsBool(parameters, self.RUNDFA, context) + + sourceFOLDEST = self.parameterAsFile(parameters, self.FOLDEST, context) + + # create folder structure (targetDir is the tmp one) + finalTargetDir, targetDir = cF.createFolderStructure(sourceFOLDEST) + + feedback.pushInfo(sourceDEM.source()) + + # copy DEM + cF.copyDEM(sourceDEM, targetDir) + + # copy all release shapefile parts + cF.copyMultipleShp(relDict, targetDir / 'Inputs' / 'REL', targetADDTONAME) + + feedback.pushInfo('Starting path generation') + feedback.pushInfo('See console for progress') + + # Prepare command for subprocess call + command = ['python', '-m', 'avaframe.runComputeDFAPath', str(targetDir)] + + # Add --runDFA argument if RUNDFA boolean is True + if sourceRUNDFA: + command.append('--runDFA') + + subprocess.call(command) + feedback.pushInfo('Done, start loading the results') + + # Move input, log and output folders to finalTargetDir + cF.moveInputAndOutputFoldersToFinal(targetDir, finalTargetDir) + + # Get path and split point shapefiles to return to QGIS + try: + pathResults = cF.getDFAPathResults(finalTargetDir) + except: + raise QgsProcessingException(self.tr('Something went wrong with path generation, please check log files')) + + context = cF.addLayersToContext(context, pathResults, self.OUTPUT) + + # If runDFA, try to get eventual peakfiles from com1DFA to return to QGIS +# if sourceRUNDFA: +# try: +# rasterResults = cF.getLatestPeak(finalTargetDir) +# except: +# raise QgsProcessingException(self.tr('Something went wrong with com1DFA, please check log files')) +# +# allRasterLayers = cF.addStyleToCom1DFAResults(rasterResults) + +# context = cF.addLayersToContext(context, allRasterLayers, self.OUTPPR) +# else: +# allRasterLayers = 0 + + feedback.pushInfo('\n---------------------------------') + feedback.pushInfo('Done, find results and logs here:') + feedback.pushInfo(str(targetDir.resolve())) + feedback.pushInfo('---------------------------------\n') + + return {self.OUTPUT: pathResults} +# return {self.OUTPUT: pathResults, self.OUTPPR: allRasterLayers} + + def name(self): + """ + Returns the algorithm name, used for identifying the algorithm. This + string should be fixed for the algorithm, and must not be localised. + The name should be unique within each provider. Names should contain + lowercase alphanumeric characters only and no spaces or other + formatting characters. + """ + return 'dfapath' + + def displayName(self): + """ + Returns the translated algorithm name, which should be used for any + user-visible display of the algorithm name. + """ + return self.tr('Generate mass average path (ana5, com1)') + + def group(self): + """ + Returns the name of the group this algorithm belongs to. This string + should be localised. + """ + return self.tr(self.groupId()) + + def groupId(self): + """ + Returns the unique ID of the group this algorithm belongs to. This + string should be fixed for the algorithm, and must not be localised. + The group id should be unique within each provider. Group id should + contain lowercase alphanumeric characters only and no spaces or other + formatting characters. + """ + return 'Experimental' + + def tr(self, string): + return QCoreApplication.translate('Processing', string) + + def shortHelpString(self) -> str: + hstring = ('Generates the mass average path from a dense flow simulation via module ana5Utils. ' + 'Check \'Run dense flow\' to run com1 with adjusted parameters to generate necessary ' + 'DFA results prior to path generation \n\ + For more information go to (or use the help button below): \n\ + AvaFrame Documentation: https://docs.avaframe.org\n\ + Homepage: https://avaframe.org\n\ + Praxisleitfaden: https://avaframe.org/reports\n') + + return self.tr(hstring) + # Praxisleitfaden: https://info.bml.gv.at/dam/jcr:edebd872-2a86-4edf-ac5e-635ef11e35fe/Praxisleitfaden%20LawSim%20WLV%202022%20Gr%C3%BCn.pdf\n' + + def helpUrl(self): + return "https://docs.avaframe.org/en/latest/connector.html" + + def createInstance(self): + return runComputeDFAPathAlgorithm()