Repository: idaholab/SR2ML (language: python)

Issue:
Merge PRA plugin with SR2ML
--------
Issue Description
--------

**Is your feature request related to a problem? Please describe.**
Merge PRAplugin into SR2ml

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

----------------
For Change Control Board: Issue Review
----------------
This review should occur before any development is performed as a response to this issue.
- [ ] 1. Is it tagged with a type: defect or task?
- [ ] 2. Is it tagged with a priority: critical, normal or minor?
- [ ] 3. If it will impact requirements or requirements tests, is it tagged with requirements?
- [ ] 4. If it is a defect, can it cause wrong results for users? If so an email needs to be sent to the users.
- [ ] 5. Is a rationale provided? (Such as explaining why the improvement is needed or why current code is wrong.)

-------
For Change Control Board: Issue Closure
-------
This review should occur when the issue is imminently going to be closed.
- [ ] 1. If the issue is a defect, is the defect fixed?
- [ ] 2. If the issue is a defect, is the defect tested for in the regression test system?  (If not explain why not.)
- [ ] 3. If the issue can impact users, has an email to the users group been written (the email should specify if the defect impacts stable or master)?
- [ ] 4. If the issue is a defect, does it impact the latest release branch? If yes, is there any issue tagged with release (create if needed)?
- [ ] 5. If the issue is being closed without a pull request, has an explanation of why it is being closed been provided?



Discussion / hints:

Fix patch:
diff --git a/__init__.py b/__init__.py
index 8e17337..b71d019 100644
--- a/__init__.py
+++ b/__init__.py
@@ -7,3 +7,4 @@
 # from SR2ML.src import TDFailureRateReliabilityModel
 from SR2ML.src import ReliabilityModel
 from SR2ML.src import MaintenanceModel
