diff --git a/ProcessLib/AbstractJacobianAssembler.h b/ProcessLib/AbstractJacobianAssembler.h new file mode 100644 index 0000000000000000000000000000000000000000..213c51dc142e3b685959e5fc7e32fd85494631dd --- /dev/null +++ b/ProcessLib/AbstractJacobianAssembler.h @@ -0,0 +1,35 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef PROCESSLIB_ABSTRACTJACOBIANASSEMBLER_H +#define PROCESSLIB_ABSTRACTJACOBIANASSEMBLER_H + +#include <vector> + +namespace ProcessLib +{ +class LocalAssemblerInterface; + +class AbstractJacobianAssembler +{ +public: + virtual void assembleWithJacobian( + LocalAssemblerInterface& local_assembler, double const t, + std::vector<double> const& local_x, + std::vector<double> const& local_xdot, const double dxdot_dx, + const double dx_dx, std::vector<double>& local_M_data, + std::vector<double>& local_K_data, std::vector<double>& local_b_data, + std::vector<double>& local_Jac_data) = 0; + + virtual ~AbstractJacobianAssembler() = default; +}; + +} // ProcessLib + +#endif // PROCESSLIB_ABSTRACTJACOBIANASSEMBLER_H diff --git a/ProcessLib/AnalyticalJacobianAssembler.cpp b/ProcessLib/AnalyticalJacobianAssembler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8691fa0eb741ee7ccac74cb979f94ec9b021c870 --- /dev/null +++ b/ProcessLib/AnalyticalJacobianAssembler.cpp @@ -0,0 +1,27 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "AnalyticalJacobianAssembler.h" +#include "LocalAssemblerInterface.h" + +namespace ProcessLib +{ +void AnalyticalJacobianAssembler::assembleWithJacobian( + LocalAssemblerInterface& local_assembler, double const t, + std::vector<double> const& local_x, std::vector<double> const& local_xdot, + const double dxdot_dx, const double dx_dx, + std::vector<double>& local_M_data, std::vector<double>& local_K_data, + std::vector<double>& local_b_data, + std::vector<double>& local_Jac_data) +{ + local_assembler.assembleWithJacobian(t, local_x, local_xdot, dxdot_dx, + dx_dx, local_M_data, local_K_data, + local_b_data, local_Jac_data); +} +} // ProcessLib diff --git a/ProcessLib/AnalyticalJacobianAssembler.h b/ProcessLib/AnalyticalJacobianAssembler.h new file mode 100644 index 0000000000000000000000000000000000000000..56ed30334a158ce802ba52e7142ddebe94c89918 --- /dev/null +++ b/ProcessLib/AnalyticalJacobianAssembler.h @@ -0,0 +1,36 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef PROCESSLIB_ANALYTICALJACOBIANASSEMBLER_H +#define PROCESSLIB_ANALYTICALJACOBIANASSEMBLER_H + +#include "AbstractJacobianAssembler.h" + +namespace BaseLib +{ +class ConfigTree; +} + +namespace ProcessLib +{ +class AnalyticalJacobianAssembler final : public AbstractJacobianAssembler +{ +public: + void assembleWithJacobian( + LocalAssemblerInterface& local_assembler, double const t, + std::vector<double> const& local_x, + std::vector<double> const& local_xdot, const double dxdot_dx, + const double dx_dx, std::vector<double>& local_M_data, + std::vector<double>& local_K_data, std::vector<double>& local_b_data, + std::vector<double>& local_Jac_data) override; +}; + +} // ProcessLib + +#endif // PROCESSLIB_ANALYTICALJACOBIANASSEMBLER_H diff --git a/ProcessLib/CentralDifferencesJacobianAssembler.cpp b/ProcessLib/CentralDifferencesJacobianAssembler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f770a68931de361ea3e1182b088c502645df44b --- /dev/null +++ b/ProcessLib/CentralDifferencesJacobianAssembler.cpp @@ -0,0 +1,160 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "CentralDifferencesJacobianAssembler.h" +#include "BaseLib/Error.h" +#include "MathLib/LinAlg/Eigen/EigenMapTools.h" +#include "LocalAssemblerInterface.h" + +namespace ProcessLib +{ +CentralDifferencesJacobianAssembler::CentralDifferencesJacobianAssembler( + std::vector<double>&& absolute_epsilons) + : _absolute_epsilons(std::move(absolute_epsilons)) +{ +} + +void CentralDifferencesJacobianAssembler::assembleWithJacobian( + LocalAssemblerInterface& local_assembler, const double t, + const std::vector<double>& local_x_data, + const std::vector<double>& local_xdot_data, const double dxdot_dx, + const double dx_dx, std::vector<double>& local_M_data, + std::vector<double>& local_K_data, std::vector<double>& local_b_data, + std::vector<double>& local_Jac_data) +{ + // TODO do not check in every call. + if (local_x_data.size() % _absolute_epsilons.size() != 0) { + OGS_FATAL( + "The number of specified epsilons and the number of local d.o.f.s " + "do not match"); + } + + auto const num_r_c = + static_cast<Eigen::MatrixXd::Index>(local_x_data.size()); + + auto const local_x = MathLib::toVector(local_x_data, num_r_c); + auto const local_xdot = MathLib::toVector(local_xdot_data, num_r_c); + + auto local_Jac = MathLib::toZeroedMatrix(local_Jac_data, num_r_c, num_r_c); + _local_x_perturbed_data = local_x_data; + + auto const num_dofs_per_component = + local_x_data.size() / _absolute_epsilons.size(); + + // Residual res := M xdot + K x - b + // Computing Jac := dres/dx + // = M dxdot/dx + dM/dx xdot + K dx/dx + dK/dx x - db/dx + // (Note: dM/dx and dK/dx actually have the second and + // third index transposed.) + // The loop computes the dM/dx, dK/dx and db/dx terms, the rest is computed + // afterwards. + for (Eigen::MatrixXd::Index i = 0; i < num_r_c; ++i) + { + auto const component = i / num_dofs_per_component; + auto const eps = _absolute_epsilons[component]; + + _local_x_perturbed_data[i] += eps; + local_assembler.assemble(t, _local_x_perturbed_data, local_M_data, + local_K_data, local_b_data); + + _local_x_perturbed_data[i] = local_x_data[i] - eps; + local_assembler.assemble(t, _local_x_perturbed_data, _local_M_data, + _local_K_data, _local_b_data); + + _local_x_perturbed_data[i] = local_x_data[i]; + + if (!local_M_data.empty()) { + auto const local_M_p = + MathLib::toMatrix(local_M_data, num_r_c, num_r_c); + auto const local_M_m = + MathLib::toMatrix(_local_M_data, num_r_c, num_r_c); + local_Jac.col(i).noalias() += + // dM/dxi * x_dot + (local_M_p - local_M_m) * local_xdot / (2.0 * eps); + local_M_data.clear(); + _local_M_data.clear(); + } + if (!local_K_data.empty()) { + auto const local_K_p = + MathLib::toMatrix(local_K_data, num_r_c, num_r_c); + auto const local_K_m = + MathLib::toMatrix(_local_K_data, num_r_c, num_r_c); + local_Jac.col(i).noalias() += + // dK/dxi * x + (local_K_p - local_K_m) * local_x / (2.0 * eps); + local_K_data.clear(); + _local_K_data.clear(); + } + if (!local_b_data.empty()) { + auto const local_b_p = MathLib::toVector(local_b_data, num_r_c); + auto const local_b_m = MathLib::toVector(_local_b_data, num_r_c); + local_Jac.col(i).noalias() -= + // db/dxi + (local_b_p - local_b_m) / (2.0 * eps); + local_b_data.clear(); + _local_b_data.clear(); + } + } + + // Assemble with unperturbed local x. + local_assembler.assemble(t, local_x_data, local_M_data, local_K_data, + local_b_data); + + // Compute remaining terms of the Jacobian. + if (dxdot_dx != 0 && !local_M_data.empty()) { + auto local_M = MathLib::toMatrix(local_M_data, num_r_c, num_r_c); + local_Jac.noalias() += local_M * dxdot_dx; + } + if (dx_dx != 0 && !local_K_data.empty()) { + auto local_K = MathLib::toMatrix(local_K_data, num_r_c, num_r_c); + local_Jac.noalias() += local_K * dx_dx; + } +} + +std::unique_ptr<CentralDifferencesJacobianAssembler> +createCentralDifferencesJacobianAssembler(BaseLib::ConfigTree const& config) +{ + config.checkConfigParameter("type", "CentralDifferences"); + + // TODO make non-optional. + auto rel_eps = config.getConfigParameterOptional<std::vector<double>>( + "relative_epsilons"); + auto comp_mag = config.getConfigParameterOptional<std::vector<double>>( + "component_magnitudes"); + + if (!!rel_eps != !!comp_mag) { + OGS_FATAL( + "Either both or none of <relative_epsilons> and " + "<component_magnitudes> have to be specified."); + } + + std::vector<double> abs_eps; + + if (rel_eps) { + if (rel_eps->size() != comp_mag->size()) { + OGS_FATAL( + "The numbers of components of <relative_epsilons> and " + "<component_magnitudes> do not match."); + } + + abs_eps.resize(rel_eps->size()); + for (std::size_t i=0; i<rel_eps->size(); ++i) { + abs_eps[i] = (*rel_eps)[i] * (*comp_mag)[i]; + } + } else { + // By default 1e-8 is used as epsilon for all components. + // TODO: remove this default value. + abs_eps.emplace_back(1e-8); + } + + return std::unique_ptr<CentralDifferencesJacobianAssembler>( + new CentralDifferencesJacobianAssembler(std::move(abs_eps))); +} + +} // ProcessLib diff --git a/ProcessLib/CentralDifferencesJacobianAssembler.h b/ProcessLib/CentralDifferencesJacobianAssembler.h new file mode 100644 index 0000000000000000000000000000000000000000..38b1aad7b301f2831428186d728155ef09b40807 --- /dev/null +++ b/ProcessLib/CentralDifferencesJacobianAssembler.h @@ -0,0 +1,50 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef PROCESSLIB_CENTRALDIFFERENCESJACOBIANASSEMBLER_H +#define PROCESSLIB_CENTRALDIFFERENCESJACOBIANASSEMBLER_H + +#include <memory> +#include "AbstractJacobianAssembler.h" + +namespace BaseLib +{ +class ConfigTree; +} // BaseLib + +namespace ProcessLib +{ +class CentralDifferencesJacobianAssembler : public AbstractJacobianAssembler +{ +public: + explicit CentralDifferencesJacobianAssembler( + std::vector<double>&& absolute_epsilons); + + void assembleWithJacobian( + LocalAssemblerInterface& local_assembler, double const t, + std::vector<double> const& local_x, + std::vector<double> const& local_xdot, const double dxdot_dx, + const double dx_dx, std::vector<double>& local_M_data, + std::vector<double>& local_K_data, std::vector<double>& local_b_data, + std::vector<double>& local_Jac_data) override; + +private: + std::vector<double> const _absolute_epsilons; + std::vector<double> _local_M_data; + std::vector<double> _local_K_data; + std::vector<double> _local_b_data; + std::vector<double> _local_x_perturbed_data; +}; + +std::unique_ptr<CentralDifferencesJacobianAssembler> +createCentralDifferencesJacobianAssembler(BaseLib::ConfigTree const& config); + +} // ProcessLib + +#endif // PROCESSLIB_CENTRALDIFFERENCESJACOBIANASSEMBLER_H diff --git a/ProcessLib/CreateJacobianAssembler.cpp b/ProcessLib/CreateJacobianAssembler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4b6788eab2fb6802aaafb02b0d7f328757965fe --- /dev/null +++ b/ProcessLib/CreateJacobianAssembler.cpp @@ -0,0 +1,37 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "CreateJacobianAssembler.h" +#include "BaseLib/Error.h" + +#include "AnalyticalJacobianAssembler.h" +#include "CentralDifferencesJacobianAssembler.h" + +namespace ProcessLib +{ +std::unique_ptr<AbstractJacobianAssembler> createJacobianAssembler( + boost::optional<BaseLib::ConfigTree> const& config) +{ + if (!config) + return std::unique_ptr<AbstractJacobianAssembler>( + new AnalyticalJacobianAssembler); + + auto const type = config->peekConfigParameter<std::string>("type"); + + if (type == "Analytical") { + config->ignoreConfigParameter("type"); + return std::unique_ptr<AbstractJacobianAssembler>( + new AnalyticalJacobianAssembler); + } else if (type == "CentralDifferences") { + return createCentralDifferencesJacobianAssembler(*config); + } + + OGS_FATAL("Unknown Jacobian assembler type: `%s'.", type.c_str()); +} +} // ProcessLib diff --git a/ProcessLib/CreateJacobianAssembler.h b/ProcessLib/CreateJacobianAssembler.h new file mode 100644 index 0000000000000000000000000000000000000000..d539beafb466d6c72011357a589eaa2b91affb52 --- /dev/null +++ b/ProcessLib/CreateJacobianAssembler.h @@ -0,0 +1,23 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef PROCESSLIB_CREATEJACOBIANASSEMBLER_H +#define PROCESSLIB_CREATEJACOBIANASSEMBLER_H + +#include "BaseLib/ConfigTree.h" + +namespace ProcessLib +{ +class AbstractJacobianAssembler; + +std::unique_ptr<AbstractJacobianAssembler> createJacobianAssembler( + boost::optional<BaseLib::ConfigTree> const& config); +} // ProcessLib + +#endif // PROCESSLIB_CREATEJACOBIANASSEMBLER_H