Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IMEX protocols #5618

Merged
merged 2 commits into from
Dec 1, 2023
Merged

Conversation

wthrowe
Copy link
Member

@wthrowe wthrowe commented Nov 7, 2023

The examples for the ImplicitSector protocol that will be added later with the actual solver are

template <bool TestWithAnalyticSolution>
struct ImplicitSector : tt::ConformsTo<imex::protocols::ImplicitSector> {
  using tensors = tmpl::list<Var2, Var3>;
  using initial_guess = tmpl::conditional_t<TestWithAnalyticSolution,
                                            AnalyticSolution, InitialGuess>;
 
  struct SolveAttempt {
    using tags_from_evolution =
        tmpl::list<Var1, NonTensor, VariablesFromEvolution>;
    using simple_tags = tmpl::list<RecordPreparersForTest, VariablesTemporary>;
    using compute_tags = tmpl::list<SomeComputeTag>;
 
    using source_prep =
        tmpl::list<Preparer<PrepId::Shared>, Preparer<PrepId::Source>>;
    using jacobian_prep =
        tmpl::list<Preparer<PrepId::Shared>, Preparer<PrepId::Jacobian>>;
 
    using source = Source;
    using jacobian =
        tmpl::conditional_t<TestWithAnalyticSolution,
                            imex::NoJacobianBecauseSolutionIsAnalytic,
                            Jacobian>;
  };
 
  using solve_attempts = tmpl::list<SolveAttempt>;
};
struct AnalyticSolution {
  using return_tags = tmpl::list<Var2, Var3>;
  using argument_tags = tmpl::list<Var1, NonTensor>;
  static std::vector<imex::GuessResult> apply(
      const gsl::not_null<tnsr::II<DataVector, 2>*> var2,
      const gsl::not_null<tnsr::I<DataVector, 2>*> var3,
      const Scalar<DataVector>& var1, const double non_tensor,
      const Variables<tmpl::list<Var2, Var3>>& inhomogeneous_terms,
      const double implicit_weight) {
    // Solution for source terms
    // S[v2^ij] = v3^i v3^j - nt v2^ij
    // S[v3^i] = -v1 v3^i
 
    // Solving  v3^i = X - w v1 v3^i  gives  v3^i = X / (1 + w v1)
    tenex::evaluate<ti::I>(var3, get<Var3>(inhomogeneous_terms)(ti::I) /
                                     (1.0 + implicit_weight * var1()));
    tenex::evaluate<ti::I, ti::J>(
        var2, (get<Var2>(inhomogeneous_terms)(ti::I, ti::J) +
               implicit_weight * (*var3)(ti::I) * (*var3)(ti::J)) /
                  (1.0 + implicit_weight * non_tensor));
    return {get(var1).size(), imex::GuessResult::ExactSolution};
  }
};

Edit: decided to add two more examples:

struct Source {
  using return_tags = tmpl::list<::Tags::Source<Var2>, ::Tags::Source<Var3>>;
  using argument_tags = tmpl::list<Var1, Var2, Var3, NonTensor,
                                   RecordPreparersForTest, SomeComputeTagBase>;
 