+from SR2ML.src import MCSSolver
diff --git a/doc/user_manual/include/MCSsolver.tex b/doc/user_manual/include/MCSsolver.tex
new file mode 100644
index 0000000..321fb5c
--- /dev/null
+++ b/doc/user_manual/include/MCSsolver.tex
@@ -0,0 +1,76 @@
+\section{MCSSolver}
+\label{sec:MCSSolver}
+
+This model is designed to read from file a list of Minimal Cut Sets (MCSs) and to import such Boolean logic structure as a RAVEN model.
+Provided the sampled values of Basic Events (BEs) probabilities, the MCSSolver determines the probability of Top Event (TE), i.e., the union of the MCSs.
+The list of MCS must be provided through a CSV file with the following format:
+
+\begin{table}
+  \begin{center}
+    \caption{MCS file format.}
+    \label{tab:table1}
+    \begin{tabular}{c|c|c} 
+      \textbf{ID} & \textbf{Prob} & \textbf{MCS}\\
+      \hline
+      1, & 0.01, & BE1\\
+      2, & 0.02, & BE3\\
+      3, & 0.03, & BE2,BE4\\
+    \end{tabular}
+  \end{center}
+\end{table}
+
+In this example:
+\begin{itemize}
+  \item three MCSs are defined: MCS1 = BE1, MCS2 = BE3 and MCS3 = BE2 and BE4 
+  \item four BEs are defined: BE1, BE2, BE3 and BE4
+  \item probability of TE, i.e. P(TE), is equal to: $P(TE) = P(MCS1 \cup MCS2 \cup MCS3)$
+\end{itemize}
+
+Note that the MCSSolver considers only the list of MCSs and it discards the rest of data contained in the csv file.
+
+All the specifications of the MCSSolver model are given in the \xmlNode{ExternalModel} block. 
+Inside the \xmlNode{ExternalModel} block, the XML nodes that belong to this models are:
+\begin{itemize}
+  \item  \xmlNode{variables}, \xmlDesc{string, required parameter}, a list containing the names of both the input and output variables of the model
+  \item  \xmlNode{solverOrder},\xmlDesc{integer, required parameter}, solver order for $P(TE)$: it specifies the maximum calculation envelope 
+                                                                      for $P(TE)$, i.e., the maximum number of MCSs to be considered when evaluating the 
+                                                                      probability of their union
+  \item  \xmlNode{topEventID},\xmlDesc{string, required parameter}, the name of the alias variable for the Top Event
+  \item  \xmlNode{map},\xmlDesc{string, required parameter}, the name ID of the ET branching variable
+	  \begin{itemize}
+	    \item \xmlAttr{var}, \xmlDesc{required string attribute}, the ALIAS name ID of the basic event
+	  \end{itemize}
+\end{itemize}
+
+An example of RAVEN input file is the following:
+
+\begin{lstlisting}[style=XML,morekeywords={anAttribute},caption=MCSSolver model input example., label=lst:MCSSolver_InputExample]
+  <Models> 
+    ...
+    <Models>
+      <ExternalModel name="MCSmodel" subType="PRAplugin.MCSSolver">
+        <variables>statusBE1,statusBE2,statusBE3,statusBE4,TOP</variables>
+        <solverOrder>3</solverOrder>
+        <topEventID>TOP</topEventID>>
+        <map var='statusBE1'>BE1</map>
+        <map var='statusBE2'>BE2</map>
+        <map var='statusBE3'>BE3</map>
+        <map var='statusBE4'>BE4</map>
+      </ExternalModel>
+    </Models>
+    ...
+  </Models>
+\end{lstlisting}
+
+If $solverOrder=1$ then: $P(TE) = P(MCS1)+P(MCS2)+P(MCS3)$.  
+If $solverOrder=2$ then: $P(TE) = P(MCS1)+P(MCS2)+P(MCS3) - P(MCS1 MCS2) - P(MCS1 MCS3) - P(MCS2 MCS3)$.  
+If $solverOrder=3$ then: $P(TE) = P(MCS1)+P(MCS2)+P(MCS3) - P(MCS1 MCS2) - P(MCS1 MCS3) - P(MCS2 MCS3) + P(MCS1 MCS2 MCS3)$
+
+\subsection{MCSSolver model reference tests}
+The following is the provided analytic test:
+\begin{itemize}
+	\item test\_MCSSolver.xml
+\end{itemize}
+
+
+
diff --git a/doc/user_manual/user_manual.tex b/doc/user_manual/user_manual.tex
index a2b2006..404bb6d 100644
--- a/doc/user_manual/user_manual.tex
+++ b/doc/user_manual/user_manual.tex
@@ -299,6 +299,7 @@
     \input{include/DataClassifier.tex}
     \input{include/ETdataImporter.tex}
     \input{include/FTdataImporter.tex}
+    \input{include/MCSsolver.tex}
     \input{include/ReliabilityModels.tex}
     \input{include/MaintenanceModels.tex}
 
