From 31dc566d10bb8381da2facef5e3aaf16f5551375 Mon Sep 17 00:00:00 2001 From: garibay-j <jaimegaribay.1@gmail.com> Date: Fri, 9 Jul 2021 07:29:26 +0000 Subject: [PATCH] [CL] Use MPL to input amounts of ion exchanging species --- .../CreateChemicalSolverInterface.cpp | 11 ++- ChemistryLib/PhreeqcIO.cpp | 71 +++++++++++++------ ChemistryLib/PhreeqcIO.h | 3 - ChemistryLib/PhreeqcIOData/ChemicalSystem.cpp | 5 ++ ChemistryLib/PhreeqcIOData/ChemicalSystem.h | 8 ++- .../PhreeqcIOData/CreateChemicalSystem.cpp | 10 ++- ChemistryLib/PhreeqcIOData/CreateExchange.cpp | 18 ++--- ChemistryLib/PhreeqcIOData/CreateExchange.h | 7 +- ChemistryLib/PhreeqcIOData/Exchange.cpp | 7 +- ChemistryLib/PhreeqcIOData/Exchange.h | 16 +++-- .../exchange/exchange_site/t_molality.md | 1 - .../exchange_site/i_exchange_site.md | 0 .../exchange_site/t_ion_exchanging_species.md | 0 .../i_exchangers.md} | 0 .../CationExchange/exchange.prj | 26 +++++-- 15 files changed, 120 insertions(+), 63 deletions(-) delete mode 100644 Documentation/ProjectFile/prj/chemical_system/exchange/exchange_site/t_molality.md rename Documentation/ProjectFile/prj/chemical_system/{exchange => exchangers}/exchange_site/i_exchange_site.md (100%) rename Documentation/ProjectFile/prj/chemical_system/{exchange => exchangers}/exchange_site/t_ion_exchanging_species.md (100%) rename Documentation/ProjectFile/prj/chemical_system/{exchange/i_exchange.md => exchangers/i_exchangers.md} (100%) diff --git a/ChemistryLib/CreateChemicalSolverInterface.cpp b/ChemistryLib/CreateChemicalSolverInterface.cpp index 448f87e5948..e3e6275b677 100644 --- a/ChemistryLib/CreateChemicalSolverInterface.cpp +++ b/ChemistryLib/CreateChemicalSolverInterface.cpp @@ -25,7 +25,6 @@ #include "PhreeqcIOData/CreateSurface.h" #include "PhreeqcIOData/CreateUserPunch.h" #include "PhreeqcIOData/Dump.h" -#include "PhreeqcIOData/Exchange.h" #include "PhreeqcIOData/Knobs.h" #include "PhreeqcIOData/ReactionRate.h" #include "PhreeqcIOData/Surface.h" @@ -100,23 +99,21 @@ createChemicalSolverInterface<ChemicalSolver::Phreeqc>( config.getConfigSubtreeOptional("surface")); // exchange - auto exchange = PhreeqcIOData::createExchange( - //! \ogs_file_param{prj__chemical_system__exchange} - config.getConfigSubtreeOptional("exchange")); + auto const& exchangers = chemical_system->exchangers; // dump auto const project_file_name = BaseLib::joinPaths( output_directory, BaseLib::extractBaseNameWithoutExtension(config.getProjectFileName())); - if (!surface.empty() && !exchange.empty()) + if (!surface.empty() && !exchangers.empty()) { OGS_FATAL( "Using surface and exchange reactions simultaneously is not " "supported at the moment"); } - auto dump = surface.empty() && exchange.empty() + auto dump = surface.empty() && exchangers.empty() ? nullptr : std::make_unique<PhreeqcIOData::Dump>(project_file_name); @@ -140,7 +137,7 @@ createChemicalSolverInterface<ChemicalSolver::Phreeqc>( return std::make_unique<PhreeqcIOData::PhreeqcIO>( std::move(project_file_name), std::move(path_to_database), std::move(chemical_system), std::move(reaction_rates), - std::move(surface), std::move(exchange), std::move(user_punch), + std::move(surface), std::move(user_punch), std::move(output), std::move(dump), std::move(knobs)); } diff --git a/ChemistryLib/PhreeqcIO.cpp b/ChemistryLib/PhreeqcIO.cpp index f48e3b39398..41a517db190 100644 --- a/ChemistryLib/PhreeqcIO.cpp +++ b/ChemistryLib/PhreeqcIO.cpp @@ -28,12 +28,12 @@ #include "PhreeqcIOData/ChemicalSystem.h" #include "PhreeqcIOData/Dump.h" #include "PhreeqcIOData/EquilibriumReactant.h" +#include "PhreeqcIOData/Exchange.h" #include "PhreeqcIOData/KineticReactant.h" #include "PhreeqcIOData/Knobs.h" #include "PhreeqcIOData/Output.h" #include "PhreeqcIOData/ReactionRate.h" #include "PhreeqcIOData/Surface.h" -#include "PhreeqcIOData/Exchange.h" #include "PhreeqcIOData/UserPunch.h" namespace ChemistryLib @@ -71,15 +71,14 @@ void setAqueousSolution(std::vector<double> const& concentrations, template <typename Reactant> void initializeReactantMolality(Reactant& reactant, GlobalIndexType const& chemical_system_id, + MaterialPropertyLib::Phase const& solid_phase, + MaterialPropertyLib::Phase const& liquid_phase, MaterialPropertyLib::Medium const& medium, ParameterLib::SpatialPosition const& pos, double const t) { - auto const& solid_phase = medium.phase("Solid"); auto const& solid_constituent = solid_phase.component(reactant.name); - auto const& liquid_phase = medium.phase("AqueousLiquid"); - if (solid_constituent.hasProperty( MaterialPropertyLib::PropertyType::molality)) { @@ -124,12 +123,12 @@ void initializeReactantMolality(Reactant& reactant, template <typename Reactant> void setReactantMolality(Reactant& reactant, GlobalIndexType const& chemical_system_id, - MaterialPropertyLib::Medium const* medium, + MaterialPropertyLib::Phase const& solid_phase, + MaterialPropertyLib::Phase const& liquid_phase, MaterialPropertyLib::VariableArray const& vars, ParameterLib::SpatialPosition const& pos, double const t, double const dt) { - auto const& solid_phase = medium->phase("Solid"); auto const& solid_constituent = solid_phase.component(reactant.name); if (solid_constituent.hasProperty( @@ -147,7 +146,6 @@ void setReactantMolality(Reactant& reactant, (*reactant.volume_fraction_prev)[chemical_system_id] = (*reactant.volume_fraction)[chemical_system_id]; - auto const& liquid_phase = medium->phase("AqueousLiquid"); auto const fluid_density = liquid_phase[MaterialPropertyLib::PropertyType::density] .template value<double>(vars, pos, t, dt); @@ -166,6 +164,22 @@ void setReactantMolality(Reactant& reactant, (*reactant.molality)[chemical_system_id]; } +template <typename Exchanger> +void initializeExchangerMolality(Exchanger& exchanger, + GlobalIndexType const& chemical_system_id, + MaterialPropertyLib::Phase const& solid_phase, + ParameterLib::SpatialPosition const& pos, + double const t) +{ + auto const& solid_constituent = solid_phase.component(exchanger.name); + + auto const molality = + solid_constituent[MaterialPropertyLib::PropertyType::molality] + .template initialValue<double>(pos, t); + + (*exchanger.molality)[chemical_system_id] = molality; +} + template <typename Reactant> void updateReactantVolumeFraction(Reactant& reactant, GlobalIndexType const& chemical_system_id, @@ -243,7 +257,6 @@ PhreeqcIO::PhreeqcIO(std::string const& project_file_name, std::unique_ptr<ChemicalSystem>&& chemical_system, std::vector<ReactionRate>&& reaction_rates, std::vector<SurfaceSite>&& surface, - std::vector<ExchangeSite>&& exchange, std::unique_ptr<UserPunch>&& user_punch, std::unique_ptr<Output>&& output, std::unique_ptr<Dump>&& dump, @@ -253,7 +266,6 @@ PhreeqcIO::PhreeqcIO(std::string const& project_file_name, _chemical_system(std::move(chemical_system)), _reaction_rates(std::move(reaction_rates)), _surface(std::move(surface)), - _exchange(std::move(exchange)), _user_punch(std::move(user_punch)), _output(std::move(output)), _dump(std::move(dump)), @@ -314,16 +326,25 @@ void PhreeqcIO::initializeChemicalSystemConcrete( setAqueousSolution(concentrations, chemical_system_id, *_chemical_system->aqueous_solution); + auto const& solid_phase = medium.phase("Solid"); + auto const& liquid_phase = medium.phase("AqueousLiquid"); + for (auto& kinetic_reactant : _chemical_system->kinetic_reactants) { - initializeReactantMolality(kinetic_reactant, chemical_system_id, medium, - pos, t); + initializeReactantMolality(kinetic_reactant, chemical_system_id, + solid_phase, liquid_phase, medium, pos, t); } for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants) { initializeReactantMolality(equilibrium_reactant, chemical_system_id, - medium, pos, t); + solid_phase, liquid_phase, medium, pos, t); + } + + for (auto& exchanger : _chemical_system->exchangers) + { + initializeExchangerMolality(exchanger, chemical_system_id, solid_phase, pos, + t); } } @@ -337,16 +358,19 @@ void PhreeqcIO::setChemicalSystemConcrete( setAqueousSolution(concentrations, chemical_system_id, *_chemical_system->aqueous_solution); + auto const& solid_phase = medium->phase("Solid"); + auto const& liquid_phase = medium->phase("AqueousLiquid"); + for (auto& kinetic_reactant : _chemical_system->kinetic_reactants) { - setReactantMolality(kinetic_reactant, chemical_system_id, medium, vars, - pos, t, dt); + setReactantMolality(kinetic_reactant, chemical_system_id, solid_phase, + liquid_phase, vars, pos, t, dt); } for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants) { - setReactantMolality(equilibrium_reactant, chemical_system_id, medium, - vars, pos, t, dt); + setReactantMolality(equilibrium_reactant, chemical_system_id, + solid_phase, liquid_phase, vars, pos, t, dt); } } @@ -508,8 +532,8 @@ std::ostream& operator<<(std::ostream& os, PhreeqcIO const& phreeqc_io) os << "SAVE solution " << chemical_system_id + 1 << "\n"; } - auto const& exchange = phreeqc_io._exchange; - if (!exchange.empty()) + auto const& exchangers = phreeqc_io._chemical_system->exchangers; + if (!exchangers.empty()) { os << "EXCHANGE " << chemical_system_id + 1 << "\n"; std::size_t const aqueous_solution_id = @@ -517,7 +541,10 @@ std::ostream& operator<<(std::ostream& os, PhreeqcIO const& phreeqc_io) ? chemical_system_id + 1 : phreeqc_io._num_chemical_systems + chemical_system_id + 1; os << "-equilibrate with solution " << aqueous_solution_id << "\n"; - os << exchange << "\n"; + for (auto const& exchanger : exchangers) + { + exchanger.print(os, chemical_system_id); + } os << "SAVE solution " << chemical_system_id + 1 << "\n"; } @@ -581,16 +608,16 @@ std::istream& operator>>(std::istream& in, PhreeqcIO& phreeqc_io) auto const& dropped_item_ids = output.dropped_item_ids; auto const& surface = phreeqc_io._surface; - auto const& exchange = phreeqc_io._exchange; + auto const& exchangers = phreeqc_io._chemical_system->exchangers; - if (!surface.empty() && !exchange.empty()) + if (!surface.empty() && !exchangers.empty()) { OGS_FATAL( "Using surface and exchange reactions simultaneously is not " "supported at the moment"); } - int const num_skipped_lines = surface.empty() && exchange.empty() ? 1 : 2; + int const num_skipped_lines = surface.empty() && exchangers.empty() ? 1 : 2; auto& equilibrium_reactants = phreeqc_io._chemical_system->equilibrium_reactants; diff --git a/ChemistryLib/PhreeqcIO.h b/ChemistryLib/PhreeqcIO.h index dc73f5fa138..22d31ff3f7f 100644 --- a/ChemistryLib/PhreeqcIO.h +++ b/ChemistryLib/PhreeqcIO.h @@ -28,7 +28,6 @@ struct ChemicalSystem; struct ReactionRate; struct Output; struct SurfaceSite; -struct ExchangeSite; struct Dump; struct UserPunch; @@ -40,7 +39,6 @@ public: std::unique_ptr<ChemicalSystem>&& chemical_system, std::vector<ReactionRate>&& reaction_rates, std::vector<SurfaceSite>&& surface, - std::vector<ExchangeSite>&& exchange, std::unique_ptr<UserPunch>&& user_punch, std::unique_ptr<Output>&& output, std::unique_ptr<Dump>&& dump, @@ -109,7 +107,6 @@ private: std::unique_ptr<ChemicalSystem> _chemical_system; std::vector<ReactionRate> const _reaction_rates; std::vector<SurfaceSite> const _surface; - std::vector<ExchangeSite> const _exchange; std::unique_ptr<UserPunch> _user_punch; std::unique_ptr<Output> const _output; std::unique_ptr<Dump> const _dump; diff --git a/ChemistryLib/PhreeqcIOData/ChemicalSystem.cpp b/ChemistryLib/PhreeqcIOData/ChemicalSystem.cpp index 67367d585a9..c3b704f0ee0 100644 --- a/ChemistryLib/PhreeqcIOData/ChemicalSystem.cpp +++ b/ChemistryLib/PhreeqcIOData/ChemicalSystem.cpp @@ -51,6 +51,11 @@ void ChemicalSystem::initialize(std::size_t const num_chemical_systems) equilibrium_reactant.volume_fraction->resize(num_chemical_systems); equilibrium_reactant.volume_fraction_prev->resize(num_chemical_systems); } + + for (auto& exchanger : exchangers) + { + exchanger.molality->resize(num_chemical_systems); + } } } // namespace PhreeqcIOData } // namespace ChemistryLib diff --git a/ChemistryLib/PhreeqcIOData/ChemicalSystem.h b/ChemistryLib/PhreeqcIOData/ChemicalSystem.h index a2bced5dade..9e50e9cb5ff 100644 --- a/ChemistryLib/PhreeqcIOData/ChemicalSystem.h +++ b/ChemistryLib/PhreeqcIOData/ChemicalSystem.h @@ -15,6 +15,7 @@ #include "AqueousSolution.h" #include "EquilibriumReactant.h" +#include "Exchange.h" #include "KineticReactant.h" namespace ChemistryLib @@ -25,10 +26,12 @@ struct ChemicalSystem { ChemicalSystem(std::unique_ptr<AqueousSolution>&& aqueous_solution_, std::vector<KineticReactant>&& kinetic_reactants_, - std::vector<EquilibriumReactant>&& equilibrium_reactants_) + std::vector<EquilibriumReactant>&& equilibrium_reactants_, + std::vector<ExchangeSite>&& exchangers_) : aqueous_solution(std::move(aqueous_solution_)), kinetic_reactants(std::move(kinetic_reactants_)), - equilibrium_reactants(std::move(equilibrium_reactants_)) + equilibrium_reactants(std::move(equilibrium_reactants_)), + exchangers(std::move(exchangers_)) { } @@ -37,6 +40,7 @@ struct ChemicalSystem std::unique_ptr<AqueousSolution> aqueous_solution; std::vector<KineticReactant> kinetic_reactants; std::vector<EquilibriumReactant> equilibrium_reactants; + std::vector<ExchangeSite> exchangers; }; } // namespace PhreeqcIOData } // namespace ChemistryLib diff --git a/ChemistryLib/PhreeqcIOData/CreateChemicalSystem.cpp b/ChemistryLib/PhreeqcIOData/CreateChemicalSystem.cpp index eebaf944793..6319c899a41 100644 --- a/ChemistryLib/PhreeqcIOData/CreateChemicalSystem.cpp +++ b/ChemistryLib/PhreeqcIOData/CreateChemicalSystem.cpp @@ -14,8 +14,10 @@ #include "ChemicalSystem.h" #include "CreateAqueousSolution.h" #include "CreateEquilibriumReactants.h" +#include "CreateExchange.h" #include "CreateKineticReactant.h" #include "EquilibriumReactant.h" +#include "Exchange.h" #include "KineticReactant.h" namespace ChemistryLib @@ -40,9 +42,15 @@ std::unique_ptr<ChemicalSystem> createChemicalSystem( //! \ogs_file_param{prj__chemical_system__equilibrium_reactants} config.getConfigSubtreeOptional("equilibrium_reactants"), mesh); + // exchangers + auto exchangers = createExchange( + //! \ogs_file_param{prj__chemical_system__exchangers} + config.getConfigSubtreeOptional("exchangers"), mesh); + return std::make_unique<ChemicalSystem>(std::move(aqueous_solution), std::move(kinetic_reactants), - std::move(equilibrium_reactants)); + std::move(equilibrium_reactants), + std::move(exchangers)); } } // namespace PhreeqcIOData } // namespace ChemistryLib diff --git a/ChemistryLib/PhreeqcIOData/CreateExchange.cpp b/ChemistryLib/PhreeqcIOData/CreateExchange.cpp index a51962314b3..d9eaab0b1ee 100644 --- a/ChemistryLib/PhreeqcIOData/CreateExchange.cpp +++ b/ChemistryLib/PhreeqcIOData/CreateExchange.cpp @@ -12,36 +12,36 @@ #include "BaseLib/ConfigTree.h" #include "Exchange.h" +#include "MeshLib/Mesh.h" namespace ChemistryLib { namespace PhreeqcIOData { std::vector<ExchangeSite> createExchange( - std::optional<BaseLib::ConfigTree> const& config) + std::optional<BaseLib::ConfigTree> const& config, MeshLib::Mesh& mesh) { if (!config) { return {}; } - std::vector<ExchangeSite> exchange; + std::vector<ExchangeSite> exchangers; for (auto const& site_config : - //! \ogs_file_param{prj__chemical_system__exchange__exchange_site} + //! \ogs_file_param{prj__chemical_system__exchangers__exchange_site} config->getConfigSubtreeList("exchange_site")) { - //! \ogs_file_param{prj__chemical_system__exchange__exchange_site__ion_exchanging_species} + //! \ogs_file_param{prj__chemical_system__exchangers__exchange_site__ion_exchanging_species} auto name = site_config.getConfigParameter<std::string>( "ion_exchanging_species"); - auto const molality = - //! \ogs_file_param{prj__chemical_system__exchange__exchange_site__molality} - site_config.getConfigParameter<double>("molality"); + auto const molality = MeshLib::getOrCreateMeshProperty<double>( + mesh, name, MeshLib::MeshItemType::IntegrationPoint, 1); - exchange.emplace_back(std::move(name), molality); + exchangers.emplace_back(std::move(name), molality); } - return exchange; + return exchangers; } } // namespace PhreeqcIOData } // namespace ChemistryLib diff --git a/ChemistryLib/PhreeqcIOData/CreateExchange.h b/ChemistryLib/PhreeqcIOData/CreateExchange.h index 4fdbb9fc9a2..54221e658a0 100644 --- a/ChemistryLib/PhreeqcIOData/CreateExchange.h +++ b/ChemistryLib/PhreeqcIOData/CreateExchange.h @@ -18,6 +18,11 @@ namespace BaseLib class ConfigTree; } +namespace MeshLib +{ +class Mesh; +} + namespace ChemistryLib { namespace PhreeqcIOData @@ -25,6 +30,6 @@ namespace PhreeqcIOData struct ExchangeSite; std::vector<ExchangeSite> createExchange( - std::optional<BaseLib::ConfigTree> const& config); + std::optional<BaseLib::ConfigTree> const& config, MeshLib::Mesh& mesh); } // namespace PhreeqcIOData } // namespace ChemistryLib diff --git a/ChemistryLib/PhreeqcIOData/Exchange.cpp b/ChemistryLib/PhreeqcIOData/Exchange.cpp index ac7786785a3..142da1d5a37 100644 --- a/ChemistryLib/PhreeqcIOData/Exchange.cpp +++ b/ChemistryLib/PhreeqcIOData/Exchange.cpp @@ -16,11 +16,10 @@ namespace ChemistryLib { namespace PhreeqcIOData { -std::ostream& operator<<(std::ostream& os, ExchangeSite const& exchange_site) +void ExchangeSite::print(std::ostream& os, + std::size_t const chemical_system_id) const { - os << exchange_site.ion_exchanging_species << " " << exchange_site.molality << "\n"; - - return os; + os << name << " " << (*molality)[chemical_system_id] << "\n"; } } // namespace PhreeqcIOData } // namespace ChemistryLib diff --git a/ChemistryLib/PhreeqcIOData/Exchange.h b/ChemistryLib/PhreeqcIOData/Exchange.h index ed591c95f0e..92c0e38b0e8 100644 --- a/ChemistryLib/PhreeqcIOData/Exchange.h +++ b/ChemistryLib/PhreeqcIOData/Exchange.h @@ -12,6 +12,9 @@ #include <iosfwd> #include <string> +#include <vector> + +#include "MeshLib/PropertyVector.h" namespace BaseLib { @@ -24,17 +27,16 @@ namespace PhreeqcIOData { struct ExchangeSite { - ExchangeSite(std::string ion_exchanging_species_, double const molality_) - : ion_exchanging_species(std::move(ion_exchanging_species_)), - molality(molality_) + ExchangeSite(std::string name_, MeshLib::PropertyVector<double>* molality_) + : name(std::move(name_)), molality(molality_) { } - std::string const ion_exchanging_species; - double const molality; -}; + void print(std::ostream& os, std::size_t const chemical_system_id) const; -std::ostream& operator<<(std::ostream& os, ExchangeSite const& exchange_site); + std::string const name; + MeshLib::PropertyVector<double>* molality; +}; } // namespace PhreeqcIOData } // namespace ChemistryLib diff --git a/Documentation/ProjectFile/prj/chemical_system/exchange/exchange_site/t_molality.md b/Documentation/ProjectFile/prj/chemical_system/exchange/exchange_site/t_molality.md deleted file mode 100644 index 5f1ab418601..00000000000 --- a/Documentation/ProjectFile/prj/chemical_system/exchange/exchange_site/t_molality.md +++ /dev/null @@ -1 +0,0 @@ -This keyword is used to input the amount (mol/kg of water) of the exchange site. \ No newline at end of file diff --git a/Documentation/ProjectFile/prj/chemical_system/exchange/exchange_site/i_exchange_site.md b/Documentation/ProjectFile/prj/chemical_system/exchangers/exchange_site/i_exchange_site.md similarity index 100% rename from Documentation/ProjectFile/prj/chemical_system/exchange/exchange_site/i_exchange_site.md rename to Documentation/ProjectFile/prj/chemical_system/exchangers/exchange_site/i_exchange_site.md diff --git a/Documentation/ProjectFile/prj/chemical_system/exchange/exchange_site/t_ion_exchanging_species.md b/Documentation/ProjectFile/prj/chemical_system/exchangers/exchange_site/t_ion_exchanging_species.md similarity index 100% rename from Documentation/ProjectFile/prj/chemical_system/exchange/exchange_site/t_ion_exchanging_species.md rename to Documentation/ProjectFile/prj/chemical_system/exchangers/exchange_site/t_ion_exchanging_species.md diff --git a/Documentation/ProjectFile/prj/chemical_system/exchange/i_exchange.md b/Documentation/ProjectFile/prj/chemical_system/exchangers/i_exchangers.md similarity index 100% rename from Documentation/ProjectFile/prj/chemical_system/exchange/i_exchange.md rename to Documentation/ProjectFile/prj/chemical_system/exchangers/i_exchangers.md diff --git a/Tests/Data/Parabolic/ComponentTransport/ReactiveTransport/CationExchange/exchange.prj b/Tests/Data/Parabolic/ComponentTransport/ReactiveTransport/CationExchange/exchange.prj index eb2a96d0f75..9e6f4286a75 100644 --- a/Tests/Data/Parabolic/ComponentTransport/ReactiveTransport/CationExchange/exchange.prj +++ b/Tests/Data/Parabolic/ComponentTransport/ReactiveTransport/CationExchange/exchange.prj @@ -167,6 +167,21 @@ </property> </properties> </phase> + <phase> + <type>Solid</type> + <components> + <component> + <name>X</name> + <properties> + <property> + <name>molality</name> + <type>Constant</type> + <value>1.1e-3</value> + </property> + </properties> + </component> + </components> + </phase> </phases> <properties> <property> @@ -439,12 +454,11 @@ </components> <charge_balance>pH</charge_balance> </solution> - <exchange> - <exchange_site> - <ion_exchanging_species>X</ion_exchanging_species> - <molality>1.1e-3</molality> - </exchange_site> - </exchange> + <exchangers> + <exchange_site> + <ion_exchanging_species>X</ion_exchanging_species> + </exchange_site> + </exchangers> <knobs> <max_iter>500</max_iter> <relative_convergence_tolerance>1e-12</relative_convergence_tolerance> -- GitLab