  static void apply(const gsl::not_null<tnsr::II<DataVector, 2>*> source_var2,
                    const gsl::not_null<tnsr::I<DataVector, 2>*> source_var3,
                    const Scalar<DataVector>& var1,
                    const tnsr::II<DataVector, 2>& var2,
                    const tnsr::I<DataVector, 2>& var3, const double non_tensor,
                    const RecordPreparersForTest::type& prep_run_values,
                    const double compute_tag_value) {
struct Jacobian {
  using return_tags =
      tmpl::list<imex::Tags::Jacobian<Var2, ::Tags::Source<Var2>>,
                 imex::Tags::Jacobian<Var3, ::Tags::Source<Var2>>,
                 imex::Tags::Jacobian<Var3, ::Tags::Source<Var3>>>;
  using argument_tags =
      tmpl::list<Var1, Var3, NonTensor, RecordPreparersForTest>;
 
  static void apply(const gsl::not_null<tnsr::iiJJ<DataVector, 2>*> dvar2_dvar2,
                    const gsl::not_null<tnsr::iJJ<DataVector, 2>*> dvar2_dvar3,
                    const gsl::not_null<tnsr::iJ<DataVector, 2>*> dvar3_dvar3,
                    const Scalar<DataVector>& var1,
                    const tnsr::I<DataVector, 2>& var3, const double non_tensor,
                    const RecordPreparersForTest::type& prep_run_values) {

Proposed changes

Upgrade instructions

Code review checklist

  • The code is documented and the documentation renders correctly. Run
    make doc to generate the documentation locally into BUILD_DIR/docs/html.
    Then open index.html.
  • The code follows the stylistic and code quality guidelines listed in the
    code review guide.
  • The PR lists upgrade instructions and is labeled bugfix or
    new feature if appropriate.

Further comments

@wthrowe wthrowe added the new design technical with long discussions expected label Nov 7, 2023
@yoonso0-0 yoonso0-0 self-requested a review November 8, 2023 06:57
Copy link
Member

@nilsdeppe nilsdeppe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can squash any changes directly

@@ -0,0 +1,28 @@
# Distributed under the MIT License.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't there be a add_subdirectory one level higher in this commit?

@@ -0,0 +1,26 @@
# Distributed under the MIT License.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't there be a add_subdirectory one level higher in this commit?

///
/// In addition to the usual requirements for an evolution system, an
/// IMEX system must specify an `implicit_sectors` typelist of structs
/// conforming to protocols::ImplicitSector, each of which described
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

described -> describes?

Copy link
Contributor

@yoonso0-0 yoonso0-0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor fix requests on documentation as the first customer :)

Please squash everything

#include "Utilities/TMPL.hpp"

namespace imex {
/// Accuracy of a guess returned from an implicit sector's
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Accuracy -> Type?

/// `std::vector<GuessResult>` indicating, for each point, whether
/// the implicit equation has been solved analytically or whether
/// the numerical solve should continue. An empty return is
/// equivalent to `GuessResult::InitialGuess` for every point. When
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imex::GuessResult::InitialGuess

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q. Does this mean that an empty return is exactly same as using imex::GuessExplicitResult ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. GuessExplicitResult guesses the explicit result. You are free to guess something else. I added a bit to the documentation of the GuessExplicitResult struct. Do you think something should be added here?

/// equivalent to `GuessResult::InitialGuess` for every point. When
/// this is called, the sector variables will have the value from
/// the explicit part of the time step. This mutator will not be
/// called if the implicit weight is zero, as a system-independent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the comment after ".. weight is zero" is a little confusing, since implicit weight being zero means no implicit step is required, not that it's analytically invertible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort of. The step becomes explicit and no source evaluations are performed, but there is still a step. Admittedly, calling the result of solving y = constant for y an analytic solution is a bit grandiose, so I changed it to "This mutator will not be called if the implicit weight is zero, as the solution is trivial in that case.".

/// * `tags_from_evolution` for tags to be made available from the
/// evolution DataBox. Volume quantities will be reduced to
/// have one grid point, with the appropriate value for the
/// point being solved for.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please mention that this excludes the tags from tensors (that needs to be solved).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and also added a check to the protocol verification below.

Copy link
Member Author

@wthrowe wthrowe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also added a sanity check now assumed after some local changes to the solver.

/// `std::vector<GuessResult>` indicating, for each point, whether
/// the implicit equation has been solved analytically or whether
/// the numerical solve should continue. An empty return is
/// equivalent to `GuessResult::InitialGuess` for every point. When
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. GuessExplicitResult guesses the explicit result. You are free to guess something else. I added a bit to the documentation of the GuessExplicitResult struct. Do you think something should be added here?

/// equivalent to `GuessResult::InitialGuess` for every point. When
/// this is called, the sector variables will have the value from
/// the explicit part of the time step. This mutator will not be
/// called if the implicit weight is zero, as a system-independent
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort of. The step becomes explicit and no source evaluations are performed, but there is still a step. Admittedly, calling the result of solving y = constant for y an analytic solution is a bit grandiose, so I changed it to "This mutator will not be called if the implicit weight is zero, as the solution is trivial in that case.".

/// * `tags_from_evolution` for tags to be made available from the
/// evolution DataBox. Volume quantities will be reduced to
/// have one grid point, with the appropriate value for the
/// point being solved for.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and also added a check to the protocol verification below.

Copy link
Contributor

@yoonso0-0 yoonso0-0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Please squash

/// `std::vector<GuessResult>` indicating, for each point, whether
/// the implicit equation has been solved analytically or whether
/// the numerical solve should continue. An empty return is
/// equivalent to `imex::GuessResult::InitialGuess` for every point.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a short extension like "empty return is equivalent to returning GuessResult::InitialGuess everywhere and the numerical solve will be done for every point"?

@nilsdeppe
Copy link
Member

I'm also happy! Please go ahead and squash

@nilsdeppe nilsdeppe merged commit 6ab1b8c into sxs-collaboration:develop Dec 1, 2023
21 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new design technical with long discussions expected
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants