From 9d49999bff0140f760b1c89b1573b06bbb748afe Mon Sep 17 00:00:00 2001 From: David Andrs Date: Sun, 5 Jan 2025 07:49:21 -0700 Subject: [PATCH 1/2] refact: SNESolver is created via polymorphic function --- include/godzilla/ExplicitDGLinearProblem.h | 1 + include/godzilla/ExplicitFELinearProblem.h | 1 + include/godzilla/ExplicitFVLinearProblem.h | 1 + include/godzilla/ImplicitFENonlinearProblem.h | 2 ++ include/godzilla/NonlinearProblem.h | 3 +++ src/ExplicitDGLinearProblem.cpp | 9 +++++++-- src/ExplicitFELinearProblem.cpp | 9 +++++++-- src/ExplicitFVLinearProblem.cpp | 9 +++++++-- src/ImplicitFENonlinearProblem.cpp | 10 +++++++--- src/NonlinearProblem.cpp | 17 ++++++++++++----- 10 files changed, 48 insertions(+), 14 deletions(-) diff --git a/include/godzilla/ExplicitDGLinearProblem.h b/include/godzilla/ExplicitDGLinearProblem.h index 20eb4f20..85f688f6 100644 --- a/include/godzilla/ExplicitDGLinearProblem.h +++ b/include/godzilla/ExplicitDGLinearProblem.h @@ -33,6 +33,7 @@ class ExplicitDGLinearProblem : void post_step() override; private: + SNESolver create_sne_solver() override; void compute_residual(const Vector & x, Vector & f) final; void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) final; diff --git a/include/godzilla/ExplicitFELinearProblem.h b/include/godzilla/ExplicitFELinearProblem.h index 112f214d..0b9672bb 100644 --- a/include/godzilla/ExplicitFELinearProblem.h +++ b/include/godzilla/ExplicitFELinearProblem.h @@ -33,6 +33,7 @@ class ExplicitFELinearProblem : public FENonlinearProblem, public ExplicitProble void post_step() override; private: + SNESolver create_sne_solver() override; void compute_rhs_local(Real time, const Vector & x, Vector & F) override; void compute_rhs_function_fem(Real time, const Vector & loc_x, Vector & loc_g); diff --git a/include/godzilla/ExplicitFVLinearProblem.h b/include/godzilla/ExplicitFVLinearProblem.h index 718f007f..108dd055 100644 --- a/include/godzilla/ExplicitFVLinearProblem.h +++ b/include/godzilla/ExplicitFVLinearProblem.h @@ -32,6 +32,7 @@ class ExplicitFVLinearProblem : void post_step() override; private: + SNESolver create_sne_solver() override; void compute_rhs_local(Real time, const Vector & x, Vector & F) override; void compute_residual(const Vector & x, Vector & f) final; void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) final; diff --git a/include/godzilla/ImplicitFENonlinearProblem.h b/include/godzilla/ImplicitFENonlinearProblem.h index b69261ea..4e618316 100644 --- a/include/godzilla/ImplicitFENonlinearProblem.h +++ b/include/godzilla/ImplicitFENonlinearProblem.h @@ -38,6 +38,8 @@ class ImplicitFENonlinearProblem : public FENonlinearProblem, public TransientPr } private: + SNESolver create_sne_solver() override; + /// Form the local residual `f` from the local input `x` /// /// @param time The time diff --git a/include/godzilla/NonlinearProblem.h b/include/godzilla/NonlinearProblem.h index e88e0bb1..b112f416 100644 --- a/include/godzilla/NonlinearProblem.h +++ b/include/godzilla/NonlinearProblem.h @@ -79,6 +79,9 @@ class NonlinearProblem : public Problem { void solve(); private: + /// Create a SNESolver + virtual SNESolver create_sne_solver(); + /// Set up line search virtual void set_up_line_search(); diff --git a/src/ExplicitDGLinearProblem.cpp b/src/ExplicitDGLinearProblem.cpp index d7e9dfb3..140711ed 100644 --- a/src/ExplicitDGLinearProblem.cpp +++ b/src/ExplicitDGLinearProblem.cpp @@ -41,13 +41,18 @@ ExplicitDGLinearProblem::get_step_num() const return ExplicitProblemInterface::get_step_number(); } +SNESolver +ExplicitDGLinearProblem::create_sne_solver() +{ + return ExplicitProblemInterface::get_snes(); +} + void ExplicitDGLinearProblem::init() { CALL_STACK_MSG(); ExplicitProblemInterface::init(); - auto snes = ExplicitProblemInterface::get_snes(); - NonlinearProblem::set_snes(snes); + NonlinearProblem::init(); DGProblemInterface::init(); } diff --git a/src/ExplicitFELinearProblem.cpp b/src/ExplicitFELinearProblem.cpp index 18942506..8d8fbfc7 100644 --- a/src/ExplicitFELinearProblem.cpp +++ b/src/ExplicitFELinearProblem.cpp @@ -69,13 +69,18 @@ ExplicitFELinearProblem::get_step_num() const return ExplicitProblemInterface::get_step_number(); } +SNESolver +ExplicitFELinearProblem::create_sne_solver() +{ + return ExplicitProblemInterface::get_snes(); +} + void ExplicitFELinearProblem::init() { CALL_STACK_MSG(); ExplicitProblemInterface::init(); - auto snes = ExplicitProblemInterface::get_snes(); - NonlinearProblem::set_snes(snes); + NonlinearProblem::init(); FEProblemInterface::init(); // so that the call to DMTSCreateRHSMassMatrix would form the mass matrix for (Int i = 0; i < get_num_fields(); i++) diff --git a/src/ExplicitFVLinearProblem.cpp b/src/ExplicitFVLinearProblem.cpp index 4f3787c0..4d991421 100644 --- a/src/ExplicitFVLinearProblem.cpp +++ b/src/ExplicitFVLinearProblem.cpp @@ -39,13 +39,18 @@ ExplicitFVLinearProblem::get_step_num() const return ExplicitProblemInterface::get_step_number(); } +SNESolver +ExplicitFVLinearProblem::create_sne_solver() +{ + return ExplicitProblemInterface::get_snes(); +} + void ExplicitFVLinearProblem::init() { CALL_STACK_MSG(); ExplicitProblemInterface::init(); - auto snes = ExplicitProblemInterface::get_snes(); - NonlinearProblem::set_snes(snes); + NonlinearProblem::init(); FVProblemInterface::init(); } diff --git a/src/ImplicitFENonlinearProblem.cpp b/src/ImplicitFENonlinearProblem.cpp index b839af22..a47a31f2 100644 --- a/src/ImplicitFENonlinearProblem.cpp +++ b/src/ImplicitFENonlinearProblem.cpp @@ -70,14 +70,18 @@ ImplicitFENonlinearProblem::get_step_num() const return TransientProblemInterface::get_step_number(); } +SNESolver +ImplicitFENonlinearProblem::create_sne_solver() +{ + return TransientProblemInterface::get_snes(); +} + void ImplicitFENonlinearProblem::init() { CALL_STACK_MSG(); TransientProblemInterface::init(); - auto snes = TransientProblemInterface::get_snes(); - NonlinearProblem::set_snes(snes); - FEProblemInterface::init(); + FENonlinearProblem::init(); } void diff --git a/src/NonlinearProblem.cpp b/src/NonlinearProblem.cpp index a9415076..158287c6 100644 --- a/src/NonlinearProblem.cpp +++ b/src/NonlinearProblem.cpp @@ -131,15 +131,22 @@ NonlinearProblem::get_ksp() const return this->ksp; } +SNESolver +NonlinearProblem::create_sne_solver() +{ + CALL_STACK_MSG(); + SNESolver snes; + snes.create(get_comm()); + snes.set_dm(get_dm()); + PETSC_CHECK(DMSetApplicationContext(get_dm(), this)); + return snes; +} + void NonlinearProblem::init() { CALL_STACK_MSG(); - DM dm = get_dm(); - this->snes.create(get_comm()); - this->snes.set_dm(dm); - PETSC_CHECK(DMSetApplicationContext(dm, this)); - set_snes(this->snes); + set_snes(create_sne_solver()); } void From df4a292b4fdfad5535977502377157d13f3ef405 Mon Sep 17 00:00:00 2001 From: David Andrs Date: Sun, 5 Jan 2025 08:56:07 -0700 Subject: [PATCH 2/2] refact: NonlinearProblem uses delegates to set {residual|Jacobian} evaluation functions --- include/godzilla/ExplicitDGLinearProblem.h | 2 - include/godzilla/ExplicitFVLinearProblem.h | 2 - include/godzilla/FENonlinearProblem.h | 4 +- include/godzilla/NonlinearProblem.h | 27 ++++++++-- src/ExplicitDGLinearProblem.cpp | 10 ---- src/ExplicitFVLinearProblem.cpp | 10 ---- src/NonlinearProblem.cpp | 2 - test/src/NonlinearProblem_test.cpp | 61 +++++++++++++--------- 8 files changed, 62 insertions(+), 56 deletions(-) diff --git a/include/godzilla/ExplicitDGLinearProblem.h b/include/godzilla/ExplicitDGLinearProblem.h index 85f688f6..c00312fa 100644 --- a/include/godzilla/ExplicitDGLinearProblem.h +++ b/include/godzilla/ExplicitDGLinearProblem.h @@ -34,8 +34,6 @@ class ExplicitDGLinearProblem : private: SNESolver create_sne_solver() override; - void compute_residual(const Vector & x, Vector & f) final; - void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) final; public: static Parameters parameters(); diff --git a/include/godzilla/ExplicitFVLinearProblem.h b/include/godzilla/ExplicitFVLinearProblem.h index 108dd055..d5cfbc3e 100644 --- a/include/godzilla/ExplicitFVLinearProblem.h +++ b/include/godzilla/ExplicitFVLinearProblem.h @@ -34,8 +34,6 @@ class ExplicitFVLinearProblem : private: SNESolver create_sne_solver() override; void compute_rhs_local(Real time, const Vector & x, Vector & F) override; - void compute_residual(const Vector & x, Vector & f) final; - void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) final; public: static Parameters parameters(); diff --git a/include/godzilla/FENonlinearProblem.h b/include/godzilla/FENonlinearProblem.h index 14c234d2..860e92f5 100644 --- a/include/godzilla/FENonlinearProblem.h +++ b/include/godzilla/FENonlinearProblem.h @@ -115,8 +115,8 @@ class FENonlinearProblem : public NonlinearProblem, public FEProblemInterface { const IndexSet & facets); private: - void compute_residual(const Vector & x, Vector & f) override; - void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) override; + void compute_residual(const Vector & x, Vector & f); + void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp); virtual void compute_boundary(Vector & x); enum State { INITIAL, FINAL } state; diff --git a/include/godzilla/NonlinearProblem.h b/include/godzilla/NonlinearProblem.h index b112f416..dbb26fc8 100644 --- a/include/godzilla/NonlinearProblem.h +++ b/include/godzilla/NonlinearProblem.h @@ -78,6 +78,30 @@ class NonlinearProblem : public Problem { void solve(); + /// Set residual evaluation function + /// + /// @tparam T C++ class type + /// @param instance Instance of class T + /// @param method Member function in class T to compute residual + template + void + set_function(T * instance, void (T::*method)(const Vector &, Vector &)) + { + this->snes.set_function(this->r, instance, method); + } + + /// Set Jacobian evaluation function + /// + /// @tparam T C++ class type + /// @param instance Instance of class T + /// @param method Member function in class T to compute Jacobian + template + void + set_jacobian(T * instance, void (T::*method)(const Vector &, Matrix &, Matrix &)) + { + this->snes.set_jacobian(this->J, this->J, instance, method); + } + private: /// Create a SNESolver virtual SNESolver create_sne_solver(); @@ -94,9 +118,6 @@ class NonlinearProblem : public Problem { /// Method for setting matrix properties virtual void set_up_matrix_properties(); - virtual void compute_residual(const Vector & x, Vector & f) = 0; - virtual void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) = 0; - /// Nonlinear solver SNESolver snes; /// Linear solver diff --git a/src/ExplicitDGLinearProblem.cpp b/src/ExplicitDGLinearProblem.cpp index 140711ed..823e4030 100644 --- a/src/ExplicitDGLinearProblem.cpp +++ b/src/ExplicitDGLinearProblem.cpp @@ -134,14 +134,4 @@ ExplicitDGLinearProblem::post_step() output(EXECUTE_ON_TIMESTEP); } -void -ExplicitDGLinearProblem::compute_residual(const Vector & x, Vector & f) -{ -} - -void -ExplicitDGLinearProblem::compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) -{ -} - } // namespace godzilla diff --git a/src/ExplicitFVLinearProblem.cpp b/src/ExplicitFVLinearProblem.cpp index 4d991421..5a555e7a 100644 --- a/src/ExplicitFVLinearProblem.cpp +++ b/src/ExplicitFVLinearProblem.cpp @@ -129,16 +129,6 @@ ExplicitFVLinearProblem::compute_rhs_local(Real time, const Vector & x, Vector & PETSC_CHECK(DMPlexTSComputeRHSFunctionFVM(get_dm(), time, x, F, this)); } -void -ExplicitFVLinearProblem::compute_residual(const Vector & x, Vector & f) -{ -} - -void -ExplicitFVLinearProblem::compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) -{ -} - void ExplicitFVLinearProblem::post_step() { diff --git a/src/NonlinearProblem.cpp b/src/NonlinearProblem.cpp index 158287c6..b004e3b4 100644 --- a/src/NonlinearProblem.cpp +++ b/src/NonlinearProblem.cpp @@ -198,8 +198,6 @@ void NonlinearProblem::set_up_callbacks() { CALL_STACK_MSG(); - this->snes.set_function(this->r, this, &NonlinearProblem::compute_residual); - this->snes.set_jacobian(this->J, this->J, this, &NonlinearProblem::compute_jacobian); } void diff --git a/test/src/NonlinearProblem_test.cpp b/test/src/NonlinearProblem_test.cpp index 61835ecb..3d1a5904 100644 --- a/test/src/NonlinearProblem_test.cpp +++ b/test/src/NonlinearProblem_test.cpp @@ -20,8 +20,10 @@ class G1DTestNonlinearProblem : public NonlinearProblem { void call_initial_guess(); protected: - void compute_residual(const Vector & x, Vector & f) override; - void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) override; + void set_up_callbacks() override; + void compute_residual(const Vector & x, Vector & f); + void compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp); + PetscSection s; }; @@ -56,6 +58,13 @@ G1DTestNonlinearProblem::call_initial_guess() NonlinearProblem::set_up_initial_guess(); } +void +G1DTestNonlinearProblem::set_up_callbacks() +{ + set_function(this, &G1DTestNonlinearProblem::compute_residual); + set_jacobian(this, &G1DTestNonlinearProblem::compute_jacobian); +} + void G1DTestNonlinearProblem::compute_residual(const Vector & x, Vector & f) { @@ -139,8 +148,29 @@ TEST(NonlinearProblemTest, run) MOCK_METHOD(void, set_up_initial_guess, ()); MOCK_METHOD(void, on_initial, ()); - MOCK_METHOD(void, compute_residual, (const Vector & x, Vector & f)); - MOCK_METHOD(void, compute_jacobian, (const Vector & x, Matrix & J, Matrix & Jp)); + + void + compute_residual(const Vector & x, Vector & f) + { + f.zero(); + this->compute_residual_called = true; + } + + void + compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) + { + this->compute_jacobian_called = true; + } + + void + set_up_callbacks() + { + set_function(this, &MockNonlinearProblem::compute_residual); + set_jacobian(this, &MockNonlinearProblem::compute_jacobian); + } + + bool compute_residual_called = false; + bool compute_jacobian_called = false; }; TestApp app; @@ -159,8 +189,9 @@ TEST(NonlinearProblemTest, run) EXPECT_CALL(prob, set_up_initial_guess); EXPECT_CALL(prob, on_initial); - EXPECT_CALL(prob, compute_residual); prob.run(); + EXPECT_TRUE(prob.compute_residual_called); + EXPECT_FALSE(prob.compute_jacobian_called); } TEST(NonlinearProblemTest, line_search_type) @@ -174,16 +205,6 @@ TEST(NonlinearProblemTest, line_search_type) { return NonlinearProblem::get_snes(); } - - void - compute_residual(const Vector & x, Vector & F) override - { - } - - void - compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) override - { - } }; TestApp app; @@ -219,16 +240,6 @@ TEST(NonlinearProblemTest, invalid_line_search_type) class MockNonlinearProblem : public NonlinearProblem { public: explicit MockNonlinearProblem(const Parameters & params) : NonlinearProblem(params) {} - - void - compute_residual(const Vector & x, Vector & f) override - { - } - - void - compute_jacobian(const Vector & x, Matrix & J, Matrix & Jp) override - { - } }; TestApp app;