Skip to content

Commit d1ed7d1

Browse files
committed
Steps towards executing models
1 parent 1df9f6b commit d1ed7d1

4 files changed

Lines changed: 95 additions & 85 deletions

File tree

‎python/plugins/processing/gui/NumberInputPanel.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def showExpressionsBuilder(self):
125125
def getValue(self):
126126
value = self.leText.text()
127127
values = []
128-
for param in self.modelParametersDialog.model.parameters:
128+
for param in self.modelParametersDialog.model.parameterDefinitions():
129129
if isinstance(param, QgsProcessingParameterNumber):
130130
if "@" + param.name() in value:
131131
values.append(ValueFromInput(param.name()))

‎python/plugins/processing/modeler/ModelerAlgorithm.py‎

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -197,17 +197,6 @@ def prepareAlgorithm(self, alg):
197197
self.tr("Parameter {0} in algorithm {1} in the model is run with default value! Edit the model to make sure that this is correct.").format(param.name(), alg.displayName()),
198198
QgsMessageBar.WARNING, 4)
199199
value = param.defaultValue()
200-
# We allow unexistent filepaths, since that allows
201-
# algorithms to skip some conversion routines
202-
203-
# TODO
204-
#if not param.checkValueIsAcceptable(value) and not isinstance(param,
205-
# ParameterDataObject):
206-
# raise GeoAlgorithmExecutionException(
207-
# self.tr('Wrong value {0} for {1} {2}', 'ModelerAlgorithm').format(
208-
# value, param.__class__.__name__, param.name()
209-
# )
210-
# )
211200

212201
# note to self - these are parameters, not outputs
213202
for out in algInstance.outputDefinitions():
@@ -240,50 +229,6 @@ def resolveValue(self, value, param):
240229
v = value
241230
return param.evaluateForModeler(v, self)
242231

243-
def processAlgorithm(self, parameters, context, feedback):
244-
executed = []
245-
toExecute = [alg for alg in list(self.childAlgorithms().values()) if alg.isActive()]
246-
while len(executed) < len(toExecute):
247-
for alg in toExecute:
248-
if alg.childId() not in executed:
249-
canExecute = True
250-
required = self.dependsOnChildAlgorithms(alg.childId())
251-
for requiredAlg in required:
252-
if requiredAlg not in executed:
253-
canExecute = False
254-
break
255-
if canExecute:
256-
try:
257-
feedback.pushDebugInfo(
258-
self.tr('Prepare algorithm: {0}', 'ModelerAlgorithm').format(alg.childId()))
259-
self.prepareAlgorithm(alg)
260-
feedback.setProgressText(
261-
self.tr('Running {0} [{1}/{2}]', 'ModelerAlgorithm').format(alg.description, len(executed) + 1, len(toExecute)))
262-
feedback.pushDebugInfo('Parameters: ' + ', '.join([str(p).strip() +
263-
'=' + str(p.value) for p in alg.algorithm.parameters]))
264-
t0 = time.time()
265-
alg.algorithm().execute(parameters, context, feedback)
266-
dt = time.time() - t0
267-
268-
# copy algorithm output value(s) back to model in case the algorithm modified those
269-
for out in alg.algorithm().outputs:
270-
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
271-
if out.name() in alg.modelOutputs():
272-
modelOut = self.getOutputFromName(self.getSafeNameForOutput(alg.childId(), out.name()))
273-
if modelOut:
274-
modelOut.value = out.value
275-
276-
executed.append(alg.childId())
277-
feedback.pushDebugInfo(
278-
self.tr('OK. Execution took %{0:.3f} ms ({1} outputs).', 'ModelerAlgorithm').format(dt, len(alg.algorithm.modelOutputs())))
279-
except GeoAlgorithmExecutionException as e:
280-
feedback.pushDebugInfo(self.tr('Failed', 'ModelerAlgorithm'))
281-
raise GeoAlgorithmExecutionException(
282-
self.tr('Error executing algorithm {0}\n{1}', 'ModelerAlgorithm').format(alg.description, e.msg))
283-
284-
feedback.pushDebugInfo(
285-
self.tr('Model processed ok. Executed {0} algorithms total', 'ModelerAlgorithm').format(len(executed)))
286-
287232
def asPythonCommand(self, parameters, context):
288233
if self.descriptionFile:
289234
return QgsProcessingAlgorithm.asPythonCommand(self, parameters, context)

