LCOV - code coverage report
Current view: top level - src/actions - ChemicalCompositionAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose chemical_reactions: #31405 (292dce) with base fef103 Lines: 299 309 96.8 %
Date: 2025-09-04 07:52:33 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         471 : ChemicalCompositionAction::validParams()
      33             : {
      34         471 :   InputParameters params = Action::validParams();
      35         471 :   params += BlockRestrictable::validParams();
      36             : 
      37         471 :   ThermochimicaUtils::addClassDescription(params,
      38             :                                           "Sets up the thermodynamic model and variables for the "
      39             :                                           "thermochemistry solve using Thermochimica.");
      40             : 
      41             :   // Required variables
      42        1884 :   params.addParam<std::vector<std::string>>(
      43             :       "elements", {"ALL"}, "List of chemical elements (or ALL)");
      44         942 :   params.addCoupledVar("temperature", "Name of temperature variable");
      45         942 :   params.addCoupledVar("pressure", "Name of pressure variable");
      46         942 :   MooseEnum reinit_type("none time nodal", "nodal");
      47         942 :   params.addParam<MooseEnum>(
      48             :       "reinitialization_type", reinit_type, "Reinitialization scheme to use with Thermochimica");
      49         942 :   params.addParam<FileName>("initial_values", "The CSV file name with initial conditions.");
      50         942 :   params.addParam<FileName>("thermofile", "Thermodynamics model file");
      51             : 
      52         942 :   MooseEnum tUnit("K C F R");
      53         942 :   params.addParam<MooseEnum>("tunit", tUnit, "Temperature Unit");
      54         942 :   MooseEnum pUnit("atm psi bar Pa kPa");
      55         942 :   params.addParam<MooseEnum>("punit", pUnit, "Pressure Unit");
      56             :   MooseEnum mUnit(
      57         942 :       "mole_fraction atom_fraction atoms moles gram-atoms mass_fraction kilograms grams pounds");
      58         942 :   params.addParam<MooseEnum>("munit", mUnit, "Mass Unit");
      59         471 :   ExecFlagEnum exec_enum = MooseUtils::getDefaultExecFlagEnum();
      60        1884 :   exec_enum = {EXEC_INITIAL, EXEC_TIMESTEP_END};
      61         942 :   params.addParam<ExecFlagEnum>(
      62             :       "execute_on", exec_enum, "When to execute the ThermochimicaData UO");
      63         942 :   params.addParam<bool>("is_fv", false, "Should the variables set up by action be of FV type");
      64             : 
      65         942 :   params.addParam<std::vector<std::string>>("output_phases", {}, "List of phases to be output");
      66         942 :   params.addParam<std::vector<std::string>>(
      67             :       "output_species", {}, "List species for which concentration in the phases is needed");
      68         942 :   MooseEnum mUnit_op("moles mole_fraction");
      69         942 :   params.addParam<MooseEnum>(
      70             :       "output_species_unit", mUnit_op, "Mass unit for output species: mole_fractions or moles");
      71         942 :   params.addParam<std::vector<std::string>>(
      72             :       "output_element_potentials",
      73             :       {},
      74             :       "List of chemical elements for which chemical potentials are requested");
      75         942 :   params.addParam<std::vector<std::string>>(
      76             :       "output_vapor_pressures",
      77             :       {},
      78             :       "List of gas phase species for which vapor pressures are requested");
      79         942 :   params.addParam<std::vector<std::string>>(
      80             :       "output_element_phases",
      81             :       {},
      82             :       "List of elements whose molar amounts in specific phases are requested");
      83         942 :   params.addParam<std::string>(
      84             :       "uo_name", "Thermochimica", "Name of the ThermochimicaDataUserObject.");
      85         471 :   return params;
      86        2355 : }
      87             : 
      88         245 : ChemicalCompositionAction::ChemicalCompositionAction(const InputParameters & parameters)
      89         245 :   : Action(parameters)
      90             : {
      91         245 :   const auto & params = _app.getInputParameterWarehouse().getInputParameters();
      92         245 :   InputParameters & pars(*(params.find(uniqueActionName())->second.get()));
      93             : 
      94             :   // check if a container block with common parameters is found
      95         245 :   auto action = _awh.getActions<CommonChemicalCompositionAction>();
      96         245 :   if (action.size() == 1)
      97         245 :     pars.applyParameters(action[0]->parameters());
      98             : 
      99         490 :   if (!isParamValid("tunit"))
     100           2 :     paramError(
     101             :         "tunit",
     102             :         "The temperature unit must be specified for Thermochimica objects to be constructed");
     103             : 
     104         486 :   if (!isParamValid("punit"))
     105           2 :     paramError("punit",
     106             :                "The pressure unit must be specified for Thermochimica objects to be constructed");
     107             : 
     108         482 :   if (!isParamValid("munit"))
     109           2 :     paramError("munit",
     110             :                "The mass unit must be specified for Thermochimica objects to be constructed");
     111             : 
     112         478 :   if (!isParamValid("temperature"))
     113           0 :     paramError("temperature",
     114             :                "Temperature variable must be specified for this object to be constructed");
     115             : 
     116         956 :   if ((isParamValid("output_species") || isParamValid("output_element_phases")) &&
     117         717 :       !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         237 :   ThermochimicaUtils::checkLibraryAvailability(*this);
     123             : 
     124             : #ifdef THERMOCHIMICA_ENABLED
     125             :   // Initialize database in Thermochimica
     126         474 :   if (isParamValid("thermofile"))
     127             :   {
     128         474 :     const auto thermo_file = getParam<FileName>("thermofile");
     129             : 
     130         237 :     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         237 :     Thermochimica::setThermoFilename(thermo_file);
     138             : 
     139             :     // Read in thermodynamics model for setting up variables
     140         237 :     Thermochimica::parseThermoFile();
     141             : 
     142         237 :     const auto idbg = Thermochimica::checkInfoThermo();
     143         237 :     if (idbg != 0)
     144           2 :       paramError("thermofile", "Thermochimica data file cannot be parsed. ", idbg);
     145             :   }
     146             : 
     147             :   // Set thermochimica units
     148         470 :   auto tunit = Moose::stringify(getParam<MooseEnum>("tunit"));
     149         235 :   Thermochimica::checkTemperature(tunit);
     150         235 :   Thermochimica::setUnitTemperature(tunit);
     151         235 :   int idbg = Thermochimica::checkInfoThermo();
     152         235 :   if (idbg != 0)
     153           0 :     paramError("tunit", "Cannot set temperature unit in Thermochimica", idbg);
     154             : 
     155         470 :   auto punit = Moose::stringify(getParam<MooseEnum>("punit"));
     156         235 :   Thermochimica::checkPressure(punit);
     157         235 :   Thermochimica::setUnitPressure(punit);
     158         235 :   idbg = Thermochimica::checkInfoThermo();
     159         235 :   if (idbg != 0)
     160           0 :     paramError("punit", "Cannot set pressure unit in Thermochimica", idbg);
     161             : 
     162         705 :   auto munit = Moose::stringify(getParam<MooseEnum>("munit"));
     163             :   std::replace(munit.begin(), munit.end(), '_', ' ');
     164         235 :   Thermochimica::checkMass(munit);
     165         235 :   Thermochimica::setUnitMass(munit);
     166         235 :   idbg = Thermochimica::checkInfoThermo();
     167         235 :   if (idbg != 0)
     168           0 :     paramError("munit", "Cannot set mass unit in Thermochimica", idbg);
     169             : 
     170         705 :   _elements = getParam<std::vector<std::string>>("elements");
     171         235 :   if (_elements.size() == 1 && _elements[0] == "ALL")
     172             :   {
     173          19 :     _elements.resize(Thermochimica::getNumberElementsDatabase());
     174          38 :     _elements = Thermochimica::getElementsDatabase();
     175          19 :     mooseInfo("Thermochimica elements: 'ALL' specified in input file. Using: ",
     176          38 :               Moose::stringify(_elements));
     177             :   }
     178             :   else
     179             :   {
     180         216 :     std::vector<std::string> db_elements(Thermochimica::getNumberElementsDatabase());
     181         432 :     db_elements = Thermochimica::getElementsDatabase();
     182         739 :     for (const auto i : index_range(_elements))
     183         525 :       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         214 :   }
     186         233 :   _element_ids.resize(_elements.size());
     187         832 :   for (const auto i : index_range(_elements))
     188         599 :     _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         233 :   Thermochimica::setTemperaturePressure(1000.0, 1.0);
     195         233 :   Thermochimica::setElementMass(0, 0.0);
     196             : 
     197         832 :   for (const auto i : make_range(_elements.size()))
     198         599 :     Thermochimica::setElementMass(Thermochimica::atomicNumber(_elements[i]), 1.0);
     199             : 
     200         233 :   Thermochimica::setup();
     201             : 
     202         466 :   if (isParamValid("output_phases"))
     203             :   {
     204         699 :     _phases = getParam<std::vector<std::string>>("output_phases");
     205         233 :     if (_phases.size() == 1 && _phases[0] == "ALL")
     206             :     {
     207          19 :       auto [soln_phases, stoich_phases] = Thermochimica::getNumberPhasesSystem();
     208          19 :       _phases.resize(soln_phases + stoich_phases);
     209          38 :       _phases = Thermochimica::getPhaseNamesSystem();
     210          19 :       mooseInfo("ChemicalCompositionAction phases: 'ALL' specified in input file. Using: ",
     211          38 :                 Moose::stringify(_phases));
     212             :     }
     213             :     else
     214             :     {
     215         214 :       auto db_phases = Thermochimica::getPhaseNamesSystem();
     216         661 :       for (const auto i : index_range(_phases))
     217         449 :         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         212 :     }
     220             :   }
     221             : 
     222         462 :   if (isParamValid("output_species"))
     223             :   {
     224         462 :     auto species = getParam<std::vector<std::string>>("output_species");
     225         231 :     auto db_phases = Thermochimica::getPhaseNamesSystem();
     226         231 :     auto n_db_species = Thermochimica::getNumberSpeciesSystem();
     227         231 :     auto db_species = Thermochimica::getSpeciesSystem();
     228        2044 :     for (auto i : index_range(n_db_species))
     229        1813 :       if (Thermochimica::isPhaseMQM(i))
     230             :       {
     231             :         auto [pairs, quads, idbg] =
     232          57 :             Thermochimica::getMqmqaNumberPairsQuads(Thermochimica::getPhaseNamesSystem()[i]);
     233          57 :         n_db_species[i] = pairs;
     234             :       }
     235             : 
     236         231 :     if (species.size() == 1 && species[0] == "ALL")
     237             :     {
     238          19 :       if (!n_db_species.empty())
     239          19 :         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          19 :       species.clear();
     245          19 :       _tokenized_species.clear();
     246         190 :       for (const auto i : make_range(db_species.size()))
     247         836 :         for (const auto j : index_range(db_species[i]))
     248             :         {
     249        1330 :           species.push_back(db_phases[i] + ":" + db_species[i][j]);
     250         665 :           _tokenized_species.push_back(std::make_pair(db_phases[i], db_species[i][j]));
     251             :         }
     252          19 :       mooseInfo("ChemicalCompositionAction species: 'ALL' specified in input file. Using: ",
     253          38 :                 Moose::stringify(species));
     254             :     }
     255             :     else
     256         795 :       for (const auto i : index_range(species))
     257             :       {
     258         589 :         _tokenized_species.resize(species.size());
     259             :         std::vector<std::string> tokens;
     260        1178 :         MooseUtils::tokenize(species[i], tokens, 1, ":");
     261         589 :         if (tokens.size() == 1)
     262           2 :           paramError("output_species", "No ':' separator found in variable '", species[i], "'");
     263             : 
     264         587 :         auto phase_index = std::find(db_phases.begin(), db_phases.end(), tokens[0]);
     265         587 :         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         585 :         auto sp = db_species[std::distance(db_phases.begin(), phase_index)];
     273         585 :         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         583 :         _tokenized_species[i] = std::make_pair(tokens[0], tokens[1]);
     277         583 :       }
     278         225 :   }
     279             : 
     280         450 :   if (isParamValid("output_element_potentials"))
     281             :   {
     282         675 :     auto element_potentials = getParam<std::vector<std::string>>("output_element_potentials");
     283         225 :     if (element_potentials.size() == 1 && element_potentials[0] == "ALL")
     284             :     {
     285          19 :       _tokenized_element_potentials.resize(_elements.size());
     286          19 :       _tokenized_element_potentials = _elements;
     287          19 :       element_potentials.resize(_elements.size());
     288          95 :       for (const auto i : index_range(_elements))
     289         152 :         element_potentials[i] = "mu:" + _elements[i];
     290          19 :       mooseInfo(
     291             :           "ChemicalCompositionAction element potentials: 'ALL' specified in input file. Using: ",
     292          38 :           Moose::stringify(element_potentials));
     293             :     }
     294             :     else
     295             :     {
     296         206 :       _tokenized_element_potentials.resize(element_potentials.size());
     297         557 :       for (const auto i : index_range(element_potentials))
     298             :       {
     299             :         std::vector<std::string> tokens;
     300         710 :         MooseUtils::tokenize(element_potentials[i], tokens, 1, ":");
     301         355 :         if (tokens.size() == 1)
     302           2 :           paramError("output_element_potentials",
     303             :                      "No ':' separator found in variable '",
     304             :                      element_potentials[i],
     305             :                      "'");
     306         353 :         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         351 :       }
     313             :     }
     314         221 :   }
     315             : 
     316         442 :   if (isParamValid("output_vapor_pressures"))
     317             :   {
     318         442 :     auto vapor_pressures = getParam<std::vector<std::string>>("output_vapor_pressures");
     319         221 :     if (!Thermochimica::isPhaseGas(0))
     320           0 :       paramError("output_vapor_pressures",
     321             :                  "No gas phase found in the simulation. Cannot output vapor pressures.");
     322         221 :     if (vapor_pressures.size() == 1 && vapor_pressures[0] == "ALL")
     323             :     {
     324          19 :       vapor_pressures.resize(Thermochimica::getNumberSpeciesSystem()[0]);
     325          19 :       _tokenized_vapor_species.resize(Thermochimica::getNumberSpeciesSystem()[0]);
     326          19 :       auto db_gas_species = Thermochimica::getSpeciesInPhase(0);
     327          19 :       auto gas_name = Thermochimica::getPhaseNamesSystem()[0];
     328         114 :       for (const auto i : index_range(db_gas_species))
     329             :       {
     330         190 :         vapor_pressures[i] = "vp:" + gas_name + ':' + db_gas_species[i];
     331         190 :         _tokenized_vapor_species[i] = std::make_pair(gas_name, db_gas_species[i]);
     332             :       }
     333          19 :       mooseInfo("ChemicalCompositionAction vapor pressures: 'ALL' specified in input file. Using: ",
     334          38 :                 Moose::stringify(vapor_pressures));
     335          19 :     }
     336             :     else
     337             :     {
     338         202 :       auto db_gas_species = Thermochimica::getSpeciesInPhase(0);
     339         202 :       _tokenized_vapor_species.resize(vapor_pressures.size());
     340         360 :       for (const auto i : index_range(vapor_pressures))
     341             :       {
     342             :         std::vector<std::string> tokens;
     343         328 :         MooseUtils::tokenize(vapor_pressures[i], tokens, 1, ":");
     344         164 :         if (tokens.size() == 1)
     345           2 :           paramError("output_vapor_pressures",
     346             :                      "No ':' separator found in variable '",
     347             :                      vapor_pressures[i],
     348             :                      "'");
     349         162 :         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         160 :         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         158 :         _tokenized_vapor_species[i] = std::make_pair(tokens[1], tokens[2]);
     363         158 :       }
     364         196 :     }
     365         215 :   }
     366             : 
     367         430 :   if (isParamValid("output_element_phases"))
     368             :   {
     369         430 :     auto element_phases = getParam<std::vector<std::string>>("output_element_phases");
     370         215 :     auto db_phases = Thermochimica::getPhaseNamesSystem();
     371         215 :     if (element_phases.size() == 1 && element_phases[0] == "ALL")
     372             :     {
     373          19 :       element_phases.resize(_elements.size() * db_phases.size());
     374          19 :       _tokenized_phase_elements.resize(_elements.size() * db_phases.size());
     375         247 :       for (const auto i : index_range(db_phases))
     376        1140 :         for (const auto j : index_range(_elements))
     377             :         {
     378        1824 :           element_phases[i * _elements.size() + j] = db_phases[i] + ':' + _elements[j];
     379         912 :           _tokenized_phase_elements[i * _elements.size() + j] =
     380        1824 :               std::make_pair(db_phases[i], _elements[j]);
     381             :         }
     382          19 :       mooseInfo(
     383             :           "ChemicalCompositionAction elements in phase: 'ALL' specified in input file. Using: ",
     384          38 :           Moose::stringify(element_phases));
     385             :     }
     386             :     else
     387             :     {
     388         196 :       _tokenized_phase_elements.resize(element_phases.size());
     389         310 :       for (const auto i : index_range(element_phases))
     390             :       {
     391             :         std::vector<std::string> tokens;
     392         240 :         MooseUtils::tokenize(element_phases[i], tokens, 1, ":");
     393         120 :         if (tokens.size() == 1)
     394           2 :           paramError("output_element_phases",
     395             :                      "No ':' separator found in variable '",
     396             :                      element_phases[i],
     397             :                      "'");
     398         118 :         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         116 :         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         114 :         _tokenized_phase_elements[i] = std::make_pair(tokens[1], tokens[2]);
     411         114 :       }
     412             :     }
     413         209 :   }
     414             : 
     415         209 :   Thermochimica::resetThermoAll();
     416             : 
     417             : #endif
     418         209 : }
     419             : 
     420             : void
     421        1045 : ChemicalCompositionAction::act()
     422             : {
     423             : #ifdef THERMOCHIMICA_ENABLED
     424             :   //
     425             :   // Add AuxVariables
     426             :   //
     427        1045 :   if (_current_task == "add_aux_variable")
     428             :   {
     429             :     auto aux_var_type = AddVariableAction::variableType(
     430         627 :         FEType(Utility::string_to_enum<Order>(_problem->mesh().hasSecondOrderElements() ? "SECOND"
     431             :                                                                                         : "FIRST"),
     432             :                Utility::string_to_enum<libMesh::FEFamily>("LAGRANGE")),
     433         209 :         /* is_fv = */ getParam<bool>("is_fv"),
     434         418 :         /* is_array = */ false);
     435         209 :     auto params = _factory.getValidParams(aux_var_type);
     436             : 
     437         760 :     for (const auto i : index_range(_elements))
     438         551 :       _problem->addAuxVariable(aux_var_type, _elements[i], params);
     439             : 
     440         836 :     for (const auto i : index_range(_phases))
     441         627 :       _problem->addAuxVariable(aux_var_type, _phases[i], params);
     442             : 
     443        1387 :     for (const auto i : index_range(_tokenized_species))
     444        2356 :       _problem->addAuxVariable(
     445        2356 :           aux_var_type, Moose::stringify(_tokenized_species[i], /* delim = */ ":"), params);
     446             : 
     447         608 :     for (const auto i : index_range(_tokenized_element_potentials))
     448         798 :       _problem->addAuxVariable(aux_var_type, "mu:" + _tokenized_element_potentials[i], params);
     449             : 
     450         456 :     for (const auto i : index_range(_tokenized_vapor_species))
     451         494 :       _problem->addAuxVariable(aux_var_type,
     452         247 :                                "vp:" +
     453         494 :                                    Moose::stringify(_tokenized_vapor_species[i], /* delim = */ ":"),
     454             :                                params);
     455             : 
     456        1235 :     for (const auto i : index_range(_tokenized_phase_elements))
     457        2052 :       _problem->addAuxVariable(
     458             :           aux_var_type,
     459        2052 :           "ep:" + Moose::stringify(_tokenized_phase_elements[i], /* delim = */ ":"),
     460             :           params);
     461         209 :   }
     462             : 
     463             :   //
     464             :   // Set up initial conditions from a file
     465             :   //
     466        1463 :   if (_current_task == "add_ic" && isParamValid("initial_values"))
     467             :   {
     468          38 :     readCSV();
     469         152 :     for (auto it : _initial_conditions)
     470             :     {
     471         114 :       const std::string class_name = "ConstantIC";
     472         114 :       auto params = _factory.getValidParams(class_name);
     473         228 :       params.set<VariableName>("variable") = it.first;
     474         114 :       params.set<Real>("value") = it.second;
     475         114 :       _problem->addInitialCondition(class_name, it.first + "_ic", params);
     476         114 :     }
     477             :   }
     478             : 
     479             :   //
     480             :   // Set up user object
     481             :   //
     482        1045 :   if (_current_task == "add_user_object")
     483             :   {
     484         418 :     std::string uo_name = getParam<std::string>("uo_name");
     485             : 
     486         494 :     if (isParamValid("block") && !isParamSetByUser("uo_name"))
     487         114 :       uo_name += "_" + Moose::stringify(getParam<std::vector<SubdomainName>>("block"));
     488             : 
     489             :     const auto uo_type =
     490         418 :         getParam<bool>("is_fv") ? "ThermochimicaElementData" : "ThermochimicaNodalData";
     491             : 
     492         209 :     auto uo_params = _factory.getValidParams(uo_type);
     493             : 
     494         209 :     std::copy(_elements.begin(),
     495             :               _elements.end(),
     496             :               std::back_inserter(uo_params.set<std::vector<VariableName>>("elements")));
     497             : 
     498         418 :     if (isParamValid("output_phases"))
     499         418 :       std::copy(_phases.begin(),
     500             :                 _phases.end(),
     501             :                 std::back_inserter(uo_params.set<std::vector<VariableName>>("output_phases")));
     502             : 
     503         418 :     if (isParamValid("output_species"))
     504             :     {
     505             :       std::vector<std::string> species;
     506        1387 :       for (auto token : _tokenized_species)
     507        2356 :         species.push_back(Moose::stringify(token, ":"));
     508         209 :       uo_params.set<std::vector<VariableName>>("output_species")
     509         418 :           .insert(uo_params.set<std::vector<VariableName>>("output_species").end(),
     510             :                   species.begin(),
     511             :                   species.end());
     512         209 :     }
     513             : 
     514         418 :     if (isParamValid("output_element_potentials"))
     515             :     {
     516             :       std::vector<std::string> element_potentials;
     517         608 :       for (auto token : _tokenized_element_potentials)
     518         798 :         element_potentials.push_back("mu:" + token);
     519         209 :       uo_params.set<std::vector<VariableName>>("output_element_potentials")
     520         418 :           .insert(uo_params.set<std::vector<VariableName>>("output_element_potentials").end(),
     521             :                   element_potentials.begin(),
     522             :                   element_potentials.end());
     523         209 :     }
     524             : 
     525         418 :     if (isParamValid("output_vapor_pressures"))
     526             :     {
     527             :       std::vector<std::string> vapor_pressures;
     528         456 :       for (auto token : _tokenized_vapor_species)
     529         494 :         vapor_pressures.push_back("vp:" + Moose::stringify(token, ":"));
     530         209 :       uo_params.set<std::vector<VariableName>>("output_vapor_pressures")
     531         418 :           .insert(uo_params.set<std::vector<VariableName>>("output_vapor_pressures").end(),
     532             :                   vapor_pressures.begin(),
     533             :                   vapor_pressures.end());
     534         209 :     }
     535             : 
     536         418 :     if (isParamValid("output_element_phases"))
     537             :     {
     538             :       std::vector<std::string> element_phases;
     539        1235 :       for (auto token : _tokenized_phase_elements)
     540        2052 :         element_phases.push_back("ep:" + Moose::stringify(token, ":"));
     541         209 :       uo_params.set<std::vector<VariableName>>("output_element_phases")
     542         418 :           .insert(uo_params.set<std::vector<VariableName>>("output_element_phases").end(),
     543             :                   element_phases.begin(),
     544             :                   element_phases.end());
     545         209 :     }
     546         418 :     uo_params.set<std::vector<VariableName>>("temperature") =
     547         418 :         getParam<std::vector<VariableName>>("temperature");
     548             : 
     549         209 :     uo_params.set<ChemicalCompositionAction *>("_chemical_composition_action") = this;
     550             : 
     551         627 :     uo_params.set<FileName>("thermofile") = getParam<FileName>("thermofile");
     552             : 
     553         627 :     uo_params.set<MooseEnum>("reinit_type") = getParam<MooseEnum>("reinitialization_type");
     554             : 
     555         627 :     uo_params.set<MooseEnum>("output_species_unit") = getParam<MooseEnum>("output_species_unit");
     556             : 
     557         209 :     uo_params.applyParameters(parameters());
     558             : 
     559         209 :     _problem->addUserObject(uo_type, uo_name, uo_params);
     560         209 :   }
     561             : 
     562             : #endif
     563        1045 : }
     564             : 
     565             : void
     566          38 : ChemicalCompositionAction::readCSV()
     567             : {
     568          76 :   const auto & filename = getParam<FileName>("initial_values");
     569          38 :   std::ifstream file(filename.c_str());
     570          38 :   if (!file.good())
     571           0 :     paramError("initial_values", "Error opening file '", filename, "'.");
     572             : 
     573             :   std::string line;
     574             :   std::vector<std::string> items;
     575             : 
     576             :   // skip header
     577          38 :   std::getline(file, line);
     578         152 :   while (std::getline(file, line))
     579             :   {
     580         228 :     MooseUtils::tokenize(line, items, 1, ",");
     581         114 :     if (items.empty())
     582           0 :       continue;
     583         114 :     if (items.size() != 2)
     584           0 :       paramError("initial_value", "Unexpected line in CSV file: ", line);
     585             : 
     586         114 :     _initial_conditions[items[0]] = MooseUtils::convert<Real>(items[1]);
     587             :   }
     588          76 : }

Generated by: LCOV version 1.14