Skip to content

Commit

Permalink
Merge branch 'timeloop_local_solution' into 'master'
Browse files Browse the repository at this point in the history
Timeloop: Bind processes

See merge request ogs/ogs!4724
  • Loading branch information
endJunction committed Nov 11, 2023
2 parents 94d1231 + 49cf561 commit 465f15f
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Specifies processes that will be solved in a locally coupled loop within the staggered solution scheme.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Defines the local process coupling.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Defines the name of the process. The name is used, for example in the local coupling loop in the staggered scheme.
45 changes: 44 additions & 1 deletion ProcessLib/CreateProcessData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
*
*/

#include <range/v3/algorithm/contains.hpp>

#include "BaseLib/Algorithm.h"
#include "BaseLib/ConfigTree.h"
#include "NumLib/ODESolver/TimeDiscretizationBuilder.h"
Expand Down Expand Up @@ -69,9 +71,11 @@ std::vector<std::unique_ptr<ProcessData>> createPerProcessData(
std::map<std::string, std::unique_ptr<NumLib::NonlinearSolverBase>> const&
nonlinear_solvers,
bool const compensate_non_equilibrium_initial_residuum,
std::vector<double> const& fixed_times_for_output)
std::vector<double> const& fixed_times_for_output,
std::map<std::string, int>& local_coupling_processes)
{
std::vector<std::unique_ptr<ProcessData>> per_process_data;
std::vector<std::string> process_names;
int process_id = 0;

//! \ogs_file_param{prj__time_loop__processes__process}
Expand All @@ -85,6 +89,35 @@ std::vector<std::unique_ptr<ProcessData>> createPerProcessData(
{ return p->name == pcs_name; },
"A process with the given name has not been defined.");

auto const process_name =
//! \ogs_file_param{prj__time_loop__processes__process__process_name}
pcs_config.getConfigParameterOptional<std::string>("process_name");
if (process_name)
{
if (!local_coupling_processes.contains(*process_name))
{
OGS_FATAL(
"The given process name '{}' for the element "
"'time_loop/processes/process/process_name' is not found "
"in the element "
"'time_loop/global_process_coupling/"
"local_coupling_processes/process_name' in the project "
"file.",
*process_name);
}

if (ranges::contains(process_names, *process_name))
{
OGS_FATAL(
"The given process name '{}' for the element "
"'time_loop/processes/process/process_name' is not unique! "
"Please check this in the project file.",
*process_name);
}
process_names.emplace_back(*process_name);
local_coupling_processes[*process_name] = process_id;
}

auto const nl_slv_name =
//! \ogs_file_param{prj__time_loop__processes__process__nonlinear_solver}
pcs_config.getConfigParameter<std::string>("nonlinear_solver");
Expand Down Expand Up @@ -142,6 +175,16 @@ std::vector<std::unique_ptr<ProcessData>> createPerProcessData(
}
}

if (process_names.size() != local_coupling_processes.size())
{
OGS_FATAL(
"The number of the given process names for the element "
"'time_loop/processes/process/process_name' is not equal to that "
"in the element "
"'time_loop/global_process_coupling/local_coupling_processes/"
"process_name' in the project file.");
}

return per_process_data;
}
} // namespace ProcessLib
3 changes: 2 additions & 1 deletion ProcessLib/CreateProcessData.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ std::vector<std::unique_ptr<ProcessData>> createPerProcessData(
std::map<std::string, std::unique_ptr<NumLib::NonlinearSolverBase>> const&
nonlinear_solvers,
bool const compensate_non_equilibrium_initial_residuum,
std::vector<double> const& fixed_times_for_output);
std::vector<double> const& fixed_times_for_output,
std::map<std::string, int>& local_coupling_processes);

} // namespace ProcessLib
49 changes: 47 additions & 2 deletions ProcessLib/CreateTimeLoop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ std::unique_ptr<TimeLoop> createTimeLoop(

std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>
global_coupling_conv_criteria;
std::map<std::string, int> local_coupling_processes;
int max_coupling_iterations = 1;
if (coupling_config)
{
Expand All @@ -55,6 +56,49 @@ std::unique_ptr<TimeLoop> createTimeLoop(
std::back_inserter(global_coupling_conv_criteria),
[](BaseLib::ConfigTree const& c)
{ return NumLib::createConvergenceCriterion(c); });

auto const& local_coupling_processes_config =
coupling_config
//! \ogs_file_param{prj__time_loop__global_process_coupling__local_coupling_processes}
->getConfigSubtreeOptional("local_coupling_processes");
if (local_coupling_processes_config)
{
for (
auto name :
local_coupling_processes_config
//! \ogs_file_param{prj__time_loop__global_process_coupling__local_coupling_processes__process_name}
->getConfigParameterList<std::string>("process_name"))
{
BaseLib::insertIfKeyUniqueElseError(
local_coupling_processes, name, -1,
"The name of locally coupled process is not unique.");
}

static std::string const error_info =
"Please check the number of elements in the tag "
"'time_loop/global_process_coupling/"
"local_coupling_processes' in the project file.";
if (local_coupling_processes.size() >
global_coupling_conv_criteria.size() - 1)
{
OGS_FATAL(
"The number of the locally coupled processes is greater "
"than or equal to the number of total coupled processes. "
"{}",
error_info);
}

INFO("There are {:d} locally coupled processes.",
local_coupling_processes.size());

if (local_coupling_processes.size() < 2)
{
OGS_FATAL(
"At least two locally coupled processes are required for "
"the local iteration solution! {} ",
error_info);
}
}
}

//! \ogs_file_param{prj__time_loop__output}
Expand Down Expand Up @@ -106,7 +150,8 @@ std::unique_ptr<TimeLoop> createTimeLoop(
auto per_process_data = createPerProcessData(
//! \ogs_file_param{prj__time_loop__processes}
config.getConfigSubtree("processes"), processes, nonlinear_solvers,
compensate_non_equilibrium_initial_residuum, fixed_times_for_output);
compensate_non_equilibrium_initial_residuum, fixed_times_for_output,
local_coupling_processes);

const bool use_staggered_scheme =
ranges::any_of(processes.begin(), processes.end(),
Expand Down Expand Up @@ -153,6 +198,6 @@ std::unique_ptr<TimeLoop> createTimeLoop(
return std::make_unique<TimeLoop>(
std::move(outputs), std::move(per_process_data),
max_coupling_iterations, std::move(global_coupling_conv_criteria),
start_time, end_time);
std::move(local_coupling_processes), start_time, end_time);
}
} // namespace ProcessLib
45 changes: 45 additions & 0 deletions ProcessLib/ThermoMechanicalPhaseField/Tests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,48 @@ AddTest(
DIFF_DATA
expected_slab_5_pcs_2_ts_1_t_1.000000.vtu slab_5_ts_1_t_1.000000.vtu phasefield phasefield 1e-6 0
)

