LCOV - code coverage report
Current view: top level - src/actions - ChemicalCompositionAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose chemical_reactions: #32971 (54bef8) with base c6cf66 Lines: 301 311 96.8 %
Date: 2026-05-29 20:35:47 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "ChemicalCompositionAction.h"
      11             : #include "ThermochimicaUtils.h"
      12             : #include "FEProblemBase.h"
      13             : #include "MooseMesh.h"
      14             : #include "MooseUtils.h"
      15             : #include "AddVariableAction.h"
      16             : #include "libmesh/string_to_enum.h"
      17             : #include "BlockRestrictable.h"
      18             : #include "InputParameterWarehouse.h"
      19             : 
      20             : #ifdef THERMOCHIMICA_ENABLED
      21             : #include "Thermochimica-cxx.h"
      22             : #include "checkUnits.h"
      23             : #endif
      24             : 
      25             : registerMooseAction("ChemicalReactionsApp", ChemicalCompositionAction, "add_variable");
      26             : registerMooseAction("ChemicalReactionsApp", ChemicalCompositionAction, "add_aux_variable");
      27             : registerMooseAction("ChemicalReactionsApp", ChemicalCompositionAction, "add_ic");
      28             : registerMooseAction("ChemicalReactionsApp", ChemicalCompositionAction, "add_user_object");
      29             : registerMooseAction("ChemicalReactionsApp", ChemicalCompositionAction, "add_aux_kernel");
      30             : 
      31             : InputParameters
      32         261 : ChemicalCompositionAction::validParams()
      33             : {
      34         261 :   InputParameters params = Action::validParams();
      35         261 :   params += BlockRestrictable::validParams();
      36             : 
      37         261 :   ThermochimicaUtils::addClassDescription(params,
      38             :                                           "Sets up the thermodynamic model and variables for the "
      39             :                                           "thermochemistry solve using Thermochimica.");
      40             : 
      41             :   // Required variables
      42        1044 :   params.addParam<std::vector<std::string>>(
      43             :       "elements", {"ALL"}, "List of chemical elements (or ALL)");
      44         522 :   params.addCoupledVar("temperature", "Name of temperature variable");
      45         522 :   params.addCoupledVar("pressure", "Name of pressure variable");
      46         522 :   MooseEnum reinit_type("none time nodal", "nodal");
      47         522 :   params.addParam<MooseEnum>(
      48             :       "reinitialization_type", reinit_type, "Reinitialization scheme to use with Thermochimica");
      49         522 :   params.addParam<FileName>("initial_values", "The CSV file name with initial conditions.");
      50         522 :   params.addParam<FileName>("thermofile", "Thermodynamics model file");
      51             : 
      52         522 :   MooseEnum tUnit("K C F R");
      53         522 :   params.addParam<MooseEnum>("tunit", tUnit, "Temperature Unit");
      54         522 :   MooseEnum pUnit("atm psi bar Pa kPa");
      55         522 :   params.addParam<MooseEnum>("punit", pUnit, "Pressure Unit");
      56             :   MooseEnum mUnit(
      57         522 :       "mole_fraction atom_fraction atoms moles gram-atoms mass_fraction kilograms grams pounds");
      58         522 :   params.addParam<MooseEnum>("munit", mUnit, "Mass Unit");
      59         261 :   ExecFlagEnum exec_enum = MooseUtils::getDefaultExecFlagEnum();
      60        1044 :   exec_enum = {EXEC_INITIAL, EXEC_TIMESTEP_END};
      61         522 :   params.addParam<ExecFlagEnum>(
      62             :       "execute_on", exec_enum, "When to execute the ThermochimicaData UO");
      63         522 :   params.addParam<bool>("is_fv", false, "Should the variables set up by action be of FV type");
      64             : 
      65         522 :   params.addParam<std::vector<std::string>>("output_phases", {}, "List of phases to be output");
      66         522 :   params.addParam<std::vector<std::string>>(
      67             :       "output_species", {}, "List species for which concentration in the phases is needed");
      68         522 :   MooseEnum mUnit_op("moles mole_fraction");
      69         522 :   params.addParam<MooseEnum>(
      70             :       "output_species_unit", mUnit_op, "Mass unit for output species: mole_fractions or moles");
      71         522 :   params.addParam<std::vector<std::string>>(
      72             :       "output_element_potentials",
      73             :       {},
      74             :       "List of chemical elements for which chemical potentials are requested");
      75         522 :   params.addParam<std::vector<std::string>>(
      76             :       "output_vapor_pressures",
      77             :       {},
      78             :       "List of gas phase species for which vapor pressures are requested");
      79         522 :   params.addParam<std::vector<std::string>>(
      80             :       "output_element_phases",
      81             :       {},
      82             :       "List of elements whose molar amounts in specific phases are requested");
      83         522 :   params.addParam<std::string>(
      84             :       "uo_name", "Thermochimica", "Name of the ThermochimicaDataUserObject.");
      85         261 :   return params;
      86        1305 : }
      87             : 
      88         135 : ChemicalCompositionAction::ChemicalCompositionAction(const InputParameters & parameters)
      89         135 :   : Action(parameters)
      90             : {
      91         135 :   const auto & params = _app.getInputParameterWarehouse().getInputParameters();
      92         135 :   InputParameters & pars(*(params.find(uniqueActionName())->second.get()));
      93             : 
      94             :   // check if a container block with common parameters is found
      95         135 :   auto action = _awh.getActions<CommonChemicalCompositionAction>();
      96         135 :   if (action.size() == 1)
      97         135 :     pars.applyParameters(action[0]->parameters());
      98             : 
      99         270 :   if (!isParamValid("tunit"))
     100           2 :     paramError(
     101             :         "tunit",
     102             :         "The temperature unit must be specified for Thermochimica objects to be constructed");
     103             : 
     104         266 :   if (!isParamValid("punit"))
     105           2 :     paramError("punit",
     106             :                "The pressure unit must be specified for Thermochimica objects to be constructed");
     107             : 
     108         262 :   if (!isParamValid("munit"))
     109           2 :     paramError("munit",
     110             :                "The mass unit must be specified for Thermochimica objects to be constructed");
     111             : 
     112         258 :   if (!isParamValid("temperature"))
     113           0 :     paramError("temperature",
     114             :                "Temperature variable must be specified for this object to be constructed");
     115             : 
     116         516 :   if ((isParamValid("output_species") || isParamValid("output_element_phases")) &&
     117         387 :       !isParamValid("output_species_unit"))
     118           2 :     paramError(
     119             :         "output_species_unit",
     120             :         "Output mass unit must be specified for Thermochimica user object to be constructed");
     121             : 
     122         127 :   ThermochimicaUtils::checkLibraryAvailability(*this);
     123             : 
     124             : #ifdef THERMOCHIMICA_ENABLED
     125             :   // Initialize database in Thermochimica
     126         254 :   if (isParamValid("thermofile"))
     127             :   {
     128         254 :     const auto thermo_file = getParam<FileName>("thermofile");
     129             : 
     130         127 :     if (thermo_file.length() > 1024)
     131           0 :       paramError("thermofile",
     132             :                  "Path exceeds Thermochimica's maximal permissible length of 1024 with ",
     133             :                  thermo_file.length(),
     134             :                  " characters: ",
     135             :                  thermo_file);
     136             : 
     137         127 :     Thermochimica::setThermoFilename(thermo_file);
     138             : 
     139             :     // Read in thermodynamics model for setting up variables
     140         127 :     Thermochimica::parseThermoFile();
     141             : 
     142         127 :     const auto idbg = Thermochimica::checkInfoThermo();
     143         127 :     if (idbg != 0)
     144           2 :       paramError("thermofile", "Thermochimica data file cannot be parsed. ", idbg);
     145             :   }
     146             : 
     147             :   // Set thermochimica units
     148         250 :   auto tunit = Moose::stringify(getParam<MooseEnum>("tunit"));
     149         125 :   Thermochimica::checkTemperature(tunit);
     150         125 :   Thermochimica::setUnitTemperature(tunit);
     151         125 :   int idbg = Thermochimica::checkInfoThermo();
     152         125 :   if (idbg != 0)
     153           0 :     paramError("tunit", "Cannot set temperature unit in Thermochimica", idbg);
     154             : 
     155         250 :   auto punit = Moose::stringify(getParam<MooseEnum>("punit"));
     156         125 :   Thermochimica::checkPressure(punit);
     157         125 :   Thermochimica::setUnitPressure(punit);
     158         125 :   idbg = Thermochimica::checkInfoThermo();
     159         125 :   if (idbg != 0)
     160           0 :     paramError("punit", "Cannot set pressure unit in Thermochimica", idbg);
     161             : 
     162         375 :   auto munit = Moose::stringify(getParam<MooseEnum>("munit"));
     163             :   std::replace(munit.begin(), munit.end(), '_', ' ');
     164         125 :   Thermochimica::checkMass(munit);
     165         125 :   Thermochimica::setUnitMass(munit);
     166         125 :   idbg = Thermochimica::checkInfoThermo();
     167         125 :   if (idbg != 0)
     168           0 :     paramError("munit", "Cannot set mass unit in Thermochimica", idbg);
     169             : 
     170         375 :   _elements = getParam<std::vector<std::string>>("elements");
     171         125 :   if (_elements.size() == 1 && _elements[0] == "ALL")
     172             :   {
     173           9 :     _elements.resize(Thermochimica::getNumberElementsDatabase());
     174          18 :     _elements = Thermochimica::getElementsDatabase();
     175           9 :     mooseInfo("Thermochimica elements: 'ALL' specified in input file. Using: ",
     176          18 :               Moose::stringify(_elements));
     177             :   }
     178             :   else
     179             :   {
     180         116 :     std::vector<std::string> db_elements(Thermochimica::getNumberElementsDatabase());
     181         232 :     db_elements = Thermochimica::getElementsDatabase();
     182         389 :     for (const auto i : index_range(_elements))
     183         275 :       if (std::find(db_elements.begin(), db_elements.end(), _elements[i]) == db_elements.end())
     184           2 :         paramError("elements", "Element '", _elements[i], "' was not found in the database.");
     185         114 :   }
     186         123 :   _element_ids.resize(_elements.size());
     187         432 :   for (const auto i : index_range(_elements))
     188         309 :     _element_ids[i] = Thermochimica::atomicNumber(_elements[i]);
     189             : 
     190             :   // I want to check all the input parameters here and have a list of possible phases and species
     191             :   // for setting up the Aux variables with "ALL" option
     192             : 
     193             :   // Temporarily set Thermochimica state space to get the list of possible phases and species
     194         123 :   Thermochimica::setTemperaturePressure(1000.0, 1.0);
     195         123 :   Thermochimica::setElementMass(0, 0.0);
     196             : 
     197         432 :   for (const auto i : make_range(_elements.size()))
     198         309 :     Thermochimica::setElementMass(Thermochimica::atomicNumber(_elements[i]), 1.0);
     199             : 
     200         123 :   Thermochimica::setup();
     201             : 
     202         246 :   if (isParamValid("output_phases"))
     203             :   {
     204         369 :     _phases = getParam<std::vector<std::string>>("output_phases");
     205         123 :     if (_phases.size() == 1 && _phases[0] == "ALL")
     206             :     {
     207           9 :       auto [soln_phases, stoich_phases] = Thermochimica::getNumberPhasesSystem();
     208           9 :       _phases.resize(soln_phases + stoich_phases);
     209          18 :       _phases = Thermochimica::getPhaseNamesSystem();
     210           9 :       mooseInfo("ChemicalCompositionAction phases: 'ALL' specified in input file. Using: ",
     211          18 :                 Moose::stringify(_phases));
     212             :     }
     213             :     else
     214             :     {
     215         114 :       auto db_phases = Thermochimica::getPhaseNamesSystem();
     216         351 :       for (const auto i : index_range(_phases))
     217         239 :         if (std::find(db_phases.begin(), db_phases.end(), _phases[i]) == db_phases.end())
     218           2 :           paramError("output_phases", "Phase '", _phases[i], "' was not found in the simulation.");
     219         112 :     }
     220             :   }
     221             : 
     222         242 :   if (isParamValid("output_species"))
     223             :   {
     224         242 :     auto species = getParam<std::vector<std::string>>("output_species");
     225         121 :     auto db_phases = Thermochimica::getPhaseNamesSystem();
     226         121 :     auto n_db_species = Thermochimica::getNumberSpeciesSystem();
     227         121 :     auto db_species = Thermochimica::getSpeciesSystem();
     228        1084 :     for (auto i : index_range(n_db_species))
     229         963 :       if (Thermochimica::isPhaseMQM(i))
     230             :       {
     231             :         auto [pairs, quads, idbg] =
     232          27 :             Thermochimica::getMqmqaNumberPairsQuads(Thermochimica::getPhaseNamesSystem()[i]);
     233          27 :         n_db_species[i] = pairs;
     234             :       }
     235             : 
     236         121 :     if (species.size() == 1 && species[0] == "ALL")
     237             :     {
     238           9 :       if (!n_db_species.empty())
     239           9 :         species.resize(n_db_species.back());
     240             :       else
     241           0 :         mooseInfo("ChemicalCompositionAction species: 'ALL' specified in input file. Thermochimica "
     242             :                   "returned no possible species.");
     243             : 
     244           9 :       species.clear();
     245           9 :       _tokenized_species.clear();
     246          90 :       for (const auto i : make_range(db_species.size()))
     247         396 :         for (const auto j : index_range(db_species[i]))
     248             :         {
     249         630 :           species.push_back(db_phases[i] + ":" + db_species[i][j]);
     250         315 :           _tokenized_species.push_back(std::make_pair(db_phases[i], db_species[i][j]));
     251             :         }
     252           9 :       mooseInfo("ChemicalCompositionAction species: 'ALL' specified in input file. Using: ",
     253          18 :                 Moose::stringify(species));
     254             :     }
     255             :     else
     256         425 :       for (const auto i : index_range(species))
     257             :       {
     258         319 :         _tokenized_species.resize(species.size());
     259             :         std::vector<std::string> tokens;
     260         638 :         MooseUtils::tokenize(species[i], tokens, 1, ":");
     261         319 :         if (tokens.size() == 1)
     262           2 :           paramError("output_species", "No ':' separator found in variable '", species[i], "'");
     263             : 
     264         317 :         auto phase_index = std::find(db_phases.begin(), db_phases.end(), tokens[0]);
     265         317 :         if (phase_index == db_phases.end())
     266           2 :           paramError("output_species",
     267             :                      "Phase '",
     268             :                      tokens[0],
     269             :                      "' of output species '",
     270             :                      species[i],
     271             :                      "' not found in the simulation.");
     272         315 :         auto sp = db_species[std::distance(db_phases.begin(), phase_index)];
     273         315 :         if (std::find(sp.begin(), sp.end(), tokens[1]) == sp.end())
     274           2 :           paramError(
     275             :               "output_species", "Species '", tokens[1], "' was not found in the simulation.");
     276         313 :         _tokenized_species[i] = std::make_pair(tokens[0], tokens[1]);
     277         313 :       }
     278         115 :   }
     279             : 
     280         230 :   if (isParamValid("output_element_potentials"))
     281             :   {
     282         345 :     auto element_potentials = getParam<std::vector<std::string>>("output_element_potentials");
     283         115 :     if (element_potentials.size() == 1 && element_potentials[0] == "ALL")
     284             :     {
     285           9 :       _tokenized_element_potentials.resize(_elements.size());
     286           9 :       _tokenized_element_potentials = _elements;
     287           9 :       element_potentials.resize(_elements.size());
     288          45 :       for (const auto i : index_range(_elements))
     289          72 :         element_potentials[i] = "mu:" + _elements[i];
     290           9 :       mooseInfo(
     291             :           "ChemicalCompositionAction element potentials: 'ALL' specified in input file. Using: ",
     292          18 :           Moose::stringify(element_potentials));
     293             :     }
     294             :     else
     295             :     {
     296         106 :       _tokenized_element_potentials.resize(element_potentials.size());
     297         287 :       for (const auto i : index_range(element_potentials))
     298             :       {
     299             :         std::vector<std::string> tokens;
     300         370 :         MooseUtils::tokenize(element_potentials[i], tokens, 1, ":");
     301         185 :         if (tokens.size() == 1)
     302           2 :           paramError("output_element_potentials",
     303             :                      "No ':' separator found in variable '",
     304             :                      element_potentials[i],
     305             :                      "'");
     306         183 :         if (std::find(_elements.begin(), _elements.end(), tokens[1]) == _elements.end())
     307           2 :           paramError("output_element_potentials",
     308             :                      "Element '",
     309             :                      tokens[1],
     310             :                      "' was not found in the simulation.");
     311             :         _tokenized_element_potentials[i] = tokens[1];
     312         181 :       }
     313             :     }
     314         111 :   }
     315             : 
     316         222 :   if (isParamValid("output_vapor_pressures"))
     317             :   {
     318         222 :     auto vapor_pressures = getParam<std::vector<std::string>>("output_vapor_pressures");
     319         111 :     if (!Thermochimica::isPhaseGas(0))
     320           0 :       paramError("output_vapor_pressures",
     321             :                  "No gas phase found in the simulation. Cannot output vapor pressures.");
     322         111 :     if (vapor_pressures.size() == 1 && vapor_pressures[0] == "ALL")
     323             :     {
     324           9 :       vapor_pressures.resize(Thermochimica::getNumberSpeciesSystem()[0]);
     325           9 :       _tokenized_vapor_species.resize(Thermochimica::getNumberSpeciesSystem()[0]);
     326           9 :       auto db_gas_species = Thermochimica::getSpeciesInPhase(0);
     327           9 :       auto gas_name = Thermochimica::getPhaseNamesSystem()[0];
     328          54 :       for (const auto i : index_range(db_gas_species))
     329             :       {
     330          90 :         vapor_pressures[i] = "vp:" + gas_name + ':' + db_gas_species[i];
     331          90 :         _tokenized_vapor_species[i] = std::make_pair(gas_name, db_gas_species[i]);
     332             :       }
     333           9 :       mooseInfo("ChemicalCompositionAction vapor pressures: 'ALL' specified in input file. Using: ",
     334          18 :                 Moose::stringify(vapor_pressures));
     335           9 :     }
     336             :     else
     337             :     {
     338         102 :       auto db_gas_species = Thermochimica::getSpeciesInPhase(0);
     339         102 :       _tokenized_vapor_species.resize(vapor_pressures.size());
     340         180 :       for (const auto i : index_range(vapor_pressures))
     341             :       {
     342             :         std::vector<std::string> tokens;
     343         168 :         MooseUtils::tokenize(vapor_pressures[i], tokens, 1, ":");
     344          84 :         if (tokens.size() == 1)
     345           2 :           paramError("output_vapor_pressures",
     346             :                      "No ':' separator found in variable '",
     347             :                      vapor_pressures[i],
     348             :                      "'");
     349          82 :         if (tokens[1] != Thermochimica::getPhaseNamesSystem()[0])
     350           2 :           paramError("output_vapor_pressures",
     351             :                      "Phase '",
     352             :                      tokens[1],
     353             :                      "' of vapor species '",
     354             :                      vapor_pressures[i],
     355             :                      "' is not a gas phase. Cannot calculate vapor pressure.");
     356          80 :         if (std::find(db_gas_species.begin(), db_gas_species.end(), tokens[2]) ==
     357             :             db_gas_species.end())
     358           2 :           paramError("output_vapor_pressures",
     359             :                      "Species '",
     360             :                      tokens[2],
     361             :                      "' was not found in the gas phase of simulation.");
     362          78 :         _tokenized_vapor_species[i] = std::make_pair(tokens[1], tokens[2]);
     363          78 :       }
     364          96 :     }
     365         105 :   }
     366             : 
     367         210 :   if (isParamValid("output_element_phases"))
     368             :   {
     369         210 :     auto element_phases = getParam<std::vector<std::string>>("output_element_phases");
     370         105 :     auto db_phases = Thermochimica::getPhaseNamesSystem();
     371         105 :     if (element_phases.size() == 1 && element_phases[0] == "ALL")
     372             :     {
     373           9 :       element_phases.resize(_elements.size() * db_phases.size());
     374           9 :       _tokenized_phase_elements.resize(_elements.size() * db_phases.size());
     375         117 :       for (const auto i : index_range(db_phases))
     376         540 :         for (const auto j : index_range(_elements))
     377             :         {
     378         864 :           element_phases[i * _elements.size() + j] = db_phases[i] + ':' + _elements[j];
     379         432 :           _tokenized_phase_elements[i * _elements.size() + j] =
     380         864 :               std::make_pair(db_phases[i], _elements[j]);
     381             :         }
     382           9 :       mooseInfo(
     383             :           "ChemicalCompositionAction elements in phase: 'ALL' specified in input file. Using: ",
     384          18 :           Moose::stringify(element_phases));
     385             :     }
     386             :     else
     387             :     {
     388          96 :       _tokenized_phase_elements.resize(element_phases.size());
     389         150 :       for (const auto i : index_range(element_phases))
     390             :       {
     391             :         std::vector<std::string> tokens;
     392         120 :         MooseUtils::tokenize(element_phases[i], tokens, 1, ":");
     393          60 :         if (tokens.size() == 1)
     394           2 :           paramError("output_element_phases",
     395             :                      "No ':' separator found in variable '",
     396             :                      element_phases[i],
     397             :                      "'");
     398          58 :         if (std::find(db_phases.begin(), db_phases.end(), tokens[1]) == db_phases.end())
     399           2 :           paramError("output_element_phases",
     400             :                      "Phase '",
     401             :                      tokens[1],
     402             :                      "' of '",
     403             :                      element_phases[i],
     404             :                      "' not found in the simulation.");
     405          56 :         if (std::find(_elements.begin(), _elements.end(), tokens[2]) == _elements.end())
     406           2 :           paramError("output_element_phases",
     407             :                      "Element '",
     408             :                      tokens[2],
     409             :                      "' was not found in the simulation.");
     410          54 :         _tokenized_phase_elements[i] = std::make_pair(tokens[1], tokens[2]);
     411          54 :       }
     412             :     }
     413          99 :   }
     414             : 
     415          99 :   Thermochimica::resetThermoAll();
     416             : 
     417             : #endif
     418          99 : }
     419             : 
     420             : void
     421         495 : ChemicalCompositionAction::act()
     422             : {
     423             : #ifdef THERMOCHIMICA_ENABLED
     424             :   //
     425             :   // Add AuxVariables
     426             :   //
     427         495 :   if (_current_task == "add_aux_variable")
     428             :   {
     429             :     auto aux_var_type = AddVariableAction::variableType(
     430         297 :         FEType(Utility::string_to_enum<Order>(_problem->mesh().hasSecondOrderElements() ? "SECOND"
     431             :                                                                                         : "FIRST"),
     432             :                Utility::string_to_enum<libMesh::FEFamily>("LAGRANGE")),
     433          99 :         /* is_fv = */ getParam<bool>("is_fv"),
     434         198 :         /* is_array = */ false);
     435          99 :     auto params = _factory.getValidParams(aux_var_type);
     436          99 :     params.applySpecificParameters(parameters(), {"block"});
     437             : 
     438         360 :     for (const auto i : index_range(_elements))
     439         261 :       _problem->addAuxVariable(aux_var_type, _elements[i], params);
     440             : 
     441         396 :     for (const auto i : index_range(_phases))
     442         297 :       _problem->addAuxVariable(aux_var_type, _phases[i], params);
     443             : 
     444         657 :     for (const auto i : index_range(_tokenized_species))
     445        1116 :       _problem->addAuxVariable(
     446        1116 :           aux_var_type, Moose::stringify(_tokenized_species[i], /* delim = */ ":"), params);
     447             : 
     448         288 :     for (const auto i : index_range(_tokenized_element_potentials))
     449         378 :       _problem->addAuxVariable(aux_var_type, "mu:" + _tokenized_element_potentials[i], params);
     450             : 
     451         216 :     for (const auto i : index_range(_tokenized_vapor_species))
     452         234 :       _problem->addAuxVariable(aux_var_type,
     453         117 :                                "vp:" +
     454         234 :                                    Moose::stringify(_tokenized_vapor_species[i], /* delim = */ ":"),
     455             :                                params);
     456             : 
     457         585 :     for (const auto i : index_range(_tokenized_phase_elements))
     458         972 :       _problem->addAuxVariable(
     459             :           aux_var_type,
     460         972 :           "ep:" + Moose::stringify(_tokenized_phase_elements[i], /* delim = */ ":"),
     461             :           params);
     462          99 :   }
     463             : 
     464             :   //
     465             :   // Set up initial conditions from a file
     466             :   //
     467         693 :   if (_current_task == "add_ic" && isParamValid("initial_values"))
     468             :   {
     469          18 :     readCSV();
     470          72 :     for (auto it : _initial_conditions)
     471             :     {
     472          54 :       const std::string class_name = "ConstantIC";
     473          54 :       auto params = _factory.getValidParams(class_name);
     474         108 :       params.set<VariableName>("variable") = it.first;
     475          54 :       params.set<Real>("value") = it.second;
     476          54 :       params.applySpecificParameters(parameters(), {"block"});
     477          54 :       _problem->addInitialCondition(class_name, it.first + "_ic", params);
     478          54 :     }
     479             :   }
     480             : 
     481             :   //
     482             :   // Set up user object
     483             :   //
     484         495 :   if (_current_task == "add_user_object")
     485             :   {
     486         198 :     std::string uo_name = getParam<std::string>("uo_name");
     487             : 
     488         234 :     if (isParamValid("block") && !isParamSetByUser("uo_name"))
     489          54 :       uo_name += "_" + Moose::stringify(getParam<std::vector<SubdomainName>>("block"));
     490             : 
     491             :     const auto uo_type =
     492         198 :         getParam<bool>("is_fv") ? "ThermochimicaElementData" : "ThermochimicaNodalData";
     493             : 
     494          99 :     auto uo_params = _factory.getValidParams(uo_type);
     495             : 
     496          99 :     std::copy(_elements.begin(),
     497             :               _elements.end(),
     498             :               std::back_inserter(uo_params.set<std::vector<VariableName>>("elements")));
     499             : 
     500         198 :     if (isParamValid("output_phases"))
     501         198 :       std::copy(_phases.begin(),
     502             :                 _phases.end(),
     503             :                 std::back_inserter(uo_params.set<std::vector<VariableName>>("output_phases")));
     504             : 
     505         198 :     if (isParamValid("output_species"))
     506             :     {
     507             :       std::vector<std::string> species;
     508         657 :       for (auto token : _tokenized_species)
     509        1116 :         species.push_back(Moose::stringify(token, ":"));
     510          99 :       uo_params.set<std::vector<VariableName>>("output_species")
     511         198 :           .insert(uo_params.set<std::vector<VariableName>>("output_species").end(),
     512             :                   species.begin(),
     513             :                   species.end());
     514          99 :     }
     515             : 
     516         198 :     if (isParamValid("output_element_potentials"))
     517             :     {
     518             :       std::vector<std::string> element_potentials;
     519         288 :       for (auto token : _tokenized_element_potentials)
     520         378 :         element_potentials.push_back("mu:" + token);
     521          99 :       uo_params.set<std::vector<VariableName>>("output_element_potentials")
     522         198 :           .insert(uo_params.set<std::vector<VariableName>>("output_element_potentials").end(),
     523             :                   element_potentials.begin(),
     524             :                   element_potentials.end());
     525          99 :     }
     526             : 
     527         198 :     if (isParamValid("output_vapor_pressures"))
     528             :     {
     529             :       std::vector<std::string> vapor_pressures;
     530         216 :       for (auto token : _tokenized_vapor_species)
     531         234 :         vapor_pressures.push_back("vp:" + Moose::stringify(token, ":"));
     532          99 :       uo_params.set<std::vector<VariableName>>("output_vapor_pressures")
     533         198 :           .insert(uo_params.set<std::vector<VariableName>>("output_vapor_pressures").end(),
     534             :                   vapor_pressures.begin(),
     535             :                   vapor_pressures.end());
     536          99 :     }
     537             : 
     538         198 :     if (isParamValid("output_element_phases"))
     539             :     {
     540             :       std::vector<std::string> element_phases;
     541         585 :       for (auto token : _tokenized_phase_elements)
     542         972 :         element_phases.push_back("ep:" + Moose::stringify(token, ":"));
     543          99 :       uo_params.set<std::vector<VariableName>>("output_element_phases")
     544         198 :           .insert(uo_params.set<std::vector<VariableName>>("output_element_phases").end(),
     545             :                   element_phases.begin(),
     546             :                   element_phases.end());
     547          99 :     }
     548         198 :     uo_params.set<std::vector<VariableName>>("temperature") =
     549         198 :         getParam<std::vector<VariableName>>("temperature");
     550             : 
     551          99 :     uo_params.set<ChemicalCompositionAction *>("_chemical_composition_action") = this;
     552             : 
     553         297 :     uo_params.set<FileName>("thermofile") = getParam<FileName>("thermofile");
     554             : 
     555         297 :     uo_params.set<MooseEnum>("reinit_type") = getParam<MooseEnum>("reinitialization_type");
     556             : 
     557         297 :     uo_params.set<MooseEnum>("output_species_unit") = getParam<MooseEnum>("output_species_unit");
     558             : 
     559          99 :     uo_params.applyParameters(parameters());
     560             : 
     561          99 :     _problem->addUserObject(uo_type, uo_name, uo_params);
     562          99 :   }
     563             : 
     564             : #endif
     565         495 : }
     566             : 
     567             : void
     568          18 : ChemicalCompositionAction::readCSV()
     569             : {
     570          36 :   const auto & filename = getParam<FileName>("initial_values");
     571          18 :   std::ifstream file(filename.c_str());
     572          18 :   if (!file.good())
     573           0 :     paramError("initial_values", "Error opening file '", filename, "'.");
     574             : 
     575             :   std::string line;
     576             :   std::vector<std::string> items;
     577             : 
     578             :   // skip header
     579          18 :   std::getline(file, line);
     580          72 :   while (std::getline(file, line))
     581             :   {
     582         108 :     MooseUtils::tokenize(line, items, 1, ",");
     583          54 :     if (items.empty())
     584           0 :       continue;
     585          54 :     if (items.size() != 2)
     586           0 :       paramError("initial_value", "Unexpected line in CSV file: ", line);
     587             : 
     588          54 :     _initial_conditions[items[0]] = MooseUtils::convert<Real>(items[1]);
     589             :   }
     590          36 : }

Generated by: LCOV version 1.14