diff --git a/src/MCSSolver.py b/src/MCSSolver.py
new file mode 100644
index 0000000..3782d96
--- /dev/null
+++ b/src/MCSSolver.py
@@ -0,0 +1,145 @@
+# 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 June 24, 2020
+
+@author: mandd
+"""
+
+#External Modules---------------------------------------------------------------
+import numpy as np
+import itertools
+import math
+#External Modules End-----------------------------------------------------------
+
+#Internal Modules---------------------------------------------------------------
+from PluginsBaseClasses.ExternalModelPluginBase import ExternalModelPluginBase
+from PostProcessors.MCSimporter import mcsReader
+#Internal Modules End-----------------------------------------------------------
+
+class MCSSolver(ExternalModelPluginBase):
+  """
+    This class is designed to create a MCS solver model
+  """
+  def __init__(self):
+    """
+      Constructor
+      @ In, None
+      @ Out, None
+    """
+    ExternalModelPluginBase.__init__(self)
+
+  def initialize(self, container, runInfoDict, inputFiles):
+    """
+      Method to initialize the Event-Tree model
+      @ In, container, object, self-like object where all the variables can be stored
+      @ In, runInfoDict, dict, dictionary containing all the RunInfo parameters (XML node <RunInfo>)
+      @ In, inputFiles, list, list of input files (if any)
+      @ Out, None
+    """
+
+
+  def _readMoreXML(self, container, xmlNode):
+    """
+      Method to read the portion of the XML that belongs to the MCS solver model
+      @ In, container, object, self-like object where all the variables can be stored
+      @ In, xmlNode, xml.etree.ElementTree.Element, XML node that needs to be read
+      @ Out, None
+    """
+    container.filename = None
+    container.mapping    = {}
+    container.invMapping = {}
+
+    for child in xmlNode:
+      if child.tag == 'topEventID':
+        container.topEventID = child.text.strip()
+      elif child.tag == 'solverOrder':
+        try:
+          self.solverOrder = int(child.text.strip())
+        except:
+          raise IOError("MCSSolver: xml node solverOrder must contain an integer value")
+      elif child.tag == 'variables':
+        variables = [str(var.strip()) for var in child.text.split(",")]
+      elif child.tag == 'map':
+        container.mapping[child.get('var')]      = child.text.strip()
+        container.invMapping[child.text.strip()] = child.get('var')
+      else:
+        raise IOError("MCSSolver: xml node " + str(child.tag) + " is not allowed")
+
+
+  def createNewInput(self, container, inputs, samplerType, **kwargs):
+    """
+      This function has been added for this model in order to generate the terms in each order
+      @ In, container, object, self-like object where all the variables can be stored
+      @ In, inputs, list, the inputs (list) to start from to generate the new one
+      @ In, samplerType, string, is the type of sampler that is calling to generate a new input
+      @ In, **kwargs, dict,  is a dictionary that contains the information coming from the sampler,
+           a mandatory key is the sampledVars'that contains a dictionary {'name variable':value}
+      @ Out, kwargs, dict, dictionary which contains the information coming from the sampler
+    """
+    if len(inputs) > 1:
+      raise IOError("MCSSolver: More than one file has been passed to the MCS solver")
+
+    mcsIDs, probability, mcsList, beList = mcsReader(inputs[0])
+
+    self.topEventTerms = {}
+
+    # mcsList is supposed to be a list of lists
+    # E.g., if the MCS are ABC CD and AE --> MCS1=['A','B','C'], MCS2=['D','C'], MCS3=['A','E']
+    #       then mcsList = [MCS1,MCS2,MCS3] =
+    #                    = [['A', 'B', 'C'], ['D', 'C'], ['A', 'E']]
+    # Top event should be:   ABC + CD + AE +
+    #                      - ABCD - ABCE - ACDE
+    #                      + ABCDE
+
+    for order in range(1,self.solverOrder+1):
+      self.topEventTerms[order]=[]
+      terms = list(itertools.combinations(mcsList,order))
+      # terms is a list of tuples
+      # E.g., for order=2: [ (['A', 'B', 'C'], ['D', 'C']),
+      #                      (['A', 'B', 'C'], ['A', 'E']),
+      #                      (['D', 'C'], ['A', 'E']) ]
+
+      basicEventCombined = list(set(itertools.chain.from_iterable(term)) for term in terms)
+      self.topEventTerms[order]=basicEventCombined
+
+    return kwargs
+
+  def run(self, container, inputs):
+    """
+      This method determines the status of the TopEvent of the FT provided the status of its Basic Events
+      @ In, container, object, self-like object where all the variables can be stored
+      @ In, inputs, dict, dictionary of inputs from RAVEN
+      @ Out, None
+    """
+    inputForSolver = {}
+    for key in container.invMapping.keys():
+      inputForSolver[key] = inputs[container.invMapping[key]]
+
+    teProbability = 0.0
+    multiplier = 1.0
+
+    # perform probability calculation for each order level
+    for order in range(1,self.solverOrder+1):
+      orderProbability=0
+      for term in self.topEventTerms[order]:
+        # map the sampled values of the basic event probabilities to the MCS basic events ID
+        termValues = list(map(inputForSolver.get,term))
+        orderProbability = orderProbability + np.prod(termValues)
+      teProbability = teProbability + multiplier * orderProbability
+      multiplier = -1.0 * multiplier
+
+    container.__dict__[container.topEventID] = np.asarray(float(teProbability))
+
+


Test patch:
diff --git a/tests/MCSSolver/MCSlist.csv b/tests/MCSSolver/MCSlist.csv
new file mode 100644
index 0000000..5a6a6bc
--- /dev/null
+++ b/tests/MCSSolver/MCSlist.csv
@@ -0,0 +1,4 @@
+ID, Prob, MCS
+1,4.0E-02,BE1
+2,4.0E-02,BE3
+3,3.0E-03,BE2,BE4
\ No newline at end of file
diff --git a/tests/MCSSolverMcCormick/MCSlist.csv b/tests/MCSSolverMcCormick/MCSlist.csv
new file mode 100644
index 0000000..536c1db
--- /dev/null
+++ b/tests/MCSSolverMcCormick/MCSlist.csv
@@ -0,0 +1,6 @@
+ID, Prob, MCS
+1,1.0E-02,A
+2,1.0E-02,B,D
+3,5.0E-03,B,E
+4,5.0E-03,C,D
+5,5.0E-03,C,E
\ No newline at end of file
diff --git a/tests/gold/MCSSolver/Print_sim_PS.csv b/tests/gold/MCSSolver/Print_sim_PS.csv
new file mode 100644
index 0000000..3cd100b
--- /dev/null
+++ b/tests/gold/MCSSolver/Print_sim_PS.csv
@@ -0,0 +1,2 @@
+statusBE1,statusBE2,statusBE3,statusBE4,TOP
+0.1,0.2,0.3,0.4,0.4204
diff --git a/tests/gold/MCSSolverMcCormick/Print_sim_PS1.csv b/tests/gold/MCSSolverMcCormick/Print_sim_PS1.csv
new file mode 100644
index 0000000..2e2a733
--- /dev/null
+++ b/tests/gold/MCSSolverMcCormick/Print_sim_PS1.csv
@@ -0,0 +1,2 @@
+statusA,statusB,statusC,statusD,statusE,TOP
+0.01,0.1,0.1,0.1,0.1,0.05
diff --git a/tests/gold/MCSSolverMcCormick/Print_sim_PS2.csv b/tests/gold/MCSSolverMcCormick/Print_sim_PS2.csv
new file mode 100644
index 0000000..8d2c023
--- /dev/null
+++ b/tests/gold/MCSSolverMcCormick/Print_sim_PS2.csv
@@ -0,0 +1,2 @@
+statusA,statusB,statusC,statusD,statusE,TOP
+0.01,0.1,0.1,0.1,0.1,0.0454
diff --git a/tests/gold/MCSSolverMcCormick/Print_sim_PS3.csv b/tests/gold/MCSSolverMcCormick/Print_sim_PS3.csv
new file mode 100644
index 0000000..5d1e7ca
--- /dev/null
+++ b/tests/gold/MCSSolverMcCormick/Print_sim_PS3.csv
@@ -0,0 +1,2 @@
+statusA,statusB,statusC,statusD,statusE,TOP
+0.01,0.1,0.1,0.1,0.1,0.045842
diff --git a/tests/gold/MCSSolverMcCormick/Print_sim_PS4.csv b/tests/gold/MCSSolverMcCormick/Print_sim_PS4.csv
new file mode 100644
index 0000000..34645a7
--- /dev/null
+++ b/tests/gold/MCSSolverMcCormick/Print_sim_PS4.csv
@@ -0,0 +1,2 @@
+statusA,statusB,statusC,statusD,statusE,TOP
+0.01,0.1,0.1,0.1,0.1,0.045738
diff --git a/tests/gold/MCSSolverMcCormick/Print_sim_PS5.csv b/tests/gold/MCSSolverMcCormick/Print_sim_PS5.csv
new file mode 100644
index 0000000..cc521f9
--- /dev/null
+++ b/tests/gold/MCSSolverMcCormick/Print_sim_PS5.csv
@@ -0,0 +1,2 @@
+statusA,statusB,statusC,statusD,statusE,TOP
+0.01,0.1,0.1,0.1,0.1,0.045739
diff --git a/tests/test_MCSSolver.xml b/tests/test_MCSSolver.xml
new file mode 100644
index 0000000..6a42d2d
--- /dev/null
+++ b/tests/test_MCSSolver.xml
@@ -0,0 +1,88 @@
+<Simulation verbosity="debug">
+  <!--
+  This is a test for the system: TopEvent = BE1 or BE3 or (BE2 or BE4)
+  MCS = BE1, BE3, BE2 BE4
+  Hence: P(TopEvent) = P(BE1) + P(BE3) + P(BE2)*P(BE4)
+                     - P(BE1)*P(BE3) - P(BE1)*P(BE2)*P(BE4) - P(BE2)*P(BE3)*P(BE4)
+                     + P(BE1)*P(BE2)*P(BE3)*P(BE4)
+  -->
+  <TestInfo>
+    <name>SR2ML/tests.MCSSolver</name>
+    <author>mandd</author>
+    <created>2020-06-25</created>
+    <classesTested>SR2ML.MCSSolver</classesTested>
+    <description>
+      This model is designed to read from file a list of Minimal Cut Sets (MCSs) and
+      to import such Boolean logic structure as a RAVEN model. Provided the sampled
+      values of Basic Events (BEs) probabilities, the MCSSolver determines the
+      probability of Top Event (TE), i.e., the union of the MCSs.
+    </description>
+    <revisions>
+      <revision author="wangc" date="2021-01-13">move test from PRAplugin to SR2ML</revision>
+    </revisions>
+  </TestInfo>
+
+  <RunInfo>
+    <WorkingDir>MCSSolver</WorkingDir>
+    <Sequence>simRun</Sequence>
+    <batchSize>1</batchSize>
+  </RunInfo>
+
+  <Files>
+    <Input name="MCSlistFile" type="MCSlist">MCSlist.csv</Input>
+  </Files>
+
+  <Models>
+    <ExternalModel name="MCSmodel" subType="SR2ML.MCSSolver">
+      <variables>statusBE1,statusBE2,statusBE3,statusBE4,TOP</variables>
+      <solverOrder>3</solverOrder>
+      <topEventID>TOP</topEventID>>
+      <map var='statusBE1'>BE1</map>
+      <map var='statusBE2'>BE2</map>
+      <map var='statusBE3'>BE3</map>
+      <map var='statusBE4'>BE4</map>
+    </ExternalModel>
+  </Models>
+
+  <Samplers>
+    <MonteCarlo name="MC_external">
+      <samplerInit>
+        <limit>1</limit>
+      </samplerInit>
+      <constant name="statusBE1">0.1</constant>
+      <constant name="statusBE2">0.2</constant>
+      <constant name="statusBE3">0.3</constant>
+      <constant name="statusBE4">0.4</constant>
+    </MonteCarlo>
+  </Samplers>
+
+  <Steps>
+    <MultiRun name="simRun">
+      <Input   class="Files"        type="MCSlist"         >MCSlistFile</Input>
+      <Model   class="Models"       type="ExternalModel"   >MCSmodel</Model>
+      <Sampler class="Samplers"     type="MonteCarlo"      >MC_external</Sampler>
+      <Output  class="DataObjects"  type="PointSet"        >sim_PS</Output>
+      <Output  class="OutStreams"   type="Print"           >Print_sim_PS</Output>
+    </MultiRun>
+  </Steps>
+
+  <OutStreams>
+    <Print name="Print_sim_PS">
+      <type>csv</type>
+      <source>sim_PS</source>
+      <what>input,output</what>
+    </Print>
+  </OutStreams>
+
+  <DataObjects>
+    <PointSet name="inputPlaceHolder">
+      <Input>statusBE1,statusBE2,statusBE3,statusBE4</Input>
+      <Output>OutputPlaceHolder</Output>
+    </PointSet>
+    <PointSet name="sim_PS">
+      <Input>statusBE1,statusBE2,statusBE3,statusBE4</Input>
+      <Output>TOP</Output>
+    </PointSet>
+  </DataObjects>
+
+</Simulation>
diff --git a/tests/test_MCSSolverMcCormick.xml b/tests/test_MCSSolverMcCormick.xml
new file mode 100644
index 0000000..0ba96ac
--- /dev/null
+++ b/tests/test_MCSSolverMcCormick.xml
@@ -0,0 +1,196 @@
+<Simulation verbosity="debug">
+  <!--
+  This is an analytical test for the system: TopEvent = A + BD + BE + CD + CE
+  See McCormick book page 108-110
+  -->
+  <TestInfo>
+    <name>SR2ML/tests.MCSSolver</name>
+    <author>mandd</author>
+    <created>2020-06-25</created>
+    <classesTested>SR2ML.MCSSolver</classesTested>
+    <description>
+      This model is designed to read from file a list of Minimal Cut Sets (MCSs) and
+      to import such Boolean logic structure as a RAVEN model. Provided the sampled
+      values of Basic Events (BEs) probabilities, the MCSSolver determines the
+      probability of Top Event (TE), i.e., the union of the MCSs.
+    </description>
+    <analytic>
+    This test evaluates the MCSSolver model for a specific case found in literature (see pages 108-110
+    of N. J. McCormick, ``Reliability and Risk Analysis'', Academic Press inc. [1981]).
+    Provided this set of minimal cuts sets (MCSs) for the top event TopEvent: TopEvent = A + BD + BE + CD + CE
+    </analytic>
+    <revisions>
+      <revision author="wangc" date="2021-01-13">move test from PRAplugin to SR2ML</revision>
+    </revisions>
+  </TestInfo>
+
+  <RunInfo>
+    <WorkingDir>MCSSolverMcCormick</WorkingDir>
+    <Sequence>simRun1,simRun2,simRun3,simRun4,simRun5</Sequence>
+    <batchSize>1</batchSize>
+  </RunInfo>
+
+  <Files>
+    <Input name="MCSlistFile" type="MCSlist">MCSlist.csv</Input>
+  </Files>
+
+  <Models>
+    <ExternalModel name="MCSmodel1" subType="SR2ML.MCSSolver">
+      <variables>statusA,statusB,statusC,statusD,statusE,TOP</variables>
+      <solverOrder>1</solverOrder>
+      <topEventID>TOP</topEventID>>
+      <map var='statusA'>A</map>
+      <map var='statusB'>B</map>
+      <map var='statusC'>C</map>
+      <map var='statusD'>D</map>
+      <map var='statusE'>E</map>
+    </ExternalModel>
+    <ExternalModel name="MCSmodel2" subType="SR2ML.MCSSolver">
+      <variables>statusA,statusB,statusC,statusD,statusE,TOP</variables>
+      <solverOrder>2</solverOrder>
+      <topEventID>TOP</topEventID>>
+      <map var='statusA'>A</map>
+      <map var='statusB'>B</map>
+      <map var='statusC'>C</map>
+      <map var='statusD'>D</map>
+      <map var='statusE'>E</map>
+    </ExternalModel>
+    <ExternalModel name="MCSmodel3" subType="SR2ML.MCSSolver">
+      <variables>statusA,statusB,statusC,statusD,statusE,TOP</variables>
+      <solverOrder>3</solverOrder>
+      <topEventID>TOP</topEventID>>
+      <map var='statusA'>A</map>
+      <map var='statusB'>B</map>
+      <map var='statusC'>C</map>
+      <map var='statusD'>D</map>
+      <map var='statusE'>E</map>
+    </ExternalModel>
+    <ExternalModel name="MCSmodel4" subType="SR2ML.MCSSolver">
+      <variables>statusA,statusB,statusC,statusD,statusE,TOP</variables>
+      <solverOrder>4</solverOrder>
+      <topEventID>TOP</topEventID>>
+      <map var='statusA'>A</map>
+      <map var='statusB'>B</map>
+      <map var='statusC'>C</map>
+      <map var='statusD'>D</map>
+      <map var='statusE'>E</map>
+    </ExternalModel>
+    <ExternalModel name="MCSmodel5" subType="SR2ML.MCSSolver">
+      <variables>statusA,statusB,statusC,statusD,statusE,TOP</variables>
+      <solverOrder>5</solverOrder>
+      <topEventID>TOP</topEventID>>
+      <map var='statusA'>A</map>
+      <map var='statusB'>B</map>
+      <map var='statusC'>C</map>
+      <map var='statusD'>D</map>
+      <map var='statusE'>E</map>
+    </ExternalModel>
+  </Models>
+
+  <Samplers>
+    <MonteCarlo name="MC_external">
+      <samplerInit>
+        <limit>1</limit>
+      </samplerInit>
+      <constant name="statusA">0.01</constant>
+      <constant name="statusB">0.1</constant>
+      <constant name="statusC">0.1</constant>
+      <constant name="statusD">0.1</constant>
+      <constant name="statusE">0.1</constant>
+    </MonteCarlo>
+  </Samplers>
+
+  <Steps>
+    <MultiRun name="simRun1">
+      <Input   class="Files"        type="MCSlist"         >MCSlistFile</Input>
+      <Model   class="Models"       type="ExternalModel"   >MCSmodel1</Model>
+      <Sampler class="Samplers"     type="MonteCarlo"      >MC_external</Sampler>
+      <Output  class="DataObjects"  type="PointSet"        >sim_PS1</Output>
+      <Output  class="OutStreams"   type="Print"           >Print_sim_PS1</Output>
+    </MultiRun>
+    <MultiRun name="simRun2">
+      <Input   class="Files"        type="MCSlist"         >MCSlistFile</Input>
+      <Model   class="Models"       type="ExternalModel"   >MCSmodel2</Model>
+      <Sampler class="Samplers"     type="MonteCarlo"      >MC_external</Sampler>
+      <Output  class="DataObjects"  type="PointSet"        >sim_PS2</Output>
+      <Output  class="OutStreams"   type="Print"           >Print_sim_PS2</Output>
+    </MultiRun>
+    <MultiRun name="simRun3">
+      <Input   class="Files"        type="MCSlist"         >MCSlistFile</Input>
+      <Model   class="Models"       type="ExternalModel"   >MCSmodel3</Model>
+      <Sampler class="Samplers"     type="MonteCarlo"      >MC_external</Sampler>
+      <Output  class="DataObjects"  type="PointSet"        >sim_PS3</Output>
+      <Output  class="OutStreams"   type="Print"           >Print_sim_PS3</Output>
+    </MultiRun>
+    <MultiRun name="simRun4">
+      <Input   class="Files"        type="MCSlist"         >MCSlistFile</Input>
+      <Model   class="Models"       type="ExternalModel"   >MCSmodel4</Model>
+      <Sampler class="Samplers"     type="MonteCarlo"      >MC_external</Sampler>
+      <Output  class="DataObjects"  type="PointSet"        >sim_PS4</Output>
+      <Output  class="OutStreams"   type="Print"           >Print_sim_PS4</Output>
+    </MultiRun>
+    <MultiRun name="simRun5">
+      <Input   class="Files"        type="MCSlist"         >MCSlistFile</Input>
+      <Model   class="Models"       type="ExternalModel"   >MCSmodel5</Model>
+      <Sampler class="Samplers"     type="MonteCarlo"      >MC_external</Sampler>
+      <Output  class="DataObjects"  type="PointSet"        >sim_PS5</Output>
+      <Output  class="OutStreams"   type="Print"           >Print_sim_PS5</Output>
+    </MultiRun>
+  </Steps>
+
+  <OutStreams>
+    <Print name="Print_sim_PS1">
+      <type>csv</type>
+      <source>sim_PS1</source>
+      <what>input,output</what>
+    </Print>
+    <Print name="Print_sim_PS2">
+      <type>csv</type>
+      <source>sim_PS2</source>
+      <what>input,output</what>
+    </Print>
+    <Print name="Print_sim_PS3">
+      <type>csv</type>
+      <source>sim_PS3</source>
+      <what>input,output</what>
+    </Print>
+    <Print name="Print_sim_PS4">
+      <type>csv</type>
+      <source>sim_PS4</source>
+      <what>input,output</what>
+    </Print>
+    <Print name="Print_sim_PS5">
+      <type>csv</type>
+      <source>sim_PS5</source>
+      <what>input,output</what>
+    </Print>
+  </OutStreams>
+
+  <DataObjects>
+    <PointSet name="inputPlaceHolder">
+      <Input>statusA,statusB,statusC,statusD,statusE</Input>
+      <Output>OutputPlaceHolder</Output>
+    </PointSet>
+    <PointSet name="sim_PS1">
+      <Input>statusA,statusB,statusC,statusD,statusE</Input>
+      <Output>TOP</Output>
+    </PointSet>
+    <PointSet name="sim_PS2">
+      <Input>statusA,statusB,statusC,statusD,statusE</Input>
+      <Output>TOP</Output>
+    </PointSet>
+    <PointSet name="sim_PS3">
+      <Input>statusA,statusB,statusC,statusD,statusE</Input>
+      <Output>TOP</Output>
+    </PointSet>
+    <PointSet name="sim_PS4">
+      <Input>statusA,statusB,statusC,statusD,statusE</Input>
+      <Output>TOP</Output>
+    </PointSet>
+    <PointSet name="sim_PS5">
+      <Input>statusA,statusB,statusC,statusD,statusE</Input>
+      <Output>TOP</Output>
+    </PointSet>
+  </DataObjects>
+
+</Simulation>
diff --git a/tests/tests b/tests/tests
index c874a10..081f6a3 100644
--- a/tests/tests
+++ b/tests/tests
@@ -1,47 +1,47 @@
 [Tests]
- 
+
  [./TestGraphModel]
   type  = 'RavenFramework'
   input = 'test_graphModel.xml'
   UnorderedCsv   = 'graphModel/Print_sim_PS.csv'
  [../]
- 
+
  [./TestMarkovModel_2states]
   type  = 'RavenFramework'
   input = 'test_markovModel_2states.xml'
   UnorderedCsv   = 'markovModel_2states/Print_sim_PS.csv'
  [../]
- 
+
  [./TestMarkovModel_3states]
   type  = 'RavenFramework'
   input = 'test_markovModel_3states.xml'
   UnorderedCsv   = 'markovModel_3states/Print_sim_PS.csv'
- [../] 
- 
+ [../]
+
  [./TestMarkovModel_3states_complexTrans]
   type  = 'RavenFramework'
   input = 'test_markovModel_3states_complexTrans.xml'
   UnorderedCsv   = 'markovModel_3states_complexTrans/Print_sim_PS.csv'
- [../] 
- 
+ [../]
+
  [./TestMarkovModel_3states_instantTrans]
   type  = 'RavenFramework'
   input = 'test_markovModel_3states_instantTrans.xml'
   UnorderedCsv   = 'markovModel_3states_instantTrans/Print_sim_PS.csv'
- [../] 
- 
+ [../]
+
  [./TestMarkovModel_2states_tau]
   type  = 'RavenFramework'
   input = 'test_markovModel_2states_tau.xml'
   UnorderedCsv   = 'markovModel_2states_tau/Print_sim_PS.csv'
  [../]
- 
+
  [./TestETModel]
   type  = 'RavenFramework'
   input = 'test_ETmodel.xml'
   UnorderedCsv   = 'ETmodel/Print_sim_PS.csv'
  [../]
- 
+
  [./TestFTModel]
   type  = 'RavenFramework'
   input = 'test_FTmodel.xml'
@@ -77,4 +77,16 @@
   input = 'test_ensemblePRAModel_mixed.xml'
   UnorderedCsv   = 'ensembleMixed/Print_sim_PS.csv'
  [../]
+
+ [./TestMCSSolver]
+  type  = 'RavenFramework'
+  input = 'test_MCSSolver.xml'
+  UnorderedCsv   = 'MCSSolver/Print_sim_PS.csv'
+ [../]
+
+ [./TestMCSSolverMcCormick]
+  type  = 'RavenFramework'
+  input = 'test_MCSSolverMcCormick.xml'
+  UnorderedCsv   = 'MCSSolverMcCormick/Print_sim_PS1.csv MCSSolverMcCormick/Print_sim_PS2.csv MCSSolverMcCormick/Print_sim_PS3.csv MCSSolverMcCormick/Print_sim_PS4.csv MCSSolverMcCormick/Print_sim_PS5.csv'
+ [../]
 []