‎src/core/processing/qgsprocessingmodelalgorithm.cpp‎

Lines changed: 92 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -284,20 +284,81 @@ QString QgsProcessingModelAlgorithm::svgIconPath() const
284284
return QgsApplication::iconPath( QStringLiteral( "processingModel.svg" ) );
285285
}
286286

287+
QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm( const ChildAlgorithm &child, const QVariantMap &modelParameters, const QMap< QString, QVariantMap > &results ) const
288+
{
289+
QVariantMap childParams;
290+
Q_FOREACH ( const QgsProcessingParameterDefinition *def, child.algorithm()->parameterDefinitions() )
291+
{
292+
if ( def->flags() & QgsProcessingParameterDefinition::FlagHidden )
293+
continue;
294+
295+
if ( !def->isDestination() )
296+
{
297+
if ( !child.parameterSources().contains( def->name() ) )
298+
continue; // use default value
299+
300+
ChildParameterSource paramSource = child.parameterSources().value( def->name() );
301+
switch ( paramSource.source() )
302+
{
303+
case ChildParameterSource::StaticValue:
304+
childParams.insert( def->name(), paramSource.staticValue() );
305+
break;
306+
307+
case ChildParameterSource::ModelParameter:
308+
childParams.insert( def->name(), modelParameters.value( paramSource.parameterName() ) );
309+
break;
310+
311+
case ChildParameterSource::ChildOutput:
312+
{
313+
QVariantMap linkedChildResults = results.value( paramSource.outputChildId() );
314+
childParams.insert( def->name(), linkedChildResults.value( paramSource.outputName() ) );
315+
break;
316+
}
317+
}
318+
}
319+
else
320+
{
321+
// is destination linked to one of the final outputs from this model?
322+
if ( child.modelOutputs().contains( def->name() ) )
323+
{
324+
QString outputName = child.modelOutputs().value( def->name() ).outputName();
325+
QString paramName = child.childId() + ':' + outputName;
326+
if ( modelParameters.contains( paramName ) )
327+
childParams.insert( def->name(), modelParameters.value( paramName ) );
328+
}
329+
else
330+
{
331+
// output is temporary
332+
// TODO - skip if this output is optional and not used elsewhere in the model
333+
childParams.insert( def->name(), "memory:" );
334+
335+
336+
}
337+
}
338+
}
339+
return childParams;
340+
}
341+
287342
QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
288343
{
289344
QSet< QString > toExecute;
290345
QMap< QString, ChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
291346
for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
292347
{
293-
if ( childIt->isActive() )
348+
if ( childIt->isActive() && childIt->algorithm() )
294349
toExecute.insert( childIt->childId() );
295350
}
296351

297-
QMap< QString, QVariantMap > resultsMap;
352+
QTime totalTime;
353+
totalTime.start();
354+
355+
QMap< QString, QVariantMap > childResults;
356+
QVariantMap finalResults;
298357
QSet< QString > executed;
299-
while ( executed.count() < toExecute.count() )
358+
bool executedAlg = true;
359+
while ( executedAlg && executed.count() < toExecute.count() )
300360
{
361+
executedAlg = false;
301362
Q_FOREACH ( const QString &childId, toExecute )
302363
{
303364
if ( executed.contains( childId ) )
@@ -316,47 +377,47 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa
316377
if ( !canExecute )
317378
continue;
318379

380+
executedAlg = true;
319381
feedback->pushDebugInfo( QObject::tr( "Prepare algorithm: %1" ).arg( childId ) );
320382

321383
const ChildAlgorithm &child = mChildAlgorithms[ childId ];
322384

323-
// self.prepareAlgorithm( alg )
324-
385+
QVariantMap childParams = parametersForChildAlgorithm( child, parameters, childResults );
325386
feedback->setProgressText( QObject::tr( "Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) );
326387
//feedback->pushDebugInfo( "Parameters: " + ', '.join( [str( p ).strip() +
327388
// '=' + str( p.value ) for p in alg.algorithm.parameters] ) )
328-
//t0 = time.time()
329-
QVariantMap results = child.algorithm()->run( parameters, context, feedback );
330-
resultsMap.insert( childId, results );
331389

332-
//dt = time.time() - t0
333-
#if 0
390+
QTime childTime;
391+
childTime.start();
334392

335-
# copy algorithm output value(s) back to model in case the algorithm modified those
336-
for out in alg.algorithm().outputs :
337-
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
338-
if out.name() in alg.modelOutputs():
339-
modelOut = self.getOutputFromName( self.getSafeNameForOutput( alg.childId(), out.name() ) )
340-
if modelOut:
341-
modelOut.value = out.value
342-
#endif
393+
QVariantMap results = child.algorithm()->run( childParams, context, feedback );
394+
childResults.insert( childId, results );
343395

344-
executed.insert( childId );
345-
//feedback->pushDebugInfo( QObject::tr( "OK. Execution took %1 ms (%2 outputs)." ).arg( dt, len( alg.algorithm.modelOutputs() ) ) )
396+
// look through child alg's outputs to determine whether any of these should be copied
397+
// to the final model outputs
398+
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> outputs = child.modelOutputs();
399+
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput>::const_iterator outputIt = outputs.constBegin();
400+
for ( ; outputIt != outputs.constEnd(); ++outputIt )
401+
{
402+
finalResults.insert( childId + ':' + outputIt->outputName(), results.value( outputIt->outputName() ) );
403+
}
404+
405+
executed.insert( childId );
406+
feedback->pushDebugInfo( QObject::tr( "OK. Execution took %1 s (%2 outputs)." ).arg( childTime.elapsed() / 1000.0 ).arg( results.count() ) );
346407
#if 0
347-
except GeoAlgorithmExecutionException as e:
348-
feedback.pushDebugInfo( self.tr( 'Failed', 'ModelerAlgorithm' ) )
349-
raise GeoAlgorithmExecutionException(
350-
self.tr( 'Error executing algorithm {0}\n{1}', 'ModelerAlgorithm' ).format( alg.description, e.msg ) )
408+
except GeoAlgorithmExecutionException as e:
409+
feedback.pushDebugInfo( self.tr( 'Failed', 'ModelerAlgorithm' ) )
410+
raise GeoAlgorithmExecutionException(
411+
self.tr( 'Error executing algorithm {0}\n{1}', 'ModelerAlgorithm' ).format( alg.description, e.msg ) )
351412
#endif
352-
}
353413
}
354-
feedback->pushDebugInfo( QObject::tr( "Model processed ok. Executed %1 algorithms total" ).arg( executed.count() ) );
355-
356-
return QVariantMap();
357414
}
415+
feedback->pushDebugInfo( QObject::tr( "Model processed ok. Executed %1 algorithms total in %2 s." ).arg( executed.count() ).arg( totalTime.elapsed() / 1000.0 ) );
416+
417+
return finalResults;
418+
}
358419

359-
void QgsProcessingModelAlgorithm::setName( const QString &name )
420+
void QgsProcessingModelAlgorithm::setName( const QString &name )
360421
{
361422
mModelName = name;
362423
}
@@ -434,7 +495,9 @@ void QgsProcessingModelAlgorithm::updateDestinationParameters()
434495
{
435496
QgsProcessingOutputDefinition *output = destParam->toOutputDefinition();
436497
if ( output )
498+
{
437499
addOutput( output );
500+
}
438501
}
439502
}
440503
}

‎src/core/processing/qgsprocessingmodelalgorithm.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,8 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
763763
void dependsOnChildAlgorithmsRecursive( const QString &childId, QSet<QString> &depends ) const;
764764
void dependentChildAlgorithmsRecursive( const QString &childId, QSet<QString> &depends ) const;
765765

766+
QVariantMap parametersForChildAlgorithm( const ChildAlgorithm &child, const QVariantMap &modelParameters, const QMap<QString, QVariantMap> &results ) const;
767+
766768
/**
767769
* Saves this model to a QVariantMap, wrapped in a QVariant.
768770
* You can use QgsXmlUtils::writeVariant to save it to an XML document.

0 commit comments

Comments
 (0)