Skip to content

Commit

Permalink
Implementation of the SampleSelector postprocessor (#787)
Browse files Browse the repository at this point in the history
* implementation of the SampleSelector postprocessor

* removed debug prints from Post Processor file

* removed trailing blanks from PostProcessor file

* added max in the test and addressed reviewer's comments

* corrected the tests file
  • Loading branch information
gmaronati authored and alfoa committed Sep 14, 2018
1 parent 9814a9f commit da4ec50
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 0 deletions.
36 changes: 36 additions & 0 deletions doc/user_manual/postprocessor.tex
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ \subsection{PostProcessor}
\item \textbf{Metric}
\item \textbf{CrossValidation}
\item \textbf{ValueDuration}
\item \textbf{SampleSelector}
%\item \textbf{PrintCSV}
%\item \textbf{LoadCsvIntoInternalObject}
\end{itemize}
Expand Down Expand Up @@ -2190,3 +2191,38 @@ \subsubsection{ValueDuration}
...
</Simulation>
\end{lstlisting}
%%%%%%%%%%%%%% SampleSelector %%%%%%%%%%%%%%%%%%%
\subsubsection{SampleSelector}
\label{SampleSelectorPP}
The \xmlNode{SampleSelector} postprocessor is a tool to select the row in which the minimum or the maximum of a target is found.
The \xmlNode{SampleSelector} postprocessor can act on \xmlNode{DataObjects}, and generates a
\xmlNode{DataObject} in return.
\ppType{SampleSelector}{SampleSelector}
%
\begin{itemize}
\item \xmlNode{target}, \xmlDesc{string, required field}, specifies the name of the
target for which the minimum or maximum should be found.
\item \xmlNode{criterion}, \xmlDesc{string, required field}, specifies whether the minimum or maximum should be found.
\end{itemize}
\textbf{Example:}
\begin{lstlisting}[style=XML]
<Simulation>
...
<Models>
...
<PostProcessor name="pp" subType="SampleSelector">
<target>x</target>
<criterion>min</criterion>
</PostProcessor>
...
</Models>
...
</Simulation>
\end{lstlisting}
1 change: 1 addition & 0 deletions framework/PostProcessors/Factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from .SafestPoint import SafestPoint
from .LimitSurface import LimitSurface
from .ValueDuration import ValueDuration
from .SampleSelector import SampleSelector
from .ImportanceRank import ImportanceRank
from .BasicStatistics import BasicStatistics
from .CrossValidation import CrossValidation
Expand Down
140 changes: 140 additions & 0 deletions framework/PostProcessors/SampleSelector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Copyright 2017 Battelle Energy Alliance, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Created on August 28, 2018
@author: giovannimaronati
"""
from __future__ import division, print_function , unicode_literals, absolute_import
import warnings
warnings.simplefilter('default', DeprecationWarning)

#External Modules---------------------------------------------------------------
import numpy as np
#External Modules End-----------------------------------------------------------

#Internal Modules---------------------------------------------------------------
from .PostProcessor import PostProcessor
from utils import utils
from utils import InputData
import Runners
#Internal Modules End-----------------------------------------------------------

class SampleSelector(PostProcessor):
"""
This postprocessor selects the row in which the minimum or the maximum
of a target is found.The postprocessor can act on DataObject, and
generates a DataObject in return.
"""

@classmethod
def getInputSpecification(cls):
"""
Method to get a reference to a class that specifies the input data for
class cls.
@ In, cls, the class for which we are retrieving the specification
@ Out, inputSpecification, InputData.ParameterInput, class to use for
specifying input of cls.
"""
inSpec= super(SampleSelector, cls).getInputSpecification()
inSpec.addSub(InputData.parameterInputFactory('target',
contentType=InputData.StringType,
strictMode=True))
inSpec.addSub(InputData.parameterInputFactory('criterion',
contentType=InputData.StringType,
strictMode=True))
return inSpec

def __init__(self, messageHandler):
"""
Constructor
@ In, messageHandler, MessageHandler, message handler object
@ Out, None
"""
PostProcessor.__init__(self, messageHandler)
self.dynamic = True # from base class, indicates time-dependence is handled internally
self.target = None # string, variable to apply postprocessor to

def _localReadMoreXML(self, xmlNode):
"""
Function to read the portion of the xml input that belongs to this specialized class
and initialize some stuff based on the inputs got
@ In, xmlNode, xml.etree.Element, Xml element node
@ Out, None
"""
paramInput = self.getInputSpecification()()
paramInput.parseNode(xmlNode)
self._handleInput(paramInput)

def _handleInput(self, paramInput):
"""
Function to handle the parsed paramInput for this class.
@ In, paramInput, ParameterInput, the already-parsed input.
@ Out, None
"""
for child in paramInput.subparts:
tag = child.getName()
if tag == 'target':
self.target = child.value
if tag == 'criterion':
self.criterion = child.value
elif tag == 'number':
self.numBins = child.value

def inputToInternal(self, currentInp):
"""
Method to convert an input object into the internal format that is
understandable by this pp.
In this case, we only want data objects!
@ In, currentInp, list, an object that needs to be converted
@ Out, currentInp, DataObject.HistorySet, input data
"""
if len(currentInp) > 1:
self.raiseAnError(IOError, 'Expected 1 input DataObject, but received {} inputs!'.format(len(currentInp)))
currentInp = currentInp[0]
if currentInp.type not in ['PointSet','HistorySet','DataSet']:
self.raiseAnError(IOError, 'SampleSelector postprocessor "{}" requires a DataObject input! Got "{}".'
.format(self.name, currentInput.type))
return currentInp

def run(self, inputIn):
"""
This method executes the postprocessor action.
@ In, inputIn, object, object contained the data to process. (inputToInternal output)
@ Out, realizations, list, list of realizations obtained
"""
inData = self.inputToInternal(inputIn)
realizations = []
# actual method: pick min/max target
d = inData.asDataset()
i = d[self.target].argmin()
pick = inData.realization(index = i)

return pick

def collectOutput(self, finishedJob, output):
"""
Function to place all of the computed data into the output object
@ In, finishedJob, JobHandler External or Internal instance, A JobHandler object that is in charge of running this post-processor
@ In, output, DataObject.DataObject, The object where we want to place our computed results
@ Out, None
"""
evaluation = finishedJob.getEvaluation()
if isinstance(evaluation, Runners.Error):
self.raiseAnError(RuntimeError, "No available output to collect!")

pick = evaluation[1]
for key,value in pick.items():
pick[key] = np.atleast_1d(value)
output.addRealization(pick)
2 changes: 2 additions & 0 deletions framework/PostProcessors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from .SafestPoint import SafestPoint
from .LimitSurface import LimitSurface
from .ValueDuration import ValueDuration
from .SampleSelector import SampleSelector
from .ImportanceRank import ImportanceRank
from .CrossValidation import CrossValidation
from .BasicStatistics import BasicStatistics
Expand Down Expand Up @@ -73,6 +74,7 @@
'Metric',
'CrossValidation',
'ValueDuration',
'SampleSelector',
'ETImporter'] + additionalModules

# 'RavenOutput', # deprecated for now
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2017 Battelle Energy Alliance, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import copy as cp
def run(self,Input):
self.x1 = 2.5*cp.deepcopy(Input["x"])
self.y1 = 3.5*cp.deepcopy(Input['y'])
114 changes: 114 additions & 0 deletions tests/framework/PostProcessors/SampleSelector/basic.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?xml version="1.0" ?>
<Simulation verbosity="debug">
<RunInfo>
<WorkingDir>Basic</WorkingDir>
<Sequence>Sample,Process_min,Process_max</Sequence>
<batchSize>1</batchSize>
</RunInfo>

<TestInfo>
<name>framework/PostProcessors/SampleSelector.Basic</name>
<author>gm</author>
<created>2018-09-12</created>
<classesTested>PostProcessors.SampleSelector</classesTested>
<description>
This test checks basic functionalities of the Sample Selector. The model
multiplies the input x by 2.5 to obtain x1, and y is multiplied by 3.5 to obtain y1.
x and y are sampled through a Monte Carlo sampler, with 10 realizations. The
SampleSelector postprocessor is called twice, once to pick the minimum of x1,
and once to pick the maximum of y1.
</description>
</TestInfo>

<Models>
<ExternalModel ModuleToLoad="simpleMirrowModel" name="mirrowModel" subType="">
<variables>x,y,x1,y1</variables>
</ExternalModel>
<PostProcessor name="PPmin" subType="SampleSelector" verbosity="debug">
<target> x1 </target>
<criterion> min </criterion>
</PostProcessor>
<PostProcessor name="PPmax" subType="SampleSelector" verbosity="debug">
<target> y1 </target>
<criterion> max </criterion>
</PostProcessor>
</Models>


<Distributions>
<Normal name="x0_distrib">
<mean>100</mean>
<sigma>50.0</sigma>
</Normal>
<Normal name="y0_distrib">
<mean>100</mean>
<sigma>50.0</sigma>
</Normal>
</Distributions>

<Samplers>
<MonteCarlo name="MC_external">
<samplerInit>
<limit>10</limit>
</samplerInit>
<variable name="x">
<distribution>x0_distrib</distribution>
</variable>
<variable name="y">
<distribution>y0_distrib</distribution>
</variable>
</MonteCarlo>
</Samplers>

<Steps>
<MultiRun name="Sample" re-seeding="20021986">
<Input class="DataObjects" type="PointSet">inputPlaceHolder2</Input>
<Model class="Models" type="ExternalModel">mirrowModel</Model>
<Sampler class="Samplers" type="MonteCarlo">MC_external</Sampler>
<Output class="DataObjects" type="PointSet">outputDataMC</Output>
</MultiRun>
<PostProcess name="Process_min">
<Input class="DataObjects" type="PointSet">outputDataMC</Input>
<Model class="Models" type="PostProcessor">PPmin</Model>
<Output class="DataObjects" type="PointSet">selected_min</Output>
<Output class="OutStreams" type="Print">selected_printed_min</Output>
</PostProcess>
<PostProcess name="Process_max">
<Input class="DataObjects" type="PointSet">outputDataMC</Input>
<Model class="Models" type="PostProcessor">PPmax</Model>
<Output class="DataObjects" type="PointSet">selected_max</Output>
<Output class="OutStreams" type="Print">selected_printed_max</Output>
</PostProcess>
</Steps>

<OutStreams>
<Print name="selected_printed_min">
<type>csv</type>
<source>selected_min</source>
</Print>
<Print name="selected_printed_max">
<type>csv</type>
<source>selected_max</source>
</Print>
</OutStreams>

<DataObjects>
<PointSet name="inputPlaceHolder2">
<Input>x,y</Input>
<Output>OutputPlaceHolder</Output>
</PointSet>
<PointSet name="outputDataMC">
<Input>x,y</Input>
<Output>x1,y1</Output>
</PointSet>
<PointSet name="selected_min">
<Input>x,y</Input>
<Output>x1</Output>
</PointSet>
<PointSet name="selected_max">
<Input>x,y</Input>
<Output>y1</Output>
</PointSet>
</DataObjects>

</Simulation>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x,y,y1
144.449814059,4.76195963805,16.6668587332
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x,y,x1
57.5565999227,132.31459623,143.891499807
8 changes: 8 additions & 0 deletions tests/framework/PostProcessors/SampleSelector/tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Tests]
[./Basic]
type = 'RavenFramework'
input = 'basic.xml'
output = 'Basic/selected_printed_min.xml Basic/selected_printed_max.xml'
csv = 'Basic/selected_printed_min.csv Basic/selected_printed_max.csv'
[../]
[]

0 comments on commit da4ec50

Please sign in to comment.