diff --git a/CHANGELOG.md b/CHANGELOG.md index 17ae0c01..8a4fde76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. executable to be used ([#75](https://github.com/watts-dev/watts/pull/75)) * A `verbose` argument has been added to `Plugin.__call__` that controls whether screen output is printed ([#82](https://github.com/watts-dev/watts/pull/82)) +* Develop capability to run WATTS with NEAMS Workbench. ## [0.4.0] diff --git a/doc/source/dev/workbench.rst b/doc/source/dev/workbench.rst new file mode 100644 index 00000000..9e3e55c7 --- /dev/null +++ b/doc/source/dev/workbench.rst @@ -0,0 +1,103 @@ +.. devguide_workbench: + +Adding Application to Workbench +------------------------------- + +If you wish to use WATTS on the NEAMS Workbench with a code +that is not already available, adding the code can be done quite easily. + +First, you have to develop a plugin for the code and add it to WATTS following +the steps described previously. Once the plugin is available, you can then add it +to `watts_ui.py`. + +In the `run_direct()` function, you will need to add an `elif` statement as follows, + +.. code-block:: + + elif plugin['code'].upper() == '': + app_plugin = watts.name_of_new_plugin( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + +Note tha additional steps might be necessary here depending on the code that +is being added. + +If the plugin is developed to be similar to the other plugins on WATTS, +no other changes are necessary to `watts_ui.py`. Otherwise, the developer +is responsible for making sure that `watt_ui.py` can read the results +produced by the plugin. Within `run_direct()`, the results from the plugin +should be extracted and saved to `watts_params` as individual entries. This +is required for the coupling and data-transfer between different codes. + +Next, the `watts.sch` file needs to be updated. The name of the new code needs +to be added to the `code` block as follows:: + + watts{ + plugins{ + plugin{ + code{ + Description = "[Required] All - Name of application" + ... + ValEnums=[PyARC RELAP5 ... ] + } + } + } + } + +Note that the name used for the new code used here must match that used in +`watts_ui.py`. + +Adding new plugin options ++++++++++++++++++++++++++ + +Any additional options needed by the plugin can be added under the `plugin` +block as follows:: + + watts{ + plugins{ + plugin{ + additional_plugin_option{ + Description = "[optional] New_code - Description of the new option" + MinOccurs=0 + MaxOccurs=1 + ValType=String + InputTmpl="plugin.additional_plugin_option" + } + } + } + } + +Note that `MinOccurs` and `MaxOccurs` represent the minimum and maximum occurences of +this option, `ValType` is the input type of the new option, and `InputTmpl` is the +template file for the new option located in the `etc/templates` directory. Template +file is optional but highly recommended as it provides a template or example to other users. + +If new plugin options are added, the `create_plugins()` function in `watts_ui.py` must +be updated. The function essentially creates a nested Python dictionary that contains one +or more individual dictionaries where each individual dictionary stores the information +of each plugin. The function utilizes a series of `if` statements to decide what information +should be stored for each plugin. + +If the input of the new option is a string, the new option can be added as follows :: + + if plg.new_option_name is not None: + nested_plugins['new_option_name'] = str( + plg.new_option_name.value).strip('\"') + +If the input is a list :: + + if plg.new_option_name is not None: + nested_plugins['new_option_name'] = convert_to_list(plg.new_option_name) + +If the input is a bool :: + + nested_plugins['new_option_name'] = False + + if plg.new_option_name is not None and str(plg.new_option_name.value).capitalize() == 'True': + nested_plugins['new_option_name'] = True + +Similar approach can be used for plugin options of different input types. diff --git a/doc/source/user/workbench.rst b/doc/source/user/workbench.rst new file mode 100755 index 00000000..13aa6f53 --- /dev/null +++ b/doc/source/user/workbench.rst @@ -0,0 +1,227 @@ +.. _workbench: + +Setup WATTS in NEAMS Workbench Environment +------------------------------------------ + +The `NEAMS Workbench ` is a tool +that facilitates the use of multiple tools in analysis +by providing a commom user interface for model creation, review, execution, output, +and visualization for integrated codes. Instructions on how to download and install +Workbench can be found on the Workbench +`Gitlab repository `. + +To set up WATTS in the Workbench environment, you first need to first provide the path to +where Workbench is installed in `workbench.sh` under the `scripts` directory. You can +then run `setup_conda_wb.sh` under the same directory to set up WATTS within +the Workbench environment. + +Optional: To install OpenMC in the Workbench environemnt, run `setup_openmc.sh`. + +To finish setting up WATTS, open Workbench and go to the `File` tab at the top-left corner +then select `Configurations` from the drop menu. In the `Application configurations` +window, click `Add` on the top most row then select `Watts` from the pop-up window. +In the list of `Application Options`, input the path of `watts_ui.py` to `Executable`. +The file should exist by default in `/watts/src/watt_ui/`. Next, click `Load Grammar`. +Click `OK` to complete the setup. + +Optional: Environment variables can be added be added under `Run Environment`. + +WATTS Workbench Input File +++++++++++++++++++++++++++ + +To create a new WATTS input file in Workbench, go to `File`, select `New File`, +and select `WATTS files (*.son)` from the drop down menu. An existing `*.son` +file can also be dragged and dropped to the Workbench window. + +The WATTS input file utilizes a hierarchical block-based system where a block +is defined with opening and closing curly braces `{ }`. A `watts` block is first +created within which other blocks and variables can be defined. + +Plugins +~~~~~~~ + +The `plugins` block is required. Within the `plugins` blocks are +`plugin` sub-blocks where WATTS plugins are defined. + +.. code-block:: text + plugins{ + plugin(ID1){ + code = moose + template = "sam_template" + exec_dir = SAM_DIR + exec_name = "sam-opt" + extra_inputs=["file1", "file2", "file3"] + extra_template_inputs=["template1", "template2", "template3"] + show_stderr = False + show_stdout = False + } + + plugin(ID2){ + code = PyARC + template = "pyarc_template" + executable = "path/to/pyarc/executable" + show_stderr = False + show_stdout = False + } + } + +Multiple `plugin` sub-blocks can be defined within the `plugins` block where +each plugin is given a unique identity, as represented by `(ID1)` and `(ID2)` +in the snippet above. For each sub-block the basic inputs are:: + + `code` : Name of the application + `template` : Name of the template file + `show_stderr` : Option to display error + `show_stdout` : Option to display output + `exec_dir` : Environment variable that points to the directory in which the application's executable is stored + `extra_inputs` : Additional non-templated input files + `extra_template_inputs` : Additional tempalted input files + `exec_name` : Name of the executable + `executable` : Path to the executable + +Note that user must provide either BOTH `exec_dir` and `exec_name` or +ONLY `executable`. Additionally, there are application-specific inputs +that can be provided to the plugins such as:: + + `extra_args` (multiple apps) : Extra arguments to applications + 'transfer_params' (multiple apps) : Output to transfer between applications for multi-apps run + `plotfl_to_csv` (RELAP5) : Option to convert `plotfl` file to `csv` file + `conv_channel` (SAS) : Path to `CHANNELtoCSV.x` + `conv_primar4` (SAS) : Path to `PRIMAR4toCSV.x` + `auto_link_files` (Dakota) : List of files for Dakota to link automatically + `scores` (OpenMC) : List of filters for tallies + `score_names` (OpenMC) : List of user-given names for tally filters + +Currently all applications/codes already integrated to WATTS can be run on Workbench, these include +PyARC, OpenMC, SERPENT, ABCE, MCNP, MOOSE, SAS, Dakota, Serpent, and RELAP5. + +For OpenMC, multiple `scores` can be provided at once. If provided, the number of `score_names` must be the +same as the number of `scores`. For instance, :: + + scores = ["elastic", "nu-fission"] + score_names = ["total_elastic_scatter_rate", "total_fission_neutron_prod"] + +and there are N tallies where N > 1, then the outputs of the run will be named as:: + + total_elastic_scatter_rate_1, total_elastic_scatter_rate_2, ..., total_elastic_scatter_rate_N + total_fission_neutron_prod_1, total_fission_neutron_prod_2, ..., total_fission_neutron_prod_N + +If `score_names` is not provided, `scores` will be used as the base name for the outputs. + +Workflow level +~~~~~~~~~~~~~~ + +The `workflow_level1` block is required. The plugin to be used is specified +by the `plugin` keyword:: + + plugin = ID1 + +where 'ID1' is the ID of the plugin provided in the `plugins` block. When performing +a multi-app run where more than one plugins are used, the sequence of the run is +determined by the order of plugins. For example, when the order of the plugins is:: + + plugin = ID1 + plugin = ID2 + +Workbench will run ID1 first then ID2. On the other than, when the order is :: + + plugin = ID2 + plugin = ID1 + +Workbench will instead run ID1 first then ID2. + +The`variable` sub-block is where the values of the templated variables are +specified, as shown below:: + + variables{ + param(T_inlet) {value = 873.15} + param(T_outlet) {value = 1000.15} + param(flow_area) {value = 3.14e-4} + param(component_name) {value = pipe1} + param(Dh) {value = 1 unit = m} + param(location) {list = [top bottom left right]} + param(length) {list = [3.0 5.0 7.0 10.0]} + param(T_mean) {func = "0.5 * ( T_inlet + T_outlet )"} + param(wall_bc) {bool = "True"} + } + +Each `param` has a unique ID represented by the string in the parantheses +shown in the snippet above. A `param` can accept different types of inputs +depending on the provided key word provided. The `value` keyword is used +for when a numeric or a string is provided. A `unit` keyword can be added +if a user intends to utilize WATTS' internal unit-conversion capability. +The `list` keyword is used for a list of numerics or strings. The `bool` +keyword is used for booleans. The `func` keyword is used when a user +intends to perform arithmetic with existing `param`. Note that each elemet +in `func` must be separated by a space. + +Execution ++++++++++ + +Three types of executions can be performed by WATTS on Workbench, namely +direct execution, parametric study, and Picard iteration. + +Direct execution +~~~~~~~~~~~~~~~~ + +Direct execution is the simplest execution type. The user only needs to +provide `workflow_dir`, `plugins` block, and `workflow_level1` block to +perform direct execution. + +Parametric study +~~~~~~~~~~~~~~~~ + +To perform parametric study, a `parametric` block needs to be added to +the `workflow_level1` block as follows:: + + workflow_level1{ + plugin = ID1 + variables{ + param(He_inlet_temp) {value = 873.15} + param(He_outlet_temp) {value = 1023.15} + ... + } + parametric{ + changing_params = "heat_source" + changing_values = [0, 1e5, 2e5, 3e5] + } + } + +where `changing_params` is the parameter whose values are varied and +`changing_values` is a list of intended varied values. + +Picard iteration +~~~~~~~~~~~~~~~~ + +To perform Picard iteration, the `iteration` block needs to be added +to the `workflow_level1` block:: + + workflow_level1{ + plugin = ID1 + variables{ + param(He_inlet_temp) {value = 873.15} + param(He_outlet_temp) {value = 1023.15} + ... + } + iteration{ + plugin = ID2 + nmax = 10 + convergence_params = "keff" + convergence_criteria = 0.0001 + to_sub_params = ["avg_Tf_1" "avg_Tf_2" "avg_Tf_3" "avg_Tf_4" "avg_Tf_5"] + to_main_params = ["Init_P_1" "Init_P_2" "Init_P_3" "Init_P_4" "Init_P_5"] + } + } + +`plugin` in the `iteration` block is the plugin ID (ID2 in this example) of the +application that will be used along with the the first plugin (ID1 in this example) +to perform iteration. `nmax` is the maximum number of iterations, +`convergence_params` is the parameter used for evaluating convergence, +`convergence_criteria` is the tolerance for +convergence, `to_sub_params` and `to_main_params` are lists of parameters whose +values are iterated between the two applications where they each must have at least +one parameter. Note that the parameter supplied to `convergence_params` must be +an output from the second plugin. For instance, in the above example, "keff" is +an output produced by the plugin of "ID2". Note that the choice of "keff" in +this example is arbitrary and `convergence_params` should be chosen according to +the applications used and the objective of iteration runs. diff --git a/examples/1App_OpenMC_VHTR/README.md b/examples/1App_OpenMC_VHTR/README.md index 7bedcac0..818e7186 100644 --- a/examples/1App_OpenMC_VHTR/README.md +++ b/examples/1App_OpenMC_VHTR/README.md @@ -18,4 +18,4 @@ This example provides a demonstration on how to use WATTS to perform a single SA - [__watts_exec.py__](watts_exec.py): WATTS workflow for this example. This is the file to execute to run the problem described above. - [__openmc_template__](openmc_template.py): OpenMC templated model. - +- [__watts_wb.son__](watts_wb.son): Workbench input file for this example. diff --git a/examples/1App_OpenMC_VHTR/watts_wb.son b/examples/1App_OpenMC_VHTR/watts_wb.son new file mode 100644 index 00000000..52427b21 --- /dev/null +++ b/examples/1App_OpenMC_VHTR/watts_wb.son @@ -0,0 +1,43 @@ +watts{ + plugins{ + plugin(ID1){ + code = openmc + template = "openmc_template.py" + scores = ["nu-fission"] % Name of scores for OpenMC tallies. + score_names = ["power"] % A more representative name for the scores. Optional but might be necessary for score names with + % hyphens because Jinja and Workbench have difficulties reading hyphens. + } + } + + workflow_level1{ + plugin = ID1 + variables{ + param(ax_ref) {value = 2.0} + param(num_cool_pins) {value = 24} + param(num_fuel_pins) {value = 44} + param(Height_FC) {value = 2.0} + param(Lattice_pitch) {value = 2.0} + param(FuelPin_rad) {value = 0.9} + param(cool_hole_rad) {value = 0.6} + param(Coolant_channel_diam) {value = 0.012} + param(Graphite_thickness) {value = 0.5} + param(Assembly_pitch) {value = 17.3205080756887} + param(lbp_rad) {value = 0.25} + param(mod_ext_rad) {value = 0.90} + param(shell_thick) {value = 0.05} + param(liner_thick) {value = 0.007} + param(control_pin_rad) {value = 9.9, unit = mm} + param(cl) {value = 160.0} + param(pf) {value = 40.0} + param(temp) {value = 725.0} + param(temp_F1) {value = 725.0} + param(temp_F2) {value = 725.0} + param(temp_F3) {value = 725.0} + param(temp_F4) {value = 725.0} + param(temp_F5) {value = 725.0} + param(use_sab) = {bool = True} + param(use_sab_BeO) = {bool = True} + param(use_sab_YH2) = {bool = False} + } + } +} \ No newline at end of file diff --git a/examples/1App_PyARC_UnitCell/README.md b/examples/1App_PyARC_UnitCell/README.md index 1ca1251f..651b85bb 100644 --- a/examples/1App_PyARC_UnitCell/README.md +++ b/examples/1App_PyARC_UnitCell/README.md @@ -18,3 +18,4 @@ This example provides a demonstration on how to use WATTS to perform a single Py - [__watts_exec.py__](watts_exec.py): WATTS workflow for this example. This is the file to execute to run the problem described above. - [__pyarc_template__](pyarc_template): PyARC templated input file. - [__lumped.son__](lumped.son): SON file referenced in PyARC input with description of lumped fission products. +- [__watts_wb.son__](watts_wb.son): Workbench input file for this example. \ No newline at end of file diff --git a/examples/1App_PyARC_UnitCell/watts_wb.son b/examples/1App_PyARC_UnitCell/watts_wb.son new file mode 100644 index 00000000..c157804f --- /dev/null +++ b/examples/1App_PyARC_UnitCell/watts_wb.son @@ -0,0 +1,22 @@ +watts{ + plugins{ + plugin(ID1){ + code = "PyARC" + template = "pyarc_template" + extra_inputs = ["lumped.son"] + executable = "path/to/pyarc/executable" + show_stderr = False + show_stdout = True + } + } + + workflow_level1{ + plugin = ID1 + variables{ + param(assembly_pitch) {value = 20 unit = cm} + param(assembly_length) {value = 13 unit = cm} + param(temp) {value = 26.85 unit = Celsius} + } + } + +} \ No newline at end of file diff --git a/examples/1App_RELAP5_SingleChannel/README.md b/examples/1App_RELAP5_SingleChannel/README.md index 16e8b049..ea2feff9 100755 --- a/examples/1App_RELAP5_SingleChannel/README.md +++ b/examples/1App_RELAP5_SingleChannel/README.md @@ -17,3 +17,4 @@ This example provides a demonstration on how to use WATTS to run RELAP5-3D. - [__watts_exec.py__](watts_exec.py): This is the file to execute to run the problem described above. - [__relap5_template__](relap5_template): Templated RELAP5-3D input. +- [__watts_wb.son__](watts_wb.son): Workbench input file for this example. diff --git a/examples/1App_RELAP5_SingleChannel/watts_wb.son b/examples/1App_RELAP5_SingleChannel/watts_wb.son new file mode 100644 index 00000000..822b3eab --- /dev/null +++ b/examples/1App_RELAP5_SingleChannel/watts_wb.son @@ -0,0 +1,25 @@ +watts{ + % Make sure that all necessary files (executable, fluid property files, etc) are in the + % same directory as the input and template files. + plugins{ + plugin(ID1){ + code = "RELAP5" + template = "relap5_template" + executable = "/path/to/relap5/executable" + show_stderr = False + show_stdout = False + plotfl_to_csv = True + % extra_args = ["-w", "tpfh2o", "-e", "tpfn2", "-tpfdir", "C:/Users/zooi/Documents/NSTF/watts/R5/"] + } + } + + workflow_level1{ + plugin = ID1 + variables{ + param(inlet_pressure) {value = 3.0e5} + param(outlet_pressure) {value = 1.013e5} + param(heater_power) {value = 20000} + } + } + +} \ No newline at end of file diff --git a/examples/1App_SAM_VHTR/README.md b/examples/1App_SAM_VHTR/README.md index 4815167b..5364cfeb 100644 --- a/examples/1App_SAM_VHTR/README.md +++ b/examples/1App_SAM_VHTR/README.md @@ -18,3 +18,4 @@ This example provides a demonstration on how to use WATTS to perform a single SA - [__watts_exec.py__](watts_exec.py): WATTS workflow for this example. This is the file to execute to run the problem described above. - [__sam_template__](sam_template): SAM templated input file. +- [__watts_wb__.son__](watts_wb.son): Workbench input file for this example. diff --git a/examples/1App_SAM_VHTR/watts_wb.son b/examples/1App_SAM_VHTR/watts_wb.son new file mode 100644 index 00000000..3b2f5a87 --- /dev/null +++ b/examples/1App_SAM_VHTR/watts_wb.son @@ -0,0 +1,55 @@ +watts{ + plugins{ + plugin(ID1){ + code = moose + template = "sam_template" + exec_dir = SAM_DIR + exec_name = "sam-opt" + show_stderr = False + show_stdout = False + } + } + + workflow_level1{ + plugin = ID1 + variables{ + param(He_inlet_temp) {value = 873.15} + param(He_outlet_temp) {value = 1023.15} + param(He_cp) {value = 5189.2} + param(He_K) {value = 0.32802} + param(He_density) {value = 3.8815} + param(He_viscosity) {value = 4.16e-5} + param(He_Pressure) {value = 7e6} + param(Tot_assembly_power) {value = 250000} + + param("Init_P_1") {value = 1} + param("Init_P_2") {value = 1} + param("Init_P_3") {value = 1} + param("Init_P_4") {value = 1} + param("Init_P_5") {value = 1} + + param(ax_ref) {value = 2.0} + param(num_cool_pins) {value = 24} + param(num_fuel_pins) {value = 44} + param(Height_FC) {value = 2.0} + param(Lattice_pitch) {value = 2.0} + param(FuelPin_rad) {value = 0.9} + param(cool_hole_rad) {value = 0.6} + param(Coolant_channel_diam) {value = 0.012} + param(Graphite_thickness) {value = 0.5} + param(Assembly_pitch) {value = 17.3205080756887} + param(lbp_rad) {value = 0.25} + param(mod_ext_rad) {value = 0.90} + param(shell_thick) {value = 0.05} + param(liner_thick) {value = 0.007} + param(control_pin_rad) {value = 9.9, unit = mm} + param(cl) {value = 160.0} + param(pf) {value = 40.0} + param(temp) {value = 700.0} + param(use_sab) = {bool = True} + param(use_sab_BeO) = {bool = True} + param(use_sab_YH2) = {bool = False} + } + } + +} \ No newline at end of file diff --git a/examples/1App_SAS_MultiTemplates_SodiumLoop/README.md b/examples/1App_SAS_MultiTemplates_SodiumLoop/README.md index a32ff8d7..95eb9bcb 100644 --- a/examples/1App_SAS_MultiTemplates_SodiumLoop/README.md +++ b/examples/1App_SAS_MultiTemplates_SodiumLoop/README.md @@ -25,3 +25,4 @@ This example provides a demonstration on how to use WATTS to perform a simulatio - [__PointKinetics__](PointKinetics): Extra templated SAS input. - [__PRIMAR4__](PRIMAR4): Extra templated SAS input. - [__Primary__](Primary): Extra templated SAS input. +- [__watts_wb.son__](watts_wb.son): Workbench input file for this example. \ No newline at end of file diff --git a/examples/1App_SAS_MultiTemplates_SodiumLoop/watts_wb.son b/examples/1App_SAS_MultiTemplates_SodiumLoop/watts_wb.son new file mode 100644 index 00000000..b5a17b35 --- /dev/null +++ b/examples/1App_SAS_MultiTemplates_SodiumLoop/watts_wb.son @@ -0,0 +1,34 @@ +watts{ + plugins{ + plugin(ID1){ + code = "sas" + template = "sas_template" + executable = "/Users/zhieejhiaooi/Documents/ANL/SAS/SAS/sas.x" + show_stderr = False + show_stdout = False + extra_template_inputs=["Primary", "FuelCladding", "Channel", "DecayPower", "PointKinetics", "PRIMAR4"] + % conv_channel = "path\to\CHANNELtoCSV.x" % Assumed to be in the same dir as the SAS executable if not provided + % conv_primar4 = "path\to\PRIMAR4toCSV.x" % Assumed to be in the same dir as the SAS executable if not provided + } + } + + workflow_level1{ + plugin = ID1 + variables{ + param(sas_version) {value = 5.5} + param(tmax) {value = 1000.0} + param(flow_per_pin) {value = 0.15} + param(total_reactor_power) {value = 20.0 unit = kW} + param(betai_1) {value = 2.0E-04} %Effective delayed neutron fraction + param(betai_2) {value = 1.0E-03} + param(betai_3) {value = 1.2E-03} + param(betai_4) {value = 2.5E-03} + param(betai_5) {value = 1.5E-03} + param(betai_6) {value = 5.0E-04} + param(fuel_axial_exp_coeff) {value = 2.0E-05} + param(clad_axial_exp_coeff) {value = 1.4E-05} + param(outlet_pressure) {value = 200000.0} + } + } + +} \ No newline at end of file diff --git a/examples/1App_SAS_SodiumLoop/README.md b/examples/1App_SAS_SodiumLoop/README.md index aec1580b..b16105f5 100644 --- a/examples/1App_SAS_SodiumLoop/README.md +++ b/examples/1App_SAS_SodiumLoop/README.md @@ -18,3 +18,4 @@ This example provides a demonstration on how to use WATTS for a simple SAS model - [__watts_exec.py__](watts_exec.py): This is the file to execute to run the problem described above. - [__sas_template__](sas_template): Templated SAS input. +- [__watts_wb.son__](watts_wb.son): Workbench input file for this example. \ No newline at end of file diff --git a/examples/1App_SAS_SodiumLoop/watts_wb.son b/examples/1App_SAS_SodiumLoop/watts_wb.son new file mode 100644 index 00000000..a70ea297 --- /dev/null +++ b/examples/1App_SAS_SodiumLoop/watts_wb.son @@ -0,0 +1,30 @@ +watts{ + plugins{ + plugin(ID1){ + code = "sas" + template = "sas_template" + executable = "/Users/zhieejhiaooi/Documents/ANL/SAS/SAS/sas.x" + show_stderr = False + show_stdout = False + % conv_channel = "path\to\CHANNELtoCSV.x" % Assumed to be in the same dir as the SAS executable if not provided + % conv_primar4 = "path\to\PRIMAR4toCSV.x" % Assumed to be in the same dir as the SAS executable if not provided + } + } + + workflow_level1{ + plugin = ID1 + variables{ + param(sas_version) {value = 5.5} + param(tmax) {value = 1000.0} + param(flow_per_pin) {value = 0.15} + param(total_reactor_power) {value = 20.0 unit = kW} + param(betai_1) {value = 2.0E-04} %Effective delayed neutron fraction + param(betai_2) {value = 1.0E-03} + param(betai_3) {value = 1.2E-03} + param(betai_4) {value = 2.5E-03} + param(betai_5) {value = 1.5E-03} + param(betai_6) {value = 5.0E-04} + } + } + +} \ No newline at end of file diff --git a/examples/MultiApp_SAM_SimpleJunction_Workbench/README.md b/examples/MultiApp_SAM_SimpleJunction_Workbench/README.md new file mode 100644 index 00000000..8622f448 --- /dev/null +++ b/examples/MultiApp_SAM_SimpleJunction_Workbench/README.md @@ -0,0 +1,21 @@ +# MultiApp_SAM_SimpleJunction_Workbench + +## Purpose + +This example provides a demonstration on how to use WATTS on Workbench to run a coupled calculation where the results from one application is used as the input of another application + +## Code(s) + +- SAM + +## Keywords + +- Multiple applications +- Coupled run + +## File descriptions + +- [__watts_exec.py__](watts_exec.py): WATTS workflow for this example. This is the file to execute to run the problem described above. +- [__sam_template_0__](sam_template_0): SAM templated input file for the first run. +- [__sam_template_1__](sam_template_1): SAM templated input file for the second run. +- [__watts_wb.son__](watts_wb.son): Workbench input file for this example. \ No newline at end of file diff --git a/examples/MultiApp_SAM_SimpleJunction_Workbench/sam_template_0 b/examples/MultiApp_SAM_SimpleJunction_Workbench/sam_template_0 new file mode 100644 index 00000000..130fa857 --- /dev/null +++ b/examples/MultiApp_SAM_SimpleJunction_Workbench/sam_template_0 @@ -0,0 +1,149 @@ +[GlobalParams] + global_init_P = 1.2e5 + global_init_V = 1 + global_init_T = 628.15 + scaling_factor_var = '1 1e-3 1e-6' +[] + +[EOS] + [./eos] + type = PBSodiumEquationOfState + [../] +[] + +[Functions] + [./time_stepper] + type = PiecewiseLinear + x = ' 0 20 21 100 101 1e5' + y = '0.1 0.1 0.5 0.5 1 1' + [../] +[] + +[Components] + [./pipe1] + type = PBOneDFluidComponent + eos = eos + position = '0 0 0' + orientation = '0 0 1' + heat_source = {{ heat_source }} + f= {{ friction_factor }} + Dh = {{ Dh }} + length = 1 + # A = 3.14e-4 + A = {{ flow_area }} + n_elems = 10 + [../] + + [./pipe2] + type = PBOneDFluidComponent + eos = eos + position = '0 0 1' + orientation = '0 0 1' + f=0.1 + Dh = 0.01 + length = 1 + heat_source = 1e7 + A = 3.14e-4 + n_elems = 10 + [../] + + [./joint] + type = PBSingleJunction + eos = eos + inputs='pipe1(out)' + outputs='pipe2(in)' + weak_constraint = true + [../] + [./inlet] + type = PBTDJ + input = 'pipe1(in)' + eos = eos + v_bc = {{ velocity_inlet }} + T_bc = {{ temperature_inlet }} + [../] + + [./outlet] + type = PBTDV + input = 'pipe2(out)' + eos = eos + p_bc = '1.0e5' + T_bc = 728.15 + [../] +[] + +[Postprocessors] + [./TotalMassFlowRateInlet_2] + type = ComponentBoundaryFlow + input = 'pipe2(out)' + [../] + [./Inlet_Temperature_1] + type = ComponentBoundaryVariableValue + variable = temperature + input = 'pipe1(in)' + [../] + [./T_out_sam_template_0] + type = ComponentBoundaryVariableValue + variable = temperature + input = 'pipe2(out)' + [../] +[] + +[Preconditioning] + active = 'SMP_PJFNK' + + [./SMP_PJFNK] + type = SMP + full = true + solve_type = 'PJFNK' + petsc_options_iname = '-pc_type' + petsc_options_value = 'lu' + [../] +[] # End preconditioning block + + +[Executioner] + type = Transient + + dt = 1e-1 + dtmin = 1e-5 + + # setting time step range + [./TimeStepper] + type = FunctionDT + function = time_stepper + [../] + + petsc_options_iname = '-ksp_gmres_restart' + petsc_options_value = '100' + + nl_rel_tol = 1e-8 + nl_abs_tol = 1e-7 + nl_max_its = 20 + + l_tol = 1e-5 # Relative linear tolerance for each Krylov solve + l_max_its = 100 # Number of linear iterations for each Krylov solve + + start_time = 0.0 + end_time = 100. + + [./Quadrature] + type = TRAP + order = FIRST + [../] +[] # close Executioner section + +[Outputs] + perf_graph = true + [./out_displaced] + type = Exodus + use_displaced = true + execute_on = 'initial timestep_end' + sequence = false + [../] + [./csv] + type = CSV + [../] + [./console] + type = Console + [../] +[] diff --git a/examples/MultiApp_SAM_SimpleJunction_Workbench/sam_template_1 b/examples/MultiApp_SAM_SimpleJunction_Workbench/sam_template_1 new file mode 100644 index 00000000..eb2bd4bc --- /dev/null +++ b/examples/MultiApp_SAM_SimpleJunction_Workbench/sam_template_1 @@ -0,0 +1,149 @@ +[GlobalParams] + global_init_P = 1.2e5 + global_init_V = 1 + global_init_T = 628.15 + scaling_factor_var = '1 1e-3 1e-6' +[] + +[EOS] + [./eos] + type = PBSodiumEquationOfState + [../] +[] + +[Functions] + [./time_stepper] + type = PiecewiseLinear + x = ' 0 20 21 100 101 1e5' + y = '0.1 0.1 0.5 0.5 1 1' + [../] +[] + +[Components] + [./pipe1] + type = PBOneDFluidComponent + eos = eos + position = '0 0 0' + orientation = '0 0 1' + heat_source = {{ heat_source }} + f= {{ friction_factor }} + Dh = {{ Dh }} + length = 1 + # A = 3.14e-4 + A = {{ flow_area }} + n_elems = 10 + [../] + + [./pipe2] + type = PBOneDFluidComponent + eos = eos + position = '0 0 1' + orientation = '0 0 1' + f=0.1 + Dh = 0.01 + length = 1 + heat_source = 1e7 + A = 3.14e-4 + n_elems = 10 + [../] + + [./joint] + type = PBSingleJunction + eos = eos + inputs='pipe1(out)' + outputs='pipe2(in)' + weak_constraint = true + [../] + [./inlet] + type = PBTDJ + input = 'pipe1(in)' + eos = eos + v_bc = {{ velocity_inlet }} + T_bc = {{ T_out_sam_template_0 }} # Outlet temperature of Pipe_2 from file 'sam_template_0' + [../] + + [./outlet] + type = PBTDV + input = 'pipe2(out)' + eos = eos + p_bc = '1.0e5' + T_bc = 728.15 + [../] +[] + +[Postprocessors] + [./TotalMassFlowRateInlet_2] + type = ComponentBoundaryFlow + input = 'pipe2(out)' + [../] + [./Inlet_Temperature_1] + type = ComponentBoundaryVariableValue + variable = temperature + input = 'pipe1(in)' + [../] + [./Outlet_Temperature_2] + type = ComponentBoundaryVariableValue + variable = temperature + input = 'pipe2(out)' + [../] +[] + +[Preconditioning] + active = 'SMP_PJFNK' + + [./SMP_PJFNK] + type = SMP + full = true + solve_type = 'PJFNK' + petsc_options_iname = '-pc_type' + petsc_options_value = 'lu' + [../] +[] # End preconditioning block + + +[Executioner] + type = Transient + + dt = 1e-1 + dtmin = 1e-5 + + # setting time step range + [./TimeStepper] + type = FunctionDT + function = time_stepper + [../] + + petsc_options_iname = '-ksp_gmres_restart' + petsc_options_value = '100' + + nl_rel_tol = 1e-8 + nl_abs_tol = 1e-7 + nl_max_its = 20 + + l_tol = 1e-5 # Relative linear tolerance for each Krylov solve + l_max_its = 100 # Number of linear iterations for each Krylov solve + + start_time = 0.0 + end_time = 100. + + [./Quadrature] + type = TRAP + order = FIRST + [../] +[] # close Executioner section + +[Outputs] + perf_graph = true + [./out_displaced] + type = Exodus + use_displaced = true + execute_on = 'initial timestep_end' + sequence = false + [../] + [./csv] + type = CSV + [../] + [./console] + type = Console + [../] +[] diff --git a/examples/MultiApp_SAM_SimpleJunction_Workbench/watts_wb.son b/examples/MultiApp_SAM_SimpleJunction_Workbench/watts_wb.son new file mode 100644 index 00000000..db43a1bf --- /dev/null +++ b/examples/MultiApp_SAM_SimpleJunction_Workbench/watts_wb.son @@ -0,0 +1,36 @@ +watts{ + plugins{ + plugin(ID1){ + code = moose + template = "sam_template_0" + exec_dir = "SAM_DIR" + exec_name = "sam-opt" + show_stderr = False + show_stdout = False + transfer_params = ["T_out_sam_template_0"] + } + plugin(ID2){ + code = moose + template = "sam_template_1" + exec_dir = "SAM_DIR" + exec_name = "sam-opt" + show_stderr = False + show_stdout = False + } + } + + workflow_level1{ + plugin = ID1 + plugin = ID2 + variables{ + param(temperature_inlet) {value = 628.0} + param(friction_factor) {value = 0.1} + param(flow_area) {value = 3.14e-4} + param(Dh) {value = 1 unit = m} + param(velocity_inlet) {value = 1} + param(wall_bc) {bool = "True"} + param(heat_source) {value = 3e5} + } + } + +} \ No newline at end of file diff --git a/examples/ParamStudy_SAM_SimpleJunction_Workbench/README.md b/examples/ParamStudy_SAM_SimpleJunction_Workbench/README.md new file mode 100644 index 00000000..cff2587f --- /dev/null +++ b/examples/ParamStudy_SAM_SimpleJunction_Workbench/README.md @@ -0,0 +1,20 @@ +# ParamStudy_SAM_SimpleJunction_Workbench + +## Purpose + +This example provides a demonstration on how to use WATTS on Workbench to perform parametric studies where the value of a parameter +is varied. + +## Code(s) + +- SAM + +## Keywords + +- Parametric study + +## File descriptions + +- [__watts_exec.py__](watts_exec.py): WATTS workflow for this example. This is the file to execute to run the problem described above. +- [__sam_template__](sam_template): SAM templated input file. +- [__watts_wb.son__](watts_wb.son): Workbench input file for this example. \ No newline at end of file diff --git a/examples/ParamStudy_SAM_SimpleJunction_Workbench/sam_template b/examples/ParamStudy_SAM_SimpleJunction_Workbench/sam_template new file mode 100644 index 00000000..f6866344 --- /dev/null +++ b/examples/ParamStudy_SAM_SimpleJunction_Workbench/sam_template @@ -0,0 +1,144 @@ +[GlobalParams] + global_init_P = 1.2e5 + global_init_V = 1 + global_init_T = 628.15 + scaling_factor_var = '1 1e-3 1e-6' +[] + +[EOS] + [./eos] + type = PBSodiumEquationOfState + [../] +[] + +[Functions] + [./time_stepper] + type = PiecewiseLinear + x = ' 0 20 21 100 101 1e5' + y = '0.1 0.1 0.5 0.5 1 1' + [../] +[] + +[Components] + [./pipe1] + type = PBOneDFluidComponent + eos = eos + position = '0 0 0' + orientation = '0 0 1' + heat_source = {{ heat_source }} + f= {{ friction_factor }} + Dh = {{ Dh }} + length = 1 + # A = 3.14e-4 + A = {{ flow_area }} + n_elems = 10 + [../] + + [./pipe2] + type = PBOneDFluidComponent + eos = eos + position = '0 0 1' + orientation = '0 0 1' + f=0.1 + Dh = 0.01 + length = 1 + heat_source = 1e7 + A = 3.14e-4 + n_elems = 10 + [../] + + [./joint] + type = PBSingleJunction + eos = eos + inputs='pipe1(out)' + outputs='pipe2(in)' + weak_constraint = true + [../] + [./inlet] + type = PBTDJ + input = 'pipe1(in)' + eos = eos + v_bc = {{ velocity_inlet }} + T_bc = {{ temperature_inlet }} + [../] + + [./outlet] + type = PBTDV + input = 'pipe2(out)' + eos = eos + p_bc = '1.0e5' + T_bc = 728.15 + [../] +[] + +[Postprocessors] + [./TotalMassFlowRateInlet_2] + type = ComponentBoundaryFlow + input = 'pipe2(out)' + [../] + [./Outlet_Temperature_2] + type = ComponentBoundaryVariableValue + variable = temperature + input = 'pipe2(out)' + [../] +[] + +[Preconditioning] + active = 'SMP_PJFNK' + + [./SMP_PJFNK] + type = SMP + full = true + solve_type = 'PJFNK' + petsc_options_iname = '-pc_type' + petsc_options_value = 'lu' + [../] +[] # End preconditioning block + + +[Executioner] + type = Transient + + dt = 1e-1 + dtmin = 1e-5 + + # setting time step range + [./TimeStepper] + type = FunctionDT + function = time_stepper + [../] + + petsc_options_iname = '-ksp_gmres_restart' + petsc_options_value = '100' + + nl_rel_tol = 1e-8 + nl_abs_tol = 1e-7 + nl_max_its = 20 + + l_tol = 1e-5 # Relative linear tolerance for each Krylov solve + l_max_its = 100 # Number of linear iterations for each Krylov solve + + start_time = 0.0 + end_time = 100. + + [./Quadrature] + type = TRAP + order = FIRST + [../] +[] # close Executioner section + +[Outputs] + perf_graph = true + [./out_displaced] + type = Exodus + use_displaced = true + execute_on = 'initial timestep_end' + sequence = false + [../] + [./csv] + type = CSV + [../] + [./console] + type = Console + [../] +[] diff --git a/examples/ParamStudy_SAM_SimpleJunction_Workbench/watts_wb.son b/examples/ParamStudy_SAM_SimpleJunction_Workbench/watts_wb.son new file mode 100644 index 00000000..b4d6d41c --- /dev/null +++ b/examples/ParamStudy_SAM_SimpleJunction_Workbench/watts_wb.son @@ -0,0 +1,30 @@ +watts{ + plugins{ + plugin(ID1){ + code = moose + template = "sam_template" + exec_dir = "SAM_DIR" + exec_name = "sam-opt" + show_stderr = False + show_stdout = False + } + } + + workflow_level1{ + plugin = ID1 + variables{ + param(temperature_inlet) {value = 628.0} + param(friction_factor) {value = 0.1} + param(flow_area) {value = 3.14e-4} + param(Dh) {value = 1 unit = m} + param(velocity_inlet) {value = 1} + param(wall_bc) {bool = "True"} + } + + parametric{ + changing_params = "heat_source" + changing_values = [0, 1e5, 2e5, 3e5] + } + } + +} \ No newline at end of file diff --git a/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/README.md b/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/README.md new file mode 100644 index 00000000..09f38832 --- /dev/null +++ b/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/README.md @@ -0,0 +1,22 @@ +# PicardIterations_SAM-OpenMC_VHTR_Workbench + +## Purpose + +This example demonstrates how to use WATTS on Workbench to perform several iterations where SAM calculations are followed by OpenMC calculation and temperature/power information are exchanged until convergence. This example is slightly different from the non Workbench example under the same name. + +## Code(s) + +- SAM +- OpenMC + +## Keywords + +- Information transfer from SAM to OpenMC +- Picard iterations until convergence + +## File descriptions + +- [__watts_exec.py__](watts_exec.py): WATTS workflow for this example. This is the file to execute to run the problem described above. +- [__openmc_template__](openmc_template.py): Link to OpenMC templated model. +- [__sam_template__](sam_template): Link to SAM templated model. +- [__watts_wb.son__](watts_wb.son): Workbench input file for this example. \ No newline at end of file diff --git a/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/openmc_template.py b/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/openmc_template.py new file mode 100644 index 00000000..bee18f80 --- /dev/null +++ b/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/openmc_template.py @@ -0,0 +1,355 @@ +# SPDX-FileCopyrightText: 2022 UChicago Argonne, LLC +# SPDX-License-Identifier: MIT + +from math import sqrt + +import openmc +import openmc.model + + +def build_openmc_model(params): + """ OpenMC Model """ + + materials = [] + + homfuel1 = openmc.Material(name="homfuel_1", temperature=params['avg_Tf_1']) + homfuel1.set_density('g/cm3', 2.2767E+00) + homfuel1.add_nuclide('U235', 4.0841E-02, 'wo') + homfuel1.add_nuclide('U238', 1.6597E-01, 'wo') + homfuel1.add_nuclide('O16', 7.0029E-01, 'wo') + homfuel1.add_element('C', 2.0896E-02, 'wo') + homfuel1.add_nuclide('Si28', 6.6155E-02, 'wo') + homfuel1.add_nuclide('Si29', 3.4772E-03, 'wo') + homfuel1.add_nuclide('Si30', 2.3671E-03, 'wo') + materials.append(homfuel1) + + homfuel2 = openmc.Material(name="homfuel_2", temperature=params['avg_Tf_2']) + homfuel2.set_density('g/cm3', 2.2767E+00) + homfuel2.add_nuclide('U235', 4.0841E-02, 'wo') + homfuel2.add_nuclide('U238', 1.6597E-01, 'wo') + homfuel2.add_nuclide('O16', 7.0029E-01, 'wo') + homfuel2.add_element('C', 2.0896E-02, 'wo') + homfuel2.add_nuclide('Si28', 6.6155E-02, 'wo') + homfuel2.add_nuclide('Si29', 3.4772E-03, 'wo') + homfuel2.add_nuclide('Si30', 2.3671E-03, 'wo') + materials.append(homfuel2) + + homfuel3 = openmc.Material(name="homfuel_1", temperature=params['avg_Tf_3']) + homfuel3.set_density('g/cm3', 2.2767E+00) + homfuel3.add_nuclide('U235', 4.0841E-02, 'wo') + homfuel3.add_nuclide('U238', 1.6597E-01, 'wo') + homfuel3.add_nuclide('O16', 7.0029E-01, 'wo') + homfuel3.add_element('C', 2.0896E-02, 'wo') + homfuel3.add_nuclide('Si28', 6.6155E-02, 'wo') + homfuel3.add_nuclide('Si29', 3.4772E-03, 'wo') + homfuel3.add_nuclide('Si30', 2.3671E-03, 'wo') + materials.append(homfuel3) + + homfuel4 = openmc.Material(name="homfuel_1", temperature=params['avg_Tf_4']) + homfuel4.set_density('g/cm3', 2.2767E+00) + homfuel4.add_nuclide('U235', 4.0841E-02, 'wo') + homfuel4.add_nuclide('U238', 1.6597E-01, 'wo') + homfuel4.add_nuclide('O16', 7.0029E-01, 'wo') + homfuel4.add_element('C', 2.0896E-02, 'wo') + homfuel4.add_nuclide('Si28', 6.6155E-02, 'wo') + homfuel4.add_nuclide('Si29', 3.4772E-03, 'wo') + homfuel4.add_nuclide('Si30', 2.3671E-03, 'wo') + materials.append(homfuel4) + + homfuel5 = openmc.Material(name="homfuel_1", temperature=params['avg_Tf_5']) + homfuel5.set_density('g/cm3', 2.2767E+00) + homfuel5.add_nuclide('U235', 4.0841E-02, 'wo') + homfuel5.add_nuclide('U238', 1.6597E-01, 'wo') + homfuel5.add_nuclide('O16', 7.0029E-01, 'wo') + homfuel5.add_element('C', 2.0896E-02, 'wo') + homfuel5.add_nuclide('Si28', 6.6155E-02, 'wo') + homfuel5.add_nuclide('Si29', 3.4772E-03, 'wo') + homfuel5.add_nuclide('Si30', 2.3671E-03, 'wo') + materials.append(homfuel5) + + boro_ctr = openmc.Material(name="B4C-CTR", temperature=params['temp']) + boro_ctr.set_density('g/cm3', 2.47) + boro_ctr.add_nuclide('B10', 0.16, 'ao') + boro_ctr.add_nuclide('B11', 0.64, 'ao') + boro_ctr.add_element('C', 0.20, 'ao') + materials.append(boro_ctr) + + matrix = openmc.Material(name="matrix", temperature=params['temp']) + matrix.set_density('g/cm3', 1.806) + matrix.add_element('C', 1.0 - 0.0000003, 'ao') + matrix.add_nuclide('B10', 0.0000003, 'ao') + if params['use_sab']: + matrix.add_s_alpha_beta('c_Graphite') + materials.append(matrix) + + refl = openmc.Material(name="BeO", temperature=params['temp']) + refl.set_density('g/cm3', 2.7987) + refl.add_nuclide('Be9', 0.50, 'ao') + refl.add_nuclide('O16', 0.50, 'ao') + if params['use_sab_BeO']: + refl.add_s_alpha_beta('c_Be_in_BeO') + refl.add_s_alpha_beta('c_O_in_BeO') + materials.append(refl) + + yh2 = openmc.Material(name="moderator", temperature=params['temp']) + yh2.set_density('g/cm3', 4.30*0.95) + yh2.add_nuclide('Y89', 0.357142857, 'ao') + yh2.add_nuclide('H1', 0.642857143, 'ao') + if params['use_sab'] and params['use_sab_YH2']: + yh2.add_s_alpha_beta('c_H_in_YH2') + yh2.add_s_alpha_beta('c_Y_in_YH2') + materials.append(yh2) + + coolant = openmc.Material(name="coolant", temperature=params['temp']) + coolant.set_density('g/cm3', 0.00365) + coolant.add_nuclide('He4', 1, 'ao') + materials.append(coolant) + + Cr = openmc.Material(name="Cr", temperature=params['temp']) + Cr.set_density('g/cm3', 7.19) + Cr.add_nuclide('Cr50', -4.345e-2, 'ao') + Cr.add_nuclide('Cr52', -83.789e-2, 'ao') + Cr.add_nuclide('Cr53', -9.501e-2, 'ao') + Cr.add_nuclide('Cr54', -2.365e-2, 'ao') + materials.append(Cr) + + shell_mod = openmc.Material(name="shell_mod", temperature=params['temp']) + shell_mod.set_density('g/cm3', 7.055) # FeCrAl + shell_mod.add_nuclide('Cr50', 20.0e-2 * 4.340E-02,'ao') + shell_mod.add_nuclide('Cr52', 20.0e-2 * 8.381E-01,'ao') + shell_mod.add_nuclide('Cr53', 20.0e-2 * 9.490E-02,'ao') + shell_mod.add_nuclide('Cr54', 20.0e-2 * 2.360E-02,'ao') + shell_mod.add_nuclide('Fe54', 75.5e-2 * 5.800E-02,'ao') + shell_mod.add_nuclide('Fe56', 75.5e-2 * 9.172E-01,'ao') + shell_mod.add_nuclide('Fe57', 75.5e-2 * 2.200E-02,'ao') + shell_mod.add_nuclide('Fe58', 75.5e-2 * 2.800E-03,'ao') + shell_mod.add_nuclide('Al27', 4.5e-2 * 1.000 ,'ao') + materials.append(shell_mod) + + mat_dict = {} + for k,v in list(locals().items()): + if v in materials: + mat_dict[k] = v + + materials_file = openmc.Materials() + for mat in materials: + materials_file.append(mat) + materials_file.export_to_xml() + + Z_min = 0 + Z_cl = params['ax_ref'] + Z_cl_out = params['ax_ref'] - params['shell_thick'] + Z_up = params['ax_ref'] + params['cl'] + Z_up_out = params['ax_ref'] + params['cl'] + params['shell_thick'] + Z_max = params['cl'] + 2 * params['ax_ref'] + + # Create cylinder for fuel and coolant + + fuel_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=params['FuelPin_rad']) + mod_rad_0 = openmc.ZCylinder(x0=0.0, y0=0.0, r=params['mod_ext_rad'] - params['shell_thick'] - params['liner_thick']) + mod_rad_1a = openmc.ZCylinder(x0=0.0, y0=0.0, r=params['mod_ext_rad'] - params['shell_thick']) + mod_rad_1b = openmc.ZCylinder(x0=0.0, y0=0.0, r=params['mod_ext_rad']) + cool_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=params['cool_hole_rad']) + ctr_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=params['control_pin_rad']) + lbp_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=params['lbp_rad']) + + pin_pitch = params['Lattice_pitch'] + + min_z=openmc.ZPlane(z0=Z_min, boundary_type='vacuum') + max_z=openmc.ZPlane(z0=Z_max, boundary_type='vacuum') + sz_cl=openmc.ZPlane(z0=Z_cl) + + sz_cor1=openmc.ZPlane(z0= Z_cl + 1 * params['cl']/5) + sz_cor2=openmc.ZPlane(z0= Z_cl + 2 * params['cl']/5) + sz_cor3=openmc.ZPlane(z0= Z_cl + 3 * params['cl']/5) + sz_cor4=openmc.ZPlane(z0= Z_cl + 4 * params['cl']/5) + + sz_cl_out=openmc.ZPlane(z0=Z_cl_out) + sz_up=openmc.ZPlane(z0=Z_up) + sz_up_out=openmc.ZPlane(z0=Z_up_out) + cpin_low =openmc.ZPlane(z0=Z_up) + + Hex_Pitch = openmc.model.hexagonal_prism(orientation='x',edge_length=params['Assembly_pitch']/sqrt(3),origin=(0.0, 0.0), + boundary_type = 'reflective') # THIS SHOULD BE REFLECTIVE BONDARY + + + fuel_cell_1_1 = openmc.Cell(name='Fuel Pin', fill=homfuel1 , region=-fuel_radius & +sz_cl & -sz_cor1) + fuel_cell_1_2 = openmc.Cell(name='Fuel Pin', fill=homfuel2 , region=-fuel_radius & +sz_cor1 & -sz_cor2) + fuel_cell_1_3 = openmc.Cell(name='Fuel Pin', fill=homfuel3 , region=-fuel_radius & +sz_cor2 & -sz_cor3) + fuel_cell_1_4 = openmc.Cell(name='Fuel Pin', fill=homfuel4 , region=-fuel_radius & +sz_cor3 & -sz_cor4) + fuel_cell_1_5 = openmc.Cell(name='Fuel Pin', fill=homfuel5 , region=-fuel_radius & +sz_cor4 & -sz_up) + fuel_cell_2 = openmc.Cell(name='matrix', fill=matrix , region=+fuel_radius & +sz_cl & -sz_up) + fuel_cell_3 = openmc.Cell(name='reflL', fill=refl , region=-sz_cl) + fuel_cell_4 = openmc.Cell(name='reflO', fill=refl , region=+sz_up) + fuel_universe= openmc.Universe(cells=(fuel_cell_1_1, fuel_cell_1_2,fuel_cell_1_3,fuel_cell_1_4,fuel_cell_1_5,fuel_cell_2,fuel_cell_3,fuel_cell_4)) + TALLY_REGIONS=[fuel_cell_1_1, fuel_cell_1_2,fuel_cell_1_3,fuel_cell_1_4,fuel_cell_1_5] + + mod_cell_1 = openmc.Cell(name='YH2', fill=yh2, region=-mod_rad_0 & +sz_cl & -sz_up ) + mod_cell_2a = openmc.Cell(name='Liner', fill=Cr , region=+mod_rad_0 & -mod_rad_1a & +sz_cl & -sz_up) + mod_cell_2b = openmc.Cell(name='steel', fill=shell_mod , region=+mod_rad_1a & -mod_rad_1b & +sz_cl & -sz_up) + mod_cell_3 = openmc.Cell(name='matrix', fill=matrix , region=+mod_rad_1b & +sz_cl & -sz_up) + mod_cell_5 = openmc.Cell(name='Plug_L', fill=shell_mod , region=-mod_rad_1b & +sz_cl_out & -sz_cl) + mod_cell_6 = openmc.Cell(name='Plug_LR', fill=refl , region=+mod_rad_1b & +sz_cl_out & -sz_cl) + mod_cell_7 = openmc.Cell(name='Plug_U', fill=shell_mod , region=-mod_rad_1b & +sz_up & -sz_up_out) + mod_cell_8 = openmc.Cell(name='Plug_UR', fill=refl , region=+mod_rad_1b & +sz_up & -sz_up_out) + mod_cell_9 = openmc.Cell(name='LowRef', fill=refl , region=-sz_cl_out) + mod_cell_10 = openmc.Cell(name='UpRef', fill=refl , region=+sz_up) + mod_universe= openmc.Universe(cells=(mod_cell_1,mod_cell_2a, mod_cell_2b,mod_cell_3,mod_cell_5,mod_cell_6,mod_cell_7,mod_cell_8,mod_cell_9,mod_cell_10)) + + coolant_cell_1 = openmc.Cell(name='coolant', fill=coolant , region=-cool_radius) + coolant_cell_2 = openmc.Cell(name='matrix', fill=matrix , region=+cool_radius & +sz_cl & -sz_up) + coolant_cell_3 = openmc.Cell(name='reflL', fill=refl , region=+cool_radius & -sz_cl) + coolant_cell_4 = openmc.Cell(name='reflO', fill=refl , region=+cool_radius & +sz_up) + coolant_universe= openmc.Universe(cells=(coolant_cell_1,coolant_cell_2,coolant_cell_3,coolant_cell_4)) + + ctr_cell_1a = openmc.Cell(name='coolant', fill=coolant , region=-ctr_radius & +sz_cl & -cpin_low) + ctr_cell_1b = openmc.Cell(name='abs', fill=boro_ctr , region=-ctr_radius & +cpin_low) + ctr_cell_1c = openmc.Cell(name='refl', fill=refl , region=-ctr_radius & -sz_cl) + ctr_cell_2 = openmc.Cell(name='matrix', fill=matrix , region=+ctr_radius & +sz_cl & -sz_up) + ctr_cell_3 = openmc.Cell(name='reflL', fill=refl , region=+ctr_radius & -sz_cl) + ctr_cell_4 = openmc.Cell(name='reflO', fill=refl , region=+ctr_radius & +sz_up) + ctr_universe= openmc.Universe(cells=(ctr_cell_1a,ctr_cell_1b,ctr_cell_1c, ctr_cell_2,ctr_cell_3,ctr_cell_4)) + + Graph_cell_1= openmc.Cell(name='Graph cell', fill=matrix) + Graph_universe= openmc.Universe(cells=(Graph_cell_1,)) + + # Fill the hexagone with fuel and coolant cells + + assembly_description=[[]]*6 + assembly_description[5]=([ctr_universe]) + assembly_description[4] =([fuel_universe])*6 + assembly_description[3] =([fuel_universe]+[coolant_universe])*6 + assembly_description[2] =([coolant_universe] + [fuel_universe] + [mod_universe] + [coolant_universe] + [fuel_universe] + [mod_universe])*3 + assembly_description[1] =([fuel_universe]+[fuel_universe]+[coolant_universe]+[fuel_universe])*6 + assembly_description[0] =([fuel_universe]+[coolant_universe]+[fuel_universe]+[fuel_universe]+[coolant_universe])*6 + #print(assembly_description) + + lat_core = openmc.HexLattice() + lat_core.center=(0,0) + lat_core.pitch=[pin_pitch] + lat_core.outer=Graph_universe + lat_core.universes=assembly_description + # print(lat_core) + rotated_lat_core = openmc.Cell(fill=lat_core) + rotated_universe_lat_core = openmc.Universe(cells=(rotated_lat_core,)) + new_cell_lat_core=openmc.Cell() + new_cell_lat_core.fill=rotated_universe_lat_core + new_cell_lat_core.rotation=(0.,0.,90.) + new_universe_lat_core = openmc.Universe(cells=(new_cell_lat_core,)) + + main_cell = openmc.Cell(name="MainCell",fill=new_universe_lat_core, region=Hex_Pitch & +min_z & -max_z ) + + + # OpenMC expects that there is a root universe assigned number zero. Here we + # assign our three cells to this root universe. + root_universe = openmc.Universe(name='root universe', cells=(main_cell,)) + + # Finally we must create a geometry and assign the root universe + geometry = openmc.Geometry() + geometry.root_universe = root_universe + geometry.export_to_xml() + + # Now let's define our simulation parameters. These will go into our + # settings.xml via the SettingsFile object. + batches = 100 + inactive = 30 + particles = 5000 + + # Instantiate a SettingsFile + settings_file = openmc.Settings() + settings_file.run_mode = 'eigenvalue' + settings_file.cross_sections = '/software/openmc/data/v0.12pre-3/lanl_endfb80/cross_sections.xml' + settings_file.batches = batches + settings_file.inactive = inactive + settings_file.particles = particles + settings_file.material_cell_offsets = False + settings_file.temperature = {'method' : 'interpolation'} + + source = openmc.Source() + ll = [-params['Assembly_pitch']/4, -params['Assembly_pitch']/4, Z_min] + ur = [params['Assembly_pitch']/4, params['Assembly_pitch']/4, Z_max] + source.space = openmc.stats.Box(ll, ur) + source.strength = 1.0 + settings_file.source = source + + #lower_left, upper_right = main_cell.region.bounding_box + + list_tally_cell = [cell.id for cell in TALLY_REGIONS] + list_tally_scores = ['flux', 'nu-fission'] + cell_filter = openmc.CellFilter(list_tally_cell) + tally_file = openmc.Tally() + tally_file.filters.append(cell_filter) + tally_file.scores = list_tally_scores + tallies = openmc.Tallies() + tallies.append(tally_file) + tallies.export_to_xml() + + settings_file.export_to_xml() + + # Create a plots.xml file + radius = params['Assembly_pitch']/sqrt(3) + p1 = openmc.Plot() + p1.origin = (0, 0, (Z_max-Z_min)/2) + p1.width = (radius*2, radius*2) + p1.pixels = (2000, 2000) + p1.color = 'mat' + p1.basis = 'xy' + p1.color_by = 'material' + p1.col_spec = { + homfuel1.id: (255, 0, 0), + homfuel2.id: (255, 0, 0), + homfuel3.id: (255, 0, 0), + homfuel4.id: (255, 0, 0), + homfuel5.id: (255, 0, 0), + matrix.id: (100, 100, 100), + yh2.id: (20, 200, 50), + boro_ctr.id: (200, 20, 50), + shell_mod.id: (150,150,150), + coolant.id: (180,110,150), + refl.id: (80,210,50) + } + p2 = openmc.Plot() + p2.origin = (0, 0, (Z_max-Z_min)/2) + p2.width = (radius*2, Z_max) + p2.pixels = (200, 2000) + p2.color = 'mat' + p2.basis ='yz' + p2.color_by = 'material' + p2.col_spec = { + homfuel1.id: (255, 0, 0), + homfuel2.id: (255, 0, 0), + homfuel3.id: (255, 0, 0), + homfuel4.id: (255, 0, 0), + homfuel5.id: (255, 0, 0), + matrix.id: (100, 100, 100), + yh2.id: (20, 200, 50), + boro_ctr.id: (200, 20, 50), + shell_mod.id: (150,150,150), + coolant.id: (180,110,150), + refl.id: (80,210,50) + } + p3 = openmc.Plot() + p3.origin = (0, 0, (Z_max-1)) + p3.width = (radius*2, radius*2) + p3.pixels = (2000, 2000) + p3.color = 'mat' + p3.basis = 'xy' + p3.color_by = 'material' + p3.col_spec = { + homfuel1.id: (255, 0, 0), + homfuel2.id: (255, 0, 0), + homfuel3.id: (255, 0, 0), + homfuel4.id: (255, 0, 0), + homfuel5.id: (255, 0, 0), + matrix.id: (100, 100, 100), + yh2.id: (20, 200, 50), + boro_ctr.id: (200, 20, 50), + shell_mod.id: (150,150,150), + coolant.id: (180,110,150), + refl.id: (80,210,50) + } + plots = openmc.Plots() + plots.append(p1) + plots.append(p2) + plots.append(p3) + plots.export_to_xml() diff --git a/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/sam_template b/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/sam_template new file mode 100644 index 00000000..6742c196 --- /dev/null +++ b/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/sam_template @@ -0,0 +1,574 @@ + + {#- + Create variables + #} + {%- set Mass_flow_rate = Tot_assembly_power / (He_cp * (He_outlet_temp - He_inlet_temp)) %} + {%- set Channel_mass_flow_rate = Mass_flow_rate / num_cool_pins %} + {%- set Coolant_channel_XS = 3.14 * (Coolant_channel_diam/2)**2 %} + {%- set He_velocity = Channel_mass_flow_rate / (He_density * Coolant_channel_XS) %} + {%- set Re_num = Coolant_channel_diam * He_velocity * He_density / He_viscosity %} + {%- set Prandtl_num = He_cp * He_viscosity / He_K %} + {%- set F_blausius = (100*Re_num)**(-0.25) %} + {%- set Nu_DittBoe = 0.023 * (Re_num ** 0.8) * (Prandtl_num ** 0.4) %} + {%- set H_sam = Nu_DittBoe * He_K / Coolant_channel_diam %} + {%- set total_XS_coolant_area_per_fuel_assembly = Coolant_channel_XS * num_cool_pins %} + {%- set surface_area_den = num_fuel_pins * 3.14 * 2 * (FuelPin_rad + Graphite_thickness) / (100 * num_cool_pins * Coolant_channel_XS) %} + {%- set Power_fuel_pin = Tot_assembly_power / (num_fuel_pins) %} + {%- set graph_x = Coolant_channel_diam / 2 + Graphite_thickness / 100 %} + {%- set fuel_x = graph_x + FuelPin_rad / 100 %} + {#- + Render the parameters + #} + +[GlobalParams] + global_init_P = {{ He_Pressure }} + global_init_V = {{ He_velocity }} + global_init_T = {{ He_inlet_temp }} + gravity = '-9.8 0 0' + scaling_factor_var = '1 1e-3 1e-6' + Tsolid_sf = 1e-3 # Scaling factors for solid temperature +[] +[Functions] + active = 'power_dist kf cpf kclad cpclad rhoclad kgraphite cpgraphite rhographite kHe cpHe rhoHe muHe HHe beta_fn' + # [./power_dist] # Function name + # type = PiecewiseLinear # Function type + # axis = x # X-co-ordinate is used for x + # x = ' 0.0 0.5 1.0 1.5 2.0' + # y = ' {{ Init_P_1 }} {{ Init_P_2 }} {{ Init_P_3 }} {{ Init_P_4 }} {{ Init_P_5 }}' + # [../] + + [./power_dist] # Function name + type = PiecewiseLinear # Function type + axis = x # X-co-ordinate is used for x + x = ' 0.0 0.5 1.0 1.5 2.0' + y = ' 1.0 1.0 1.0 1.0 1.0' + [../] + + + [./kf] #fuel thermal conductivity (UO2); x- Temperature [K], y- Thermal condiuctivity [W/m-K] + type = PiecewiseLinear + x ='600 700 800 900 1000 1100 1200 1300 1400 1500' + y ='55.6153061 51.02219975 47.11901811 43.95203134 41.16924224 38.85202882 36.89323509 35.04777834 33.20027175 31.3520767' + [../] + [./cpf] #fuel matrix specific heat (UO2); x- Temperature [K], y- sp. heat [J/kg-K] + type = PiecewiseLinear + x ='300 325 350 375 400 425 450 475 500 525 550 575 600 625 650 675 700 725 750 775 800 825 850 875 900 925 950 975 1000 1025 1050 1075 1100 1125 1150 1175 1200 1225 1250 1275 1300 1325 1350 1375 1400 1425 1450 1475 1500' + y ='44.87198213 57.09373669 71.35471375 87.81224925 106.6236791 127.9463393 151.9375658 178.7546944 208.5550611 241.4960019 277.7348528 317.4289495 360.7356281 407.8122246 458.8160748 513.9045146 573.2348801 636.9645072 705.2507318 778.2508898 856.1223171 939.0223498 1027.108324 1120.537575 1219.467439 1324.055252 1434.458351 1550.83407 1673.339746 1802.132715 1937.370313 2079.209875 2227.808738 2383.324238 2545.91371 2715.73449 2892.943915 3077.69932 3270.158042 3470.477415 3678.814777 3895.327463 4120.172809 4353.508151 4595.490824 4846.278166 5106.027511 5374.896196 5653.041556' + [../] + [./kclad] #clad therm. cond; x- Temperature [K], y-Thermal condiuctivity [W/m-K] + type = PiecewiseLinear + x ='0 478.1709374 571.7659 668.7480342 769.1357153 871.2212698 969.9012774 1068.58496 1167.263743 1274.445367 2118.255351 5000' + y ='3.812850324 3.812850324 3.453993823 3.678279136 3.812850324 4.0819927 4.440849201 4.665134514 5.068848078 5.651989892 11.43855097 11.43855097' + [../] + [./cpclad] #clad specific heat; x- Temperature [K], y- sp. heat [J/kg-K] + type = PiecewiseLinear + x ='300 325 350 375 400 425 450 475 500 525 550 575 600 625 650 675 700 725 750 775 800 825 850 875 900 925 950 975 1000 1025 1050 1075 1100 1125 1150 1175 1200 1225 1250 1275 1300 1325 1350 1375 1400 1425 1450 1475 1500' + y ='286.38 288.94 291.5 294.06 296.62 299.18 301.74 304.3 306.86 309.42 311.98 314.54 317.1 319.66 322.22 324.78 327.34 329.9 332.46 335.02 337.58 340.14 342.7 345.26 347.82 350.38 352.94 355.5 358.06 360.62 363.18 365.74 336.785 335.2703125 333.95125 332.8278125 331.9 331.1678125 330.63125 330.2903125 330.145 330.1953125 330.44125 330.8828125 331.52 332.3528125 333.38125 334.6053125 336.025' + [../] + [./rhoclad] #clad density; x- Temperature [K], y- density [kg/m3] + type = PiecewiseLinear + x ='300 325 350 375 400 425 450 475 500 525 550 575 600 625 650 675 700 725 750 775 800 825 850 875 900 925 950 975 1000 1025 1050 1075 1100 1125 1150 1175 1200 1225 1250 1275 1300 1325 1350 1375 1400 1425 1450 1475 1500' + y ='6550.89 6547.1975 6543.505 6539.8125 6536.12 6532.4275 6528.735 6525.0425 6521.35 6517.6575 6513.965 6510.2725 6506.58 6502.8875 6499.195 6495.5025 6491.81 6488.1175 6484.425 6480.7325 6477.04 6473.3475 6469.655 6465.9625 6462.27 6458.5775 6454.885 6451.1925 6447.5 6443.8075 6440.115 6436.4225 6485.95 6481.3125 6476.675 6472.0375 6467.4 6462.7625 6458.125 6453.4875 6448.85 6444.2125 6439.575 6434.9375 6430.3 6425.6625 6421.025 6416.3875 6411.75' + [../] + [./kgraphite] #G-348 graphite therm. cond; x- Temperature [K], y-Thermal condiuctivity [W/m-K] + type = PiecewiseLinear + x ='295.75 374.15 472.45 574.75 674.75 774.75 874.75 974.85 1074.45 1173.95 1274.05' + y ='133.02 128.54 117.62 106.03 96.7 88.61 82.22 76.52 71.78 67.88 64.26' + [../] + [./cpgraphite] #G-348 graphite specific heat; x- Temperature [K], y- sp. heat [J/kg-K] + type = PiecewiseLinear + x ='295.75 374.15 472.45 574.75 674.75 774.75 874.75 974.85 1074.45 1173.95 1274.05' + y ='726.19 933.15 1154.47 1341.07 1486.83 1603.53 1697.43 1773.6 1835.58 1886.68 1929.44' + [../] + [./rhographite] #G-348 graphite density; x- Temperature [K], y- density [kg/m3] + type = PiecewiseLinear + x ='295.75 374.15 472.45 574.75 674.75 774.75 874.75 974.85 1074.45 1173.95 1274.05' + y ='1888.5 1886.3 1883.5 1880.4 1877.2 1873.9 1870.5 1867 1863.4 1859.6 1855.7' + [../] + [./kHe] #Helium therm. cond; x- Temperature [K], y-Thermal condiuctivity [W/m-K] + type = PiecewiseLinear + x ='300 320 340 360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680 700 720 740 760 780 800 820 840 860 880 900 920 940 960 980 1000 1020 1040 1060 1080 1100 1120 1140 1160 1180 1200 1220 1240 1260 1280 1300 1320 1340 1360 1380 1400 1420 1440 1460 1480 1500' + y ='0.16053 0.16754 0.17444 0.18123 0.18792 0.19451 0.20102 0.20743 0.21377 0.22003 0.22622 0.23233 0.23838 0.24437 0.2503 0.25616 0.26198 0.26773 0.27344 0.27909 0.2847 0.29026 0.29578 0.30126 0.30669 0.31208 0.31743 0.32275 0.32802 0.33327 0.33847 0.34365 0.34879 0.3539 0.35897 0.36402 0.36904 0.37403 0.37899 0.38392 0.38883 0.39371 0.39856 0.40339 0.4082 0.41298 0.41774 0.42248 0.42719 0.43188 0.43655 0.4412 0.44583 0.45043 0.45502 0.45959 0.46414 0.46867 0.47318 0.47767 0.48215' + [../] + [./muHe] #Helium viscosity; x- Temperature [K], y-viscosity [Pa.s] + type = PiecewiseLinear + x ='300 320 340 360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680 700 720 740 760 780 800 820 840 860 880 900 920 940 960 980 1000 1020 1040 1060 1080 1100 1120 1140 1160 1180 1200 1220 1240 1260 1280 1300 1320 1340 1360 1380 1400 1420 1440 1460 1480 1500' + y ='0.00002016 0.0002148 0.000021921 0.000022782 0.00002363 0.000024467 0.000025294 0.00002611 0.000026917 0.000027715 0.000028504 0.000029285 0.000030058 0.000030823 0.000031582 0.000032333 0.000033078 0.000033816 0.000034549 0.000035275 0.000035996 0.000036711 0.00003742 0.000038125 0.000038825 0.00003952 0.00004021 0.000040895 0.000041576 0.000042253 0.000042926 0.000043595 0.00004426 0.00004492 0.000045578 0.000046231 0.000046881 0.000047528 0.000048171 0.000048811 0.000049447 0.000050081 0.000050711 0.000051338 0.000051963 0.000052584 0.000053203 0.000053818 0.000054432 0.000055042 0.00005565 0.000056255 0.000056858 0.000057458 0.000058056 0.000058651 0.000059244 0.000059835 0.000060424 0.00006101 0.000061594' + [../] + [./cpHe] #Helium specific heat; x- Temperature [K], y- sp. heat [J/kg-K] + type = PiecewiseLinear + x ='300 320 340 360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680 700 720 740 760 780 800 820 840 860 880 900 920 940 960 980 1000 1020 1040 1060 1080 1100 1120 1140 1160 1180 1200 1220 1240 1260 1280 1300 1320 1340 1360 1380 1400 1420 1440 1460 1480 1500' + y ='5188.5 5188 5187.6 5187.4 5187.2 5187.2 5187.1 5187.2 5187.2 5187.3 5187.4 5187.5 5187.6 5187.7 5187.8 5187.9 5188 5188.1 5188.2 5188.3 5188.4 5188.5 5188.7 5188.8 5188.8 5188.9 5189 5189.1 5189.2 5189.3 5189.4 5189.5 5189.5 5189.6 5189.7 5189.7 5189.8 5189.9 5189.9 5190 5190.1 5190.1 5190.2 5190.2 5190.3 5190.3 5190.4 5190.4 5190.5 5190.5 5190.6 5190.6 5190.7 5190.7 5190.7 5190.8 5190.8 5190.8 5190.9 5190.9 5190.9' + [../] + [./rhoHe] #Helium density; x- Temperature [K], y- density [kg/m3] + type = PiecewiseLinear + x ='300 320 340 360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680 700 720 740 760 780 800 820 840 860 880 900 920 940 960 980 1000 1020 1040 1060 1080 1100 1120 1140 1160 1180 1200 1220 1240 1260 1280 1300 1320 1340 1360 1380 1400 1420 1440 1460 1480 1500' + y ='10.883 10.225 9.6425 9.1224 8.6555 8.234 7.8516 7.5031 7.1842 6.8912 6.6212 6.3715 6.14 5.9246 5.7239 5.5363 5.3605 5.1956 5.0405 4.8944 4.7565 4.6262 4.5028 4.3858 4.2747 4.1691 4.0686 3.9729 3.8815 3.7942 3.7108 3.6309 3.5545 3.4811 3.4108 3.3432 3.2782 3.2157 3.1556 3.0976 3.0418 2.9879 2.9359 2.8857 2.8371 2.7902 2.7448 2.7009 2.6583 2.617 2.577 2.5383 2.5006 2.4641 2.4286 2.3941 2.3606 2.328 2.2963 2.2655 2.2354' + [../] + [./HHe] #Helium Enthalpy; x- Temperature [K], y- denthalpy [j/kg] + type = PiecewiseLinear + x ='300 320 340 360 380 400 420 440 460 480 500 520 540 560 580 600 620 640 660 680 700 720 740 760 780 800 820 840 860 880 900 920 940 960 980 1000 1020 1040 1060 1080 1100 1120 1140 1160 1180 1200 1220 1240 1260 1280 1300 1320 1340 1360 1380 1400 1420 1440 1460 1480 1500' + y ='1585700 1689500 1793300 1897000 2000800 2104500 2208200 2312000 2415700 2519500 2623200 2727000 2830700 2934500 3038200 3142000 3245700 3349500 3453300 3557000 3660800 3764600 3868300 3972100 4075900 4179700 4283400 4387200 4491000 4594800 4698600 4802400 4906200 5010000 5113700 5217500 5321300 5425100 5528900 5632700 5736500 5840300 5944100 6047900 6151700 6255600 6359400 6463200 6567000 6670800 6774600 6878400 6982200 7086000 7189800 7293700 7397500 7501300 7605100 7708900 7812700' + [../] + [./beta_fn] + type = PiecewiseLinear + x = '300 2000' + y = '0 0' + [../] + + [./T_max_fuel] + type = ParsedFunction + value = Tf1+Tf2 + vars = 'Tf1 Tf2' + vals = 'max_Tf_1 max_Tf_2' + [../] + +[] +[EOS] + [./eos] + type = PTFluidPropertiesEOS + p_0 = {{ He_Pressure }} # Pa + fp = fluid_props1 + [../] +[] +[MaterialProperties] + [./fluid_props1] + type = FunctionFluidProperties + rho = rhoHe + beta = beta_fn + cp = cpHe + mu = muHe + k = kHe + enthalpy = HHe + [../] + [./fuel-mat] # Material name + type = SolidMaterialProps + k = kf # Thermal conductivity + Cp = cpf # Specific heat + rho = 1.104e4 # Density + [../] + [./clad-mat] # Material name + type = SolidMaterialProps + k = kgraphite # Thermal conductivity + Cp = cpgraphite # Specific heat + rho = rhographite # Density + [../] + [./graphite-mat] # Material name + type = SolidMaterialProps + k = kgraphite # Thermal conductivity + Cp = cpgraphite # Specific heat + rho = rhographite # Density + [../] + [./leadBUF-mat] # Material name + type = SolidMaterialProps + k = kgraphite # Thermal conductivity + Cp = cpgraphite # Specific heat + rho = rhographite # Density + [../] +[] +[Components] + [./reactor] + type = ReactorPower + initial_power = {{ Tot_assembly_power }} # Initial total reactor power + [../] + + [./CH1] # Component name + type = PBCoreChannel # PBCorechannel component + eos = eos # The equation-of-state name + position = '0 {{Height_FC/5 * 0}} 0' + orientation = '0 1 0' + assembly_type = Block-Channel + n_rods = {{ num_fuel_pins }} + A = {{ total_XS_coolant_area_per_fuel_assembly }} + Dh = {{ Coolant_channel_diam }} + length = {{ Height_FC/5 }} + n_elems = 20 + f = {{ F_blausius }} # User specified friction coefficient (Blausis f=(100 Re)^-0.25 + Hw = {{ H_sam }} # User specified heat transfer coefficient (Dittus-Boelter) + HT_surface_area_density = {{ surface_area_den }} # Heat transfer surface area density, Ph/Ac + name_of_hs = 'fuel graphite' # Heat structure names + Ts_init = {{ He_inlet_temp }} # Initial structure temeprature + n_heatstruct = 2 # Number of heat structures + fuel_type = cylinder # Fuel geometric type, cylinder or plate + width_of_hs = '{{FuelPin_rad/100}} {{ Graphite_thickness/100 }}' # The width of all heat structures + elem_number_of_hs = '50 10' # The element numbers of all heat structures + material_hs = 'fuel-mat graphite-mat' # The material used for all heat structures + power_fraction = '0.2 0.0' # The power fractions of all heat structures + power_shape_function = power_dist # the axial power shape function name + [../] + + [./CH2] # Component name + type = PBCoreChannel # PBCorechannel component + eos = eos # The equation-of-state name + position = '0 {{Height_FC/5 * 1}} 0' + orientation = '0 1 0' + assembly_type = Block-Channel + n_rods = {{ num_fuel_pins }} + A = {{ total_XS_coolant_area_per_fuel_assembly }} + Dh = {{ Coolant_channel_diam }} + length = {{ Height_FC/5 }} + n_elems = 20 + f = {{ F_blausius }} # User specified friction coefficient (Blausis f=(100 Re)^-0.25 + Hw = {{ H_sam }} # User specified heat transfer coefficient (Dittus-Boelter) + HT_surface_area_density = {{ surface_area_den }} # Heat transfer surface area density, Ph/Ac + name_of_hs = 'fuel graphite' # Heat structure names + Ts_init = {{ He_inlet_temp }} # Initial structure temeprature + n_heatstruct = 2 # Number of heat structures + fuel_type = cylinder # Fuel geometric type, cylinder or plate + width_of_hs = '{{FuelPin_rad/100}} {{ Graphite_thickness/100 }}' # The width of all heat structures + elem_number_of_hs = '50 10' # The element numbers of all heat structures + material_hs = 'fuel-mat graphite-mat' # The material used for all heat structures + power_fraction = '0.2 0.0' # The power fractions of all heat structures + power_shape_function = power_dist # the axial power shape function name + [../] + + [./CH3] # Component name + type = PBCoreChannel # PBCorechannel component + eos = eos # The equation-of-state name + position = '0 {{Height_FC/5 * 2}} 0' + orientation = '0 1 0' + assembly_type = Block-Channel + n_rods = {{ num_fuel_pins }} + A = {{ total_XS_coolant_area_per_fuel_assembly }} + Dh = {{ Coolant_channel_diam }} + length = {{ Height_FC/5 }} + n_elems = 20 + f = {{ F_blausius }} # User specified friction coefficient (Blausis f=(100 Re)^-0.25 + Hw = {{ H_sam }} # User specified heat transfer coefficient (Dittus-Boelter) + HT_surface_area_density = {{ surface_area_den }} # Heat transfer surface area density, Ph/Ac + name_of_hs = 'fuel graphite' # Heat structure names + Ts_init = {{ He_inlet_temp }} # Initial structure temeprature + n_heatstruct = 2 # Number of heat structures + fuel_type = cylinder # Fuel geometric type, cylinder or plate + width_of_hs = '{{FuelPin_rad/100}} {{ Graphite_thickness/100 }}' # The width of all heat structures + elem_number_of_hs = '50 10' # The element numbers of all heat structures + material_hs = 'fuel-mat graphite-mat' # The material used for all heat structures + power_fraction = '0.2 0.0' # The power fractions of all heat structures + power_shape_function = power_dist # the axial power shape function name + [../] + + [./CH4] # Component name + type = PBCoreChannel # PBCorechannel component + eos = eos # The equation-of-state name + position = '0 {{Height_FC/5 * 3}} 0' + orientation = '0 1 0' + assembly_type = Block-Channel + n_rods = {{ num_fuel_pins }} + A = {{ total_XS_coolant_area_per_fuel_assembly }} + Dh = {{ Coolant_channel_diam }} + length = {{ Height_FC/5 }} + n_elems = 20 + f = {{ F_blausius }} # User specified friction coefficient (Blausis f=(100 Re)^-0.25 + Hw = {{ H_sam }} # User specified heat transfer coefficient (Dittus-Boelter) + HT_surface_area_density = {{ surface_area_den }} # Heat transfer surface area density, Ph/Ac + name_of_hs = 'fuel graphite' # Heat structure names + Ts_init = {{ He_inlet_temp }} # Initial structure temeprature + n_heatstruct = 2 # Number of heat structures + fuel_type = cylinder # Fuel geometric type, cylinder or plate + width_of_hs = '{{FuelPin_rad/100}} {{ Graphite_thickness/100 }}' # The width of all heat structures + elem_number_of_hs = '50 10' # The element numbers of all heat structures + material_hs = 'fuel-mat graphite-mat' # The material used for all heat structures + power_fraction = '0.2 0.0' # The power fractions of all heat structures + power_shape_function = power_dist # the axial power shape function name + [../] + + [./CH5] # Component name + type = PBCoreChannel # PBCorechannel component + eos = eos # The equation-of-state name + position = '0 {{Height_FC/5 * 4}} 0' + orientation = '0 1 0' + assembly_type = Block-Channel + n_rods = {{ num_fuel_pins }} + A = {{ total_XS_coolant_area_per_fuel_assembly }} + Dh = {{ Coolant_channel_diam }} + length = {{ Height_FC/5 }} + n_elems = 20 + f = {{ F_blausius }} # User specified friction coefficient (Blausis f=(100 Re)^-0.25 + Hw = {{ H_sam }} # User specified heat transfer coefficient (Dittus-Boelter) + HT_surface_area_density = {{ surface_area_den }} # Heat transfer surface area density, Ph/Ac + name_of_hs = 'fuel graphite' # Heat structure names + Ts_init = {{ He_inlet_temp }} # Initial structure temeprature + n_heatstruct = 2 # Number of heat structures + fuel_type = cylinder # Fuel geometric type, cylinder or plate + width_of_hs = '{{FuelPin_rad/100}} {{ Graphite_thickness/100 }}' # The width of all heat structures + elem_number_of_hs = '50 10' # The element numbers of all heat structures + material_hs = 'fuel-mat graphite-mat' # The material used for all heat structures + power_fraction = '0.2 0.0' # The power fractions of all heat structures + power_shape_function = power_dist # the axial power shape function name + [../] + + [./junc_CH1_CH2] + type = PBSingleJunction + eos = eos + inputs = 'CH1(out)' + outputs = 'CH2(in)' + [../] + [./junc_CH2_CH3] + type = PBSingleJunction + eos = eos + inputs = 'CH2(out)' + outputs = 'CH3(in)' + [../] + [./junc_CH3_CH4] + type = PBSingleJunction + eos = eos + inputs = 'CH3(out)' + outputs = 'CH4(in)' + [../] + [./junc_CH4_CH5] + type = PBSingleJunction + eos = eos + inputs = 'CH4(out)' + outputs = 'CH5(in)' + [../] + + + [./inlet] #Boundary components + type = PBTDJ + input = 'CH1(in)' + v_bc = {{ He_velocity }} + T_bc = {{ He_inlet_temp }} + eos = eos + [../] + [./outlet] + type = PBTDV + input = 'CH5(out)' + p_bc = '{{ He_Pressure }}' + T_bc = {{ He_outlet_temp }} + eos = eos + [../] +[] +[Postprocessors] + +# [max_Tf] +# type = ParsedPostprocessor +# function = 'max(max(max_Tf_1,max_Tf_2),max(max_Tf_3,max(max_Tf_4,max_Tf_5)))' +# pp_names = 'max_Tf_1 max_Tf_2 max_Tf_3 max_Tf_4 max_Tf_5' +# [] +# +# [avg_Tgraphite] +# type = ParsedPostprocessor +# function = '(avg_Tgraphite_1+avg_Tgraphite_2+avg_Tgraphite_3+avg_Tgraphite_4+avg_Tgraphite_5)/5' +# pp_names = 'avg_Tgraphite_1 avg_Tgraphite_2 avg_Tgraphite_3 avg_Tgraphite_4 avg_Tgraphite_5' +# [] + + [./max_Tcoolant] # Output maximum fluid temperature of block CH1:pipe + type = NodalMaxValue + block = 'CH1:pipe' + variable = temperature + [../] + [./max_Tw] # Output maximum wall temperature of block CH1:pipe + type = NodalMaxValue + block = 'CH1:pipe' + variable = Tw + [../] + [./max_Tf_1] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH1:solid:fuel' + variable = T_solid + [../] + [./max_Tf_2] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH2:solid:fuel' + variable = T_solid + [../] + [./max_Tf_3] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH3:solid:fuel' + variable = T_solid + [../] + [./max_Tf_4] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH4:solid:fuel' + variable = T_solid + [../] + [./max_Tf_5] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH5:solid:fuel' + variable = T_solid + [../] + [./max_Tgraphite_1] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH1:solid:graphite' + variable = T_solid + [../] + [./max_Tgraphite_2] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH2:solid:graphite' + variable = T_solid + [../] + [./max_Tgraphite_3] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH3:solid:graphite' + variable = T_solid + [../] + [./max_Tgraphite_4] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH4:solid:graphite' + variable = T_solid + [../] + [./max_Tgraphite_5] # Output maximum solid temperature of block CH1: solid:fuel + type = NodalMaxValue + block = 'CH5:solid:graphite' + variable = T_solid + [../] + + [./max_Pcoolant_1] # Output maximum fluid temperature of block CH1:pipe + type = NodalMaxValue + block = 'CH1:pipe' + variable = pressure + [../] + [./max_Pcoolant_2] # Output maximum fluid temperature of block CH1:pipe + type = NodalMaxValue + block = 'CH2:pipe' + variable = pressure + [../] + [./max_Pcoolant_3] # Output maximum fluid temperature of block CH1:pipe + type = NodalMaxValue + block = 'CH3:pipe' + variable = pressure + [../] + [./max_Pcoolant_4] # Output maximum fluid temperature of block CH1:pipe + type = NodalMaxValue + block = 'CH4:pipe' + variable = pressure + [../] + [./max_Pcoolant_5] # Output maximum fluid temperature of block CH1:pipe + type = NodalMaxValue + block = 'CH5:pipe' + variable = pressure + [../] + + [./avg_Tcoolant_1] # Output maximum fluid temperature of block CH1:pipe + type = ElementAverageValue + block = 'CH1:pipe' + variable = temperature + [../] + [./avg_Tcoolant_2] # Output maximum fluid temperature of block CH1:pipe + type = ElementAverageValue + block = 'CH2:pipe' + variable = temperature + [../] + [./avg_Tcoolant_3] # Output maximum fluid temperature of block CH1:pipe + type = ElementAverageValue + block = 'CH3:pipe' + variable = temperature + [../] + [./avg_Tcoolant_4] # Output maximum fluid temperature of block CH1:pipe + type = ElementAverageValue + block = 'CH4:pipe' + variable = temperature + [../] + [./avg_Tcoolant_5] # Output maximum fluid temperature of block CH1:pipe + type = ElementAverageValue + block = 'CH5:pipe' + variable = temperature + [../] + + [./avg_Tf_1] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH1:solid:fuel' + variable = T_solid + [../] + [./avg_Tf_2] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH2:solid:fuel' + variable = T_solid + [../] + [./avg_Tf_3] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH3:solid:fuel' + variable = T_solid + [../] + [./avg_Tf_4] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH4:solid:fuel' + variable = T_solid + [../] + [./avg_Tf_5] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH5:solid:fuel' + variable = T_solid + [../] + + [./avg_Tgraphite_1] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH1:solid:graphite' + variable = T_solid + [../] + [./avg_Tgraphite_2] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH2:solid:graphite' + variable = T_solid + [../] + [./avg_Tgraphite_3] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH3:solid:graphite' + variable = T_solid + [../] + [./avg_Tgraphite_4] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH4:solid:graphite' + variable = T_solid + [../] + [./avg_Tgraphite_5] # Output maximum solid temperature of block CH1: solid:fuel + type = ElementAverageValue + block = 'CH5:solid:graphite' + variable = T_solid + [../] +[] +[VectorPostprocessors] + [./vel] + type = LineValueSampler + variable = velocity + start_point = '0 0 0' + end_point = '0 {{ Height_FC/5 }} 0' + num_points = 21 + use_displaced_mesh = true + sort_by = id + [../] +[] +[Preconditioning] + active = 'SMP_PJFNK' + [./SMP_PJFNK] + type = SMP + full = true + solve_type = 'PJFNK' + petsc_options_iname = '-pc_type' + petsc_options_value = 'lu' + [../] +[] +[Executioner] + type = Steady + petsc_options_iname = '-ksp_gmres_restart' + petsc_options_value = '300' + nl_rel_tol = 1e-9 + nl_abs_tol = 1e-7 + nl_max_its = 20 + l_tol = 1e-5 + l_max_its = 50 + [./Quadrature] + type = TRAP + order = FIRST + [../] +[] + +[Outputs] + print_linear_residuals = false + perf_graph = true + [./out] + type = Checkpoint + [../] + [./console] + type = Console + [../] + [./out_displaced] + type = Exodus + use_displaced = true + execute_on = 'initial timestep_end' + sequence = false + [../] + [./csv] + type = CSV + [../] +[] diff --git a/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/watts_wb.son b/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/watts_wb.son new file mode 100644 index 00000000..01171daa --- /dev/null +++ b/examples/PicardIterations_SAM-OpenMC_VHTR_Workbench/watts_wb.son @@ -0,0 +1,68 @@ +watts{ + plugins{ + plugin(ID1){ + code = moose + template = "sam_template" + exec_dir = "SAM_DIR" + exec_name = "sam-opt" + show_stderr = False + show_stdout = False + } + plugin(ID2){ + code = openmc + template = "openmc_template.py" + scores = ["nu-fission"] % Name of scores for OpenMC tallies. This will be the base name used for saving the tallies. + score_names = ["Init_P"] % A more representative name for the scores + } + } + workflow_level1{ + plugin = ID1 + variables{ + param(He_inlet_temp) {value = 873.15} + param(He_outlet_temp) {value = 1023.15} + param(He_cp) {value = 5189.2} + param(He_K) {value = 0.32802} + param(He_density) {value = 3.8815} + param(He_viscosity) {value = 4.16e-5} + param(He_Pressure) {value = 7e6} + param(Tot_assembly_power) {value = 250000} + + param("Init_P_1") {value = 1} + param("Init_P_2") {value = 1} + param("Init_P_3") {value = 1} + param("Init_P_4") {value = 1} + param("Init_P_5") {value = 1} + + param(ax_ref) {value = 2.0} + param(num_cool_pins) {value = 24} + param(num_fuel_pins) {value = 44} + param(Height_FC) {value = 2.0} + param(Lattice_pitch) {value = 2.0} + param(FuelPin_rad) {value = 0.9} + param(cool_hole_rad) {value = 0.6} + param(Coolant_channel_diam) {value = 0.012} + param(Graphite_thickness) {value = 0.5} + param(Assembly_pitch) {value = 17.3205080756887} + param(lbp_rad) {value = 0.25} + param(mod_ext_rad) {value = 0.90} + param(shell_thick) {value = 0.05} + param(liner_thick) {value = 0.007} + param(control_pin_rad) {value = 9.9, unit = mm} + param(cl) {value = 160.0} + param(pf) {value = 40.0} + param(temp) {value = 700.0} + param(use_sab) = {bool = True} + param(use_sab_BeO) = {bool = True} + param(use_sab_YH2) = {bool = False} + } + iteration{ + plugin = ID2 % ID of plugin to iterate with + nmax = 10 + convergence_params = "keff" + convergence_criteria = 0.0001 + to_sub_params = ["avg_Tf_1" "avg_Tf_2" "avg_Tf_3" "avg_Tf_4" "avg_Tf_5"] + to_main_params = ["Init_P_1" "Init_P_2" "Init_P_3" "Init_P_4" "Init_P_5"] + } + } + +} \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 73963459..072cf3ee 100644 --- a/examples/README.md +++ b/examples/README.md @@ -12,10 +12,12 @@ Training on WATTS is enabled with a suite of simple examples: * [__1App_MOOSE-MultiApp_Simple__](1App_MOOSE-MultiApp_Simple/README.md) - Simple MOOSE MultiApp calculation ## Examples with Multi Applications * [__MultiApp_SAM-OpenMC_VHTR__](MultiApp_SAM-OpenMC_VHTR/README.md) - Workflow with MOOSE/SAM and OpenMC +* [__MultiApp_SAM_SimpleJunction_Workbench__](MultiApp_SAM_SimpleJunction_Workbench/README.md) - Workflow on how to use Workbench to run a coupled simulation with multiple apps ## Multi-step workflow * [__MultiStep_Griffin-BISON-Sockeye_MR__](MultiStep_Griffin-BISON-Sockeye_MR/README.md) - Advance MOOSE MultiApp calculation with steady-state and transient calculations ## Examples with Picard Iterations * [__PicardIterations_SAM-OpenMC_VHTR__](PicardIterations_SAM-OpenMC_VHTR/README.md) - Workflow with iterative MOOSE/SAM and OpenMC +* * [__PicardIterations_SAM-OpenMC_VHTR_Workbench__](PicardIterations_SAM-OpenMC_VHTR_Workbench/README.md) - Workflow with iterative MOOSE/SAM and OpenMC using Workbench ## Examples with Optimization * [__Optimization_SAM-OpenMC_VHTR-scipy__](Optimization_SAM-OpenMC_VHTR-scipy/README.md) - 1-criteria optimization of SAM/OpenMC workflow using scipy * [__Optimization_SAM-OpenMC_VHTR-pymoo__](Optimization_SAM-OpenMC_VHTR-pymoo/README.md) - Multi-criteria optimization of SAM/OpenMC workflow using pymoo @@ -25,3 +27,4 @@ Training on WATTS is enabled with a suite of simple examples: * [__Sensitivity_SAM-OpenMC_VHTR-scipy-LHS__](Sensitivity_SAM-OpenMC_VHTR-scipy-LHS/README.md) - Sampling with LHS of SAM/OpenMC workflow using scipy ## Examples with Parameteric studies * [__ParamStudy_SAM_VHTR__](ParamStudy_SAM_VHTR/README.md) - Showcasing SAM with parametric study +* [__ParamStudy_SAM_SimpleJunction_Workbench__](ParamStudy_SAM_SimpleJunction_Workbench/README.md) - Showcasing SAM with parametric study using Workbench diff --git a/scripts/setup_conda_wb.sh b/scripts/setup_conda_wb.sh new file mode 100755 index 00000000..4ad29c85 --- /dev/null +++ b/scripts/setup_conda_wb.sh @@ -0,0 +1,102 @@ +#!/bin/bash +######################################################################## +# Date: 2022-12-22 +# Authors: zooi (zooi [at] anl [dot] gov) +# Comment: Finds the workbench conda environment and initializes it. +# Requires `workbench_path` to be set in workbench.sh +######################################################################## + +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' + +# ---------------------------------------------------------------------- +# Gather workbench_path from workbench.sh +source workbench.sh + +# check that workbench_path was retrieved +if [ -z $workbench_path ]; then + printf "${RED}ERROR: Could not find workbench_path; please confirm 'workbench_path' entry in workbench.sh file${NC}\n" + exit 1 +fi + +# Check that retrieved path to Workbench application exists +if [ ! -d $workbench_path ]; then + printf "${RED}ERROR: Path to Workbench application does not exist; please confirm 'workbench_path' entry in workbench.sh file${NC}\n" + printf " ${workbench_path}\n" + exit 1 +fi + +# # ---------------------------------------------------------------------- +# Find conda in Workbench +conda_path="${workbench_path}/rte/conda" +if [ ! -f "${conda_path}/bin/conda" ]; then + printf "${RED}ERROR: Path to conda executable within Workbench application does not exist; please confirm 'workbench_path' entry in workbench.sh file${NC}\n" + printf " ${conda_path}/bin/conda\n" + exit 1 +fi + +# ---------------------------------------------------------------------- +# Activate Workbench conda environment +# >>> conda init >>> +#!! Contents within this block are managed by 'conda init' !! +__conda_setup="$(CONDA_REPORT_ERRORS=false "${conda_path}/bin/conda" shell.bash hook 2> /dev/null)" +if [ $? -eq 0 ]; then + \eval "$__conda_setup" +else + if [ -f "${conda_path}/etc/profile.d/conda.sh" ]; then + . "${conda_path}/etc/profile.d/conda.sh" + CONDA_CHANGEPS1=false conda activate base + else + PATH="${conda_path}/conda/bin:${PATH}" + fi +fi +unset __conda_setup +# <<< conda init <<< + +# ---------------------------------------------------------------------- +# Check Python version available in Workbench (v3.x required) +pyv=$(python -V 2>&1 | sed 's/.* \([0-9]\).\([0-9]\).*/\1\2/') +if [ $pyv -lt 36 ]; then + printf "${RED}ERROR: Workbench with Python >= 3.6 enabled is required.${NC}\n" + printf " Python version: `python --version`\n" + exit 1 +fi + +# ---------------------------------------------------------------------- +printf "${GREEN}Found Workbench:${NC} ${workbench_path}\n" +printf "${GREEN}Activated Conda: ${NC} ${conda_path}\n" + +yes | python -m pip install watts + +printf "${GREEN}WATTS successfully installed in Workbench environment.\n" + +# ----------------------------------------------------------------------- +# Copying files between WATTS and Workbench +printf "${GREEN}Transfering files between WATTS and Workbench.\n" + +script_path=$(cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P) + +cd ../src/watts_ui + +current_path=$(cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P) + +# Copy watts.py to Workbench/rte +cp etc/watts.py $workbench_path/rte/ + +# Check if bin directory already exists +if [ -d "$current_path/bin" ]; then + printf "${RED}Warning: bin directory already exists in $current_path. Skipped.\n" +else + mkdir bin + ln -s $workbench_path/bin/sonvalidxml bin/sonvalidxml +fi + +# Check if wasppy already exists +if [ -d "$current_path/wasppy" ]; then + printf "${RED}Warning: wasppy already exists in $current_path. Skipped.\n" +else + ln -s $workbench_path/wasppy ./ +fi + +printf "${GREEN}Transfer complete.\n" diff --git a/scripts/setup_openmc.sh b/scripts/setup_openmc.sh new file mode 100755 index 00000000..79f6a416 --- /dev/null +++ b/scripts/setup_openmc.sh @@ -0,0 +1,86 @@ +#!/bin/bash +######################################################################## +# Date: 2022-09-08 +# Author: kkiesling (kkiesling [at] anl [dot] gov) +# Comment: Install OpenMC and its dependencies into the Workbench conda +# environment so that that are available in workbench. +######################################################################## + +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NC='\033[0m' + +# ---------------------------------------------------------------------- +# Initialize conda +script_path=$(cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P) +# source $script_path/setup_conda_wb.sh + + +# ---------------------------------------------------------------------- +# Gather workbench_path from workbench.sh +source workbench.sh + +# check that workbench_path was retrieved +if [ -z $workbench_path ]; then + printf "${RED}ERROR: Could not find workbench_path; please confirm 'workbench_path' entry in workbench.sh file${NC}\n" + exit 1 +fi + +# Check that retrieved path to Workbench application exists +if [ ! -d $workbench_path ]; then + printf "${RED}ERROR: Path to Workbench application does not exist; please confirm 'workbench_path' entry in workbench.sh file${NC}\n" + printf " ${workbench_path}\n" + exit 1 +fi + +# # ---------------------------------------------------------------------- +# Find conda in Workbench +conda_path="${workbench_path}/rte/conda" +if [ ! -f "${conda_path}/bin/conda" ]; then + printf "${RED}ERROR: Path to conda executable within Workbench application does not exist; please confirm 'workbench_path' entry in workbench.sh file${NC}\n" + printf " ${conda_path}/bin/conda\n" + exit 1 +fi + +# ---------------------------------------------------------------------- +# Activate Workbench conda environment +# >>> conda init >>> +#!! Contents within this block are managed by 'conda init' !! +__conda_setup="$(CONDA_REPORT_ERRORS=false "${conda_path}/bin/conda" shell.bash hook 2> /dev/null)" +if [ $? -eq 0 ]; then + \eval "$__conda_setup" +else + if [ -f "${conda_path}/etc/profile.d/conda.sh" ]; then + . "${conda_path}/etc/profile.d/conda.sh" + CONDA_CHANGEPS1=false conda activate base + else + PATH="${conda_path}/conda/bin:${PATH}" + fi +fi +unset __conda_setup +# <<< conda init <<< + +# ---------------------------------------------------------------------- +printf "${GREEN}Found Workbench:${NC} ${workbench_path}\n" +printf "${GREEN}Activated Conda: ${NC} ${conda_path}\n" + + +# ---------------------------------------------------------------------- +# Clone original workbench environment (if not already cloned) and +# generate .yml copy (base_original.yml) if it is not already saved locally +printf "${GREEN}Cloning original workbench environment to:${NC} ${CONDA_DEFAULT_ENV}_base\n" +# "no" == do not overwrite environment if it already exists +yes no | conda create --name ${CONDA_DEFAULT_ENV}_clone --clone ${CONDA_DEFAULT_ENV} +if [ ! -f ${script_path}/${CONDA_DEFAULT_ENV}_original.yml ]; then + conda env export -n $CONDA_DEFAULT_ENV -f ${script_path}/${CONDA_DEFAULT_ENV}_original.yml + printf "${GREEN}Original workbench environment saved to:${NC} ${script_path}/${CONDA_DEFAULT_ENV}_original.yml\n" +fi + +# ---------------------------------------------------------------------- +# Install OpenMC into the conda environment +printf "${GREEN}Installing OpenMC into Workbench conda environment${NC}\n" +yes | conda install -c conda-forge openmc + +printf "${GREEN}OpenMC successfully installed in Workbench environment.${NC}\n" +printf "To complete the setup, add ${BLUE}OPENMC_CROSS_SECTIONS${NC} variable to Arc Workbench configuration.\n" diff --git a/scripts/workbench.sh b/scripts/workbench.sh new file mode 100755 index 00000000..eac2e043 --- /dev/null +++ b/scripts/workbench.sh @@ -0,0 +1,8 @@ +######################################################################## +# Date: 2022-12-22 +# Authors: zooi (zooi [at] anl [dot] gov) +# Comment: Set the path to Workbench to be used for setting up WATTS in Workbench. +######################################################################## + +# Provide path to workbench-.app/Contents +workbench_path="/Applications/Workbench-5.0.1.app/Contents" \ No newline at end of file diff --git a/src/watts_ui/etc/templates/iteration.tmpl b/src/watts_ui/etc/templates/iteration.tmpl new file mode 100644 index 00000000..c15dd4c9 --- /dev/null +++ b/src/watts_ui/etc/templates/iteration.tmpl @@ -0,0 +1,9 @@ +% Define input for iteration +iteration{ + plugin = plugin_name % ID of plugin to iterate with + nmax = max_number_of_iterations % Max number of iterations + convergence_params = "name_of_param" % Name of parameter for checking convergence + convergence_criteria = 0.0001 % Convergence criteria + to_sub_params = ["main_param_1" "main_param_2" "main_param_3"] % List of parameters to send to the sub app + to_main_params = ["sub_param_1" "sub_param_2" "sub_param_3"] % List of parameters to send to the main app +} diff --git a/src/watts_ui/etc/templates/param.bool.tmpl b/src/watts_ui/etc/templates/param.bool.tmpl new file mode 100644 index 00000000..d02401f7 --- /dev/null +++ b/src/watts_ui/etc/templates/param.bool.tmpl @@ -0,0 +1 @@ +param( id ){bool = True} diff --git a/src/watts_ui/etc/templates/param.func.tmpl b/src/watts_ui/etc/templates/param.func.tmpl new file mode 100644 index 00000000..5baa6a68 --- /dev/null +++ b/src/watts_ui/etc/templates/param.func.tmpl @@ -0,0 +1 @@ +param( id ){func = 'a + b' } diff --git a/src/watts_ui/etc/templates/param.list.tmpl b/src/watts_ui/etc/templates/param.list.tmpl new file mode 100644 index 00000000..a83f1265 --- /dev/null +++ b/src/watts_ui/etc/templates/param.list.tmpl @@ -0,0 +1 @@ +param( id ){list = [ 0 ] } diff --git a/src/watts_ui/etc/templates/param.value.tmpl b/src/watts_ui/etc/templates/param.value.tmpl new file mode 100644 index 00000000..e5e8163c --- /dev/null +++ b/src/watts_ui/etc/templates/param.value.tmpl @@ -0,0 +1 @@ +param( id ){value = 0 unit= m} diff --git a/src/watts_ui/etc/templates/parametric.tmpl b/src/watts_ui/etc/templates/parametric.tmpl new file mode 100644 index 00000000..02de9beb --- /dev/null +++ b/src/watts_ui/etc/templates/parametric.tmpl @@ -0,0 +1,5 @@ +% Define input for parametric study +parametric{ + changing_params = "param_name" % name of param to change + changing_values = [0, 1, 2, 3] % list of values to change paramter to +} diff --git a/src/watts_ui/etc/templates/plugin.auto_link_files.tmpl b/src/watts_ui/etc/templates/plugin.auto_link_files.tmpl new file mode 100644 index 00000000..016efcec --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.auto_link_files.tmpl @@ -0,0 +1 @@ +auto_link_files = "file1 file2 file3" % Dakota \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.conv_channel.tmpl b/src/watts_ui/etc/templates/plugin.conv_channel.tmpl new file mode 100644 index 00000000..e86a70b9 --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.conv_channel.tmpl @@ -0,0 +1 @@ +conv_channel = "path\to\CHANNELtoCSV.x" % SAS \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.conv_primar4.tmpl b/src/watts_ui/etc/templates/plugin.conv_primar4.tmpl new file mode 100644 index 00000000..7427eb3e --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.conv_primar4.tmpl @@ -0,0 +1 @@ +conv_primar4 = "path\to\PRIMAR4toCSV.x" % SAS \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.exec_dir.tmpl b/src/watts_ui/etc/templates/plugin.exec_dir.tmpl new file mode 100644 index 00000000..de2afb06 --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.exec_dir.tmpl @@ -0,0 +1 @@ +exec_dir = dir_of_executable \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.exec_name.tmpl b/src/watts_ui/etc/templates/plugin.exec_name.tmpl new file mode 100644 index 00000000..d5574ba6 --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.exec_name.tmpl @@ -0,0 +1 @@ +exec_name = name_of_executable \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.executable.tmpl b/src/watts_ui/etc/templates/plugin.executable.tmpl new file mode 100644 index 00000000..04e82bff --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.executable.tmpl @@ -0,0 +1 @@ +executable = path_to_executable \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.extra_args.tmpl b/src/watts_ui/etc/templates/plugin.extra_args.tmpl new file mode 100644 index 00000000..d2d9fb8f --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.extra_args.tmpl @@ -0,0 +1 @@ +extra_args = ["extra_args_1" "extra_args_2" "extra_args_3"] \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.extra_inputs.tmpl b/src/watts_ui/etc/templates/plugin.extra_inputs.tmpl new file mode 100644 index 00000000..57f51953 --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.extra_inputs.tmpl @@ -0,0 +1 @@ +extra_inputs = ["extra_input_1" "extra_input_2" "extra_input_3"] \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.extra_template_inputs.tmpl b/src/watts_ui/etc/templates/plugin.extra_template_inputs.tmpl new file mode 100644 index 00000000..c9d8892e --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.extra_template_inputs.tmpl @@ -0,0 +1 @@ +extra_template_inputs = ["extra_template_1" "extra_template_2" "extra_template_3"] \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.plotfl_to_csv.tmpl b/src/watts_ui/etc/templates/plugin.plotfl_to_csv.tmpl new file mode 100644 index 00000000..547fe9cf --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.plotfl_to_csv.tmpl @@ -0,0 +1 @@ +plotfl_to_csv = True % RELAP5 \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.score_names.tmpl b/src/watts_ui/etc/templates/plugin.score_names.tmpl new file mode 100644 index 00000000..d7fbfe1c --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.score_names.tmpl @@ -0,0 +1 @@ +score_names = ["score_name_1" "score_name_3" "score_name_3"] % OpenMC \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.scores.tmpl b/src/watts_ui/etc/templates/plugin.scores.tmpl new file mode 100644 index 00000000..9238fe32 --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.scores.tmpl @@ -0,0 +1 @@ +scores = ["score_1" "score_2" "score_3"] % OpenMC \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin.tmpl b/src/watts_ui/etc/templates/plugin.tmpl new file mode 100644 index 00000000..05e42c43 --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.tmpl @@ -0,0 +1,6 @@ +plugin(plugin_name){ + code = code_name + template = template_file_name + show_stderr = False % show stderr + show_stdout = False % show stdout +} diff --git a/src/watts_ui/etc/templates/plugin.transfer_params.tmpl b/src/watts_ui/etc/templates/plugin.transfer_params.tmpl new file mode 100644 index 00000000..1cb98e88 --- /dev/null +++ b/src/watts_ui/etc/templates/plugin.transfer_params.tmpl @@ -0,0 +1 @@ +transfer_params = ["transfer_params_1" "transfer_params_2" "transfer_params_3"] \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugin_id.tmpl b/src/watts_ui/etc/templates/plugin_id.tmpl new file mode 100644 index 00000000..9e67cc44 --- /dev/null +++ b/src/watts_ui/etc/templates/plugin_id.tmpl @@ -0,0 +1 @@ +plugin = plugin_name % Name of plugin \ No newline at end of file diff --git a/src/watts_ui/etc/templates/plugins.tmpl b/src/watts_ui/etc/templates/plugins.tmpl new file mode 100644 index 00000000..45b1b2b8 --- /dev/null +++ b/src/watts_ui/etc/templates/plugins.tmpl @@ -0,0 +1,8 @@ +plugins{ + plugin(plugin_name){ + code = code_name % Name of application + template = template_file_name % Name of template file + show_stderr = False % show stderr + show_stdout = False % show stdout + } +} diff --git a/src/watts_ui/etc/templates/variables.tmpl b/src/watts_ui/etc/templates/variables.tmpl new file mode 100644 index 00000000..df9a8005 --- /dev/null +++ b/src/watts_ui/etc/templates/variables.tmpl @@ -0,0 +1,6 @@ +variables{ + param( id ){value = 0 unit = m} % Param as a value (unit is optional) + param( id ){func = 'a + b' } % Param as a function (must include space between components and operators) + param( id ){list = [ 0 ] } % Param as a list (floats or strings are accepted) + param( id ){bool = True} % Param as a bool +} \ No newline at end of file diff --git a/src/watts_ui/etc/templates/watts.tmpl b/src/watts_ui/etc/templates/watts.tmpl new file mode 100644 index 00000000..30a4b9a4 --- /dev/null +++ b/src/watts_ui/etc/templates/watts.tmpl @@ -0,0 +1,8 @@ +watts{ + plugins{ + % define plugins + } + workflow_level1{ + % define workflows + } +} diff --git a/src/watts_ui/etc/templates/wf_plugin.tmpl b/src/watts_ui/etc/templates/wf_plugin.tmpl new file mode 100644 index 00000000..e2644eb6 --- /dev/null +++ b/src/watts_ui/etc/templates/wf_plugin.tmpl @@ -0,0 +1 @@ +plugin = plugin_name \ No newline at end of file diff --git a/src/watts_ui/etc/templates/workflow.tmpl b/src/watts_ui/etc/templates/workflow.tmpl new file mode 100644 index 00000000..42a789e7 --- /dev/null +++ b/src/watts_ui/etc/templates/workflow.tmpl @@ -0,0 +1,7 @@ +plugin = plugin_name % Name of plugin +variables{ + param( id ){value = 0 unit= m} % Param as a value (unit is optional) + param( id ){func = 'a + b' } % Param as a function (must include space between compenents and operators) + param( id ){list = [ 0 ] } % Param as a list (floats or strings are accepted) + param( id ){bool = True} % Param as a bool +} diff --git a/src/watts_ui/etc/templates/workflow_level1.tmpl b/src/watts_ui/etc/templates/workflow_level1.tmpl new file mode 100644 index 00000000..8f995038 --- /dev/null +++ b/src/watts_ui/etc/templates/workflow_level1.tmpl @@ -0,0 +1,9 @@ +workflow_level1{ + plugin = plugin_name % Name of plugin + variables{ + param( id ){value = 0 unit= m} % Param as a value (unit is optional) + param( id ){func = 'a + b' } % Param as a function (must include space between components and operators) + param( id ){list = [ 0 ] } % Param as a list (floats or strings are accepted) + param( id ){bool = True} % Param as a bool + } +} diff --git a/src/watts_ui/etc/watts.py b/src/watts_ui/etc/watts.py new file mode 100644 index 00000000..7c9934dc --- /dev/null +++ b/src/watts_ui/etc/watts.py @@ -0,0 +1,90 @@ +#!/usr/bin/python +"""watts runtime environment""" + +# standard imports +import os +import sys + +# super import +import workbench + +class wattsRuntimeEnvironment(workbench.WorkbenchRuntimeEnvironment): + """watts-specific runtime environment""" + def __init__(self): + """constructor""" + + # call super class constructor + super(wattsRuntimeEnvironment, self).__init__() + + def update_and_print_grammar(self, grammar_path): + if self.executable == None: + import argparse + # if the -grammar flag appears earlier in the arg list than the -e, it won't have been set + # so, we must parse the argv for that case + parser_for_grammar = argparse.ArgumentParser() + parser_for_grammar.add_argument("-e", type=str) + known, unknown = parser_for_grammar.parse_known_args(sys.argv) + self.executable = known.e + + if self.executable == None: + sys.stderr.write("***Error: The -grammar option requires -e argument!\n") + sys.exit(1) + + watts_bin_dir = os.path.dirname(self.executable) + watts_dir = watts_bin_dir + + watts_grammar_path = watts_dir+"/etc/watts.wbg" + + watts_grammar_mtime = os.path.getmtime(watts_grammar_path) + try: + workbench_grammar_mtime = os.path.getmtime(grammar_path) + except OSError: + # indicate grammar file is 'way old' + # which will indicate it needs to be updated + workbench_grammar_mtime = 0 + + # Update Workbench's grammar status file + if watts_grammar_mtime > workbench_grammar_mtime: + watts_grammar_name = os.path.basename(grammar_path).replace(".wbg","") + with open(grammar_path,"w") as workbench_grammar_file: + workbench_grammar_file.write("name='{0}' redirect='{1}'".format(watts_grammar_name, watts_grammar_path)) + print (grammar_path) + + + return + def app_name(self): + """returns the app's self-designated name""" + return "watts" + + def app_options(self): + """list of app-specific options""" + opts = [] + + # TODO add application unique arguments + return opts + + def prerun(self, options): + """actions to perform before the run starts""" + # override values + options.working_directory = os.path.dirname(options.input) + + # build argument list + options.input = options.input.replace(options.working_directory + "/", "") + + # call default implementation + super(wattsRuntimeEnvironment, self).prerun(options) + + # override the working directory removal - dont do it + self.cleanup = False + + def run_args(self, options): + """returns a list of arguments to pass to the given executable""" + # build argument list + args = ["-i", options.input] + + # TODO add application unique arguments + return args + +if __name__ == "__main__": + # execute runtime, ignoring first argument (the python script itself) + wattsRuntimeEnvironment().execute(sys.argv[1:]) diff --git a/src/watts_ui/etc/watts.sch b/src/watts_ui/etc/watts.sch new file mode 100644 index 00000000..86a405b9 --- /dev/null +++ b/src/watts_ui/etc/watts.sch @@ -0,0 +1,358 @@ +ChildExactlyOne = [ watts ] +watts{ + Description = "[optional] for watts calculations" + MinOccurs = 0 + MaxOccurs = 1 + InputTmpl = "watts" + workflow_level1{ + Description = "[required] Workflow definition - first level" + InputTmpl="workflow_level1" + MinOccurs=1 + MaxOccurs=1 + + % ChildAtLeastOne = [plugin workflow_level2] % we need at least to do a plugin calc or define a sub-workflow + plugin{ + Description = "[Required] name of plugin" + InputTmpl="plugin_id" + MinOccurs=0 + MaxOccurs=NoLimit + ValType=String + ExistsIn = ["../../plugins/plugin/id"] + ChildUniqueness = [ "id"] + } + variables{ + Description = "[optional] Variables definition" + InputTmpl="variables" + MinOccurs=0 + MaxOccurs=1 + ChildUniqueness = [ "param/id"] + param{ + Description = "[optional] Parameter definition" + InputVariants=[ "value" "func" "list" "bool" ] + MinOccurs=1 + MaxOccurs=NoLimit + id{ + MinOccurs=1 + MaxOccurs=1 + ValType=String + } + value{ + Description = "[optional] reference value" + InputTmpl="flagtypes" + MinOccurs=0 + MaxOccurs=1 + } + unit{ + Description = "[optional] reference value" + ValType=String + InputTmpl="flagtypes" + InputDefault= codename + MinOccurs=0 + MaxOccurs=1 + } + bool{ + Description = "[optional] boolean" + InputTmpl="flagtypes" + MinOccurs=0 + MaxOccurs=1 + } + list{ + Description = "[optional] list of real or string" + InputTmpl="sonarray" + MinOccurs=0 + MaxOccurs=1 + value{ + MinOccurs=1 + MaxOccurs=NoLimit + } + } + func{ + Description = "[optional] operation" + InputTmpl="sonarray" + MinOccurs=0 + MaxOccurs=1 + value{ + MinOccurs=1 + MaxOccurs=NoLimit + ValType=String + } + } + } + } + iteration{ + Description = "[optional] definition of iterations workflow" + InputTmpl="iteration" + MinOccurs=0 + MaxOccurs=1 + plugin{ + Description = "[required] ID of the second plugin" + InputTmpl="sonobject" + MinOccurs=1 + MaxOccurs=1 + ValType=String + } + nmax{ + Description = "[required] Maximum number of iterations" + MinOccurs=1 + MaxOccurs=1 + ValType=Real + } + convergence_criteria{ + Description = "[required] Convergence criteria" + MinOccurs=1 + MaxOccurs=1 + ValType=Real + } + convergence_params{ + Description = "[required] Parameter to compare for convergence" + MinOccurs=1 + MaxOccurs=1 + ValType=String + } + to_sub_params{ + Description = "[required] Parameter(s) to send from plugin_1 to plugin_2" + MinOccurs=1 + MaxOccurs=1 + value{ + MinOccurs=0 + MaxOccurs=NoLimit + } + } + to_main_params{ + Description = "[required] Parameter(s) to send from plugin_2 to plugin_1" + MinOccurs=1 + MaxOccurs=1 + value{ + MinOccurs=0 + MaxOccurs=NoLimit + } + } + } + parametric{ + Description = "[optional] definition of parametric workflow" + InputTmpl="parametric" + MinOccurs=0 + MaxOccurs=1 + changing_params{ + Description = "[required] the parameter to perform parametric study" + MinOccurs=1 + MaxOccurs=1 + ValType=String + } + changing_values{ + Description = "[required] values for parametric study" + MinOccurs=1 + MaxOccurs=1 + value{ + MinOccurs=1 + MaxOccurs=NoLimit + } + } + } + % optimization{ + % Description = "[optional] definition of optimization workflow" + % InputTmpl="sonobject" + % MinOccurs=0 + % MaxOccurs=1 + % objective_functions{ + % Description = "[required] the parameter to optimize" + % MinOccurs=1 + % MaxOccurs=1 + % ValType=String + % } + % method{ + % Description = "[required] optimization parameter" + % MinOccurs=1 + % MaxOccurs=1 + % ValType=String + % } + % tolerance{ + % Description = "[required] convergence criteria" + % MinOccurs=1 + % MaxOccurs=1 + % ValType=Real + % } + % } + % workflow_level2{ + % Description = "[optional] Workflow definition - second level" + % InputTmpl="sonobject" + % MinOccurs=0 + % MaxOccurs=NoLimit + % } + % postprocessors{ + % Description = "[optional] postprocessor " + % InputTmpl="sonobject" + % MinOccurs=0 + % MaxOccurs=NoLimit + % ChildUniqueness = ["id"] + % value{ + % Description = "[required] operation of the postprocessor" + % MinOccurs=1 + % MaxOccurs=1 + % ValType=String + % } + % id{ + % Description = "[required] ID of postprocessor" + % MinOccurs=1 + % MaxOccurs=1 + % ValType=String + % } + % } + } + plugins{ + Description = "[required] Plugins definition" + InputTmpl="plugins" + MinOccurs=1 + MaxOccurs=1 + ChildUniqueness = ["plugin/id"] + + plugin{ + Description = "[required] Plugins definition" + InputTmpl="plugin" + MinOccurs=1 + MaxOccurs=NoLimit + id{ + MinOccurs=0 + MaxOccurs=1 + ValType=String + } + code{ + Description = "[Required] All - Name of application" + MaxOccurs=1 + MinOccurs=1 + ValType=String + InputTmpl="flagtypes" + InputDefault= codename + ValEnums=[PyARC OpenMC SERPENT ABCE MCNP MOOSE SAS Dakota Serpent RELAP5] + } + template{ + Description = "[Required] All - Name of template file" + MaxOccurs=1 + MinOccurs=1 + ValType=String + InputDefault= "path-to-template" + } + exec_dir{ + Description = "[optional] All - Path to executable directory" + MinOccurs=0 + MaxOccurs=1 + ValType=String + InputTmpl="plugin.exec_dir" + } + exec_name{ + Description = "[optional] All - Name of executable" + MinOccurs=0 + MaxOccurs=1 + ValType=String + InputTmpl="plugin.exec_name" + } + executable{ + Description = "[optional] All - Path to executable" + MinOccurs=0 + MaxOccurs=1 + ValType=String + InputTmpl="plugin.executable" + } + extra_inputs{ + Description = "[optional] All - List of extra (non-templated) input files that are needed" + InputTmpl="plugin.extra_inputs" + MinOccurs=0 + MaxOccurs=1 + value{ + MinOccurs=0 + MaxOccurs=NoLimit + } + } + extra_template_inputs{ + Description = "[optional] All - List of extra templated input files that are needed" + MinOccurs=0 + MaxOccurs=1 + InputTmpl="plugin.extra_template_inputs" + value{ + MinOccurs=0 + MaxOccurs=NoLimit + } + } + extra_args{ + Description = "[optional] All - List of extra arguments" + InputTmpl="plugin.extra_args" + MinOccurs=0 + MaxOccurs=1 + value{ + MinOccurs=0 + MaxOccurs=NoLimit + } + } + transfer_params{ + Description = "[optional] All - List of parameters to transfer between runs" + InputTmpl="plugin.transfer_params" + MinOccurs=0 + MaxOccurs=1 + value{ + MinOccurs=0 + MaxOccurs=NoLimit + } + } + scores{ + Description = "[optional] OpenMC - List of scores for OpenMC tallies" + MinOccurs=0 + MaxOccurs=1 + InputTmpl="plugin.scores" + value{ + MinOccurs=0 + MaxOccurs=NoLimit + } + } + score_names{ + Description = "[optional] OpenMC - List of representative names for scores" + MinOccurs=0 + MaxOccurs=1 + InputTmpl="plugin.score_names" + value{ + MinOccurs=0 + MaxOccurs=NoLimit + } + } + show_stderr{ + Description = "[optional] All - Bool to print stderr" + MinOccurs=0 + MaxOccurs=1 + ValType=String + } + show_stdout{ + Description = "[optional] All - Bool to print stdout" + MinOccurs=0 + MaxOccurs=1 + ValType=String + } + plotfl_to_csv{ + Description = "[optional] RELAP5 - Bool to convert PLOTFL to CSV" + MinOccurs=0 + MaxOccurs=1 + ValType=String + InputTmpl="plugin.plotfl_to_csv" + } + conv_channel{ + Description = "[optional] SAS - Path to CHANNELtoCSV.x" + MinOccurs=0 + MaxOccurs=1 + ValType=String + InputTmpl="plugin.conv_channel" + } + conv_primar4{ + Description = "[optional] SAS - Path to PRIMAR4toCSV.x" + MinOccurs=0 + MaxOccurs=1 + ValType=String + InputTmpl="plugin.conv_primar4" + } + auto_link_files{ + Description = "[optional] Dakota - List of auto link files" + MinOccurs=0 + MaxOccurs=1 + ValType=String + InputTmpl="plugin.auto_link_files" + } + } + } +} diff --git a/src/watts_ui/etc/watts.wbg b/src/watts_ui/etc/watts.wbg new file mode 100644 index 00000000..56cd8d2d --- /dev/null +++ b/src/watts_ui/etc/watts.wbg @@ -0,0 +1,11 @@ +commentDelimiter = "%" +enabled = true +extensions = [son] +highlighter = "watts.wbh" +maxDepth = 4 +name = watts +nav = watts % indicates navigation logic for watts documents +parser = waspson +schema = "watts.sch" +templates = "templates" +validator = wasp diff --git a/src/watts_ui/etc/watts.wbh b/src/watts_ui/etc/watts.wbh new file mode 100644 index 00000000..6ac7d279 --- /dev/null +++ b/src/watts_ui/etc/watts.wbh @@ -0,0 +1,70 @@ +rule("Comment") { + foreground { + red = 0 + green = 128 + blue = 0 + } + italic = true + pattern = "(^'|%|//).*" +} +rule("Double-quoted string") { + foreground { + red = 128 + green = 0 + blue = 0 + } + pattern = '"[^"]*"' +} +rule("Single-quoted string") { + foreground { + red = 128 + green = 0 + blue = 0 + } + pattern = "'[^']*'" +} +rule("Sequence") { + bold = true + foreground { + red = 0 + green = 0 + blue = 0 + } + pattern = "^(=\S+|end\s*$)" +} +%rule("Keyword") { +% bold = true +% foreground { +% red = 0 +% green = 0 +% blue = 128 +% } +% pattern = "\s*((read|end)\s+\S+|end\s*$)" +%} +rule("Number") { + bold = true + foreground { + red = 128 + green = 0 + blue = 0 + } + pattern = "\b[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?\b" +} +rule("Keyword") { + bold = true + foreground { + red = 0 + green = 0 + blue = 128 + } + pattern = "\([^)]+\)" +} +rule("List Elements") { + bold = true + foreground { + red = 0 + green = 128 + blue = 128 + } + pattern = "\[[^]]+\]" +} diff --git a/src/watts_ui/watts_ui.py b/src/watts_ui/watts_ui.py new file mode 100755 index 00000000..2da2ba18 --- /dev/null +++ b/src/watts_ui/watts_ui.py @@ -0,0 +1,621 @@ + +import getopt +import os +from pathlib import Path +import subprocess +import sys +from typing import List, Optional +import warnings + +from astropy.units import Quantity +import numpy as np +import watts +from wasppy import xml2obj + + +def load_obj(input_path, watts_path): + """Converts son file to xml stream and create python data structure + + Parameters + ---------- + input_path + Path + watts_path + Path to Watts + + Returns + ------- + xlm stream + + """ + sonvalidxml = watts_path + "/bin/sonvalidxml" + schema = watts_path + "/etc/watts.sch" + cmd = ' '.join([sonvalidxml, schema, input_path]) + xmlresult = subprocess.check_output(cmd, shell=True) + # obtain pieces of input by name for convenience + return xml2obj.xml2obj(xmlresult) + + +def create_plugins(plugins): + """Create a dictionary to store plugins + + Parameters + ---------- + plugins + User input plugins + + Returns + ------- + watts_plugins + Watts plugins for storing user input plugins info + + """ + watts_plugins = {} + for it, plg in enumerate(watts_wb.plugins.plugin): + nested_plugins = {} + + # Initialize + nested_plugins['exec_dir'] = None + nested_plugins['exec_name'] = None + nested_plugins['executable'] = None + nested_plugins['extra_inputs'] = None + nested_plugins['extra_template_inputs'] = None + nested_plugins['show_stderr'] = False + nested_plugins['show_stdout'] = False + nested_plugins['plotfl_to_csv'] = False + nested_plugins['transfer_params'] = None + + # Save string plugin inputs + nested_plugins['code'] = str(plg.code.value).strip('\"') + nested_plugins['template'] = str(plg.template.value).strip('\"') + if plg.exec_dir is not None: + nested_plugins['exec_dir'] = str(plg.exec_dir.value).strip('\"') + if plg.exec_name is not None: + nested_plugins['exec_name'] = str(plg.exec_name.value).strip('\"') + if plg.executable is not None: + nested_plugins['executable'] = str( + plg.executable.value).strip('\"') + if plg.auto_link_files is not None: + nested_plugins['auto_link_files'] = str( + plg.auto_link_files.value).strip('\"') + if plg.conv_channel is not None: + nested_plugins['conv_channel'] = str( + plg.conv_channel.value).strip('\"') + if plg.conv_primar4 is not None: + nested_plugins['conv_primar4'] = str( + plg.conv_primar4.value).strip('\"') + + # Save list plugin inputs + if plg.extra_inputs is not None: + nested_plugins['extra_inputs'] = convert_to_list(plg.extra_inputs) + if plg.extra_template_inputs is not None: + nested_plugins['extra_template_inputs'] = convert_to_list( + plg.extra_template_inputs) + if plg.scores is not None: + nested_plugins['scores'] = convert_to_list(plg.scores) + if plg.score_names is not None: + nested_plugins['score_names'] = convert_to_list(plg.score_names) + if plg.extra_args is not None: + nested_plugins['extra_args'] = convert_to_list(plg.extra_args) + if plg.transfer_params is not None: + nested_plugins['transfer_params'] = convert_to_list( + plg.transfer_params) + + # Save bool plugin inputs + if plg.show_stderr is not None and str(plg.show_stderr.value).capitalize() == 'True': + nested_plugins['show_stderr'] = True + if plg.show_stdout is not None and str(plg.show_stdout.value).capitalize() == 'True': + nested_plugins['show_stdout'] = True + if plg.plotfl_to_csv is not None and str(plg.plotfl_to_csv.value).capitalize() == 'True': + nested_plugins['plotfl_to_csv'] = True + + watts_plugins[str(plg.id)] = nested_plugins + + return watts_plugins + + +def create_watts_params(variables): + """Creates a dictionary for input parameters + + Parameters + ---------- + variables + User input variables + + Returns + ------- + params + Watts params for storing user input variables + + """ + params = watts.Parameters() + params_id = [] + for it, param in enumerate(variables): + param_id = str(param.id).strip('\"') + if param.value is not None: + if isfloat(str(param.value.value)): + if param.unit is not None: + params[param_id] = Quantity( + float(str(param.value.value)), str(param.unit.value)) + else: + params[param_id] = float(str(param.value.value)) + else: + params[param_id] = str(param.value.value) + elif param.list is not None: + params[param_id] = convert_to_list(param.list) + elif param.func is not None: + func = '' + input_func = str(param.func.value).strip('\"').split() + for n, val in enumerate(input_func): + string = str(input_func[n]) + if string in params_id: + func += str(params[string]) + else: + func += string + params[param_id] = eval(func) + elif param.bool is not None: + bool_str = str(param.bool.value).strip('\"') + if bool_str.upper() == "TRUE": + params[param_id] = True + else: + params[param_id] = False + + params_id.append(str(param.id)) + + return (params) + + +def convert_to_list(wb_list): + """Convert a Workbench list to Python list + + Parameters + ---------- + wb_list + Workbench list to convert + + Returns + ------- + convert_list + Converted Python list + + """ + convert_list = [] + for n, val in enumerate(wb_list.value): + string = str(wb_list.value[n]).strip('\"') + if isfloat(string): + convert_list.append(float(string)) + else: + convert_list.append(string) + return (convert_list) + + +def get_last_value(watts_params, name_list: Optional[List[str]] = None): + """Extract the value of the last index from the + results created by WATTS plugins for transfer between plugins + + Parameters + ---------- + watts_params + WATTS params + name_list + List of name of params to extract values + + Returns + ------- + watts_params + Updated WATTS params + + """ + for param_name in name_list: + if isinstance(watts_params[param_name], (list, np.ndarray)): + watts_params[param_name] = watts_params[param_name][-1] + return (watts_params) + + +def isfloat(num): + """Check whether entries of a list are numeric + + Parameters + ---------- + num + Entry of list + + Returns + ------- + True + If entry is numeric + + """ + try: + float(num) + return True + except ValueError: + return False + + +def run_workflow(watts_params, wf_level, watts_plugins): + """Run workflow + + Parameters + ---------- + watts_params + Watts params with stored user input parameters + wf_level + Level of workflow + plugin + Dictionary of plugin + + Returns + ------- + app_result + WATTS results + + """ + if wf_level.iteration is not None: + watts_params, app_result_plugin_1, app_result_plugin_2 = run_iterate( + watts_params, watts_plugins, wf_level) + + # Combine the results from plugins 1 and 2 into a dictionary + app_result = {'app_result_plugin_1': app_result_plugin_1, + 'app_result_plugin_2': app_result_plugin_1} + + return (app_result, watts_params) + + elif wf_level.parametric is not None: + plugin_ID = 'ID1' + watts_params, app_result = run_parametric( + watts_params, watts_plugins[plugin_ID], wf_level) + + return (app_result, watts_params) + + elif wf_level.optimization is not None: + operation = wf_level.optimization + ... + else: + for n_plugin, plugin in enumerate(wf_level.plugin): + plugin_ID = str(plugin.value) + current_plugin = watts_plugins[plugin_ID] + + print("AAAAA") + print(current_plugin['template']) + + watts_params, app_result = run_direct( + watts_params, current_plugin) + if current_plugin['transfer_params'] is not None: + watts_params = get_last_value( + watts_params, current_plugin['transfer_params']) + + return (app_result, watts_params) + + +def run_direct(watts_params, plugin): + """Run workflow + + Parameters + ---------- + watts_params + Watts params with stored user input parameters + plugin + Dictionary of plugin + + Returns + ------- + watts_params + Updated WATTS parameters + app_result + WATTS results + + """ + + # Provide the environment variable that is the path + # to the directory of the application. If environment + # variable is not set, provide the path to the directory + # instead. + + if plugin['exec_dir'] is not None: + if plugin['exec_name'] is not None: + if plugin['exec_dir'] in os.environ: + exec = Path(os.environ[plugin['exec_dir']] + ) / plugin['exec_name'] + else: + raise RuntimeError( + f"{plugin['exec_dir']} does not exist in environment.") + else: + raise RuntimeError( + "Please specify executable name of the application.") + elif (plugin['executable'] is not None): + exec = plugin['executable'] + + if plugin['code'].upper() == 'MOOSE': + + app_plugin = watts.PluginMOOSE( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + + elif plugin['code'].upper() == 'PYARC': + app_plugin = watts.PluginPyARC( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + + elif plugin['code'].upper() == 'RELAP5': + app_plugin = watts.PluginRELAP5( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + plotfl_to_csv=plugin['plotfl_to_csv'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + + elif plugin['code'].upper() == 'SAS': + app_plugin = watts.PluginSAS( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + + if 'conv_channel' in plugin: + app_plugin.conv_channel = Path(plugin['conv_channel']) + if 'conv_primar4' in plugin: + app_plugin.conv_primar4 = Path(plugin['conv_primar4']) + + elif plugin['code'].upper() == 'SERPENT': + app_plugin = watts.PluginSerpent( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + + elif plugin['code'].upper() == 'DAKOTA': + app_plugin = watts.PluginDakota( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + auto_link_files=plugin['auto_link_files'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + + elif plugin['code'].upper() == 'ABCE': + app_plugin = watts.PluginABCE( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + + elif plugin['code'].upper() == 'MCNP': + app_plugin = watts.PluginMCNP( + template_file=plugin['template'], + executable=exec, + extra_inputs=plugin['extra_inputs'], + extra_template_inputs=plugin['extra_template_inputs'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) + + elif plugin['code'].upper() == 'OPENMC': + sys.path.insert(0, os.getcwd()) + import openmc + from openmc_template import build_openmc_model + + app_plugin = watts.PluginOpenMC( + model_builder=build_openmc_model, + extra_inputs=plugin['extra_inputs'], + show_stdout=plugin['show_stdout'], + show_stderr=plugin['show_stderr']) # show only error + + else: + raise RuntimeError("Please provide the correct application name.") + + # Set 'extra_args' if available + if 'extra_args' in plugin: + app_plugin(watts_params, extra_args=plugin['extra_args']) + + # Run plugins and save to app_result + app_result = app_plugin(watts_params) + + # Store output data from app_result to watts_params + # Special treatment for OpenMC + if plugin['code'].upper() == 'OPENMC': + # Save keff results + if hasattr(app_result, 'keff'): + watts_params['keff'] = app_result.keff + + # Save tally results + if 'scores' in plugin: + for n_score, score in enumerate(plugin['scores']): + tallies = app_result.tallies[0].get_values( + scores=[score]).ravel() + for i, result in enumerate(tallies): + if 'score_names' in plugin: + watts_params[f"{plugin['score_names'][n_score]}_{i}"] = result + else: + watts_params[f"{score}_{i}"] = result + else: + if hasattr(app_result, 'csv_data'): + for key in app_result.csv_data: + watts_params[key] = app_result.csv_data[key] + elif hasattr(app_result, 'output_data'): + for key in app_result.output_data: + watts_params[key] = app_result.output_data[key] + elif hasattr(app_result, 'results_data'): + for key in app_result.results_data: + watts_params[key] = app_result.results_data[key] + else: + warnings.warn( + "Results class has no attribute 'csv_data', 'output_data', or 'results_data'. Output results are not saved to WATTS params.") + + return (watts_params, app_result) + + +def run_iterate(watts_params, plugin, wf_level): + """Run workflow + + Parameters + ---------- + watts_params + Watts params with stored user input parameters + plugin + Dictionary of plugin + wf_level + Level of workflow + + Returns + ------- + watts_params + Updated WATTS parameters + app_result + WATTS results + + """ + operation = wf_level.iteration + plugin_1 = str(wf_level.plugin.value).strip('\"') + plugin_2 = str(operation.plugin.value).strip('\"') + nmax = float(str(operation.nmax.value)) + tolerance = float(str(operation.convergence_criteria.value)) + convergence_params = str(operation.convergence_params.value).strip('\"') + to_sub_params = convert_to_list(operation.to_sub_params) + to_main_params = convert_to_list(operation.to_main_params) + + convergence_list = [] + conv = True + while conv: + + # Run the main plugin + watts_params, app_result_plugin_1 = run_direct( + watts_params, watts_plugins[plugin_1]) + + # Extract the values of the last index of the iterating + # parameters. This step is necessary because the results + # created by WATTS plugins could be list or ndarray with + # multiple values (especially for MOOSE based app). + watts_params = get_last_value(watts_params, to_sub_params) + + # Run the sub plugin + watts_params, app_result_plugin_2 = run_direct( + watts_params, watts_plugins[plugin_2]) + + # Extract the values of the last index of the iterating + # parameters. This step is necessary because the results + # created by WATTS plugins could be list or ndarray with + # multiple values (especially for MOOSE based app). + watts_params = get_last_value(watts_params, to_main_params) + + convergence_list.append(watts_params[convergence_params]) + + if len(convergence_list) > 1 and ((convergence_list[-1] - convergence_list[-2])/convergence_list[-1]) < tolerance: + conv = False + if len(convergence_list) > nmax: + conv = False + + watts_params["convergence_list"] = convergence_list + + return (watts_params, app_result_plugin_1, app_result_plugin_2) + + +def run_parametric(watts_params, plugin, wf_level): + """Run workflow + + Parameters + ---------- + watts_params + Watts params with stored user input parameters + plugin + Dictionary of plugin + wf_level + Level of workflow + + Returns + ------- + watts_params + Updated WATTS parameters + app_result + WATTS results + + """ + operation = wf_level.parametric + parametric_name = str(operation.changing_params.value).strip('\"') + parametric_list = [] + app_result = {} + for n, val in enumerate(operation.changing_values.value): + watts_params[parametric_name] = float(str(val)) + parametric_list.append(float(str(val))) + + # watts_params, app_result_parametric = run_direct( + # watts_params, watts_plugins[plugin_ID]) + + for n_plugin, plugin in enumerate(wf_level.plugin): + plugin_ID = str(plugin.value) + current_plugin = watts_plugins[plugin_ID] + watts_params, app_result_parametric = run_direct( + watts_params, current_plugin) + if current_plugin['transfer_params'] is not None: + watts_params = get_last_value( + watts_params, current_plugin['transfer_params']) + + # Store the results from each individual run to + # the 'app_result' dictionary as individual tuple. + app_result[f"run_{n}"] = app_result_parametric + + watts_params[f"{parametric_name}_list"] = parametric_list + return (watts_params, app_result) + + +# Set watts_path +watts_path = os.path.join(os.path.dirname(__file__)) + +opts, args = getopt.getopt(sys.argv[1:], "hi:o:", ["ifile=", "ofile="]) + +for opt, arg in opts: + if opt == "-i": + input_path = os.getcwd() + "/" + str(arg) + +# Load Watts workbench +watts_wb = load_obj(input_path, watts_path).watts + +# Change the working directory to the directory where +# the extra input files are stored. This is necessary +# due to how WATTS copies extra input files to the +# temporary working directory. +os.chdir(os.getcwd()) + +# Load plugins +if watts_wb.plugins is not None: + watts_plugins = create_plugins(watts_wb.plugins) + +# Start workflow +if watts_wb.workflow_level1 is not None: + + print("Executing Workflow Level 1") + + wf_level = watts_wb.workflow_level1 + + if wf_level.plugin is None: + raise RuntimeError( + "Please specify at least one plugin.") + + if wf_level.variables is not None: + variables = wf_level.variables.param + + # Create WATTS params to store user input variables + watts_params = create_watts_params(variables) + watts_params.show_summary(show_metadata=False, sort_by='key') + + # Run workflow + app_result, watts_params = run_workflow( + watts_params, wf_level, watts_plugins) + + watts_params.show_summary(show_metadata=False, sort_by='key')