AddTest(
NAME ThermoMechanicalPhaseField_3D_beam_local_coupling_temperature_displacement
PATH ThermoMechanicalPhaseField
RUNTIME 5
EXECUTABLE ogs
EXECUTABLE_ARGS beam3d_local_coupling_temperature_displacement.xml
WRAPPER time
TESTER vtkdiff
REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI)
DIFF_DATA
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_temperature_displacement_ts_1_t_10.000000.vtu displacement displacement 1e-5 0
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_temperature_displacement_ts_1_t_10.000000.vtu phasefield phasefield 1e-6 1e-4
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_temperature_displacement_ts_1_t_10.000000.vtu temperature temperature 1e-6 0
)

AddTest(
NAME ThermoMechanicalPhaseField_3D_beam_local_coupling_temperature_phasefield
PATH ThermoMechanicalPhaseField
RUNTIME 5
EXECUTABLE ogs
EXECUTABLE_ARGS beam3d_local_coupling_temperature_phasefield.xml
WRAPPER time
TESTER vtkdiff
REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI)
DIFF_DATA
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_temperature_phasefield_ts_1_t_10.000000.vtu displacement displacement 1e-5 0
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_temperature_phasefield_ts_1_t_10.000000.vtu phasefield phasefield 1e-6 1e-4
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_temperature_phasefield_ts_1_t_10.000000.vtu temperature temperature 1e-6 0
)

AddTest(
NAME ThermoMechanicalPhaseField_3D_beam_local_coupling_displacement_phasefield
PATH ThermoMechanicalPhaseField
RUNTIME 5
EXECUTABLE ogs
EXECUTABLE_ARGS beam3d_local_coupling_displacement_phasefield.xml
WRAPPER time
TESTER vtkdiff
REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI)
DIFF_DATA
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_displacement_phasefield_ts_1_t_10.000000.vtu displacement displacement 1e-5 0
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_displacement_phasefield_ts_1_t_10.000000.vtu phasefield phasefield 1e-6 1e-4
expected_beam3d_pcs_2_ts_1_t_10.000000.vtu beam3d_local_coupling_displacement_phasefield_ts_1_t_10.000000.vtu temperature temperature 1e-6 0
)
30 changes: 27 additions & 3 deletions ProcessLib/TimeLoop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "TimeLoop.h"

#include <range/v3/algorithm/any_of.hpp>
#include <range/v3/algorithm/contains.hpp>
#include <range/v3/view/map.hpp>

#include "BaseLib/Error.h"
#include "BaseLib/RunTime.h"
Expand Down Expand Up @@ -265,13 +267,15 @@ TimeLoop::TimeLoop(std::vector<Output>&& outputs,
const int global_coupling_max_iterations,
std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>&&
global_coupling_conv_crit,
std::map<std::string, int>&& local_coupling_processes,
const double start_time, const double end_time)
: _outputs{std::move(outputs)},
_per_process_data(std::move(per_process_data)),
_start_time(start_time),
_end_time(end_time),
_global_coupling_max_iterations(global_coupling_max_iterations),
_global_coupling_conv_crit(std::move(global_coupling_conv_crit))
_global_coupling_conv_crit(std::move(global_coupling_conv_crit)),
_local_coupling_processes(std::move(local_coupling_processes))
{
}

Expand Down Expand Up @@ -713,15 +717,27 @@ TimeLoop::solveCoupledEquationSystemsByStaggeredScheme(

NumLib::NonlinearSolverStatus nonlinear_solver_status{false, -1};
bool coupling_iteration_converged = true;
bool local_coupling_iteration_converged = true;
for (int global_coupling_iteration = 0;
global_coupling_iteration < _global_coupling_max_iterations;
global_coupling_iteration++, resetCouplingConvergenceCriteria())
{
// TODO(wenqing): use process name
coupling_iteration_converged = true;
bool local_iteration_converged = true;
for (auto const& process_data : _per_process_data)
{
auto const process_id = process_data->process_id;

bool const isLocalCouplingProcess = ranges::contains(
_local_coupling_processes | ranges::views::values, process_id);

if (!local_coupling_iteration_converged && !isLocalCouplingProcess)
{
coupling_iteration_converged = false;
continue;
}

BaseLib::RunTime time_timestep_process;
time_timestep_process.start();

Expand Down Expand Up @@ -760,11 +776,19 @@ TimeLoop::solveCoupledEquationSystemsByStaggeredScheme(
coupling_iteration_converged =
coupling_iteration_converged &&
_global_coupling_conv_crit[process_id]->isSatisfied();
if (isLocalCouplingProcess)
{
local_iteration_converged =
local_iteration_converged &&
_global_coupling_conv_crit[process_id]->isSatisfied();
}
}
MathLib::LinAlg::copy(x, x_old);
} // end of for (auto& process_data : _per_process_data)

if (coupling_iteration_converged && global_coupling_iteration > 0)
local_coupling_iteration_converged = local_iteration_converged;
if (local_coupling_iteration_converged &&
coupling_iteration_converged && global_coupling_iteration > 0)
{
break;
}
Expand All @@ -775,7 +799,7 @@ TimeLoop::solveCoupledEquationSystemsByStaggeredScheme(
}
}

if (!coupling_iteration_converged)
if (!coupling_iteration_converged || !local_coupling_iteration_converged)
{
WARN(
"The coupling iterations reaches its maximum number in time step "
Expand Down
4 changes: 4 additions & 0 deletions ProcessLib/TimeLoop.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class TimeLoop
const int global_coupling_max_iterations,
std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>&&
global_coupling_conv_crit,
std::map<std::string, int>&& local_coupling_processes,
const double start_time, const double end_time);

void initialize();
Expand Down Expand Up @@ -153,6 +154,9 @@ class TimeLoop
std::vector<std::unique_ptr<NumLib::ConvergenceCriterion>>
_global_coupling_conv_crit;

/// Processes that will be solved in a local iteration.
std::map<std::string, int> _local_coupling_processes;

/// Solutions of the previous coupling iteration for the convergence
/// criteria of the coupling iteration.
std::vector<GlobalVector*> _solutions_of_last_cpl_iteration;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<OpenGeoSysProjectDiff base_file="beam3d.prj">
<add sel="/*/time_loop/global_process_coupling/convergence_criteria" after_includes="true" pos="before">
<local_coupling_processes>
<process_name>displacement</process_name>
<process_name>phasefield</process_name>
</local_coupling_processes>
</add>
<add sel="/*/time_loop/processes/process[2]">
<process_name>displacement</process_name>
</add>
<add sel="/*/time_loop/processes/process[3]">
<process_name>phasefield</process_name>
</add>
<replace msel="/*/time_loop/output/prefix/text()">beam3d_local_coupling_displacement_phasefield</replace>
</OpenGeoSysProjectDiff>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<OpenGeoSysProjectDiff base_file="beam3d.prj">
<add sel="/*/time_loop/global_process_coupling/convergence_criteria" after_includes="true" pos="before">
<local_coupling_processes>
<process_name>temperature</process_name>
<process_name>displacement</process_name>
</local_coupling_processes>
</add>
<add sel="/*/time_loop/processes/process[1]">
<process_name>temperature</process_name>
</add>
<add sel="/*/time_loop/processes/process[2]">
<process_name>displacement</process_name>
</add>
<replace msel="/*/time_loop/output/prefix/text()">beam3d_local_coupling_temperature_displacement</replace>
</OpenGeoSysProjectDiff>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<OpenGeoSysProjectDiff base_file="beam3d.prj">
<add sel="/*/time_loop/global_process_coupling/convergence_criteria" after_includes="true" pos="before">
<local_coupling_processes>
<process_name>temperature</process_name>
<process_name>phasefield</process_name>
</local_coupling_processes>
</add>
<add sel="/*/time_loop/processes/process[1]">
<process_name>temperature</process_name>
</add>
<add sel="/*/time_loop/processes/process[3]">
<process_name>phasefield</process_name>
</add>
<replace msel="/*/time_loop/output/prefix/text()">beam3d_local_coupling_temperature_phasefield</replace>
</OpenGeoSysProjectDiff>

0 comments on commit 465f15f

Please sign in to comment.