79 _pressure(coupledValue(
"pressure")),
80 _temperature(coupledValue(
"temperature")),
81 _n_phases(coupledComponents(
"output_phases")),
82 _n_species(coupledComponents(
"output_species")),
83 _n_elements(coupledComponents(
"elements")),
84 _n_vapor_species(coupledComponents(
"output_vapor_pressures")),
85 _n_phase_elements(coupledComponents(
"output_element_phases")),
86 _n_potentials(coupledComponents(
"output_element_potentials")),
89 "_chemical_composition_action")),
90 _el_ids(_action.elementIDs()),
92 _ph_names(_action.phases()),
93 _element_potentials(_action.elementPotentials()),
94 _species_phase_pairs(_action.speciesPhasePairs()),
95 _vapor_phase_pairs(_action.vaporPhasePairs()),
96 _phase_element_pairs(_action.phaseElementPairs()),
97 _output_element_potentials(isCoupled(
"output_element_potentials")),
98 _output_vapor_pressures(isCoupled(
"output_vapor_pressures")),
99 _output_element_phases(isCoupled(
"output_element_phases")),
102 _vp(_n_vapor_species),
103 _el_pot(_n_potentials),
104 _el_ph(_n_phase_elements),
110 mooseError(
"Element IDs size does not match number of elements.");
112 _el[i] = &coupledValue(
"elements", i);
114 if (isParamValid(
"output_phases"))
117 mooseError(
"Phase names vector size does not match number of phases.");
119 for (
const auto i : make_range(
_n_phases))
120 _ph[i] = &writableVariable(
"output_phases", i);
123 if (isParamValid(
"output_species"))
126 mooseError(
"Species name vector size does not match number of output species.");
129 _sp[i] = &writableVariable(
"output_species", i);
132 if (isParamValid(
"output_vapor_pressures"))
135 mooseError(
"Vapor species name vector size does not match number of output vapor species.");
138 _vp[i] = &writableVariable(
"output_vapor_pressures", i);
141 if (isParamValid(
"output_element_phases"))
144 mooseError(
"Element phase vector size does not match number of output elements in phases");
147 _el_ph[i] = &writableVariable(
"output_element_phases", i);
150 if (isParamValid(
"output_element_potentials"))
153 mooseError(
"Element potentials vector size does not match number of element potentials "
154 "specified for output.");
157 _el_pot[i] = &writableVariable(
"output_element_potentials", i);
160 const auto dofid_size = std::max( 1, 0);
161 const auto real_size =
168 static_cast<std::byte *
>(mmap(
nullptr,
169 dofid_size *
sizeof(dof_id_type) + real_size *
sizeof(Real),
170 PROT_READ | PROT_WRITE,
171 MAP_ANONYMOUS | MAP_SHARED,
174 if (shared_mem == MAP_FAILED)
175 mooseError(
"Failed to allocate shared memory for thermochimica IPC.");
179 _shared_real_mem =
reinterpret_cast<Real *
>(shared_mem + dofid_size *
sizeof(dof_id_type));
183 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0)
184 mooseError(
"Failed to create socketpair for thermochimica IPC.");
189 mooseError(
"Fork failed for thermochimica library.");
197#ifdef THERMOCHIMICA_ENABLED
199 if (isParamValid(
"thermofile"))
201 const auto thermo_file = this->
template getParam<FileName>(
"thermofile");
203 if (thermo_file.length() > 1024)
204 this->paramError(
"thermofile",
205 "Path exceeds Thermochimica's maximal permissible length of 1024 with ",
206 thermo_file.length(),
210 Thermochimica::setThermoFilename(thermo_file);
213 Thermochimica::parseThermoFile();
215 const auto idbg = Thermochimica::checkInfoThermo();
217 this->paramError(
"thermofile",
"Thermochimica data file cannot be parsed. ", idbg);
274 const unsigned int qp = 0;
277 if constexpr (is_nodal)
278 _shared_dofid_mem[0] = this->_current_node->id();
280 _shared_dofid_mem[0] = this->_current_elem->id();
283 _shared_real_mem[0] = _temperature[qp];
284 _shared_real_mem[1] = _pressure[qp];
285 for (
const auto i : make_range(_n_elements))
286 _shared_real_mem[2 + i] = (*_el[i])[qp];
297 for (
const auto i : make_range(_n_phases))
298 _ph[i]->setDofValue(_shared_real_mem[idx++], qp);
300 for (
const auto i : make_range(_n_species))
301 _sp[i]->setDofValue(_shared_real_mem[idx++], qp);
303 if (_output_element_potentials)
304 for (
const auto i : index_range(_element_potentials))
305 _el_pot[i]->setDofValue(_shared_real_mem[idx++], qp);
307 if (_output_vapor_pressures)
308 for (
const auto i : make_range(_n_vapor_species))
309 _vp[i]->setDofValue(_shared_real_mem[idx++], qp);
311 if (_output_element_phases)
312 for (
const auto i : make_range(_n_phase_elements))
313 _el_ph[i]->setDofValue(_shared_real_mem[idx++], qp);
323#ifdef THERMOCHIMICA_ENABLED
325 _current_id = _shared_dofid_mem[0];
327 auto temperature = _shared_real_mem[0];
328 auto pressure = _shared_real_mem[1];
331 Thermochimica::setTemperaturePressure(temperature, pressure);
334 Thermochimica::setElementMass(0, 0.0);
337 for (
const auto i : make_range(_n_elements))
338 Thermochimica::setElementMass(_el_ids[i], _shared_real_mem[2 + i]);
341 reinitDataMooseToTc();
344 Thermochimica::thermochimica();
347 auto idbg = Thermochimica::checkInfoThermo();
353 reinitDataMooseFromTc();
357 auto moles_phase = Thermochimica::getMolesPhase();
361 for (
const auto i : make_range(_n_phases))
364 auto [index, idbg] = Thermochimica::getPhaseIndex(_ph_names[i]);
366 mooseError(
"Failed to get index of phase '", _ph_names[i],
"'");
369 _shared_real_mem[idx] = 0.0;
371 _shared_real_mem[idx] = moles_phase[index - 1];
375 auto db_phases = Thermochimica::getPhaseNamesSystem();
376 auto getSpeciesMoles =
377 [
this, moles_phase, db_phases](
const std::string phase,
378 const std::string species) -> std::pair<double, int>
383 auto [index, idbg] = Thermochimica::getPhaseIndex(phase);
385 if (Thermochimica::isPhaseMQM(
386 std::distance(db_phases.begin(), std::find(db_phases.begin(), db_phases.end(), phase))))
388 auto [fraction, idbg] = Thermochimica::getMqmqaPairMolFraction(phase, species);
390 switch (_output_mass_unit)
392 case OutputMassUnit::FRACTION:
398 case OutputMassUnit::MOLES:
400 auto [molesPair, idbgPair] = Thermochimica::getMqmqaMolesPairs(phase);
401 value = molesPair * fraction;
402 code = idbg + idbgPair;
411 auto [fraction, idbg] = Thermochimica::getOutputMolSpeciesPhase(phase, species);
412 switch (_output_mass_unit)
414 case OutputMassUnit::FRACTION:
420 case OutputMassUnit::MOLES:
422 value = index >= 1 ? moles_phase[index - 1] * fraction : 0.0;
430 return {value, code};
433 for (
const auto i : make_range(_n_species))
435 auto [fraction, idbg] = getSpeciesMoles(
436 _species_phase_pairs[i].first,
437 _species_phase_pairs[i].second);
440 _shared_real_mem[idx] = fraction;
442 _shared_real_mem[idx] = 0.0;
445 mooseError(
"Failed to get phase speciation for phase '",
446 _species_phase_pairs[i].first,
448 _species_phase_pairs[i].second,
449 "'. Thermochimica returned ",
455 if (_output_element_potentials)
456 for (
const auto i : index_range(_element_potentials))
458 auto [potential, idbg] = Thermochimica::getOutputChemPot(_element_potentials[i]);
460 _shared_real_mem[idx] = potential;
463 _shared_real_mem[idx] = 0.0;
466 mooseError(
"Failed to get element potential for element '",
467 _element_potentials[i],
468 "'. Thermochimica returned ",
474 if (_output_vapor_pressures)
475 for (
const auto i : make_range(_n_vapor_species))
477 auto [fraction, moles, idbg] =
478 Thermochimica::getOutputMolSpecies(_vapor_phase_pairs[i].second);
479 libmesh_ignore(moles);
482 _shared_real_mem[idx] = fraction * pressure;
484 _shared_real_mem[idx] = 0.0;
487 mooseError(
"Failed to get vapor pressure for phase '",
488 _vapor_phase_pairs[i].first,
490 _vapor_phase_pairs[i].second,
491 "'. Thermochimica returned ",
497 if (_output_element_phases)
498 for (
const auto i : make_range(_n_phase_elements))
500 auto [moles, idbg] = Thermochimica::getElementMolesInPhase(_phase_element_pairs[i].second,
501 _phase_element_pairs[i].first);
504 _shared_real_mem[idx] = moles;
506 _shared_real_mem[idx] = 0.0;
509 mooseError(
"Failed to get moles of element '",
510 _phase_element_pairs[i].second,
512 _phase_element_pairs[i].first,
513 "'. Thermochimica returned ",
527#ifdef THERMOCHIMICA_ENABLED
528 auto &
d = _data[_current_id];
530 if (_reinit != ReinitializationType::NONE)
532 Thermochimica::saveReinitData();
533 auto data = Thermochimica::getReinitData();
535 if (_reinit == ReinitializationType::TIME)
537 d._assemblage = std::move(data.assemblage);
538 d._moles_phase = std::move(data.molesPhase);
539 d._element_potential = std::move(data.elementPotential);
540 d._chemical_potential = std::move(data.chemicalPotential);
541 d._mol_fraction = std::move(data.moleFraction);
542 d._elements_used = std::move(data.elementsUsed);
543 d._reinit_available = data.reinitAvailable;