From d888bde8c6f41bad81a48a764ec773d11ed34e07 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Wed, 4 Sep 2024 20:52:07 +0200 Subject: [PATCH 01/63] add documentation --- .github/workflows/build_doc.yaml | 1 + doc/conf.py | 1 + doc/finiteVolume/DSL.rst | 4 - doc/finiteVolume/cellCentred/DSL.rst | 230 +++++++++++++++++++++++++ doc/finiteVolume/cellCentred/index.rst | 1 - 5 files changed, 232 insertions(+), 5 deletions(-) delete mode 100644 doc/finiteVolume/DSL.rst create mode 100644 doc/finiteVolume/cellCentred/DSL.rst diff --git a/.github/workflows/build_doc.yaml b/.github/workflows/build_doc.yaml index b01189cfc..6c84aa5af 100644 --- a/.github/workflows/build_doc.yaml +++ b/.github/workflows/build_doc.yaml @@ -21,6 +21,7 @@ jobs: && pip3 install furo && pip3 install breathe && pip3 install sphinx-sitemap + && pip3 install sphinxcontrib-mermaid - name: Checkout repo uses: actions/checkout@v4 - name: Build docs diff --git a/doc/conf.py b/doc/conf.py index 731d51a8b..56e66dd30 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -23,6 +23,7 @@ extensions = [ 'sphinx.ext.autodoc', + 'sphinxcontrib.mermaid', 'sphinx.ext.intersphinx', 'sphinx.ext.autosectionlabel', 'sphinx.ext.todo', diff --git a/doc/finiteVolume/DSL.rst b/doc/finiteVolume/DSL.rst deleted file mode 100644 index 514441de9..000000000 --- a/doc/finiteVolume/DSL.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _fvcc_DSL: - -Domain Specific Language -======================== diff --git a/doc/finiteVolume/cellCentred/DSL.rst b/doc/finiteVolume/cellCentred/DSL.rst new file mode 100644 index 000000000..5c245ab15 --- /dev/null +++ b/doc/finiteVolume/cellCentred/DSL.rst @@ -0,0 +1,230 @@ +Domain Specific Language +======================== + +Domain Specific Language (DSL) dramatically simplifies the process of writing and solving equations. Engineers can express equations in a concise and readable form, closely resembling their mathematical representation and no or little knowledge of the numerical schemes and implementation is required. This approach allows engineers to focus on the physics of the problem rather than the numerical implementation and helps in reducing the time and effort required to develop and maintain complex simulations. + +The Navier-Stokes equations can be expressed in the DSL as follows in OpenFOAM as follows: + +.. code-block:: cpp + + fvVectorMatrix UEqn + ( + fvm::ddt(U) + + fvm::div(phi, U) + - fvm::laplacian(nu, U) + ); + + solve(UEqn == -fvc::grad(p)); + +To solve the continuity equation in OpenFOAM with the PISO or SIMPLE algorithm, the VectorMatrix, UEqn, needs to provide the diagonal and off-diagonal terms of the matrix. + +.. code-block:: cpp + + volScalarField rAU(1.0/UEqn.A()); + volVectorField HbyA(constrainHbyA(rAU*UEqn.H(), U, p)); + +This approach is readable and easy to understand for engineers familiar with OpenFOAM. However, it has several limitations due to its implementation in OpenFOAM: + + - the solution system is always a sparse matrix + - the sparse matrix is always a LDU matrix that is not supported by external linear solvers + - LDU matrix only supports finite volume cell-centred discretisation + +NeoFOAM DSL tries to address these issues by providing: + + - lazy evaluation evaluation of the equations + - a more modular design + - a standard matrix format for support of external linear solvers + +The use of standard matrix format combined with lazy evaluation allows for the use of external libraries to integrate PDEs in time and space. The equation system can be passed to **sundials** and be integrated by **RK methods** and **BDF methods** on heterogeneous architectures. + +The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adoption should be possible with minimal effort and the same equation from above should read: + +.. code-block:: cpp + + dsl::EqnSystem UEqn + ( + fvcc::impOp::ddt(U) + + fvcc::impOp::div(phi, U) + - fvcc::impOp::laplacian(nu, U) + ) + + solve(UEqn == -fvcc::expOp::grad(p)); + + +The majority of the work is done in the solve step: assemble the system and solve the system. After the system is solved or assembled, it allows needs to be provide access to the linear system for the SIMPLE and PISO algorithms. + + +EqnSystem +--------- + + +The `EqnSystem` template class in NeoFOAM represents holds, manage, builds and solves the DSL and is the core part that orchestrates the following questions: + + - How to discretize the eqnterms? + - In OpenFOAM this information is provided in **fvSchemes** + - How to integrate the system in time? + - In OpenFOAM this information is provided in **fvSchemes** + - How to solve the system? + - In OpenFOAM this information is provided in **fvSolution** + +The main difference between OpenFOAM and NeoFOAM is that the DSL in NeoFOAM is evaluated lazily. Therefore, the evaluation is no longer tied to a sparse matrix enabling other numerical integration strategies (RK method) or even substepping can be integrated inside the equation. + +To evaluate the terms lazily, `EqnSystem` stores 3 vectors: + +.. mermaid:: + + classDiagram + class EqnTerm { + + +explicitOperation(...) + +implicitOperation(...) + } + class DivEqnTerm { + +explicitOperation(...) + +implicitOperation(...) + } + class TemporalEqnTerm { + +explicitOperation(...) + +implicitOperation(...) + } + class Others["..."] { + +explicitOperation(...) + +implicitOperation(...) + } + class EqnSystem { + +temporalTerms_: vector~EqnTerm~ + +implicitTerms_: vector~EqnTerm~ + +explicitTerms_: vector~EqnTerm~ + } + EqnTerm <|-- DivEqnTerm + EqnTerm <|-- TemporalEqnTerm + EqnTerm <|-- Others + EqnSystem <|-- EqnTerm + +So, the general assumption is that a EqnSystem consists of multiple EqnTerms that are either explicit, implicit or temporal. Consequently, plus, minus or scaling with a field needs to be handled by the EqnTerm. + + +EqnTerm +------- + +.. * What does it do? +.. * how to scale terms? +.. * how to evaluate terms? +.. * how to store terms? +.. * how is it implemented? + + +`EqnTerm` represents a term in an equation. It is a template class that can be instantiated with different value types. An `EqnTerm` can be of different types, such as explicit, implicit or temporal, and can be scaled by a scalar value or a field. It is implemented as Type Erasure (more details`[1] `_ `[2] `_ `[3] `_). So, the `EqnTerm` class provides a common interface for classes without inheritance. Consequently, the classes only needs to implement the interface and can be used in the DSL as shown in the example: + + +Example: + .. code-block:: cpp + + NeoFOAM::DSL::EqnTerm divTerm = + Divergence(NeoFOAM::DSL::EqnTerm::Type::Explicit, exec, 1); + + NeoFOAM::DSL::EqnTerm ddtTerm = + TimeTerm(NeoFOAM::DSL::EqnTerm::Type::Temporal, exec, 1); + + + +To fit the specification of the EqnSystem (storage in a vector), the EqnTerm needs to be able to be scaled: + +.. code-block:: cpp + + NeoFOAM::Field scalingField(exec, nCells, 2.0); + auto sF = scalingField.span(); + + dsl::EqnTerm lapTerm = + Divergence(dsl::EqnTerm::Type::Explicit, exec, nCells, 1.0); + + auto scaledTerm = 2.0 * lapTerm; // 2.0 is the scaling factor + scaledTerm = -1.0 * lapTerm; // -1.0 is the scaling factor + scaledTerm = scalingField * lapTerm; // scalingField is the scaling field + + // EqnTerm also supports a similar syntax as OpenFOAM + auto scaledTerm = (scale + scale + scale + scale) * lapTerm; + + // EqnTerm also supports the use of a lambda as scaling function to reduce the number of temporaries generated + scaledTerm = + (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * lapTerm; + +The simplest approach to add a custom EqnTerm, is to derive a class from the EqnTermMixin and implement the required functions. The EqnTermMixin provides the interface for the EqnTerm and the EqnTermMixin can be used to implement the EqnTerm. The EqnTermMixin provides the following interface: + + - build: build the term + - explicitOperation: perform the explicit operation + - implicitOperation: perform the implicit operation + - display: display the term + - getType: get the type of the term + - exec: get the executor + - nCells: get the number of cells + - volumeField: get the volume field + +as shown below: + +.. code-block:: cpp + + class Laplacian : public dsl::EqnTermMixin + { + + public: + + // constructors .. + NeoFOAM::scalar read(const NeoFOAM::Input& input) + { + // .. + } + + void build(const NeoFOAM::Input& input) + { + value = read(input); + termEvaluated = true; + } + + std::string display() const { return "Laplacian"; } + + void explicitOperation(NeoFOAM::Field& source) + { + NeoFOAM::scalar setValue = value; + // scaleField is defined in EqnTermMixin + // and accounts for the scaling of the terms + // and considers scaling by fields and scalars + auto scale = scaleField(); + auto sourceField = source.span(); + NeoFOAM::parallelFor( + source.exec(), + {0, source.size()}, + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += scale[i] * setValue; } + ); + } + + // other helper functions + dsl::EqnTerm::Type getType() const { return termType_; } + + const NeoFOAM::Executor& exec() const { return exec_; } + + std::size_t nCells() const { return nCells_; } + + fvcc::VolumeField* volumeField() { return nullptr; } + + dsl::EqnTerm::Type termType_; + + + const NeoFOAM::Executor exec_; + std::size_t nCells_; + NeoFOAM::scalar value = 1.0; + }; + +The required scaling of the term is handle by the `scaleField` function that is provided by the EqnTermMixin. The `scaleField` function returns 'ScalingField' class that considers scaling by fields and scalars. + +.. code-block:: cpp + + template + class ScalingField + { + + // the span is only used if it is defined + KOKKOS_INLINE_FUNCTION + ValueType operator[](const size_t i) const { return useSpan ? values[i] * value : value; } + + } diff --git a/doc/finiteVolume/cellCentred/index.rst b/doc/finiteVolume/cellCentred/index.rst index 21ce5a6d2..16b862c1e 100644 --- a/doc/finiteVolume/cellCentred/index.rst +++ b/doc/finiteVolume/cellCentred/index.rst @@ -9,7 +9,6 @@ cellCenteredFiniteVolume :glob: DSL.rst - fields.rst boundaryConditions.rst operators.rst stencil.rst From 2140ab8de62e18b451a59b3d7ba80529a20f7b30 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Wed, 4 Sep 2024 21:46:24 +0200 Subject: [PATCH 02/63] documentation update --- doc/finiteVolume/cellCentred/DSL.rst | 33 +++++++++++----------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/doc/finiteVolume/cellCentred/DSL.rst b/doc/finiteVolume/cellCentred/DSL.rst index 5c245ab15..42766ee50 100644 --- a/doc/finiteVolume/cellCentred/DSL.rst +++ b/doc/finiteVolume/cellCentred/DSL.rst @@ -107,25 +107,18 @@ So, the general assumption is that a EqnSystem consists of multiple EqnTerms tha EqnTerm ------- -.. * What does it do? -.. * how to scale terms? -.. * how to evaluate terms? -.. * how to store terms? -.. * how is it implemented? - -`EqnTerm` represents a term in an equation. It is a template class that can be instantiated with different value types. An `EqnTerm` can be of different types, such as explicit, implicit or temporal, and can be scaled by a scalar value or a field. It is implemented as Type Erasure (more details`[1] `_ `[2] `_ `[3] `_). So, the `EqnTerm` class provides a common interface for classes without inheritance. Consequently, the classes only needs to implement the interface and can be used in the DSL as shown in the example: +`EqnTerm` represents a term in an equation. It is a template class that can be instantiated with different value types. An `EqnTerm` can be explicit, implicit or temporal and needs be scalable by a scalar value or a field. `EqnTerm` is implemented as Type Erasure (more details `[1] `_ `[2] `_ `[3] `_). So, the `EqnTerm` class provides a common interface for classes without inheritance. Consequently, the classes only needs to implement the interface and can be used in the DSL as shown in the example: Example: .. code-block:: cpp NeoFOAM::DSL::EqnTerm divTerm = - Divergence(NeoFOAM::DSL::EqnTerm::Type::Explicit, exec, 1); + Divergence(NeoFOAM::DSL::EqnTerm::Type::Explicit, exec, ...); NeoFOAM::DSL::EqnTerm ddtTerm = - TimeTerm(NeoFOAM::DSL::EqnTerm::Type::Temporal, exec, 1); - + TimeTerm(NeoFOAM::DSL::EqnTerm::Type::Temporal, exec, ..); To fit the specification of the EqnSystem (storage in a vector), the EqnTerm needs to be able to be scaled: @@ -135,21 +128,21 @@ To fit the specification of the EqnSystem (storage in a vector), the EqnTerm nee NeoFOAM::Field scalingField(exec, nCells, 2.0); auto sF = scalingField.span(); - dsl::EqnTerm lapTerm = - Divergence(dsl::EqnTerm::Type::Explicit, exec, nCells, 1.0); + dsl::EqnTerm customTerm = + CustomTerm(dsl::EqnTerm::Type::Explicit, exec, nCells, 1.0); - auto scaledTerm = 2.0 * lapTerm; // 2.0 is the scaling factor - scaledTerm = -1.0 * lapTerm; // -1.0 is the scaling factor - scaledTerm = scalingField * lapTerm; // scalingField is the scaling field + auto scaledTerm = 2.0 * customTerm; // 2.0 is the scaling factor + scaledTerm = -1.0 * customTerm; // -1.0 is the scaling factor + scaledTerm = scalingField * customTerm; // scalingField is the scaling field // EqnTerm also supports a similar syntax as OpenFOAM - auto scaledTerm = (scale + scale + scale + scale) * lapTerm; + auto scaledTerm = (scale + scale + scale + scale) * customTerm; // EqnTerm also supports the use of a lambda as scaling function to reduce the number of temporaries generated scaledTerm = - (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * lapTerm; + (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * customTerm; -The simplest approach to add a custom EqnTerm, is to derive a class from the EqnTermMixin and implement the required functions. The EqnTermMixin provides the interface for the EqnTerm and the EqnTermMixin can be used to implement the EqnTerm. The EqnTermMixin provides the following interface: +The simplest approach to add a custom EqnTerm, is to derive a class from the EqnTermMixin and implement the required functions. A class that want to use the EqnTerm interface needs to provide the following functions: - build: build the term - explicitOperation: perform the explicit operation @@ -160,11 +153,11 @@ The simplest approach to add a custom EqnTerm, is to derive a class from the Eqn - nCells: get the number of cells - volumeField: get the volume field -as shown below: +An example is given below: .. code-block:: cpp - class Laplacian : public dsl::EqnTermMixin + class CustomEqnTerm : public dsl::EqnTermMixin { public: From 8c97fb2f3fa6a8f436a7d198da9295601b28a6ed Mon Sep 17 00:00:00 2001 From: Henning Scheufler <16381681+HenningScheufler@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:45:58 +0200 Subject: [PATCH 03/63] Apply suggestions from code review Co-authored-by: bevanwsjones --- doc/finiteVolume/cellCentred/DSL.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/finiteVolume/cellCentred/DSL.rst b/doc/finiteVolume/cellCentred/DSL.rst index 42766ee50..d11da103a 100644 --- a/doc/finiteVolume/cellCentred/DSL.rst +++ b/doc/finiteVolume/cellCentred/DSL.rst @@ -58,18 +58,18 @@ EqnSystem --------- -The `EqnSystem` template class in NeoFOAM represents holds, manage, builds and solves the DSL and is the core part that orchestrates the following questions: +The `EqnSystem` template class in NeoFOAM holds, manages, builds and solves the expressed/programmed equation and its core responsibilities lie in the answering of the following questions: - - How to discretize the eqnterms? + - How to discretize the spatial terms? - In OpenFOAM this information is provided in **fvSchemes** - How to integrate the system in time? - In OpenFOAM this information is provided in **fvSchemes** - How to solve the system? - In OpenFOAM this information is provided in **fvSolution** -The main difference between OpenFOAM and NeoFOAM is that the DSL in NeoFOAM is evaluated lazily. Therefore, the evaluation is no longer tied to a sparse matrix enabling other numerical integration strategies (RK method) or even substepping can be integrated inside the equation. +The main difference between NeoFOAM and OpenFOAM is that the DSL is evaluated lazily. Therefore, the evaluation is not tied to the construction and solution of a sparse matrix, enabling other numerical integration strategies (e.g. RK methods or even substepping within an the equation). -To evaluate the terms lazily, `EqnSystem` stores 3 vectors: +For lazy evaluation, the `EqnSystem` stores 3 vectors: .. mermaid:: @@ -101,14 +101,14 @@ To evaluate the terms lazily, `EqnSystem` stores 3 vectors: EqnTerm <|-- Others EqnSystem <|-- EqnTerm -So, the general assumption is that a EqnSystem consists of multiple EqnTerms that are either explicit, implicit or temporal. Consequently, plus, minus or scaling with a field needs to be handled by the EqnTerm. +Thus, an `EqnSystem` consists of multiple `EqnTerms` which are either explicit, implicit, or temporal. Consequently, plus, minus, and scaling with a field needs to be handled by the `EqnTerm`. EqnTerm ------- -`EqnTerm` represents a term in an equation. It is a template class that can be instantiated with different value types. An `EqnTerm` can be explicit, implicit or temporal and needs be scalable by a scalar value or a field. `EqnTerm` is implemented as Type Erasure (more details `[1] `_ `[2] `_ `[3] `_). So, the `EqnTerm` class provides a common interface for classes without inheritance. Consequently, the classes only needs to implement the interface and can be used in the DSL as shown in the example: +The template `EqnTerm` represents a term in an equation and can be instantiated with different value types. An `EqnTerm` is either explicit, implicit or temporal, and needs to be scalable by a scalar value or a further field. The `EqnTerm` implementation used Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: Example: @@ -131,18 +131,18 @@ To fit the specification of the EqnSystem (storage in a vector), the EqnTerm nee dsl::EqnTerm customTerm = CustomTerm(dsl::EqnTerm::Type::Explicit, exec, nCells, 1.0); - auto scaledTerm = 2.0 * customTerm; // 2.0 is the scaling factor - scaledTerm = -1.0 * customTerm; // -1.0 is the scaling factor - scaledTerm = scalingField * customTerm; // scalingField is the scaling field + auto constantScaledTerm = 2.0 * customTerm; // A constant scaling factor of 2 for the term. + auto fieldScaledTerm = scalingField * customTerm; // scalingField is used to scale the term. // EqnTerm also supports a similar syntax as OpenFOAM - auto scaledTerm = (scale + scale + scale + scale) * customTerm; + auto multiScaledTerm = (scale + scale + scale + scale) * customTerm; // EqnTerm also supports the use of a lambda as scaling function to reduce the number of temporaries generated - scaledTerm = + auto lambdaScaledTerm = (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * customTerm; -The simplest approach to add a custom EqnTerm, is to derive a class from the EqnTermMixin and implement the required functions. A class that want to use the EqnTerm interface needs to provide the following functions: +To add a user-defined `EqnTerm`, a new derived class must be created, inheriting from `EqnTermMixin`, + and provide the definitions of the below virtual functions that are required for the `EquTerm` interface: - build: build the term - explicitOperation: perform the explicit operation @@ -208,7 +208,7 @@ An example is given below: NeoFOAM::scalar value = 1.0; }; -The required scaling of the term is handle by the `scaleField` function that is provided by the EqnTermMixin. The `scaleField` function returns 'ScalingField' class that considers scaling by fields and scalars. +The required scaling of the term is handle by the `scaleField` function, provided by `EqnTermMixin`. The `scaleField` function returns the 'ScalingField' class that is used to scale by fields and scalars. .. code-block:: cpp From 03ef014c608a1b24fe3667f1cc63926916e008fb Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sun, 29 Sep 2024 20:23:07 +0200 Subject: [PATCH 04/63] Apply suggestions from code review --- doc/finiteVolume/cellCentred/DSL.rst | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/finiteVolume/cellCentred/DSL.rst b/doc/finiteVolume/cellCentred/DSL.rst index d11da103a..ba7800179 100644 --- a/doc/finiteVolume/cellCentred/DSL.rst +++ b/doc/finiteVolume/cellCentred/DSL.rst @@ -3,7 +3,7 @@ Domain Specific Language Domain Specific Language (DSL) dramatically simplifies the process of writing and solving equations. Engineers can express equations in a concise and readable form, closely resembling their mathematical representation and no or little knowledge of the numerical schemes and implementation is required. This approach allows engineers to focus on the physics of the problem rather than the numerical implementation and helps in reducing the time and effort required to develop and maintain complex simulations. -The Navier-Stokes equations can be expressed in the DSL as follows in OpenFOAM as follows: +The Navier-Stokes equations can be expressed in the DSL in OpenFOAM as follows: .. code-block:: cpp @@ -27,13 +27,13 @@ This approach is readable and easy to understand for engineers familiar with Ope - the solution system is always a sparse matrix - the sparse matrix is always a LDU matrix that is not supported by external linear solvers - - LDU matrix only supports finite volume cell-centred discretisation + - Only cell-centred discretisation is supported NeoFOAM DSL tries to address these issues by providing: - - lazy evaluation evaluation of the equations + - lazy evaluation of the equations terms. This allows for better optimisation of the resulting equation and can reduce the number of required temporaries. - a more modular design - - a standard matrix format for support of external linear solvers + - Support for standard matrix formats like COO and CSR, to simplify the use of external linear solvers The use of standard matrix format combined with lazy evaluation allows for the use of external libraries to integrate PDEs in time and space. The equation system can be passed to **sundials** and be integrated by **RK methods** and **BDF methods** on heterogeneous architectures. @@ -51,7 +51,7 @@ The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adop solve(UEqn == -fvcc::expOp::grad(p)); -The majority of the work is done in the solve step: assemble the system and solve the system. After the system is solved or assembled, it allows needs to be provide access to the linear system for the SIMPLE and PISO algorithms. +In contrast to OpenFOAM, here the majority of the work is done in the solve step. That is 1. assemble the system and 2. solve the system. After the system is assembled or solved, it provides access to the linear system for the SIMPLE and PISO algorithms. EqnSystem @@ -75,7 +75,6 @@ For lazy evaluation, the `EqnSystem` stores 3 vectors: classDiagram class EqnTerm { - +explicitOperation(...) +implicitOperation(...) } @@ -108,7 +107,7 @@ EqnTerm ------- -The template `EqnTerm` represents a term in an equation and can be instantiated with different value types. An `EqnTerm` is either explicit, implicit or temporal, and needs to be scalable by a scalar value or a further field. The `EqnTerm` implementation used Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: +The template `EqnTerm` represents a term in an equation and can be instantiated with different value types. An `EqnTerm` is either explicit, implicit or temporal, and needs to be scalable by a scalar value or a further field. The `EqnTerm` implementation uses Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: Example: @@ -142,7 +141,7 @@ To fit the specification of the EqnSystem (storage in a vector), the EqnTerm nee (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * customTerm; To add a user-defined `EqnTerm`, a new derived class must be created, inheriting from `EqnTermMixin`, - and provide the definitions of the below virtual functions that are required for the `EquTerm` interface: + and provide the definitions of the below virtual functions that are required for the `EqnTerm` interface: - build: build the term - explicitOperation: perform the explicit operation From 00daf214ee63d7c0914741d754576c0568b30893 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 11:27:06 +0200 Subject: [PATCH 05/63] build always a documentation --- .github/workflows/build_doc.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build_doc.yaml b/.github/workflows/build_doc.yaml index 6c84aa5af..4ff33f9b4 100644 --- a/.github/workflows/build_doc.yaml +++ b/.github/workflows/build_doc.yaml @@ -5,8 +5,6 @@ env: on: pull_request: - branches: - - main types: [closed, synchronize, opened] push: tags: From a71a79fc96f61f0d5bb9892bb628ddb93ee99589 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 11:33:40 +0200 Subject: [PATCH 06/63] comment test url --- .github/workflows/build_doc.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build_doc.yaml b/.github/workflows/build_doc.yaml index 4ff33f9b4..59f2bfbee 100644 --- a/.github/workflows/build_doc.yaml +++ b/.github/workflows/build_doc.yaml @@ -45,6 +45,13 @@ jobs: with: folder: docs_build target-folder: latest + - name: Comment PR + uses: thollander/actions-comment-pull-request@v2 + with: + message: | + Deployed test documentation to https://exasim-project.com/NeoFOAM/Build_PR_${{ env.PR_NUMBER }} + comment_tag: build_url + - name: Echo Build PR URL run: | echo "Deploy to: https://exasim-project.com/NeoFOAM/Build_PR_${{ env.PR_NUMBER }}" From ed7c32681bd9fd4dd5f11e2b002196b1cd512f42 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 12:41:04 +0200 Subject: [PATCH 07/63] keep one sentence per line --- doc/finiteVolume/cellCentred/DSL.rst | 31 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/doc/finiteVolume/cellCentred/DSL.rst b/doc/finiteVolume/cellCentred/DSL.rst index ba7800179..9d245e5e0 100644 --- a/doc/finiteVolume/cellCentred/DSL.rst +++ b/doc/finiteVolume/cellCentred/DSL.rst @@ -1,7 +1,9 @@ -Domain Specific Language -======================== +Domain Specific Language (DSL) +============================== -Domain Specific Language (DSL) dramatically simplifies the process of writing and solving equations. Engineers can express equations in a concise and readable form, closely resembling their mathematical representation and no or little knowledge of the numerical schemes and implementation is required. This approach allows engineers to focus on the physics of the problem rather than the numerical implementation and helps in reducing the time and effort required to develop and maintain complex simulations. +The concept of a Domain Specific Language (DSL) allows to dramatically simplify the process of implementing and solving equations in a given programming language like C++. +Engineers can express equations in a concise and readable form, closely resembling their mathematical representation and no or little knowledge of the numerical schemes and implementation is required. +This approach allows engineers to focus on the physics of the problem rather than the numerical implementation and helps in reducing the time and effort required to develop and maintain complex simulations. The Navier-Stokes equations can be expressed in the DSL in OpenFOAM as follows: @@ -35,7 +37,8 @@ NeoFOAM DSL tries to address these issues by providing: - a more modular design - Support for standard matrix formats like COO and CSR, to simplify the use of external linear solvers -The use of standard matrix format combined with lazy evaluation allows for the use of external libraries to integrate PDEs in time and space. The equation system can be passed to **sundials** and be integrated by **RK methods** and **BDF methods** on heterogeneous architectures. +The use of standard matrix format combined with lazy evaluation allows for the use of external libraries to integrate PDEs in time and space. +The equation system can be passed to **sundials** and be integrated by **RK methods** and **BDF methods** on heterogeneous architectures. The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adoption should be possible with minimal effort and the same equation from above should read: @@ -51,7 +54,9 @@ The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adop solve(UEqn == -fvcc::expOp::grad(p)); -In contrast to OpenFOAM, here the majority of the work is done in the solve step. That is 1. assemble the system and 2. solve the system. After the system is assembled or solved, it provides access to the linear system for the SIMPLE and PISO algorithms. +In contrast to OpenFOAM, here the majority of the work is done in the solve step. +That is 1. assemble the system and 2. solve the system. +After the system is assembled or solved, it provides access to the linear system for the SIMPLE and PISO algorithms. EqnSystem @@ -67,9 +72,10 @@ The `EqnSystem` template class in NeoFOAM holds, manages, builds and solves the - How to solve the system? - In OpenFOAM this information is provided in **fvSolution** -The main difference between NeoFOAM and OpenFOAM is that the DSL is evaluated lazily. Therefore, the evaluation is not tied to the construction and solution of a sparse matrix, enabling other numerical integration strategies (e.g. RK methods or even substepping within an the equation). +The main difference between NeoFOAM and OpenFOAM is that the DSL is evaluated lazily, i.e. evaluation is not performed on construction by default. +Since, the evaluation is not tied to the construction but rather delayde, other numerical integration strategies (e.g. RK methods or even substepping within an the equation) are possible. -For lazy evaluation, the `EqnSystem` stores 3 vectors: +To implement lazy evaluation, the `EqnSystem` stores 3 vectors: .. mermaid:: @@ -100,14 +106,17 @@ For lazy evaluation, the `EqnSystem` stores 3 vectors: EqnTerm <|-- Others EqnSystem <|-- EqnTerm -Thus, an `EqnSystem` consists of multiple `EqnTerms` which are either explicit, implicit, or temporal. Consequently, plus, minus, and scaling with a field needs to be handled by the `EqnTerm`. +Thus, an `EqnSystem` consists of multiple `EqnTerms` which are either explicit, implicit, or temporal. +Consequently, plus, minus, and scaling with a field needs to be handled by the `EqnTerm`. EqnTerm ------- -The template `EqnTerm` represents a term in an equation and can be instantiated with different value types. An `EqnTerm` is either explicit, implicit or temporal, and needs to be scalable by a scalar value or a further field. The `EqnTerm` implementation uses Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: +The template `EqnTerm` represents a term in an equation and can be instantiated with different value types. +An `EqnTerm` is either explicit, implicit or temporal, and needs to be scalable by a scalar value or a further field. +The `EqnTerm` implementation uses Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: Example: @@ -140,8 +149,8 @@ To fit the specification of the EqnSystem (storage in a vector), the EqnTerm nee auto lambdaScaledTerm = (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * customTerm; -To add a user-defined `EqnTerm`, a new derived class must be created, inheriting from `EqnTermMixin`, - and provide the definitions of the below virtual functions that are required for the `EqnTerm` interface: +To add a user-defined `EqnTerm`, a new derived class must be created, inheriting from `EqnTermMixin`, + and provide the definitions of the below virtual functions that are required for the `EqnTerm` interface: - build: build the term - explicitOperation: perform the explicit operation From 72ed98a1aca76e59c7bdfb4624aca58ad4ebde5b Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 12:49:56 +0200 Subject: [PATCH 08/63] move DSL documentation --- doc/{finiteVolume/cellCentred => DSL}/DSL.rst | 0 doc/DSL/index.rst | 11 +++++++++++ doc/index.rst | 1 + 3 files changed, 12 insertions(+) rename doc/{finiteVolume/cellCentred => DSL}/DSL.rst (100%) create mode 100644 doc/DSL/index.rst diff --git a/doc/finiteVolume/cellCentred/DSL.rst b/doc/DSL/DSL.rst similarity index 100% rename from doc/finiteVolume/cellCentred/DSL.rst rename to doc/DSL/DSL.rst diff --git a/doc/DSL/index.rst b/doc/DSL/index.rst new file mode 100644 index 000000000..a9363b9cb --- /dev/null +++ b/doc/DSL/index.rst @@ -0,0 +1,11 @@ +.. _fvcc: + +DSL +=== + + +.. toctree:: + :maxdepth: 2 + :glob: + + DSL.rst diff --git a/doc/index.rst b/doc/index.rst index 0d7e3fef6..af18c2ae6 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -26,6 +26,7 @@ Table of Contents contributing basics/index finiteVolume/cellCentred/index + DSL/index api/index Compatibility with OpenFOAM From 5b0cac0d0da8b1f0b06c27a7ee60af62b00ad8fc Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 12:54:35 +0200 Subject: [PATCH 09/63] move DSL documentation --- doc/DSL/{DSL.rst => eqnSystem.rst} | 61 --------------- doc/DSL/eqnTerm.rst | 119 +++++++++++++++++++++++++++++ doc/DSL/index.rst | 66 +++++++++++++++- 3 files changed, 182 insertions(+), 64 deletions(-) rename doc/DSL/{DSL.rst => eqnSystem.rst} (69%) create mode 100644 doc/DSL/eqnTerm.rst diff --git a/doc/DSL/DSL.rst b/doc/DSL/eqnSystem.rst similarity index 69% rename from doc/DSL/DSL.rst rename to doc/DSL/eqnSystem.rst index 9d245e5e0..4fcebda8e 100644 --- a/doc/DSL/DSL.rst +++ b/doc/DSL/eqnSystem.rst @@ -1,64 +1,3 @@ -Domain Specific Language (DSL) -============================== - -The concept of a Domain Specific Language (DSL) allows to dramatically simplify the process of implementing and solving equations in a given programming language like C++. -Engineers can express equations in a concise and readable form, closely resembling their mathematical representation and no or little knowledge of the numerical schemes and implementation is required. -This approach allows engineers to focus on the physics of the problem rather than the numerical implementation and helps in reducing the time and effort required to develop and maintain complex simulations. - -The Navier-Stokes equations can be expressed in the DSL in OpenFOAM as follows: - -.. code-block:: cpp - - fvVectorMatrix UEqn - ( - fvm::ddt(U) - + fvm::div(phi, U) - - fvm::laplacian(nu, U) - ); - - solve(UEqn == -fvc::grad(p)); - -To solve the continuity equation in OpenFOAM with the PISO or SIMPLE algorithm, the VectorMatrix, UEqn, needs to provide the diagonal and off-diagonal terms of the matrix. - -.. code-block:: cpp - - volScalarField rAU(1.0/UEqn.A()); - volVectorField HbyA(constrainHbyA(rAU*UEqn.H(), U, p)); - -This approach is readable and easy to understand for engineers familiar with OpenFOAM. However, it has several limitations due to its implementation in OpenFOAM: - - - the solution system is always a sparse matrix - - the sparse matrix is always a LDU matrix that is not supported by external linear solvers - - Only cell-centred discretisation is supported - -NeoFOAM DSL tries to address these issues by providing: - - - lazy evaluation of the equations terms. This allows for better optimisation of the resulting equation and can reduce the number of required temporaries. - - a more modular design - - Support for standard matrix formats like COO and CSR, to simplify the use of external linear solvers - -The use of standard matrix format combined with lazy evaluation allows for the use of external libraries to integrate PDEs in time and space. -The equation system can be passed to **sundials** and be integrated by **RK methods** and **BDF methods** on heterogeneous architectures. - -The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adoption should be possible with minimal effort and the same equation from above should read: - -.. code-block:: cpp - - dsl::EqnSystem UEqn - ( - fvcc::impOp::ddt(U) - + fvcc::impOp::div(phi, U) - - fvcc::impOp::laplacian(nu, U) - ) - - solve(UEqn == -fvcc::expOp::grad(p)); - - -In contrast to OpenFOAM, here the majority of the work is done in the solve step. -That is 1. assemble the system and 2. solve the system. -After the system is assembled or solved, it provides access to the linear system for the SIMPLE and PISO algorithms. - - EqnSystem --------- diff --git a/doc/DSL/eqnTerm.rst b/doc/DSL/eqnTerm.rst new file mode 100644 index 000000000..c9ddc2e66 --- /dev/null +++ b/doc/DSL/eqnTerm.rst @@ -0,0 +1,119 @@ +EqnTerm +======= + + +The template `EqnTerm` represents a term in an equation and can be instantiated with different value types. +An `EqnTerm` is either explicit, implicit or temporal, and needs to be scalable by a scalar value or a further field. +The `EqnTerm` implementation uses Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: + + +Example: + .. code-block:: cpp + + NeoFOAM::DSL::EqnTerm divTerm = + Divergence(NeoFOAM::DSL::EqnTerm::Type::Explicit, exec, ...); + + NeoFOAM::DSL::EqnTerm ddtTerm = + TimeTerm(NeoFOAM::DSL::EqnTerm::Type::Temporal, exec, ..); + + +To fit the specification of the EqnSystem (storage in a vector), the EqnTerm needs to be able to be scaled: + +.. code-block:: cpp + + NeoFOAM::Field scalingField(exec, nCells, 2.0); + auto sF = scalingField.span(); + + dsl::EqnTerm customTerm = + CustomTerm(dsl::EqnTerm::Type::Explicit, exec, nCells, 1.0); + + auto constantScaledTerm = 2.0 * customTerm; // A constant scaling factor of 2 for the term. + auto fieldScaledTerm = scalingField * customTerm; // scalingField is used to scale the term. + + // EqnTerm also supports a similar syntax as OpenFOAM + auto multiScaledTerm = (scale + scale + scale + scale) * customTerm; + + // EqnTerm also supports the use of a lambda as scaling function to reduce the number of temporaries generated + auto lambdaScaledTerm = + (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * customTerm; + +To add a user-defined `EqnTerm`, a new derived class must be created, inheriting from `EqnTermMixin`, + and provide the definitions of the below virtual functions that are required for the `EqnTerm` interface: + + - build: build the term + - explicitOperation: perform the explicit operation + - implicitOperation: perform the implicit operation + - display: display the term + - getType: get the type of the term + - exec: get the executor + - nCells: get the number of cells + - volumeField: get the volume field + +An example is given below: + +.. code-block:: cpp + + class CustomEqnTerm : public dsl::EqnTermMixin + { + + public: + + // constructors .. + NeoFOAM::scalar read(const NeoFOAM::Input& input) + { + // .. + } + + void build(const NeoFOAM::Input& input) + { + value = read(input); + termEvaluated = true; + } + + std::string display() const { return "Laplacian"; } + + void explicitOperation(NeoFOAM::Field& source) + { + NeoFOAM::scalar setValue = value; + // scaleField is defined in EqnTermMixin + // and accounts for the scaling of the terms + // and considers scaling by fields and scalars + auto scale = scaleField(); + auto sourceField = source.span(); + NeoFOAM::parallelFor( + source.exec(), + {0, source.size()}, + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += scale[i] * setValue; } + ); + } + + // other helper functions + dsl::EqnTerm::Type getType() const { return termType_; } + + const NeoFOAM::Executor& exec() const { return exec_; } + + std::size_t nCells() const { return nCells_; } + + fvcc::VolumeField* volumeField() { return nullptr; } + + dsl::EqnTerm::Type termType_; + + + const NeoFOAM::Executor exec_; + std::size_t nCells_; + NeoFOAM::scalar value = 1.0; + }; + +The required scaling of the term is handle by the `scaleField` function, provided by `EqnTermMixin`. The `scaleField` function returns the 'ScalingField' class that is used to scale by fields and scalars. + +.. code-block:: cpp + + template + class ScalingField + { + + // the span is only used if it is defined + KOKKOS_INLINE_FUNCTION + ValueType operator[](const size_t i) const { return useSpan ? values[i] * value : value; } + + } diff --git a/doc/DSL/index.rst b/doc/DSL/index.rst index a9363b9cb..a193a40ed 100644 --- a/doc/DSL/index.rst +++ b/doc/DSL/index.rst @@ -1,11 +1,71 @@ .. _fvcc: -DSL -=== +Domain Specific Language (DSL) +============================== + +The concept of a Domain Specific Language (DSL) allows to dramatically simplify the process of implementing and solving equations in a given programming language like C++. +Engineers can express equations in a concise and readable form, closely resembling their mathematical representation and no or little knowledge of the numerical schemes and implementation is required. +This approach allows engineers to focus on the physics of the problem rather than the numerical implementation and helps in reducing the time and effort required to develop and maintain complex simulations. + +The Navier-Stokes equations can be expressed in the DSL in OpenFOAM as follows: + +.. code-block:: cpp + + fvVectorMatrix UEqn + ( + fvm::ddt(U) + + fvm::div(phi, U) + - fvm::laplacian(nu, U) + ); + + solve(UEqn == -fvc::grad(p)); + +To solve the continuity equation in OpenFOAM with the PISO or SIMPLE algorithm, the VectorMatrix, UEqn, needs to provide the diagonal and off-diagonal terms of the matrix. + +.. code-block:: cpp + + volScalarField rAU(1.0/UEqn.A()); + volVectorField HbyA(constrainHbyA(rAU*UEqn.H(), U, p)); + +This approach is readable and easy to understand for engineers familiar with OpenFOAM. However, it has several limitations due to its implementation in OpenFOAM: + + - the solution system is always a sparse matrix + - the sparse matrix is always a LDU matrix that is not supported by external linear solvers + - Only cell-centred discretisation is supported + +NeoFOAM DSL tries to address these issues by providing: + + - lazy evaluation of the equations terms. This allows for better optimisation of the resulting equation and can reduce the number of required temporaries. + - a more modular design + - Support for standard matrix formats like COO and CSR, to simplify the use of external linear solvers + +The use of standard matrix format combined with lazy evaluation allows for the use of external libraries to integrate PDEs in time and space. +The equation system can be passed to **sundials** and be integrated by **RK methods** and **BDF methods** on heterogeneous architectures. + +The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adoption should be possible with minimal effort and the same equation from above should read: + +.. code-block:: cpp + + dsl::EqnSystem UEqn + ( + fvcc::impOp::ddt(U) + + fvcc::impOp::div(phi, U) + - fvcc::impOp::laplacian(nu, U) + ) + + solve(UEqn == -fvcc::expOp::grad(p)); + + +In contrast to OpenFOAM, here the majority of the work is done in the solve step. +That is 1. assemble the system and 2. solve the system. +After the system is assembled or solved, it provides access to the linear system for the SIMPLE and PISO algorithms. + + .. toctree:: :maxdepth: 2 :glob: - DSL.rst + eqnSystem.rst + eqnTerm.rst From d96404620462ee1381e7019222603cd10b3306ec Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 12:59:38 +0200 Subject: [PATCH 10/63] wording change plus/minus ->addition,subtraction. Deduplicate --- doc/DSL/eqnSystem.rst | 123 +----------------------------------------- 1 file changed, 1 insertion(+), 122 deletions(-) diff --git a/doc/DSL/eqnSystem.rst b/doc/DSL/eqnSystem.rst index 4fcebda8e..2b865381f 100644 --- a/doc/DSL/eqnSystem.rst +++ b/doc/DSL/eqnSystem.rst @@ -46,125 +46,4 @@ To implement lazy evaluation, the `EqnSystem` stores 3 vectors: EqnSystem <|-- EqnTerm Thus, an `EqnSystem` consists of multiple `EqnTerms` which are either explicit, implicit, or temporal. -Consequently, plus, minus, and scaling with a field needs to be handled by the `EqnTerm`. - - -EqnTerm -------- - - -The template `EqnTerm` represents a term in an equation and can be instantiated with different value types. -An `EqnTerm` is either explicit, implicit or temporal, and needs to be scalable by a scalar value or a further field. -The `EqnTerm` implementation uses Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: - - -Example: - .. code-block:: cpp - - NeoFOAM::DSL::EqnTerm divTerm = - Divergence(NeoFOAM::DSL::EqnTerm::Type::Explicit, exec, ...); - - NeoFOAM::DSL::EqnTerm ddtTerm = - TimeTerm(NeoFOAM::DSL::EqnTerm::Type::Temporal, exec, ..); - - -To fit the specification of the EqnSystem (storage in a vector), the EqnTerm needs to be able to be scaled: - -.. code-block:: cpp - - NeoFOAM::Field scalingField(exec, nCells, 2.0); - auto sF = scalingField.span(); - - dsl::EqnTerm customTerm = - CustomTerm(dsl::EqnTerm::Type::Explicit, exec, nCells, 1.0); - - auto constantScaledTerm = 2.0 * customTerm; // A constant scaling factor of 2 for the term. - auto fieldScaledTerm = scalingField * customTerm; // scalingField is used to scale the term. - - // EqnTerm also supports a similar syntax as OpenFOAM - auto multiScaledTerm = (scale + scale + scale + scale) * customTerm; - - // EqnTerm also supports the use of a lambda as scaling function to reduce the number of temporaries generated - auto lambdaScaledTerm = - (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * customTerm; - -To add a user-defined `EqnTerm`, a new derived class must be created, inheriting from `EqnTermMixin`, - and provide the definitions of the below virtual functions that are required for the `EqnTerm` interface: - - - build: build the term - - explicitOperation: perform the explicit operation - - implicitOperation: perform the implicit operation - - display: display the term - - getType: get the type of the term - - exec: get the executor - - nCells: get the number of cells - - volumeField: get the volume field - -An example is given below: - -.. code-block:: cpp - - class CustomEqnTerm : public dsl::EqnTermMixin - { - - public: - - // constructors .. - NeoFOAM::scalar read(const NeoFOAM::Input& input) - { - // .. - } - - void build(const NeoFOAM::Input& input) - { - value = read(input); - termEvaluated = true; - } - - std::string display() const { return "Laplacian"; } - - void explicitOperation(NeoFOAM::Field& source) - { - NeoFOAM::scalar setValue = value; - // scaleField is defined in EqnTermMixin - // and accounts for the scaling of the terms - // and considers scaling by fields and scalars - auto scale = scaleField(); - auto sourceField = source.span(); - NeoFOAM::parallelFor( - source.exec(), - {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += scale[i] * setValue; } - ); - } - - // other helper functions - dsl::EqnTerm::Type getType() const { return termType_; } - - const NeoFOAM::Executor& exec() const { return exec_; } - - std::size_t nCells() const { return nCells_; } - - fvcc::VolumeField* volumeField() { return nullptr; } - - dsl::EqnTerm::Type termType_; - - - const NeoFOAM::Executor exec_; - std::size_t nCells_; - NeoFOAM::scalar value = 1.0; - }; - -The required scaling of the term is handle by the `scaleField` function, provided by `EqnTermMixin`. The `scaleField` function returns the 'ScalingField' class that is used to scale by fields and scalars. - -.. code-block:: cpp - - template - class ScalingField - { - - // the span is only used if it is defined - KOKKOS_INLINE_FUNCTION - ValueType operator[](const size_t i) const { return useSpan ? values[i] * value : value; } - - } +Consequently, addition, subtraction, and scaling with a field needs to be handled by the `EqnTerm`. From 00097bdff95213fe236f07cab5a4d6b1c72b1116 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Wed, 24 Jul 2024 18:26:14 +0200 Subject: [PATCH 11/63] init implemnetation of the DSL --- include/NeoFOAM/DSL/eqnSystem.hpp | 82 +++++++++++++++++++++++ include/NeoFOAM/DSL/eqnTerm.hpp | 85 +++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/dsl/CMakeLists.txt | 4 ++ test/dsl/dsl.cpp | 108 ++++++++++++++++++++++++++++++ 5 files changed, 280 insertions(+) create mode 100644 include/NeoFOAM/DSL/eqnSystem.hpp create mode 100644 include/NeoFOAM/DSL/eqnTerm.hpp create mode 100644 test/dsl/CMakeLists.txt create mode 100644 test/dsl/dsl.cpp diff --git a/include/NeoFOAM/DSL/eqnSystem.hpp b/include/NeoFOAM/DSL/eqnSystem.hpp new file mode 100644 index 000000000..2a2e25689 --- /dev/null +++ b/include/NeoFOAM/DSL/eqnSystem.hpp @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#pragma once + +#include +#include +#include +#include + +#include "NeoFOAM/DSL/eqnTerm.hpp" + +namespace NeoFOAM::DSL +{ + +class EqnSystem +{ +public: + + NeoFOAM::scalar explicitOperation() + { + NeoFOAM::scalar exp = 0; + for (auto& eqnTerm : eqnTerms_) + { + eqnTerm.explicitOperation(exp); + } + return exp; + } + + std::vector eqnTerms_; +}; + +EqnSystem operator+(EqnSystem lhs, const EqnSystem& rhs) +{ + for (auto& eqnTerm : rhs.eqnTerms_) + { + lhs.eqnTerms_.push_back(eqnTerm); + } + return lhs; +} + +EqnSystem operator+(EqnSystem lhs, const EqnTerm& rhs) +{ + lhs.eqnTerms_.push_back(rhs); + return lhs; +} + +EqnSystem operator+(const EqnTerm& lhs, const EqnTerm& rhs) +{ + EqnSystem eqnSys; + eqnSys.eqnTerms_.push_back(lhs); + eqnSys.eqnTerms_.push_back(rhs); + return eqnSys; +} + +EqnSystem operator-(EqnSystem lhs, EqnSystem rhs) +{ + for (auto& eqnTerm : rhs.eqnTerms_) + { + eqnTerm.setScale(-1.0); + lhs.eqnTerms_.push_back(eqnTerm); + } + return lhs; +} + +EqnSystem operator-(EqnSystem lhs, EqnTerm rhs) +{ + rhs.setScale(-1.0); + lhs.eqnTerms_.push_back(rhs); + return lhs; +} + +EqnSystem operator-(EqnTerm lhs, EqnTerm rhs) +{ + EqnSystem eqnSys; + rhs.setScale(-1.0); + eqnSys.eqnTerms_.push_back(lhs); + eqnSys.eqnTerms_.push_back(rhs); + return eqnSys; +} + + +} // namespace NeoFOAM::DSL diff --git a/include/NeoFOAM/DSL/eqnTerm.hpp b/include/NeoFOAM/DSL/eqnTerm.hpp new file mode 100644 index 000000000..5da2d7983 --- /dev/null +++ b/include/NeoFOAM/DSL/eqnTerm.hpp @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#pragma once + +#include +#include +#include +#include + +#include "NeoFOAM/core/primitives/scalar.hpp" + +namespace NeoFOAM::DSL +{ + +// EqnTerm class that uses type erasure without inheritance +class EqnTerm +{ +public: + + template + EqnTerm(T cls) : model_(std::make_unique>(std::move(cls))) + {} + + EqnTerm(const EqnTerm& eqnTerm) : model_ {eqnTerm.model_->clone()} {} + + EqnTerm(EqnTerm&& eqnTerm) : model_ {std::move(eqnTerm.model_)} {} + + EqnTerm& operator=(const EqnTerm& eqnTerm) + { + model_ = eqnTerm.model_->clone(); + return *this; + } + + EqnTerm& operator=(EqnTerm&& eqnTerm) + { + model_ = std::move(eqnTerm.model_); + return *this; + } + + std::string display() const { return model_->display(); } + + void explicitOperation(NeoFOAM::scalar& exp) + { + model_->explicitOperation(exp, model_->scaleCoeff); + } + + void setScale(NeoFOAM::scalar scale) { model_->scaleCoeff *= scale; } + + +private: + + // Base class to hold the type-erased value and the display function + struct Concept + { + virtual ~Concept() = default; + virtual std::string display() const = 0; + virtual void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) = 0; + // The Prototype Design Pattern + virtual std::unique_ptr clone() const = 0; + NeoFOAM::scalar scaleCoeff = 1.0; + }; + + // Templated derived class to implement the type-specific behavior + template + struct Model : Concept + { + Model(T cls) : cls_(std::move(cls)) {} + + std::string display() const override { return cls_.display(); } + + virtual void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) override + { + cls_.explicitOperation(exp, scale); + } + + T cls_; + + // The Prototype Design Pattern + std::unique_ptr clone() const override { return std::make_unique(*this); } + }; + + std::unique_ptr model_; +}; + +} // namespace NeoFOAM::DSL diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6a7629b87..80d8ffdce 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -74,3 +74,4 @@ add_subdirectory(core) add_subdirectory(fields) add_subdirectory(finiteVolume) add_subdirectory(mesh) +add_subdirectory(dsl) diff --git a/test/dsl/CMakeLists.txt b/test/dsl/CMakeLists.txt new file mode 100644 index 000000000..0674af37b --- /dev/null +++ b/test/dsl/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Unlicense +# SPDX-FileCopyrightText: 2024 NeoFOAM authors + +neofoam_unit_test(dsl) diff --git a/test/dsl/dsl.cpp b/test/dsl/dsl.cpp new file mode 100644 index 000000000..8939d674a --- /dev/null +++ b/test/dsl/dsl.cpp @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create + // a custom main +#include +#include +#include + +#include "NeoFOAM/DSL/eqnTerm.hpp" +#include "NeoFOAM/DSL/eqnSystem.hpp" + +class Laplacian +{ + +public: + + std::string display() const { return "Laplacian"; } + + void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } +}; + +class Divergence +{ + +public: + + std::string display() const { return "Divergence"; } + + void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } +}; + +namespace dsl = NeoFOAM::DSL; + +TEST_CASE("DSL") +{ + dsl::EqnTerm lapTerm = Laplacian(); + + REQUIRE("Laplacian" == lapTerm.display()); + + dsl::EqnTerm divTerm = Divergence(); + + REQUIRE("Divergence" == divTerm.display()); + NeoFOAM::scalar source = 0; + + lapTerm.explicitOperation(source); + divTerm.explicitOperation(source); + + REQUIRE(source == 2.0); + + { + dsl::EqnSystem eqnSys = lapTerm + divTerm; + REQUIRE(eqnSys.eqnTerms_.size() == 2); + REQUIRE(eqnSys.explicitOperation() == 2); + } + + { + dsl::EqnSystem eqnSys(lapTerm + lapTerm + divTerm + divTerm); + REQUIRE(eqnSys.eqnTerms_.size() == 4); + REQUIRE(eqnSys.explicitOperation() == 4.0); + } + + { + dsl::EqnSystem eqnSys(lapTerm + Laplacian()); + REQUIRE(eqnSys.eqnTerms_.size() == 2); + REQUIRE(eqnSys.explicitOperation() == 2.0); + } + + { + dsl::EqnSystem eqnSys = lapTerm - divTerm; + REQUIRE(eqnSys.eqnTerms_.size() == 2); + REQUIRE(eqnSys.explicitOperation() == 0.0); + } + + { + dsl::EqnSystem eqnSys(lapTerm - Laplacian()); + REQUIRE(eqnSys.eqnTerms_.size() == 2); + REQUIRE(eqnSys.explicitOperation() == 0.0); + } + + { + dsl::EqnSystem eqnSys(lapTerm - lapTerm - divTerm - divTerm); + REQUIRE(eqnSys.eqnTerms_.size() == 4); + REQUIRE(eqnSys.explicitOperation() == -2.0); + } + + { + dsl::EqnSystem eqnSys(lapTerm + Laplacian() + divTerm + Divergence()); + dsl::EqnSystem eqnSys2(lapTerm + Laplacian() + divTerm + Divergence()); + REQUIRE(eqnSys.eqnTerms_.size() == 4); + REQUIRE(eqnSys.explicitOperation() == 4.0); + dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; + REQUIRE(combinedEqnSys.eqnTerms_.size() == 8); + REQUIRE(combinedEqnSys.explicitOperation() == 8.0); + } + + { + dsl::EqnSystem eqnSys(lapTerm + Laplacian() - divTerm - Divergence()); + dsl::EqnSystem eqnSys2(lapTerm - Laplacian() - divTerm - Divergence()); + REQUIRE(eqnSys.eqnTerms_.size() == 4); + REQUIRE(eqnSys.explicitOperation() == 0.0); + REQUIRE(eqnSys2.eqnTerms_.size() == 4); + REQUIRE(eqnSys2.explicitOperation() == -2.0); + REQUIRE(-eqnSys2.explicitOperation() == 2.0); + dsl::EqnSystem combinedEqnSys = eqnSys2 - eqnSys; + REQUIRE(combinedEqnSys.eqnTerms_.size() == 8); + REQUIRE(combinedEqnSys.explicitOperation() == -2.0); + } +} From a79e5a799232071282c60f5e2b36d92125ac8f34 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Thu, 25 Jul 2024 11:33:14 +0200 Subject: [PATCH 12/63] categorize terms into temporal, implicit and sources --- include/NeoFOAM/DSL/eqnSystem.hpp | 136 ++++++++++++++++++++++++------ include/NeoFOAM/DSL/eqnTerm.hpp | 28 ++++++ test/dsl/dsl.cpp | 84 +++++++++++++----- 3 files changed, 198 insertions(+), 50 deletions(-) diff --git a/include/NeoFOAM/DSL/eqnSystem.hpp b/include/NeoFOAM/DSL/eqnSystem.hpp index 2a2e25689..f6fd69f84 100644 --- a/include/NeoFOAM/DSL/eqnSystem.hpp +++ b/include/NeoFOAM/DSL/eqnSystem.hpp @@ -8,6 +8,7 @@ #include #include "NeoFOAM/DSL/eqnTerm.hpp" +#include "NeoFOAM/core/error.hpp" namespace NeoFOAM::DSL { @@ -19,63 +20,142 @@ class EqnSystem NeoFOAM::scalar explicitOperation() { NeoFOAM::scalar exp = 0; - for (auto& eqnTerm : eqnTerms_) + for (auto& eqnTerm : explicitTerms_) { eqnTerm.explicitOperation(exp); } return exp; } - std::vector eqnTerms_; -}; + void addTerm(const EqnTerm& eqnTerm) + { + switch (eqnTerm.getType()) + { + case EqnTerm::Type::Temporal: + temporalTerms_.push_back(eqnTerm); + break; + case EqnTerm::Type::Implicit: + implicitTerms_.push_back(eqnTerm); + break; + case EqnTerm::Type::Explicit: + explicitTerms_.push_back(eqnTerm); + break; + } + } -EqnSystem operator+(EqnSystem lhs, const EqnSystem& rhs) -{ - for (auto& eqnTerm : rhs.eqnTerms_) + void addSystem(const EqnSystem& eqnSys) { - lhs.eqnTerms_.push_back(eqnTerm); + for (auto& eqnTerm : eqnSys.temporalTerms_) + { + temporalTerms_.push_back(eqnTerm); + } + for (auto& eqnTerm : eqnSys.implicitTerms_) + { + implicitTerms_.push_back(eqnTerm); + } + for (auto& eqnTerm : eqnSys.explicitTerms_) + { + explicitTerms_.push_back(eqnTerm); + } + } + + void solve() + { + if (temporalTerms_.size() == 0 && implicitTerms_.size() == 0) + { + NF_ERROR_EXIT("No temporal or implicit terms to solve."); + } + if (temporalTerms_.size() > 0) + { + // integrate equations in time + } + else + { + // solve sparse matrix system + } } - return lhs; + + size_t size() const + { + return temporalTerms_.size() + implicitTerms_.size() + explicitTerms_.size(); + } + + // getters + const std::vector& temporalTerms() const { return temporalTerms_; } + + const std::vector& implicitTerms() const { return implicitTerms_; } + + const std::vector& explicitTerms() const { return explicitTerms_; } + +private: + + std::vector temporalTerms_; + std::vector implicitTerms_; + std::vector explicitTerms_; +}; + +EqnSystem operator+(const EqnSystem& lhs, const EqnSystem& rhs) +{ + std::cout << "Adding EqnSystem from EqnSystem" << std::endl; + EqnSystem results = lhs; + results.addSystem(rhs); + return results; } -EqnSystem operator+(EqnSystem lhs, const EqnTerm& rhs) +EqnSystem operator+(const EqnSystem& lhs, const EqnTerm& rhs) { - lhs.eqnTerms_.push_back(rhs); - return lhs; + EqnSystem results = lhs; + results.addTerm(rhs); + return results; } EqnSystem operator+(const EqnTerm& lhs, const EqnTerm& rhs) { EqnSystem eqnSys; - eqnSys.eqnTerms_.push_back(lhs); - eqnSys.eqnTerms_.push_back(rhs); + eqnSys.addTerm(lhs); + eqnSys.addTerm(rhs); return eqnSys; } -EqnSystem operator-(EqnSystem lhs, EqnSystem rhs) +EqnSystem operator*(NeoFOAM::scalar scale, const EqnSystem& es) { - for (auto& eqnTerm : rhs.eqnTerms_) + EqnSystem results; + for (const auto& eqnTerm : es.temporalTerms()) + { + results.addTerm(scale * eqnTerm); + } + for (const auto& eqnTerm : es.implicitTerms()) + { + results.addTerm(scale * eqnTerm); + } + for (const auto& eqnTerm : es.explicitTerms()) { - eqnTerm.setScale(-1.0); - lhs.eqnTerms_.push_back(eqnTerm); + results.addTerm(scale * eqnTerm); } - return lhs; + return results; } -EqnSystem operator-(EqnSystem lhs, EqnTerm rhs) +EqnSystem operator-(const EqnSystem& lhs, const EqnSystem& rhs) { - rhs.setScale(-1.0); - lhs.eqnTerms_.push_back(rhs); - return lhs; + std::cout << "Subtracting EqnSystem from EqnSystem" << std::endl; + EqnSystem results = lhs; + results.addSystem(-1.0 * rhs); + return results; } -EqnSystem operator-(EqnTerm lhs, EqnTerm rhs) +EqnSystem operator-(const EqnSystem& lhs, const EqnTerm& rhs) { - EqnSystem eqnSys; - rhs.setScale(-1.0); - eqnSys.eqnTerms_.push_back(lhs); - eqnSys.eqnTerms_.push_back(rhs); - return eqnSys; + EqnSystem results = lhs; + results.addTerm(-1.0 * rhs); + return results; +} + +EqnSystem operator-(const EqnTerm& lhs, const EqnTerm& rhs) +{ + EqnSystem results; + results.addTerm(lhs); + results.addTerm(-1.0 * rhs); + return results; } diff --git a/include/NeoFOAM/DSL/eqnTerm.hpp b/include/NeoFOAM/DSL/eqnTerm.hpp index 5da2d7983..ee5f6a217 100644 --- a/include/NeoFOAM/DSL/eqnTerm.hpp +++ b/include/NeoFOAM/DSL/eqnTerm.hpp @@ -17,6 +17,13 @@ class EqnTerm { public: + enum class Type + { + Temporal, + Implicit, + Explicit + }; + template EqnTerm(T cls) : model_(std::make_unique>(std::move(cls))) {} @@ -44,6 +51,8 @@ class EqnTerm model_->explicitOperation(exp, model_->scaleCoeff); } + EqnTerm::Type getType() const { return model_->getType(); } + void setScale(NeoFOAM::scalar scale) { model_->scaleCoeff *= scale; } @@ -58,6 +67,7 @@ class EqnTerm // The Prototype Design Pattern virtual std::unique_ptr clone() const = 0; NeoFOAM::scalar scaleCoeff = 1.0; + virtual EqnTerm::Type getType() const = 0; }; // Templated derived class to implement the type-specific behavior @@ -73,6 +83,8 @@ class EqnTerm cls_.explicitOperation(exp, scale); } + EqnTerm::Type getType() const override { return cls_.getType(); } + T cls_; // The Prototype Design Pattern @@ -82,4 +94,20 @@ class EqnTerm std::unique_ptr model_; }; + +// add multiply operator to EqnTerm +EqnTerm operator*(NeoFOAM::scalar scale, const EqnTerm& lhs) +{ + EqnTerm result = lhs; + result.setScale(scale); + return result; +} + +// EqnTerm operator*(const EqnTerm& lhs,NeoFOAM::scalar scale) +// { +// EqnTerm result = lhs; +// result.setScale(scale); +// return result; +// } + } // namespace NeoFOAM::DSL diff --git a/test/dsl/dsl.cpp b/test/dsl/dsl.cpp index 8939d674a..0b412deb3 100644 --- a/test/dsl/dsl.cpp +++ b/test/dsl/dsl.cpp @@ -9,6 +9,9 @@ #include "NeoFOAM/DSL/eqnTerm.hpp" #include "NeoFOAM/DSL/eqnSystem.hpp" + +namespace dsl = NeoFOAM::DSL; + class Laplacian { @@ -17,6 +20,10 @@ class Laplacian std::string display() const { return "Laplacian"; } void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } + + dsl::EqnTerm::Type getType() const { return termType_; } + + dsl::EqnTerm::Type termType_; }; class Divergence @@ -27,17 +34,20 @@ class Divergence std::string display() const { return "Divergence"; } void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } + + dsl::EqnTerm::Type getType() const { return termType_; } + + dsl::EqnTerm::Type termType_; }; -namespace dsl = NeoFOAM::DSL; TEST_CASE("DSL") { - dsl::EqnTerm lapTerm = Laplacian(); + dsl::EqnTerm lapTerm = Laplacian(dsl::EqnTerm::Type::Explicit); REQUIRE("Laplacian" == lapTerm.display()); - dsl::EqnTerm divTerm = Divergence(); + dsl::EqnTerm divTerm = Divergence(dsl::EqnTerm::Type::Explicit); REQUIRE("Divergence" == divTerm.display()); NeoFOAM::scalar source = 0; @@ -49,60 +59,90 @@ TEST_CASE("DSL") { dsl::EqnSystem eqnSys = lapTerm + divTerm; - REQUIRE(eqnSys.eqnTerms_.size() == 2); + REQUIRE(eqnSys.size() == 2); REQUIRE(eqnSys.explicitOperation() == 2); } { dsl::EqnSystem eqnSys(lapTerm + lapTerm + divTerm + divTerm); - REQUIRE(eqnSys.eqnTerms_.size() == 4); + REQUIRE(eqnSys.size() == 4); REQUIRE(eqnSys.explicitOperation() == 4.0); } { - dsl::EqnSystem eqnSys(lapTerm + Laplacian()); - REQUIRE(eqnSys.eqnTerms_.size() == 2); + dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit)); + REQUIRE(eqnSys.size() == 2); REQUIRE(eqnSys.explicitOperation() == 2.0); } { dsl::EqnSystem eqnSys = lapTerm - divTerm; - REQUIRE(eqnSys.eqnTerms_.size() == 2); + REQUIRE(eqnSys.size() == 2); REQUIRE(eqnSys.explicitOperation() == 0.0); } { - dsl::EqnSystem eqnSys(lapTerm - Laplacian()); - REQUIRE(eqnSys.eqnTerms_.size() == 2); + dsl::EqnSystem eqnSys(lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit)); + REQUIRE(eqnSys.size() == 2); REQUIRE(eqnSys.explicitOperation() == 0.0); } { dsl::EqnSystem eqnSys(lapTerm - lapTerm - divTerm - divTerm); - REQUIRE(eqnSys.eqnTerms_.size() == 4); + REQUIRE(eqnSys.size() == 4); REQUIRE(eqnSys.explicitOperation() == -2.0); } { - dsl::EqnSystem eqnSys(lapTerm + Laplacian() + divTerm + Divergence()); - dsl::EqnSystem eqnSys2(lapTerm + Laplacian() + divTerm + Divergence()); - REQUIRE(eqnSys.eqnTerms_.size() == 4); + dsl::EqnSystem eqnSys( + lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit) + divTerm + + Divergence(dsl::EqnTerm::Type::Explicit) + ); + dsl::EqnSystem eqnSys2( + lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit) + divTerm + + Divergence(dsl::EqnTerm::Type::Explicit) + ); + REQUIRE(eqnSys.size() == 4); REQUIRE(eqnSys.explicitOperation() == 4.0); dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; - REQUIRE(combinedEqnSys.eqnTerms_.size() == 8); + REQUIRE(combinedEqnSys.size() == 8); REQUIRE(combinedEqnSys.explicitOperation() == 8.0); } { - dsl::EqnSystem eqnSys(lapTerm + Laplacian() - divTerm - Divergence()); - dsl::EqnSystem eqnSys2(lapTerm - Laplacian() - divTerm - Divergence()); - REQUIRE(eqnSys.eqnTerms_.size() == 4); + dsl::EqnSystem eqnSys( + lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit) - divTerm + - Divergence(dsl::EqnTerm::Type::Explicit) + ); + dsl::EqnSystem eqnSys2( + lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit) - divTerm + - Divergence(dsl::EqnTerm::Type::Explicit) + ); + REQUIRE(eqnSys.size() == 4); REQUIRE(eqnSys.explicitOperation() == 0.0); - REQUIRE(eqnSys2.eqnTerms_.size() == 4); + REQUIRE(eqnSys2.size() == 4); REQUIRE(eqnSys2.explicitOperation() == -2.0); REQUIRE(-eqnSys2.explicitOperation() == 2.0); - dsl::EqnSystem combinedEqnSys = eqnSys2 - eqnSys; - REQUIRE(combinedEqnSys.eqnTerms_.size() == 8); - REQUIRE(combinedEqnSys.explicitOperation() == -2.0); + + SECTION("multiplying eqnSys by 2") + { + dsl::EqnSystem multiplyEqnSys = 2.0 * eqnSys2; + REQUIRE(multiplyEqnSys.size() == 4); + REQUIRE(multiplyEqnSys.explicitOperation() == -4.0); + } + + SECTION("adding eqnSys to eqnSys2") + { + dsl::EqnSystem addEqnSys = eqnSys2 + eqnSys; + REQUIRE(addEqnSys.size() == 8); + REQUIRE(addEqnSys.explicitOperation() == -2.0); + } + SECTION("subtracting eqnSys from eqnSys2") + { + std::cout << "subtracting eqnSys from eqnSys2" << std::endl; + dsl::EqnSystem subtractEqnSys = eqnSys - eqnSys2; + REQUIRE(subtractEqnSys.size() == 8); + REQUIRE(subtractEqnSys.explicitOperation() == 2.0); + } } } From a2f18f8d6badafebd9192e50da9245178313f875 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Thu, 25 Jul 2024 12:22:04 +0200 Subject: [PATCH 13/63] added forward euler as integration method --- .../timeIntegration/forwardEuler.hpp | 39 ++++++++++ .../timeIntegration/timeIntegration.hpp | 76 +++++++++++++++++++ src/CMakeLists.txt | 3 +- .../timeIntegration/forwardEuler.cpp | 30 ++++++++ test/finiteVolume/CMakeLists.txt | 1 + .../timeIntegration/CMakeLists.txt | 4 + .../timeIntegration/timeIntegration.cpp | 63 +++++++++++++++ 7 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp create mode 100644 include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp create mode 100644 src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp create mode 100644 test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt create mode 100644 test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp new file mode 100644 index 000000000..303ef9022 --- /dev/null +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023 NeoFOAM authors + +#pragma once + +#include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/core/executor/executor.hpp" +#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" +#include "NeoFOAM/mesh/unstructured.hpp" + +#include "Kokkos_Core.hpp" + +#include + + +namespace NeoFOAM::finiteVolume::cellCentred +{ + + +class ForwardEuler : public TimeIntegrationFactory::Register +{ + +public: + + ForwardEuler(const dsl::EqnSystem& eqnSystem, const Dictionary& dict); + + static std::string name() { return "forwardEuler"; } + + static std::string doc() { return "forwardEuler timeIntegration"; } + + static std::string schema() { return "none"; } + + + void solve() override; + + std::unique_ptr clone() const override; +}; + +} // namespace NeoFOAM diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp new file mode 100644 index 000000000..98c34bf5a --- /dev/null +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023 NeoFOAM authors + +#pragma once + +#include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/core/executor/executor.hpp" +#include "NeoFOAM/mesh/unstructured.hpp" +#include "NeoFOAM/finiteVolume/cellCentred.hpp" + +#include "NeoFOAM/DSL/eqnTerm.hpp" +#include "NeoFOAM/DSL/eqnSystem.hpp" + +#include "Kokkos_Core.hpp" + +#include + +namespace dsl = NeoFOAM::DSL; + +namespace NeoFOAM::finiteVolume::cellCentred +{ + +class TimeIntegrationFactory : + public NeoFOAM::RuntimeSelectionFactory< + TimeIntegrationFactory, + Parameters> +{ + +public: + + static std::string name() { return "timeIntegrationFactory"; } + + TimeIntegrationFactory(const dsl::EqnSystem& eqnSystem, const Dictionary& dict) + : eqnSystem_(eqnSystem), dict_(dict) + {} + + virtual ~TimeIntegrationFactory() {} // Virtual destructor + + virtual void solve() = 0; // Pure virtual function for solving + + // Pure virtual function for cloning + virtual std::unique_ptr clone() const = 0; + +protected: + + dsl::EqnSystem eqnSystem_; + const Dictionary& dict_; +}; + +class TimeIntegration +{ + +public: + + TimeIntegration(const TimeIntegration& timeIntegrate) + : timeIntegrateStrategy_(timeIntegrate.timeIntegrateStrategy_->clone()) {}; + + TimeIntegration(TimeIntegration&& timeIntegrate) + : timeIntegrateStrategy_(std::move(timeIntegrate.timeIntegrateStrategy_)) {}; + + TimeIntegration(const dsl::EqnSystem& eqnSystem, const Dictionary& dict) + : timeIntegrateStrategy_( + TimeIntegrationFactory::create(dict.get("type"), eqnSystem, dict) + ) {}; + + + void solve() { timeIntegrateStrategy_->solve(); } + +private: + + + std::unique_ptr timeIntegrateStrategy_; +}; + + +} // namespace NeoFOAM diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e7399cd8a..86bf09ce3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,7 +29,8 @@ target_sources( "finiteVolume/cellCentred/operators/gaussGreenGrad.cpp" "finiteVolume/cellCentred/operators/gaussGreenDiv.cpp" "finiteVolume/cellCentred/interpolation/linear.cpp" - "finiteVolume/cellCentred/interpolation/upwind.cpp") + "finiteVolume/cellCentred/interpolation/upwind.cpp" + "finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp") include(${CMAKE_SOURCE_DIR}/cmake/Sanitizer.cmake) enable_sanitizers( diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp new file mode 100644 index 000000000..3de97c523 --- /dev/null +++ b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023 NeoFOAM authors + +#include + +#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp" +#include "NeoFOAM/core/error.hpp" +#include "NeoFOAM/core/parallelAlgorithms.hpp" + +namespace NeoFOAM::finiteVolume::cellCentred +{ + + +ForwardEuler::ForwardEuler(const dsl::EqnSystem& eqnSystem, const Dictionary& dict) + : TimeIntegrationFactory::Register(eqnSystem, dict) +{ + // Constructor +} + +void ForwardEuler::solve() +{ + // Solve function +} + +std::unique_ptr ForwardEuler::clone() const +{ + return std::make_unique(*this); +} + +} // namespace NeoFOAM diff --git a/test/finiteVolume/CMakeLists.txt b/test/finiteVolume/CMakeLists.txt index 564d38f7b..7213b6f5a 100644 --- a/test/finiteVolume/CMakeLists.txt +++ b/test/finiteVolume/CMakeLists.txt @@ -4,3 +4,4 @@ add_subdirectory(cellCentred/fields) add_subdirectory(cellCentred/boundary) add_subdirectory(cellCentred/interpolation) +add_subdirectory(cellCentred/timeIntegration) diff --git a/test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt b/test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt new file mode 100644 index 000000000..fd05e4245 --- /dev/null +++ b/test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Unlicense +# SPDX-FileCopyrightText: 2024 NeoFOAM authors + +neofoam_unit_test(timeIntegration) diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp new file mode 100644 index 000000000..d00fe7997 --- /dev/null +++ b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2024 NeoFOAM authors + +#define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create + // a custom main +#include +#include +#include + +#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" +#include "NeoFOAM/core/dictionary.hpp" + + +#include "NeoFOAM/DSL/eqnTerm.hpp" +#include "NeoFOAM/DSL/eqnSystem.hpp" + + +namespace dsl = NeoFOAM::DSL; + +class Divergence +{ + +public: + + std::string display() const { return "Divergence"; } + + void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } + + dsl::EqnTerm::Type getType() const { return termType_; } + + dsl::EqnTerm::Type termType_; +}; + +class TimeTerm +{ + +public: + + std::string display() const { return "TimeTerm"; } + + void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } + + dsl::EqnTerm::Type getType() const { return termType_; } + + dsl::EqnTerm::Type termType_; +}; + + +TEST_CASE("TimeIntegration") +{ + namespace fvcc = NeoFOAM::finiteVolume::cellCentred; + + NeoFOAM::Dictionary dict; + dict.insert("type", std::string("forwardEuler")); + + dsl::EqnTerm divTerm = Divergence(dsl::EqnTerm::Type::Explicit); + + dsl::EqnTerm ddtTerm = TimeTerm(dsl::EqnTerm::Type::Temporal); + + dsl::EqnSystem eqnSys = ddtTerm + divTerm; + + fvcc::TimeIntegration timeIntergrator(eqnSys, dict); +} From 29bf3f436f1626d0ced976b625304f7ec73499b0 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Thu, 25 Jul 2024 17:28:51 +0200 Subject: [PATCH 14/63] changes kokkos header --- .../finiteVolume/cellCentred/boundary/surface/calculated.hpp | 2 +- .../NeoFOAM/finiteVolume/cellCentred/boundary/surface/empty.hpp | 2 +- .../finiteVolume/cellCentred/boundary/surface/fixedValue.hpp | 2 +- .../finiteVolume/cellCentred/boundary/volume/calculated.hpp | 2 +- .../NeoFOAM/finiteVolume/cellCentred/boundary/volume/empty.hpp | 2 +- .../finiteVolume/cellCentred/boundary/volume/fixedGradient.hpp | 2 +- .../finiteVolume/cellCentred/boundary/volume/fixedValue.hpp | 2 +- .../NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp | 2 +- .../cellCentred/interpolation/surfaceInterpolation.hpp | 2 +- .../NeoFOAM/finiteVolume/cellCentred/interpolation/upwind.hpp | 2 +- .../finiteVolume/cellCentred/operators/gaussGreenDiv.hpp | 2 +- .../finiteVolume/cellCentred/operators/gaussGreenGrad.hpp | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/calculated.hpp b/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/calculated.hpp index c59d0c7bd..e508f5e9a 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/calculated.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/calculated.hpp @@ -3,7 +3,7 @@ #pragma once -#include "Kokkos_Core.hpp" +#include #include "NeoFOAM/core.hpp" #include "NeoFOAM/finiteVolume/cellCentred/boundary/surfaceBoundaryFactory.hpp" diff --git a/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/empty.hpp b/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/empty.hpp index 9220ad33b..3e327396d 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/empty.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/empty.hpp @@ -3,7 +3,7 @@ #pragma once -#include "Kokkos_Core.hpp" +#include #include "NeoFOAM/core.hpp" #include "NeoFOAM/finiteVolume/cellCentred/boundary/surfaceBoundaryFactory.hpp" diff --git a/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/fixedValue.hpp b/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/fixedValue.hpp index 8cca98fdf..b071ef7a9 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/fixedValue.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/boundary/surface/fixedValue.hpp @@ -3,7 +3,7 @@ #pragma once -#include "Kokkos_Core.hpp" +#include #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/finiteVolume/cellCentred/boundary/surfaceBoundaryFactory.hpp" diff --git a/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/calculated.hpp b/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/calculated.hpp index b85298ec8..497f77db0 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/calculated.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/calculated.hpp @@ -3,7 +3,7 @@ #pragma once -#include "Kokkos_Core.hpp" +#include #include "NeoFOAM/core.hpp" #include "NeoFOAM/finiteVolume/cellCentred/boundary/volumeBoundaryFactory.hpp" diff --git a/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/empty.hpp b/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/empty.hpp index c156310c7..4479a3374 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/empty.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/empty.hpp @@ -3,7 +3,7 @@ #pragma once -#include "Kokkos_Core.hpp" +#include #include "NeoFOAM/core.hpp" #include "NeoFOAM/finiteVolume/cellCentred/boundary/volumeBoundaryFactory.hpp" diff --git a/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/fixedGradient.hpp b/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/fixedGradient.hpp index f1b1d61cd..4b299d591 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/fixedGradient.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/fixedGradient.hpp @@ -3,7 +3,7 @@ #pragma once -#include "Kokkos_Core.hpp" +#include #include "NeoFOAM/finiteVolume/cellCentred/boundary/volumeBoundaryFactory.hpp" #include "NeoFOAM/mesh/unstructured.hpp" diff --git a/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/fixedValue.hpp b/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/fixedValue.hpp index f374b80ef..65580f4c2 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/fixedValue.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/boundary/volume/fixedValue.hpp @@ -3,7 +3,7 @@ #pragma once -#include "Kokkos_Core.hpp" +#include #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/finiteVolume/cellCentred/boundary/volumeBoundaryFactory.hpp" diff --git a/include/NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp b/include/NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp index cbcb78e6e..1bce8bc7e 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp @@ -9,7 +9,7 @@ #include "NeoFOAM/mesh/unstructured.hpp" #include "NeoFOAM/finiteVolume/cellCentred/stencil/geometryScheme.hpp" -#include "Kokkos_Core.hpp" +#include #include diff --git a/include/NeoFOAM/finiteVolume/cellCentred/interpolation/surfaceInterpolation.hpp b/include/NeoFOAM/finiteVolume/cellCentred/interpolation/surfaceInterpolation.hpp index 12a3d1ed1..d47b35cd6 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/interpolation/surfaceInterpolation.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/interpolation/surfaceInterpolation.hpp @@ -8,7 +8,7 @@ #include "NeoFOAM/mesh/unstructured.hpp" #include "NeoFOAM/finiteVolume/cellCentred.hpp" -#include "Kokkos_Core.hpp" +#include #include diff --git a/include/NeoFOAM/finiteVolume/cellCentred/interpolation/upwind.hpp b/include/NeoFOAM/finiteVolume/cellCentred/interpolation/upwind.hpp index 3cdf42ac8..469e24c7d 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/interpolation/upwind.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/interpolation/upwind.hpp @@ -9,7 +9,7 @@ #include "NeoFOAM/mesh/unstructured.hpp" #include "NeoFOAM/finiteVolume/cellCentred/stencil/geometryScheme.hpp" -#include "Kokkos_Core.hpp" +#include #include diff --git a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp index ce8dd5f68..49ec8bbfb 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp @@ -3,7 +3,7 @@ #pragma once -#include "Kokkos_Core.hpp" +#include #include diff --git a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp index 43629ec75..117f155f0 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp @@ -5,7 +5,7 @@ #include -#include "Kokkos_Core.hpp" +#include #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/core/executor/executor.hpp" From 3a954c593b5391b4401bb7f4086db58cdfb13f4b Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Thu, 25 Jul 2024 17:29:39 +0200 Subject: [PATCH 15/63] eqnTerm uses field --- include/NeoFOAM/DSL/eqnSystem.hpp | 28 +++-- include/NeoFOAM/DSL/eqnTerm.hpp | 33 ++++-- .../timeIntegration/forwardEuler.hpp | 2 - .../timeIntegration/timeIntegration.hpp | 2 - test/CMakeLists.txt | 2 +- test/catch2/test_main.cpp | 2 +- test/dsl/dsl.cpp | 103 ++++++++++++------ .../timeIntegration/timeIntegration.cpp | 40 ++++++- 8 files changed, 154 insertions(+), 58 deletions(-) diff --git a/include/NeoFOAM/DSL/eqnSystem.hpp b/include/NeoFOAM/DSL/eqnSystem.hpp index f6fd69f84..e7e695658 100644 --- a/include/NeoFOAM/DSL/eqnSystem.hpp +++ b/include/NeoFOAM/DSL/eqnSystem.hpp @@ -7,6 +7,8 @@ #include #include +#include "NeoFOAM/core/primitives/scalar.hpp" +#include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/DSL/eqnTerm.hpp" #include "NeoFOAM/core/error.hpp" @@ -17,14 +19,19 @@ class EqnSystem { public: - NeoFOAM::scalar explicitOperation() + EqnSystem(const NeoFOAM::Executor& exec, std::size_t nCells) + : exec_(exec), nCells_(nCells), temporalTerms_(), implicitTerms_(), explicitTerms_() + {} + + NeoFOAM::Field explicitOperation() { - NeoFOAM::scalar exp = 0; + NeoFOAM::Field source(exec_, nCells_); + NeoFOAM::fill(source, 0.0); for (auto& eqnTerm : explicitTerms_) { - eqnTerm.explicitOperation(exp); + eqnTerm.explicitOperation(source); } - return exp; + return source; } void addTerm(const EqnTerm& eqnTerm) @@ -87,8 +94,14 @@ class EqnSystem const std::vector& explicitTerms() const { return explicitTerms_; } + const NeoFOAM::Executor& exec() const { return exec_; } + + const std::size_t nCells() const { return nCells_; } + private: + const NeoFOAM::Executor exec_; + const std::size_t nCells_; std::vector temporalTerms_; std::vector implicitTerms_; std::vector explicitTerms_; @@ -111,7 +124,7 @@ EqnSystem operator+(const EqnSystem& lhs, const EqnTerm& rhs) EqnSystem operator+(const EqnTerm& lhs, const EqnTerm& rhs) { - EqnSystem eqnSys; + EqnSystem eqnSys(lhs.exec(), lhs.nCells()); eqnSys.addTerm(lhs); eqnSys.addTerm(rhs); return eqnSys; @@ -119,7 +132,7 @@ EqnSystem operator+(const EqnTerm& lhs, const EqnTerm& rhs) EqnSystem operator*(NeoFOAM::scalar scale, const EqnSystem& es) { - EqnSystem results; + EqnSystem results(es.exec(), es.nCells()); for (const auto& eqnTerm : es.temporalTerms()) { results.addTerm(scale * eqnTerm); @@ -137,7 +150,6 @@ EqnSystem operator*(NeoFOAM::scalar scale, const EqnSystem& es) EqnSystem operator-(const EqnSystem& lhs, const EqnSystem& rhs) { - std::cout << "Subtracting EqnSystem from EqnSystem" << std::endl; EqnSystem results = lhs; results.addSystem(-1.0 * rhs); return results; @@ -152,7 +164,7 @@ EqnSystem operator-(const EqnSystem& lhs, const EqnTerm& rhs) EqnSystem operator-(const EqnTerm& lhs, const EqnTerm& rhs) { - EqnSystem results; + EqnSystem results(lhs.exec(), lhs.nCells()); results.addTerm(lhs); results.addTerm(-1.0 * rhs); return results; diff --git a/include/NeoFOAM/DSL/eqnTerm.hpp b/include/NeoFOAM/DSL/eqnTerm.hpp index ee5f6a217..74f7dd365 100644 --- a/include/NeoFOAM/DSL/eqnTerm.hpp +++ b/include/NeoFOAM/DSL/eqnTerm.hpp @@ -8,6 +8,7 @@ #include #include "NeoFOAM/core/primitives/scalar.hpp" +#include "NeoFOAM/fields/field.hpp" namespace NeoFOAM::DSL { @@ -46,9 +47,9 @@ class EqnTerm std::string display() const { return model_->display(); } - void explicitOperation(NeoFOAM::scalar& exp) + void explicitOperation(NeoFOAM::Field& source) { - model_->explicitOperation(exp, model_->scaleCoeff); + model_->explicitOperation(source, model_->scaleCoeff); } EqnTerm::Type getType() const { return model_->getType(); } @@ -56,6 +57,11 @@ class EqnTerm void setScale(NeoFOAM::scalar scale) { model_->scaleCoeff *= scale; } + const NeoFOAM::Executor& exec() const { return model_->exec(); } + + std::size_t nCells() const { return model_->nCells(); } + + private: // Base class to hold the type-erased value and the display function @@ -63,11 +69,16 @@ class EqnTerm { virtual ~Concept() = default; virtual std::string display() const = 0; - virtual void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) = 0; - // The Prototype Design Pattern - virtual std::unique_ptr clone() const = 0; + virtual void + explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) = 0; NeoFOAM::scalar scaleCoeff = 1.0; virtual EqnTerm::Type getType() const = 0; + + virtual const NeoFOAM::Executor& exec() const = 0; + virtual std::size_t nCells() const = 0; + + // The Prototype Design Pattern + virtual std::unique_ptr clone() const = 0; }; // Templated derived class to implement the type-specific behavior @@ -78,17 +89,23 @@ class EqnTerm std::string display() const override { return cls_.display(); } - virtual void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) override + virtual void + explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) override { - cls_.explicitOperation(exp, scale); + cls_.explicitOperation(source, scale); } + EqnTerm::Type getType() const override { return cls_.getType(); } - T cls_; + const NeoFOAM::Executor& exec() const override { return cls_.exec(); } + + std::size_t nCells() const override { return cls_.nCells(); } // The Prototype Design Pattern std::unique_ptr clone() const override { return std::make_unique(*this); } + + T cls_; }; std::unique_ptr model_; diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp index 303ef9022..1509044b6 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp @@ -8,8 +8,6 @@ #include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" #include "NeoFOAM/mesh/unstructured.hpp" -#include "Kokkos_Core.hpp" - #include diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp index 98c34bf5a..63fcd57aa 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp @@ -11,8 +11,6 @@ #include "NeoFOAM/DSL/eqnTerm.hpp" #include "NeoFOAM/DSL/eqnSystem.hpp" -#include "Kokkos_Core.hpp" - #include namespace dsl = NeoFOAM::DSL; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 80d8ffdce..299581df7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -74,4 +74,4 @@ add_subdirectory(core) add_subdirectory(fields) add_subdirectory(finiteVolume) add_subdirectory(mesh) -add_subdirectory(dsl) +# add_subdirectory(dsl) diff --git a/test/catch2/test_main.cpp b/test/catch2/test_main.cpp index 35f25e599..304ac404d 100644 --- a/test/catch2/test_main.cpp +++ b/test/catch2/test_main.cpp @@ -7,7 +7,7 @@ #include "catch2/catch_test_macros.hpp" #include "catch2/generators/catch_generators_adapters.hpp" #include "catch2/reporters/catch_reporter_registrars.hpp" -#include "Kokkos_Core.hpp" +#include int main(int argc, char* argv[]) diff --git a/test/dsl/dsl.cpp b/test/dsl/dsl.cpp index 0b412deb3..859ea6df8 100644 --- a/test/dsl/dsl.cpp +++ b/test/dsl/dsl.cpp @@ -19,11 +19,26 @@ class Laplacian std::string display() const { return "Laplacian"; } - void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } + void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) + { + auto sourceField = source.span(); + NeoFOAM::parallelFor( + source.exec(), + {0, source.size()}, + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } + ); + } dsl::EqnTerm::Type getType() const { return termType_; } + const NeoFOAM::Executor& exec() const { return exec_; } + + const std::size_t nCells() const { return nCells_; } + dsl::EqnTerm::Type termType_; + + const NeoFOAM::Executor exec_; + const std::size_t nCells_; }; class Divergence @@ -33,116 +48,140 @@ class Divergence std::string display() const { return "Divergence"; } - void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } + void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) + { + auto sourceField = source.span(); + NeoFOAM::parallelFor( + source.exec(), + {0, source.size()}, + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } + ); + } dsl::EqnTerm::Type getType() const { return termType_; } + + const NeoFOAM::Executor& exec() const { return exec_; } + + const std::size_t nCells() const { return nCells_; } + dsl::EqnTerm::Type termType_; + + const NeoFOAM::Executor exec_; + const std::size_t nCells_; }; +NeoFOAM::scalar getField(const NeoFOAM::Field& source) +{ + auto sourceField = source.copyToHost().span(); + return sourceField[0]; +} TEST_CASE("DSL") { - dsl::EqnTerm lapTerm = Laplacian(dsl::EqnTerm::Type::Explicit); + auto exec = NeoFOAM::SerialExecutor(); + dsl::EqnTerm lapTerm = Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1); REQUIRE("Laplacian" == lapTerm.display()); - dsl::EqnTerm divTerm = Divergence(dsl::EqnTerm::Type::Explicit); + dsl::EqnTerm divTerm = Divergence(dsl::EqnTerm::Type::Explicit, exec, 1); REQUIRE("Divergence" == divTerm.display()); - NeoFOAM::scalar source = 0; + { + NeoFOAM::Field source(exec, 1); + NeoFOAM::fill(source, 0.0); - lapTerm.explicitOperation(source); - divTerm.explicitOperation(source); + lapTerm.explicitOperation(source); + divTerm.explicitOperation(source); - REQUIRE(source == 2.0); + REQUIRE(getField(source) == 2.0); + } { dsl::EqnSystem eqnSys = lapTerm + divTerm; REQUIRE(eqnSys.size() == 2); - REQUIRE(eqnSys.explicitOperation() == 2); + REQUIRE(getField(eqnSys.explicitOperation()) == 2); } { dsl::EqnSystem eqnSys(lapTerm + lapTerm + divTerm + divTerm); REQUIRE(eqnSys.size() == 4); - REQUIRE(eqnSys.explicitOperation() == 4.0); + REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); } { - dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit)); + dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); REQUIRE(eqnSys.size() == 2); - REQUIRE(eqnSys.explicitOperation() == 2.0); + REQUIRE(getField(eqnSys.explicitOperation()) == 2.0); } { dsl::EqnSystem eqnSys = lapTerm - divTerm; REQUIRE(eqnSys.size() == 2); - REQUIRE(eqnSys.explicitOperation() == 0.0); + REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); } { - dsl::EqnSystem eqnSys(lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit)); + dsl::EqnSystem eqnSys(lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); REQUIRE(eqnSys.size() == 2); - REQUIRE(eqnSys.explicitOperation() == 0.0); + REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); } { dsl::EqnSystem eqnSys(lapTerm - lapTerm - divTerm - divTerm); REQUIRE(eqnSys.size() == 4); - REQUIRE(eqnSys.explicitOperation() == -2.0); + REQUIRE(getField(eqnSys.explicitOperation()) == -2.0); } { dsl::EqnSystem eqnSys( - lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit) + divTerm - + Divergence(dsl::EqnTerm::Type::Explicit) + lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm + + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) ); dsl::EqnSystem eqnSys2( - lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit) + divTerm - + Divergence(dsl::EqnTerm::Type::Explicit) + lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm + + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) ); REQUIRE(eqnSys.size() == 4); - REQUIRE(eqnSys.explicitOperation() == 4.0); + REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; REQUIRE(combinedEqnSys.size() == 8); - REQUIRE(combinedEqnSys.explicitOperation() == 8.0); + REQUIRE(getField(combinedEqnSys.explicitOperation()) == 8.0); } { dsl::EqnSystem eqnSys( - lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit) - divTerm - - Divergence(dsl::EqnTerm::Type::Explicit) + lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - divTerm + - Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) ); dsl::EqnSystem eqnSys2( - lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit) - divTerm - - Divergence(dsl::EqnTerm::Type::Explicit) + lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - divTerm + - Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) ); REQUIRE(eqnSys.size() == 4); - REQUIRE(eqnSys.explicitOperation() == 0.0); + REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); REQUIRE(eqnSys2.size() == 4); - REQUIRE(eqnSys2.explicitOperation() == -2.0); - REQUIRE(-eqnSys2.explicitOperation() == 2.0); + REQUIRE(getField(eqnSys2.explicitOperation()) == -2.0); SECTION("multiplying eqnSys by 2") { dsl::EqnSystem multiplyEqnSys = 2.0 * eqnSys2; REQUIRE(multiplyEqnSys.size() == 4); - REQUIRE(multiplyEqnSys.explicitOperation() == -4.0); + REQUIRE(getField(multiplyEqnSys.explicitOperation()) == -4.0); } SECTION("adding eqnSys to eqnSys2") { dsl::EqnSystem addEqnSys = eqnSys2 + eqnSys; REQUIRE(addEqnSys.size() == 8); - REQUIRE(addEqnSys.explicitOperation() == -2.0); + REQUIRE(getField(addEqnSys.explicitOperation()) == -2.0); } SECTION("subtracting eqnSys from eqnSys2") { std::cout << "subtracting eqnSys from eqnSys2" << std::endl; dsl::EqnSystem subtractEqnSys = eqnSys - eqnSys2; REQUIRE(subtractEqnSys.size() == 8); - REQUIRE(subtractEqnSys.explicitOperation() == 2.0); + REQUIRE(getField(subtractEqnSys.explicitOperation()) == 2.0); } } } diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp index d00fe7997..748f189cc 100644 --- a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp +++ b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp @@ -9,6 +9,7 @@ #include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" #include "NeoFOAM/core/dictionary.hpp" +#include "NeoFOAM/core/parallelAlgorithms.hpp" #include "NeoFOAM/DSL/eqnTerm.hpp" @@ -24,11 +25,26 @@ class Divergence std::string display() const { return "Divergence"; } - void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } + void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) + { + auto sourceField = source.span(); + NeoFOAM::parallelFor( + source.exec(), + {0, source.size()}, + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } + ); + } dsl::EqnTerm::Type getType() const { return termType_; } + + const NeoFOAM::Executor& exec() const { return exec_; } + + std::size_t nCells() const { return nCells_; } + dsl::EqnTerm::Type termType_; + NeoFOAM::Executor exec_; + std::size_t nCells_; }; class TimeTerm @@ -38,24 +54,40 @@ class TimeTerm std::string display() const { return "TimeTerm"; } - void explicitOperation(NeoFOAM::scalar& exp, NeoFOAM::scalar scale) { exp += 1 * scale; } + void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) + { + auto sourceField = source.span(); + NeoFOAM::parallelFor( + source.exec(), + {0, source.size()}, + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1 * scale; } + ); + } dsl::EqnTerm::Type getType() const { return termType_; } + + const NeoFOAM::Executor& exec() const { return exec_; } + + std::size_t nCells() const { return nCells_; } + dsl::EqnTerm::Type termType_; + const NeoFOAM::Executor exec_; + std::size_t nCells_; }; TEST_CASE("TimeIntegration") { + auto exec = NeoFOAM::SerialExecutor(); namespace fvcc = NeoFOAM::finiteVolume::cellCentred; NeoFOAM::Dictionary dict; dict.insert("type", std::string("forwardEuler")); - dsl::EqnTerm divTerm = Divergence(dsl::EqnTerm::Type::Explicit); + dsl::EqnTerm divTerm = Divergence(dsl::EqnTerm::Type::Explicit, exec, 1); - dsl::EqnTerm ddtTerm = TimeTerm(dsl::EqnTerm::Type::Temporal); + dsl::EqnTerm ddtTerm = TimeTerm(dsl::EqnTerm::Type::Temporal, exec, 1); dsl::EqnSystem eqnSys = ddtTerm + divTerm; From 90ec6ee6515503b67aa9d1ead8bd81d46a888da7 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Thu, 11 Jul 2024 22:01:11 +0200 Subject: [PATCH 16/63] initial commit --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d8db173d..5c4050cc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Version 0.1.0 (unreleased) +- Implement a DSL interface []() - improved error handling and addition of tokenList and Input [#134](https://github.com/exasim-project/NeoFOAM/pull/134) - disable span from temporary objects and simplification related to fields [#139](https://github.com/exasim-project/NeoFOAM/pull/139) - added launch json to debug unit test in vscode [#135](https://github.com/exasim-project/NeoFOAM/pull/135) From d2aa27494147511a585aa7b03fb279859bfe54c7 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Fri, 26 Jul 2024 12:30:19 +0200 Subject: [PATCH 17/63] FIX: false specified executor --- .../cellCentred/operators/gaussGreenDiv.hpp | 4 + .../cellCentred/operators/gaussGreenDiv.cpp | 85 ++++++++++++++++++- .../cellCentred/operators/gaussGreenGrad.cpp | 2 +- 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp index 49ec8bbfb..abfd78044 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp @@ -27,6 +27,10 @@ class GaussGreenDiv div(VolumeField& divPhi, const SurfaceField& faceFlux, VolumeField& phi ); + void + div(Field& divPhi, const SurfaceField& faceFlux, VolumeField& phi + ); + private: SurfaceInterpolation surfaceInterpolation_; diff --git a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp index d1193f4bb..c8507a517 100644 --- a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp +++ b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp @@ -35,7 +35,83 @@ void computeDiv( // check if the executor is GPU - if (std::holds_alternative(exec)) + if (std::holds_alternative(exec)) + { + for (size_t i = 0; i < nInternalFaces; i++) + { + scalar flux = surfFaceFlux[i] * surfPhif[i]; + surfDivPhi[surfOwner[i]] += flux; + surfDivPhi[surfNeighbour[i]] -= flux; + } + + for (size_t i = nInternalFaces; i < surfPhif.size(); i++) + { + int32_t own = surfFaceCells[i - nInternalFaces]; + scalar valueOwn = surfFaceFlux[i] * surfPhif[i]; + surfDivPhi[own] += valueOwn; + } + + + for (size_t celli = 0; celli < mesh.nCells(); celli++) + { + surfDivPhi[celli] *= 1 / surfV[celli]; + } + } + else + { + parallelFor( + exec, + {0, nInternalFaces}, + KOKKOS_LAMBDA(const size_t i) { + scalar flux = surfFaceFlux[i] * surfPhif[i]; + Kokkos::atomic_add(&surfDivPhi[surfOwner[i]], flux); + Kokkos::atomic_sub(&surfDivPhi[surfNeighbour[i]], flux); + } + ); + + parallelFor( + exec, + {nInternalFaces, surfPhif.size()}, + KOKKOS_LAMBDA(const size_t i) { + int32_t own = surfFaceCells[i - nInternalFaces]; + scalar valueOwn = surfFaceFlux[i] * surfPhif[i]; + Kokkos::atomic_add(&surfDivPhi[own], valueOwn); + } + ); + + parallelFor( + exec, + {0, mesh.nCells()}, + KOKKOS_LAMBDA(const size_t celli) { surfDivPhi[celli] *= 1 / surfV[celli]; } + ); + } +} + +void computeDiv( + const SurfaceField& faceFlux, + const VolumeField& phi, + const SurfaceInterpolation& surfInterp, + Field& divPhi +) +{ + const UnstructuredMesh& mesh = phi.mesh(); + const auto exec = phi.exec(); + SurfaceField phif(exec, mesh, createCalculatedBCs(mesh)); + const auto surfFaceCells = mesh.boundaryMesh().faceCells().span(); + surfInterp.interpolate(phif, faceFlux, phi); + + auto surfDivPhi = divPhi.span(); + + const auto surfPhif = phif.internalField().span(); + const auto surfOwner = mesh.faceOwner().span(); + const auto surfNeighbour = mesh.faceNeighbour().span(); + const auto surfFaceFlux = faceFlux.internalField().span(); + size_t nInternalFaces = mesh.nInternalFaces(); + const auto surfV = mesh.cellVolumes().span(); + + + // check if the executor is GPU + if (std::holds_alternative(exec)) { for (size_t i = 0; i < nInternalFaces; i++) { @@ -101,4 +177,11 @@ void GaussGreenDiv::div( computeDiv(faceFlux, phi, surfaceInterpolation_, divPhi); }; +void GaussGreenDiv::div( + Field& divPhi, const SurfaceField& faceFlux, VolumeField& phi +) +{ + computeDiv(faceFlux, phi, surfaceInterpolation_, divPhi); +}; + }; diff --git a/src/finiteVolume/cellCentred/operators/gaussGreenGrad.cpp b/src/finiteVolume/cellCentred/operators/gaussGreenGrad.cpp index f0f8c4451..e29026822 100644 --- a/src/finiteVolume/cellCentred/operators/gaussGreenGrad.cpp +++ b/src/finiteVolume/cellCentred/operators/gaussGreenGrad.cpp @@ -32,7 +32,7 @@ void computeGrad( const auto surfV = mesh.cellVolumes().span(); - if (std::holds_alternative(exec)) + if (std::holds_alternative(exec)) { for (size_t i = 0; i < nInternalFaces; i++) { From 5f64d8c0c40320a77f66acfedd58d24643191b3d Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Fri, 26 Jul 2024 12:31:39 +0200 Subject: [PATCH 18/63] WIP: forwardEuler --- include/NeoFOAM/DSL/eqnSystem.hpp | 26 ++++++++- include/NeoFOAM/DSL/eqnTerm.hpp | 56 ++++++++++++++++--- .../timeIntegration/forwardEuler.cpp | 21 ++++++- .../timeIntegration/timeIntegration.cpp | 2 + 4 files changed, 95 insertions(+), 10 deletions(-) diff --git a/include/NeoFOAM/DSL/eqnSystem.hpp b/include/NeoFOAM/DSL/eqnSystem.hpp index e7e695658..a0c1ccc67 100644 --- a/include/NeoFOAM/DSL/eqnSystem.hpp +++ b/include/NeoFOAM/DSL/eqnSystem.hpp @@ -20,7 +20,7 @@ class EqnSystem public: EqnSystem(const NeoFOAM::Executor& exec, std::size_t nCells) - : exec_(exec), nCells_(nCells), temporalTerms_(), implicitTerms_(), explicitTerms_() + : exec_(exec), nCells_(nCells), temporalTerms_(), implicitTerms_(), explicitTerms_(), volumeField_(nullptr) {} NeoFOAM::Field explicitOperation() @@ -94,10 +94,33 @@ class EqnSystem const std::vector& explicitTerms() const { return explicitTerms_; } + std::vector& temporalTerms() { return temporalTerms_; } + + std::vector& implicitTerms() { return implicitTerms_; } + + std::vector& explicitTerms() { return explicitTerms_; } + const NeoFOAM::Executor& exec() const { return exec_; } const std::size_t nCells() const { return nCells_; } + fvcc::VolumeField* volumeField() + { + if (temporalTerms_.size() == 0 && implicitTerms_.size() == 0) + { + NF_ERROR_EXIT("No temporal or implicit terms to solve."); + } + if (temporalTerms_.size() > 0) + { + volumeField_ = temporalTerms_[0].volumeField(); + } + else + { + volumeField_ = implicitTerms_[0].volumeField(); + } + return volumeField_; + } + private: const NeoFOAM::Executor exec_; @@ -105,6 +128,7 @@ class EqnSystem std::vector temporalTerms_; std::vector implicitTerms_; std::vector explicitTerms_; + fvcc::VolumeField* volumeField_; }; EqnSystem operator+(const EqnSystem& lhs, const EqnSystem& rhs) diff --git a/include/NeoFOAM/DSL/eqnTerm.hpp b/include/NeoFOAM/DSL/eqnTerm.hpp index 74f7dd365..3e2eab1e2 100644 --- a/include/NeoFOAM/DSL/eqnTerm.hpp +++ b/include/NeoFOAM/DSL/eqnTerm.hpp @@ -9,10 +9,30 @@ #include "NeoFOAM/core/primitives/scalar.hpp" #include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" + +namespace fvcc = NeoFOAM::finiteVolume::cellCentred; namespace NeoFOAM::DSL { +template +concept HasTemporalTerm = requires(T t) { + { + t.temporalOperation( + std::declval&>(), std::declval() + ) + } -> std::same_as; // Adjust return type and arguments as needed +}; + +template +concept HasExplicitTerm = requires(T t) { + { + t.explicitOperation( + std::declval&>(), std::declval() + ) + } -> std::same_as; // Adjust return type and arguments as needed +}; // EqnTerm class that uses type erasure without inheritance class EqnTerm { @@ -52,6 +72,11 @@ class EqnTerm model_->explicitOperation(source, model_->scaleCoeff); } + void temporalOperation(NeoFOAM::Field& field) + { + model_->temporalOperation(field, model_->scaleCoeff); + } + EqnTerm::Type getType() const { return model_->getType(); } void setScale(NeoFOAM::scalar scale) { model_->scaleCoeff *= scale; } @@ -62,6 +87,9 @@ class EqnTerm std::size_t nCells() const { return model_->nCells(); } + fvcc::VolumeField* volumeField() { return model_->volumeField(); } + + private: // Base class to hold the type-erased value and the display function @@ -71,11 +99,14 @@ class EqnTerm virtual std::string display() const = 0; virtual void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) = 0; + virtual void + temporalOperation(NeoFOAM::Field& field, NeoFOAM::scalar scale) = 0; NeoFOAM::scalar scaleCoeff = 1.0; virtual EqnTerm::Type getType() const = 0; virtual const NeoFOAM::Executor& exec() const = 0; virtual std::size_t nCells() const = 0; + virtual fvcc::VolumeField* volumeField() = 0; // The Prototype Design Pattern virtual std::unique_ptr clone() const = 0; @@ -92,9 +123,25 @@ class EqnTerm virtual void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) override { - cls_.explicitOperation(source, scale); + if constexpr (HasExplicitTerm) + { + cls_.explicitOperation(source, scale); + } } + virtual void + temporalOperation(NeoFOAM::Field& field, NeoFOAM::scalar scale) override + { + if constexpr (HasTemporalTerm) + { + cls_.temporalOperation(field, scale); + } + } + + virtual fvcc::VolumeField* volumeField() override + { + return cls_.volumeField(); + } EqnTerm::Type getType() const override { return cls_.getType(); } @@ -120,11 +167,4 @@ EqnTerm operator*(NeoFOAM::scalar scale, const EqnTerm& lhs) return result; } -// EqnTerm operator*(const EqnTerm& lhs,NeoFOAM::scalar scale) -// { -// EqnTerm result = lhs; -// result.setScale(scale); -// return result; -// } - } // namespace NeoFOAM::DSL diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp index 3de97c523..8b043342c 100644 --- a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp +++ b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp @@ -19,7 +19,26 @@ ForwardEuler::ForwardEuler(const dsl::EqnSystem& eqnSystem, const Dictionary& di void ForwardEuler::solve() { - // Solve function + std::cout << "Solving using Forward Euler" << std::endl; + scalar dt = 0.001; // Time step + fvcc::VolumeField* refField = eqnSystem_.volumeField(); + // Field Phi(eqnSystem_.exec(), eqnSystem_.nCells()); + // NeoFOAM::fill(Phi, 0.0); + Field source = eqnSystem_.explicitOperation(); + + // for (auto& eqnTerm : eqnSystem_.temporalTerms()) + // { + // eqnTerm.temporalOperation(Phi); + // } + // Phi += source*dt; + refField->internalField() -= source*dt; + refField->correctBoundaryConditions(); + + // check if execturo is GPU + if (std::holds_alternative(eqnSystem_.exec())) + { + Kokkos::fence(); + } } std::unique_ptr ForwardEuler::clone() const diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp index 748f189cc..e276213f1 100644 --- a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp +++ b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp @@ -37,6 +37,7 @@ class Divergence dsl::EqnTerm::Type getType() const { return termType_; } + fvcc::VolumeField* volumeField() const { return nullptr; } const NeoFOAM::Executor& exec() const { return exec_; } @@ -66,6 +67,7 @@ class TimeTerm dsl::EqnTerm::Type getType() const { return termType_; } + fvcc::VolumeField* volumeField() const { return nullptr; } const NeoFOAM::Executor& exec() const { return exec_; } From 8ec3309bfbdcef81dce9250fc8c0de670f08ba04 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Fri, 26 Jul 2024 17:33:20 +0200 Subject: [PATCH 19/63] added dt to eqnsystem --- include/NeoFOAM/DSL/eqnSystem.hpp | 1 + src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/NeoFOAM/DSL/eqnSystem.hpp b/include/NeoFOAM/DSL/eqnSystem.hpp index a0c1ccc67..03550dd19 100644 --- a/include/NeoFOAM/DSL/eqnSystem.hpp +++ b/include/NeoFOAM/DSL/eqnSystem.hpp @@ -121,6 +121,7 @@ class EqnSystem return volumeField_; } + NeoFOAM::scalar dt = 0; private: const NeoFOAM::Executor exec_; diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp index 8b043342c..208e8aff7 100644 --- a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp +++ b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp @@ -20,7 +20,7 @@ ForwardEuler::ForwardEuler(const dsl::EqnSystem& eqnSystem, const Dictionary& di void ForwardEuler::solve() { std::cout << "Solving using Forward Euler" << std::endl; - scalar dt = 0.001; // Time step + scalar dt = eqnSystem_.dt; fvcc::VolumeField* refField = eqnSystem_.volumeField(); // Field Phi(eqnSystem_.exec(), eqnSystem_.nCells()); // NeoFOAM::fill(Phi, 0.0); From d2109e71d1274290de1915885114c2ea686d4954 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Sat, 10 Aug 2024 13:09:28 +0200 Subject: [PATCH 20/63] DSl use move semantics reduce complexity to linear --- include/NeoFOAM/DSL/eqnSystem.hpp | 37 ++++++------- test/CMakeLists.txt | 2 +- test/dsl/dsl.cpp | 90 +++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 21 deletions(-) diff --git a/include/NeoFOAM/DSL/eqnSystem.hpp b/include/NeoFOAM/DSL/eqnSystem.hpp index 03550dd19..f7003720f 100644 --- a/include/NeoFOAM/DSL/eqnSystem.hpp +++ b/include/NeoFOAM/DSL/eqnSystem.hpp @@ -20,7 +20,8 @@ class EqnSystem public: EqnSystem(const NeoFOAM::Executor& exec, std::size_t nCells) - : exec_(exec), nCells_(nCells), temporalTerms_(), implicitTerms_(), explicitTerms_(), volumeField_(nullptr) + : exec_(exec), nCells_(nCells), temporalTerms_(), implicitTerms_(), explicitTerms_(), + volumeField_(nullptr) {} NeoFOAM::Field explicitOperation() @@ -104,7 +105,7 @@ class EqnSystem const std::size_t nCells() const { return nCells_; } - fvcc::VolumeField* volumeField() + fvcc::VolumeField* volumeField() { if (temporalTerms_.size() == 0 && implicitTerms_.size() == 0) { @@ -118,10 +119,11 @@ class EqnSystem { volumeField_ = implicitTerms_[0].volumeField(); } - return volumeField_; + return volumeField_; } NeoFOAM::scalar dt = 0; + private: const NeoFOAM::Executor exec_; @@ -132,19 +134,16 @@ class EqnSystem fvcc::VolumeField* volumeField_; }; -EqnSystem operator+(const EqnSystem& lhs, const EqnSystem& rhs) +EqnSystem operator+(EqnSystem lhs, const EqnSystem& rhs) { - std::cout << "Adding EqnSystem from EqnSystem" << std::endl; - EqnSystem results = lhs; - results.addSystem(rhs); - return results; + lhs.addSystem(rhs); + return lhs; } -EqnSystem operator+(const EqnSystem& lhs, const EqnTerm& rhs) +EqnSystem operator+(EqnSystem lhs, const EqnTerm& rhs) { - EqnSystem results = lhs; - results.addTerm(rhs); - return results; + lhs.addTerm(rhs); + return lhs; } EqnSystem operator+(const EqnTerm& lhs, const EqnTerm& rhs) @@ -173,18 +172,16 @@ EqnSystem operator*(NeoFOAM::scalar scale, const EqnSystem& es) return results; } -EqnSystem operator-(const EqnSystem& lhs, const EqnSystem& rhs) +EqnSystem operator-(EqnSystem lhs, const EqnSystem& rhs) { - EqnSystem results = lhs; - results.addSystem(-1.0 * rhs); - return results; + lhs.addSystem(-1.0 * rhs); + return lhs; } -EqnSystem operator-(const EqnSystem& lhs, const EqnTerm& rhs) +EqnSystem operator-(EqnSystem lhs, const EqnTerm& rhs) { - EqnSystem results = lhs; - results.addTerm(-1.0 * rhs); - return results; + lhs.addTerm(-1.0 * rhs); + return lhs; } EqnSystem operator-(const EqnTerm& lhs, const EqnTerm& rhs) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 299581df7..80d8ffdce 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -74,4 +74,4 @@ add_subdirectory(core) add_subdirectory(fields) add_subdirectory(finiteVolume) add_subdirectory(mesh) -# add_subdirectory(dsl) +add_subdirectory(dsl) diff --git a/test/dsl/dsl.cpp b/test/dsl/dsl.cpp index 859ea6df8..279562c68 100644 --- a/test/dsl/dsl.cpp +++ b/test/dsl/dsl.cpp @@ -5,12 +5,14 @@ #include #include #include +#include #include "NeoFOAM/DSL/eqnTerm.hpp" #include "NeoFOAM/DSL/eqnSystem.hpp" namespace dsl = NeoFOAM::DSL; +namespace fvcc = NeoFOAM::finiteVolume::cellCentred; class Laplacian { @@ -35,6 +37,8 @@ class Laplacian const std::size_t nCells() const { return nCells_; } + fvcc::VolumeField* volumeField() { return nullptr; } + dsl::EqnTerm::Type termType_; const NeoFOAM::Executor exec_; @@ -65,6 +69,8 @@ class Divergence const std::size_t nCells() const { return nCells_; } + fvcc::VolumeField* volumeField() { return nullptr; } + dsl::EqnTerm::Type termType_; const NeoFOAM::Executor exec_; @@ -102,18 +108,33 @@ TEST_CASE("DSL") REQUIRE(eqnSys.size() == 2); REQUIRE(getField(eqnSys.explicitOperation()) == 2); } + BENCHMARK("Creation from EqnTerm") + { + dsl::EqnSystem eqnSys = lapTerm + divTerm; + return eqnSys; + }; { dsl::EqnSystem eqnSys(lapTerm + lapTerm + divTerm + divTerm); REQUIRE(eqnSys.size() == 4); REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); } + BENCHMARK("Creation from multiple terms") + { + dsl::EqnSystem eqnSys2(lapTerm + lapTerm + divTerm + divTerm); + return eqnSys2; + }; { dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); REQUIRE(eqnSys.size() == 2); REQUIRE(getField(eqnSys.explicitOperation()) == 2.0); } + BENCHMARK("Creation from term and temporary term") + { + dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); + return eqnSys; + }; { dsl::EqnSystem eqnSys = lapTerm - divTerm; @@ -148,6 +169,19 @@ TEST_CASE("DSL") REQUIRE(combinedEqnSys.size() == 8); REQUIRE(getField(combinedEqnSys.explicitOperation()) == 8.0); } + BENCHMARK("Creation from term and temporary term") + { + dsl::EqnSystem eqnSys( + lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm + + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) + ); + dsl::EqnSystem eqnSys2( + lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm + + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) + ); + dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; + return combinedEqnSys; + }; { dsl::EqnSystem eqnSys( @@ -184,4 +218,60 @@ TEST_CASE("DSL") REQUIRE(getField(subtractEqnSys.explicitOperation()) == 2.0); } } + // profiling + // with different number of terms + BENCHMARK("Creation from 2 terms") + { + dsl::EqnSystem eqnSys(divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); + + return eqnSys; + }; + + BENCHMARK("Creation from 4 terms") + { + dsl::EqnSystem eqnSys( + divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + ); + + return eqnSys; + }; + + BENCHMARK("Creation from 8 terms") + { + dsl::EqnSystem eqnSys( + divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + ); + + return eqnSys; + }; + + BENCHMARK("Creation from 16 terms") + { + dsl::EqnSystem eqnSys( + divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + ); + + return eqnSys; + }; } From fd165d0a7448fc197bfde550039b41fea76d9bc1 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 13:25:50 +0200 Subject: [PATCH 21/63] Pull scaling field from from #136 Co-authored-by: Henning Scheufler --- include/NeoFOAM/fields/scalingField.hpp | 53 +++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 include/NeoFOAM/fields/scalingField.hpp diff --git a/include/NeoFOAM/fields/scalingField.hpp b/include/NeoFOAM/fields/scalingField.hpp new file mode 100644 index 000000000..eea2ad027 --- /dev/null +++ b/include/NeoFOAM/fields/scalingField.hpp @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023 NeoFOAM authors +#pragma once + +namespace NeoFOAM +{ + +/** + * @brief A wrapper class that represents either a span of values or a single value. + * + * This class is used to store either a span of values or a single value of type `ValueType`. + * It provides an indexing operator `operator[]` that returns the value at the specified index + * or a constant value and is used to scale fields in the DSL. + * + * @tparam ValueType The type of the values stored in the class. + */ +template +struct ScalingField +{ + ScalingField() = default; + ScalingField(std::span values) : values(values), value(1.0), useSpan(true) {} + + ScalingField(std::span values, NeoFOAM::scalar value) + : values(values), value(value), useSpan(true) + {} + + ScalingField(NeoFOAM::scalar value) : values(), value(value), useSpan(false) {} + + std::span values; + NeoFOAM::scalar value; + bool useSpan; + + KOKKOS_INLINE_FUNCTION + ValueType operator[](const size_t i) const { return useSpan ? values[i] * value : value; } + + void operator*=(NeoFOAM::scalar scale) { value *= scale; } + + void operator=(NeoFOAM::scalar scale) { value = scale; } + + void operator*=(Field scalingField) + { + auto scale = scalingField.span(); + // otherwise we are unable to capture values in the lambda + auto selfValue = values; + NeoFOAM::parallelFor( + scalingField.exec(), + {0, scalingField.size()}, + KOKKOS_LAMBDA(const size_t i) { selfValue[i] *= scale[i]; } + ); + } +}; + +} // namespace NeoFOAM From b10bb2b2b3c9dd619c89e20c44498d8816d6c172 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 14:01:07 +0200 Subject: [PATCH 22/63] refactor scalingFields to coeff - updates docstrings - fix formating - fix some compilation issues --- include/NeoFOAM/DSL/coeff.hpp | 89 +++++++++++++++++++ include/NeoFOAM/fields/scalingField.hpp | 53 ----------- .../cellCentred/operators/gaussGreenDiv.hpp | 4 +- .../cellCentred/operators/gaussGreenDiv.cpp | 3 +- .../timeIntegration/forwardEuler.cpp | 4 +- test/dsl/CMakeLists.txt | 3 +- test/dsl/coeff.cpp | 58 ++++++++++++ test/dsl/dsl.cpp | 4 +- 8 files changed, 156 insertions(+), 62 deletions(-) create mode 100644 include/NeoFOAM/DSL/coeff.hpp delete mode 100644 include/NeoFOAM/fields/scalingField.hpp create mode 100644 test/dsl/coeff.cpp diff --git a/include/NeoFOAM/DSL/coeff.hpp b/include/NeoFOAM/DSL/coeff.hpp new file mode 100644 index 000000000..89b8c584c --- /dev/null +++ b/include/NeoFOAM/DSL/coeff.hpp @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023 NeoFOAM authors +#pragma once + +namespace NeoFOAM::dsl +{ + +/** + * @class Coeff + * @brief A class that represents a coefficient for the NeoFOAM DSL. + * + * This class stores a single scalar coefficient and optionally span of values. + * It is used to delay the evaluation of a scalar multiplication with a field to + * avoid the creation of a temporary field copy. + * It provides an indexing operator `operator[]` that returns the evaluated value at the specified + * index. + */ +class Coeff +{ + +public: + + Coeff() : coeff_(1.0), span_(), hasSpan_(false) {} + + Coeff(scalar value) : coeff_(value), span_(), hasSpan_(false) {} + + Coeff(scalar coeff, const Field& field) + : coeff_(coeff), span_(field.span()), hasSpan_(true) + {} + + Coeff(const Field& field) : coeff_(1.0), span_(field.span()), hasSpan_(true) {} + + KOKKOS_INLINE_FUNCTION + scalar operator[](const size_t i) const { return (hasSpan_) ? span_[i] * coeff_ : coeff_; } + + Coeff& operator*=(scalar rhs) + { + coeff_ *= rhs; + return *this; + } + + void toField(Field& rhs) + { + rhs.resize(span_.size()); + fill(rhs, 1.0); + auto rhsSpan = rhs.span(); + // otherwise we are unable to capture values in the lambda + auto& coeff = *this; + parallelFor( + rhs.exec(), rhs.range(), KOKKOS_LAMBDA(const size_t i) { rhsSpan[i] *= coeff[i]; } + ); + } + + Coeff& operator*=(const Coeff& rhs) + { + if (hasSpan_ && rhs.hasSpan_) + { + NF_ERROR_EXIT("Not implemented"); + } + + if (!hasSpan_ && rhs.hasSpan_) + { + // Take over the span + span_ = rhs.span_; + hasSpan_ = true; + } + + return this->operator*=(rhs.coeff_); + } + + +private: + + scalar coeff_; + + std::span span_; + + bool hasSpan_; +}; + + +inline Coeff operator*(const Coeff& lhs, const Coeff& rhs) +{ + Coeff result = lhs; + result *= rhs; + return result; +} + +} // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/fields/scalingField.hpp b/include/NeoFOAM/fields/scalingField.hpp deleted file mode 100644 index eea2ad027..000000000 --- a/include/NeoFOAM/fields/scalingField.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2023 NeoFOAM authors -#pragma once - -namespace NeoFOAM -{ - -/** - * @brief A wrapper class that represents either a span of values or a single value. - * - * This class is used to store either a span of values or a single value of type `ValueType`. - * It provides an indexing operator `operator[]` that returns the value at the specified index - * or a constant value and is used to scale fields in the DSL. - * - * @tparam ValueType The type of the values stored in the class. - */ -template -struct ScalingField -{ - ScalingField() = default; - ScalingField(std::span values) : values(values), value(1.0), useSpan(true) {} - - ScalingField(std::span values, NeoFOAM::scalar value) - : values(values), value(value), useSpan(true) - {} - - ScalingField(NeoFOAM::scalar value) : values(), value(value), useSpan(false) {} - - std::span values; - NeoFOAM::scalar value; - bool useSpan; - - KOKKOS_INLINE_FUNCTION - ValueType operator[](const size_t i) const { return useSpan ? values[i] * value : value; } - - void operator*=(NeoFOAM::scalar scale) { value *= scale; } - - void operator=(NeoFOAM::scalar scale) { value = scale; } - - void operator*=(Field scalingField) - { - auto scale = scalingField.span(); - // otherwise we are unable to capture values in the lambda - auto selfValue = values; - NeoFOAM::parallelFor( - scalingField.exec(), - {0, scalingField.size()}, - KOKKOS_LAMBDA(const size_t i) { selfValue[i] *= scale[i]; } - ); - } -}; - -} // namespace NeoFOAM diff --git a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp index abfd78044..203aee628 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp @@ -27,9 +27,7 @@ class GaussGreenDiv div(VolumeField& divPhi, const SurfaceField& faceFlux, VolumeField& phi ); - void - div(Field& divPhi, const SurfaceField& faceFlux, VolumeField& phi - ); + void div(Field& divPhi, const SurfaceField& faceFlux, VolumeField& phi); private: diff --git a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp index c8507a517..d2b4ca994 100644 --- a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp +++ b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp @@ -98,7 +98,8 @@ void computeDiv( const auto exec = phi.exec(); SurfaceField phif(exec, mesh, createCalculatedBCs(mesh)); const auto surfFaceCells = mesh.boundaryMesh().faceCells().span(); - surfInterp.interpolate(phif, faceFlux, phi); + // FIXME not implemented + // surfInterp.interpolate(phif, faceFlux, phi); auto surfDivPhi = divPhi.span(); diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp index 208e8aff7..b67d42cae 100644 --- a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp +++ b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp @@ -31,13 +31,13 @@ void ForwardEuler::solve() // eqnTerm.temporalOperation(Phi); // } // Phi += source*dt; - refField->internalField() -= source*dt; + refField->internalField() -= source * dt; refField->correctBoundaryConditions(); // check if execturo is GPU if (std::holds_alternative(eqnSystem_.exec())) { - Kokkos::fence(); + Kokkos::fence(); } } diff --git a/test/dsl/CMakeLists.txt b/test/dsl/CMakeLists.txt index 0674af37b..06ec5792d 100644 --- a/test/dsl/CMakeLists.txt +++ b/test/dsl/CMakeLists.txt @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Unlicense # SPDX-FileCopyrightText: 2024 NeoFOAM authors -neofoam_unit_test(dsl) +neofoam_unit_test(coeff) +# FIXME neofoam_unit_test(dsl) diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp new file mode 100644 index 000000000..64585b058 --- /dev/null +++ b/test/dsl/coeff.cpp @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create + // a custom main +#include +#include +#include +#include + +#include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/DSL/coeff.hpp" + +using Field = NeoFOAM::Field; +using Coeff = NeoFOAM::dsl::Coeff; + + +TEST_CASE("Coeff") +{ + NeoFOAM::Executor exec = GENERATE( + NeoFOAM::Executor(NeoFOAM::SerialExecutor {}), + NeoFOAM::Executor(NeoFOAM::CPUExecutor {}), + NeoFOAM::Executor(NeoFOAM::GPUExecutor {}) + ); + + std::string execName = std::visit([](auto e) { return e.print(); }, exec); + + SECTION("Coefficient evaluation on " + execName) + { + Field fA(exec, 3, 2.0); + Field res(exec, 1); + + Coeff a {}; + Coeff b {2.0}; + Coeff c = 2 * a * b; + REQUIRE(c[0] == 4.0); + + Coeff d {3.0, fA}; + d.toField(res); + auto hostResD = res.copyToHost(); + REQUIRE(hostResD.data()[0] == 6.0); + REQUIRE(hostResD.data()[1] == 6.0); + REQUIRE(hostResD.data()[2] == 6.0); + + Coeff e = d * b; + e.toField(res); + auto hostResE = res.copyToHost(); + REQUIRE(hostResE.data()[0] == 12.0); + REQUIRE(hostResE.data()[1] == 12.0); + REQUIRE(hostResE.data()[2] == 12.0); + + Coeff f = b * d; + f.toField(res); + auto hostResF = res.copyToHost(); + REQUIRE(hostResF.data()[0] == 12.0); + REQUIRE(hostResF.data()[1] == 12.0); + REQUIRE(hostResF.data()[2] == 12.0); + } +} diff --git a/test/dsl/dsl.cpp b/test/dsl/dsl.cpp index 279562c68..0aa1d02e7 100644 --- a/test/dsl/dsl.cpp +++ b/test/dsl/dsl.cpp @@ -79,8 +79,8 @@ class Divergence NeoFOAM::scalar getField(const NeoFOAM::Field& source) { - auto sourceField = source.copyToHost().span(); - return sourceField[0]; + auto sourceField = source.copyToHost(); + return sourceField.span()[0]; } TEST_CASE("DSL") From 7e43c6b43ca9bf7a443607451182211b52076f56 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 09:15:44 +0200 Subject: [PATCH 23/63] Update include/NeoFOAM/DSL/coeff.hpp --- include/NeoFOAM/DSL/coeff.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/NeoFOAM/DSL/coeff.hpp b/include/NeoFOAM/DSL/coeff.hpp index 89b8c584c..d1acdfe15 100644 --- a/include/NeoFOAM/DSL/coeff.hpp +++ b/include/NeoFOAM/DSL/coeff.hpp @@ -38,7 +38,7 @@ class Coeff coeff_ *= rhs; return *this; } - + /* function to force evaluation to a newly created field */ void toField(Field& rhs) { rhs.resize(span_.size()); From 634568a10aa8c145437ba181f1976a116f9772b9 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 09:23:43 +0200 Subject: [PATCH 24/63] fix namespace and toField docstring --- include/NeoFOAM/DSL/coeff.hpp | 33 +++++++++++++++++++++++---------- test/dsl/coeff.cpp | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/include/NeoFOAM/DSL/coeff.hpp b/include/NeoFOAM/DSL/coeff.hpp index d1acdfe15..ec2d20d60 100644 --- a/include/NeoFOAM/DSL/coeff.hpp +++ b/include/NeoFOAM/DSL/coeff.hpp @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2023 NeoFOAM authors #pragma once -namespace NeoFOAM::dsl +namespace NeoFOAM::DSL { /** @@ -38,17 +38,30 @@ class Coeff coeff_ *= rhs; return *this; } - /* function to force evaluation to a newly created field */ + + /* @brief function to force evaluation to a field, the field will be resized to hold either a + * single value or the full field + * + * @param field to store the result + */ void toField(Field& rhs) { - rhs.resize(span_.size()); - fill(rhs, 1.0); - auto rhsSpan = rhs.span(); - // otherwise we are unable to capture values in the lambda - auto& coeff = *this; - parallelFor( - rhs.exec(), rhs.range(), KOKKOS_LAMBDA(const size_t i) { rhsSpan[i] *= coeff[i]; } - ); + if (hasSpan_) + { + rhs.resize(span_.size()); + fill(rhs, 1.0); + auto rhsSpan = rhs.span(); + // otherwise we are unable to capture values in the lambda + auto& coeff = *this; + parallelFor( + rhs.exec(), rhs.range(), KOKKOS_LAMBDA(const size_t i) { rhsSpan[i] *= coeff[i]; } + ); + } + else + { + rhs.resize(1); + fill(rhs, coeff_); + } } Coeff& operator*=(const Coeff& rhs) diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp index 64585b058..a3561f625 100644 --- a/test/dsl/coeff.cpp +++ b/test/dsl/coeff.cpp @@ -11,7 +11,7 @@ #include "NeoFOAM/DSL/coeff.hpp" using Field = NeoFOAM::Field; -using Coeff = NeoFOAM::dsl::Coeff; +using Coeff = NeoFOAM::DSL::Coeff; TEST_CASE("Coeff") From fc4c38b9d0f154e6da02b73cd307ef4a331193ea Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 13:46:26 +0200 Subject: [PATCH 25/63] move toField to free function --- include/NeoFOAM/DSL/coeff.hpp | 58 ++++++++++++++++++++--------------- test/dsl/coeff.cpp | 7 +++-- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/include/NeoFOAM/DSL/coeff.hpp b/include/NeoFOAM/DSL/coeff.hpp index ec2d20d60..b78c6453b 100644 --- a/include/NeoFOAM/DSL/coeff.hpp +++ b/include/NeoFOAM/DSL/coeff.hpp @@ -33,36 +33,16 @@ class Coeff KOKKOS_INLINE_FUNCTION scalar operator[](const size_t i) const { return (hasSpan_) ? span_[i] * coeff_ : coeff_; } + bool hasSpan() { return hasSpan_; } + + std::span span() { return span_; } + Coeff& operator*=(scalar rhs) { coeff_ *= rhs; return *this; } - /* @brief function to force evaluation to a field, the field will be resized to hold either a - * single value or the full field - * - * @param field to store the result - */ - void toField(Field& rhs) - { - if (hasSpan_) - { - rhs.resize(span_.size()); - fill(rhs, 1.0); - auto rhsSpan = rhs.span(); - // otherwise we are unable to capture values in the lambda - auto& coeff = *this; - parallelFor( - rhs.exec(), rhs.range(), KOKKOS_LAMBDA(const size_t i) { rhsSpan[i] *= coeff[i]; } - ); - } - else - { - rhs.resize(1); - fill(rhs, coeff_); - } - } Coeff& operator*=(const Coeff& rhs) { @@ -92,6 +72,34 @@ class Coeff }; +namespace detail +{ +/* @brief function to force evaluation to a field, the field will be resized to hold either a + * single value or the full field + * + * @param field to store the result + */ +void toField(Coeff& coeff, Field& rhs) +{ + if (coeff.hasSpan()) + { + rhs.resize(coeff.span().size()); + fill(rhs, 1.0); + auto rhsSpan = rhs.span(); + // otherwise we are unable to capture values in the lambda + parallelFor( + rhs.exec(), rhs.range(), KOKKOS_LAMBDA(const size_t i) { rhsSpan[i] *= coeff[i]; } + ); + } + else + { + rhs.resize(1); + fill(rhs, coeff[0]); + } +} +} + + inline Coeff operator*(const Coeff& lhs, const Coeff& rhs) { Coeff result = lhs; @@ -99,4 +107,4 @@ inline Coeff operator*(const Coeff& lhs, const Coeff& rhs) return result; } -} // namespace NeoFOAM::dsl +} // namespace NeoFOAM::DSL diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp index a3561f625..883aa7d5d 100644 --- a/test/dsl/coeff.cpp +++ b/test/dsl/coeff.cpp @@ -12,6 +12,7 @@ using Field = NeoFOAM::Field; using Coeff = NeoFOAM::DSL::Coeff; +namespace detail = NeoFOAM::DSL::detail; TEST_CASE("Coeff") @@ -35,21 +36,21 @@ TEST_CASE("Coeff") REQUIRE(c[0] == 4.0); Coeff d {3.0, fA}; - d.toField(res); + detail::toField(d, res); auto hostResD = res.copyToHost(); REQUIRE(hostResD.data()[0] == 6.0); REQUIRE(hostResD.data()[1] == 6.0); REQUIRE(hostResD.data()[2] == 6.0); Coeff e = d * b; - e.toField(res); + detail::toField(e, res); auto hostResE = res.copyToHost(); REQUIRE(hostResE.data()[0] == 12.0); REQUIRE(hostResE.data()[1] == 12.0); REQUIRE(hostResE.data()[2] == 12.0); Coeff f = b * d; - f.toField(res); + detail::toField(f, res); auto hostResF = res.copyToHost(); REQUIRE(hostResF.data()[0] == 12.0); REQUIRE(hostResF.data()[1] == 12.0); From 929d37eba0eb27fb87e7d9fbc8808e612b620dda Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Sun, 6 Oct 2024 10:37:08 +0200 Subject: [PATCH 26/63] fix: getSpan tests segfault on GPU span access GPU memory from CPU --- test/fields/field.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/fields/field.cpp b/test/fields/field.cpp index b157aea32..9afde7241 100644 --- a/test/fields/field.cpp +++ b/test/fields/field.cpp @@ -274,17 +274,12 @@ TEST_CASE("getSpans") NeoFOAM::Executor(NeoFOAM::GPUExecutor {}) ); - NeoFOAM::Field a(exec, 3, 1.0); NeoFOAM::Field b(exec, 3, 2.0); NeoFOAM::Field c(exec, 3, 3.0); auto [spanA, spanB, spanC] = NeoFOAM::spans(a, b, c); - REQUIRE(spanA[0] == 1.0); - REQUIRE(spanB[0] == 2.0); - REQUIRE(spanC[0] == 3.0); - NeoFOAM::parallelFor( a, KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return spanB[i] + spanC[i]; } ); From e2af6cdbaef079d7b6274c6b464bd8bee5267b6b Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Sun, 6 Oct 2024 10:38:10 +0200 Subject: [PATCH 27/63] test coeff in parallelfor --- test/dsl/coeff.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp index 883aa7d5d..1d3cbd0c1 100644 --- a/test/dsl/coeff.cpp +++ b/test/dsl/coeff.cpp @@ -56,4 +56,65 @@ TEST_CASE("Coeff") REQUIRE(hostResF.data()[1] == 12.0); REQUIRE(hostResF.data()[2] == 12.0); } + + SECTION("evaluation in parallelFor" + execName) + { + size_t size = 3; + + NeoFOAM::Field fieldA(exec, size, 0.0); + NeoFOAM::Field fieldB(exec, size, 1.0); + + SECTION("span") + { + Coeff coeff = fieldB; // is a span with uniform value 1.0 + { + NeoFOAM::parallelFor( + fieldA, KOKKOS_LAMBDA(const size_t i) { return coeff[i] + 2.0; } + ); + }; + auto hostFieldA = fieldA.copyToHost(); + REQUIRE(coeff.hasSpan() == true); + REQUIRE(hostFieldA[0] == 3.0); + REQUIRE(hostFieldA[1] == 3.0); + REQUIRE(hostFieldA[2] == 3.0); + } + + SECTION("scalar") + { + NeoFOAM::Field fieldA(exec, size, 0.0); + + Coeff coeff = Coeff(2.0); + { + NeoFOAM::parallelFor( + fieldA, KOKKOS_LAMBDA(const size_t i) { return coeff[i] + 2.0; } + ); + }; + auto hostFieldA = fieldA.copyToHost(); + REQUIRE(coeff.hasSpan() == false); + REQUIRE(hostFieldA[0] == 4.0); + REQUIRE(hostFieldA[1] == 4.0); + REQUIRE(hostFieldA[2] == 4.0); + } + + SECTION("span and scalar") + { + NeoFOAM::Field fieldA(exec, size, 0.0); + NeoFOAM::Field fieldB(exec, size, 1.0); + Coeff coeff {-5.0,fieldB}; + { + NeoFOAM::parallelFor( + fieldA, KOKKOS_LAMBDA(const size_t i) { return coeff[i] + 2.0; } + ); + }; + auto hostFieldA = fieldA.copyToHost(); + REQUIRE(coeff.hasSpan() == true); + REQUIRE(hostFieldA[0] == -3.0); + REQUIRE(hostFieldA[1] == -3.0); + REQUIRE(hostFieldA[2] == -3.0); + } + + } + + + } From 549daa69147dfc563d2bf00dd78ff723dd58d0f7 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 14:37:53 +0200 Subject: [PATCH 28/63] wip add modifications to operators --- include/NeoFOAM/DSL/coeff.hpp | 4 +- include/NeoFOAM/DSL/eqnSystem.hpp | 120 ++++--- include/NeoFOAM/DSL/eqnTerm.hpp | 170 --------- include/NeoFOAM/DSL/operator.hpp | 322 ++++++++++++++++++ include/NeoFOAM/core/dictionary.hpp | 6 + .../timeIntegration/timeIntegration.hpp | 2 +- .../cellCentred/operators/gaussGreenDiv.cpp | 2 - .../timeIntegration/forwardEuler.cpp | 2 +- test/dsl/CMakeLists.txt | 2 + test/dsl/coeff.cpp | 4 +- test/dsl/dsl.cpp | 1 - test/dsl/operator.cpp | 93 +++++ .../timeIntegration/timeIntegration.cpp | 22 +- 13 files changed, 502 insertions(+), 248 deletions(-) delete mode 100644 include/NeoFOAM/DSL/eqnTerm.hpp create mode 100644 include/NeoFOAM/DSL/operator.hpp create mode 100644 test/dsl/operator.cpp diff --git a/include/NeoFOAM/DSL/coeff.hpp b/include/NeoFOAM/DSL/coeff.hpp index b78c6453b..d2b2a6623 100644 --- a/include/NeoFOAM/DSL/coeff.hpp +++ b/include/NeoFOAM/DSL/coeff.hpp @@ -43,7 +43,6 @@ class Coeff return *this; } - Coeff& operator*=(const Coeff& rhs) { if (hasSpan_ && rhs.hasSpan_) @@ -73,6 +72,7 @@ class Coeff namespace detail + { /* @brief function to force evaluation to a field, the field will be resized to hold either a * single value or the full field @@ -97,8 +97,8 @@ void toField(Coeff& coeff, Field& rhs) fill(rhs, coeff[0]); } } -} +} inline Coeff operator*(const Coeff& lhs, const Coeff& rhs) { diff --git a/include/NeoFOAM/DSL/eqnSystem.hpp b/include/NeoFOAM/DSL/eqnSystem.hpp index f7003720f..ae34351e9 100644 --- a/include/NeoFOAM/DSL/eqnSystem.hpp +++ b/include/NeoFOAM/DSL/eqnSystem.hpp @@ -9,7 +9,7 @@ #include "NeoFOAM/core/primitives/scalar.hpp" #include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/DSL/eqnTerm.hpp" +#include "NeoFOAM/DSL/operator.hpp" #include "NeoFOAM/core/error.hpp" namespace NeoFOAM::DSL @@ -20,60 +20,60 @@ class EqnSystem public: EqnSystem(const NeoFOAM::Executor& exec, std::size_t nCells) - : exec_(exec), nCells_(nCells), temporalTerms_(), implicitTerms_(), explicitTerms_(), - volumeField_(nullptr) + : exec_(exec), nCells_(nCells), temporalOperators_(), implicitOperators_(), + explicitOperators_(), volumeField_(nullptr) {} NeoFOAM::Field explicitOperation() { NeoFOAM::Field source(exec_, nCells_); NeoFOAM::fill(source, 0.0); - for (auto& eqnTerm : explicitTerms_) + for (auto& Operator : explicitOperators_) { - eqnTerm.explicitOperation(source); + Operator.explicitOperation(source); } return source; } - void addTerm(const EqnTerm& eqnTerm) + void addOperator(const Operator& Operator) { - switch (eqnTerm.getType()) + switch (Operator.getType()) { - case EqnTerm::Type::Temporal: - temporalTerms_.push_back(eqnTerm); + case Operator::Type::Temporal: + temporalOperators_.push_back(Operator); break; - case EqnTerm::Type::Implicit: - implicitTerms_.push_back(eqnTerm); + case Operator::Type::Implicit: + implicitOperators_.push_back(Operator); break; - case EqnTerm::Type::Explicit: - explicitTerms_.push_back(eqnTerm); + case Operator::Type::Explicit: + explicitOperators_.push_back(Operator); break; } } void addSystem(const EqnSystem& eqnSys) { - for (auto& eqnTerm : eqnSys.temporalTerms_) + for (auto& Operator : eqnSys.temporalOperators_) { - temporalTerms_.push_back(eqnTerm); + temporalOperators_.push_back(Operator); } - for (auto& eqnTerm : eqnSys.implicitTerms_) + for (auto& Operator : eqnSys.implicitOperators_) { - implicitTerms_.push_back(eqnTerm); + implicitOperators_.push_back(Operator); } - for (auto& eqnTerm : eqnSys.explicitTerms_) + for (auto& Operator : eqnSys.explicitOperators_) { - explicitTerms_.push_back(eqnTerm); + explicitOperators_.push_back(Operator); } } void solve() { - if (temporalTerms_.size() == 0 && implicitTerms_.size() == 0) + if (temporalOperators_.size() == 0 && implicitOperators_.size() == 0) { NF_ERROR_EXIT("No temporal or implicit terms to solve."); } - if (temporalTerms_.size() > 0) + if (temporalOperators_.size() > 0) { // integrate equations in time } @@ -85,52 +85,58 @@ class EqnSystem size_t size() const { - return temporalTerms_.size() + implicitTerms_.size() + explicitTerms_.size(); + return temporalOperators_.size() + implicitOperators_.size() + explicitOperators_.size(); } // getters - const std::vector& temporalTerms() const { return temporalTerms_; } + const std::vector& temporalOperators() const { return temporalOperators_; } - const std::vector& implicitTerms() const { return implicitTerms_; } + const std::vector& implicitOperators() const { return implicitOperators_; } - const std::vector& explicitTerms() const { return explicitTerms_; } + const std::vector& explicitOperators() const { return explicitOperators_; } - std::vector& temporalTerms() { return temporalTerms_; } + std::vector& temporalOperators() { return temporalOperators_; } - std::vector& implicitTerms() { return implicitTerms_; } + std::vector& implicitOperators() { return implicitOperators_; } - std::vector& explicitTerms() { return explicitTerms_; } + std::vector& explicitOperators() { return explicitOperators_; } const NeoFOAM::Executor& exec() const { return exec_; } const std::size_t nCells() const { return nCells_; } + scalar getDt() const { return dt_; } + fvcc::VolumeField* volumeField() { - if (temporalTerms_.size() == 0 && implicitTerms_.size() == 0) + if (temporalOperators_.size() == 0 && implicitOperators_.size() == 0) { NF_ERROR_EXIT("No temporal or implicit terms to solve."); } - if (temporalTerms_.size() > 0) + if (temporalOperators_.size() > 0) { - volumeField_ = temporalTerms_[0].volumeField(); + // FIXME + NF_ERROR_EXIT("Not implemented."); + // volumeField_ = temporalOperators_[0].volumeField(); } else { - volumeField_ = implicitTerms_[0].volumeField(); + // FIXME + NF_ERROR_EXIT("Not implemented."); + // volumeField_ = implicitOperators_[0].volumeField(); } return volumeField_; } - NeoFOAM::scalar dt = 0; + NeoFOAM::scalar dt_ = 0; private: const NeoFOAM::Executor exec_; const std::size_t nCells_; - std::vector temporalTerms_; - std::vector implicitTerms_; - std::vector explicitTerms_; + std::vector temporalOperators_; + std::vector implicitOperators_; + std::vector explicitOperators_; fvcc::VolumeField* volumeField_; }; @@ -140,34 +146,35 @@ EqnSystem operator+(EqnSystem lhs, const EqnSystem& rhs) return lhs; } -EqnSystem operator+(EqnSystem lhs, const EqnTerm& rhs) +EqnSystem operator+(EqnSystem lhs, const Operator& rhs) { - lhs.addTerm(rhs); + lhs.addOperator(rhs); return lhs; } -EqnSystem operator+(const EqnTerm& lhs, const EqnTerm& rhs) +EqnSystem operator+(const Operator& lhs, const Operator& rhs) { - EqnSystem eqnSys(lhs.exec(), lhs.nCells()); - eqnSys.addTerm(lhs); - eqnSys.addTerm(rhs); - return eqnSys; + NF_ERROR_EXIT("Not implemented."); + // EqnSystem eqnSys(lhs.exec(), lhs.nCells()); + // eqnSys.addOperator(lhs); + // eqnSys.addOperator(rhs); + // return eqnSys; } EqnSystem operator*(NeoFOAM::scalar scale, const EqnSystem& es) { EqnSystem results(es.exec(), es.nCells()); - for (const auto& eqnTerm : es.temporalTerms()) + for (const auto& Operator : es.temporalOperators()) { - results.addTerm(scale * eqnTerm); + results.addOperator(scale * Operator); } - for (const auto& eqnTerm : es.implicitTerms()) + for (const auto& Operator : es.implicitOperators()) { - results.addTerm(scale * eqnTerm); + results.addOperator(scale * Operator); } - for (const auto& eqnTerm : es.explicitTerms()) + for (const auto& Operator : es.explicitOperators()) { - results.addTerm(scale * eqnTerm); + results.addOperator(scale * Operator); } return results; } @@ -178,18 +185,19 @@ EqnSystem operator-(EqnSystem lhs, const EqnSystem& rhs) return lhs; } -EqnSystem operator-(EqnSystem lhs, const EqnTerm& rhs) +EqnSystem operator-(EqnSystem lhs, const Operator& rhs) { - lhs.addTerm(-1.0 * rhs); + lhs.addOperator(-1.0 * rhs); return lhs; } -EqnSystem operator-(const EqnTerm& lhs, const EqnTerm& rhs) +EqnSystem operator-(const Operator& lhs, const Operator& rhs) { - EqnSystem results(lhs.exec(), lhs.nCells()); - results.addTerm(lhs); - results.addTerm(-1.0 * rhs); - return results; + NF_ERROR_EXIT("Not implemented."); + // EqnSystem results(lhs.exec(), lhs.nCells()); + // results.addOperator(lhs); + // results.addOperator(-1.0 * rhs); + // return results; } diff --git a/include/NeoFOAM/DSL/eqnTerm.hpp b/include/NeoFOAM/DSL/eqnTerm.hpp deleted file mode 100644 index 3e2eab1e2..000000000 --- a/include/NeoFOAM/DSL/eqnTerm.hpp +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors -#pragma once - -#include -#include -#include -#include - -#include "NeoFOAM/core/primitives/scalar.hpp" -#include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" - -namespace fvcc = NeoFOAM::finiteVolume::cellCentred; - -namespace NeoFOAM::DSL -{ - -template -concept HasTemporalTerm = requires(T t) { - { - t.temporalOperation( - std::declval&>(), std::declval() - ) - } -> std::same_as; // Adjust return type and arguments as needed -}; - -template -concept HasExplicitTerm = requires(T t) { - { - t.explicitOperation( - std::declval&>(), std::declval() - ) - } -> std::same_as; // Adjust return type and arguments as needed -}; -// EqnTerm class that uses type erasure without inheritance -class EqnTerm -{ -public: - - enum class Type - { - Temporal, - Implicit, - Explicit - }; - - template - EqnTerm(T cls) : model_(std::make_unique>(std::move(cls))) - {} - - EqnTerm(const EqnTerm& eqnTerm) : model_ {eqnTerm.model_->clone()} {} - - EqnTerm(EqnTerm&& eqnTerm) : model_ {std::move(eqnTerm.model_)} {} - - EqnTerm& operator=(const EqnTerm& eqnTerm) - { - model_ = eqnTerm.model_->clone(); - return *this; - } - - EqnTerm& operator=(EqnTerm&& eqnTerm) - { - model_ = std::move(eqnTerm.model_); - return *this; - } - - std::string display() const { return model_->display(); } - - void explicitOperation(NeoFOAM::Field& source) - { - model_->explicitOperation(source, model_->scaleCoeff); - } - - void temporalOperation(NeoFOAM::Field& field) - { - model_->temporalOperation(field, model_->scaleCoeff); - } - - EqnTerm::Type getType() const { return model_->getType(); } - - void setScale(NeoFOAM::scalar scale) { model_->scaleCoeff *= scale; } - - - const NeoFOAM::Executor& exec() const { return model_->exec(); } - - std::size_t nCells() const { return model_->nCells(); } - - - fvcc::VolumeField* volumeField() { return model_->volumeField(); } - - -private: - - // Base class to hold the type-erased value and the display function - struct Concept - { - virtual ~Concept() = default; - virtual std::string display() const = 0; - virtual void - explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) = 0; - virtual void - temporalOperation(NeoFOAM::Field& field, NeoFOAM::scalar scale) = 0; - NeoFOAM::scalar scaleCoeff = 1.0; - virtual EqnTerm::Type getType() const = 0; - - virtual const NeoFOAM::Executor& exec() const = 0; - virtual std::size_t nCells() const = 0; - virtual fvcc::VolumeField* volumeField() = 0; - - // The Prototype Design Pattern - virtual std::unique_ptr clone() const = 0; - }; - - // Templated derived class to implement the type-specific behavior - template - struct Model : Concept - { - Model(T cls) : cls_(std::move(cls)) {} - - std::string display() const override { return cls_.display(); } - - virtual void - explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) override - { - if constexpr (HasExplicitTerm) - { - cls_.explicitOperation(source, scale); - } - } - - virtual void - temporalOperation(NeoFOAM::Field& field, NeoFOAM::scalar scale) override - { - if constexpr (HasTemporalTerm) - { - cls_.temporalOperation(field, scale); - } - } - - virtual fvcc::VolumeField* volumeField() override - { - return cls_.volumeField(); - } - - EqnTerm::Type getType() const override { return cls_.getType(); } - - const NeoFOAM::Executor& exec() const override { return cls_.exec(); } - - std::size_t nCells() const override { return cls_.nCells(); } - - // The Prototype Design Pattern - std::unique_ptr clone() const override { return std::make_unique(*this); } - - T cls_; - }; - - std::unique_ptr model_; -}; - - -// add multiply operator to EqnTerm -EqnTerm operator*(NeoFOAM::scalar scale, const EqnTerm& lhs) -{ - EqnTerm result = lhs; - result.setScale(scale); - return result; -} - -} // namespace NeoFOAM::DSL diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp new file mode 100644 index 000000000..48cfc6535 --- /dev/null +++ b/include/NeoFOAM/DSL/operator.hpp @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#pragma once + +#include +#include +#include +#include +#include + +#include "NeoFOAM/core/primitives/scalar.hpp" +#include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/core/parallelAlgorithms.hpp" +#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" +#include "NeoFOAM/core/inputs.hpp" +#include "NeoFOAM/DSL/coeff.hpp" + + +namespace fvcc = NeoFOAM::finiteVolume::cellCentred; + +namespace NeoFOAM::DSL +{ + +template +concept HasTemporalOperator = requires(T t) { + { + t.temporalOperation(std::declval&>(), std::declval()) + } -> std::same_as; // Adjust return type and arguments as needed +}; + +template +concept HasExplicitOperator = requires(T t) { + { + t.explicitOperation(std::declval&>()) + } -> std::same_as; // Adjust return type and arguments as needed +}; + + +/* @class OperatorMixin + * @brief A mixin class to represent simplify implementations of concrete operators + * in NeoFOAMs DSL + * + * + * @ingroup DSL + */ +class OperatorMixin +{ + +public: + + OperatorMixin(const Executor exec) : exec_(exec), coeffs_(), evaluated_(false) {}; + + // OperatorMixin(const Executor exec, const Field* field) + // : exec_(exec), field_(field), coeffs_(), evaluated_(false) {}; + + virtual ~OperatorMixin() = default; + + // void setField(const Field> field) + // { + // field_ = field; + // // FIXME + // // getCoefficient() = Coeff(field_->span(), getCoefficient().value); + // } + + const Executor& exec() const { return exec_; } + + Coeff& getCoefficient() { return coeffs_; } + + const Coeff& getCoefficient() const { return coeffs_; } + + bool evaluated() const { return evaluated_; } + + bool& evaluated() { return evaluated_; } + + // + // const Field* field() { return field_; } + +protected: + + const Executor exec_; //!< Executor associated with the field. (CPU, GPU, openMP, etc.) + + // NOTE unfortunately does not work + // std::optional&> field_; + + // const Field* field_; + + Coeff coeffs_; + + bool evaluated_; +}; + + +/* @class Operator + * @brief A class to represent a operator in NeoFOAMs DSL + * + * The design here is based on the type erasure design pattern + * see https://www.youtube.com/watch?v=4eeESJQk-mw + * + * Motivation for using type erasure is that concrete implementation + * of Operators e.g Divergence, Laplacian, etc can be stored in a vector of + * Operators + * + * @ingroup DSL + */ +class Operator +{ +public: + + enum class Type + { + Temporal, + Implicit, + Explicit + }; + + template + Operator(T cls) : model_(std::make_unique>(std::move(cls))) + {} + + Operator(const Operator& eqnOperator) : model_ {eqnOperator.model_->clone()} {} + + Operator(Operator&& eqnOperator) : model_ {std::move(eqnOperator.model_)} {} + + Operator& operator=(const Operator& eqnOperator) + { + model_ = eqnOperator.model_->clone(); + return *this; + } + + Operator& operator=(Operator&& eqnOperator) + { + model_ = std::move(eqnOperator.model_); + return *this; + } + + // std::string display() const { return model_->display(); } + + void explicitOperation(Field& source) { model_->explicitOperation(source); } + + void temporalOperation(Field& field) { model_->temporalOperation(field); } + + /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ + Operator::Type getType() const { return model_->getType(); } + + void setField(std::shared_ptr> field) { model_->setField(field); } + + Coeff& getCoefficient() { return model_->getCoefficient(); } + + Coeff getCoefficient() const { return model_->getCoefficient(); } + + bool evaluated() { return model_->evaluated(); } + + void build(const Input& input) { model_->build(input); } + + const Executor& exec() const { return model_->exec(); } + + // std::size_t nCells() const { return model_->nCells(); } + + // fvcc::VolumeField* volumeField() { return model_->volumeField(); } + + +private: + + /* @brief Base class defining the concept of a term. This effectively + * defines what functions need to be implemented by a concrete Operator implementation + * + * + * */ + struct OperatorConcept + { + virtual ~OperatorConcept() = default; + + virtual std::string display() const = 0; + + virtual void explicitOperation(Field& source) = 0; + + virtual void temporalOperation(Field& field) = 0; + + virtual void build(const Input& input) = 0; + + virtual bool evaluated() = 0; + + /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ + virtual Operator::Type getType() const = 0; + + virtual void setField(std::shared_ptr> field) = 0; + + /* @brief get the associated coefficient for this term */ + virtual Coeff& getCoefficient() = 0; + + /* @brief get the associated coefficient for this term */ + virtual Coeff getCoefficient() const = 0; + + virtual const Executor& exec() const = 0; + + // virtual std::size_t nCells() const = 0; + + // virtual fvcc::VolumeField* volumeField() = 0; + + // The Prototype Design Pattern + virtual std::unique_ptr clone() const = 0; + }; + + // Templated derived class to implement the type-specific behavior + template + struct OperatorModel : OperatorConcept + { + OperatorModel(T cls) : cls_(std::move(cls)) {} + + std::string display() const override + { /*return cls_.display();*/ + } + + virtual void explicitOperation(Field& source) override + { + if constexpr (HasExplicitOperator) + { + cls_.explicitOperation(source); + } + } + + virtual void temporalOperation(Field& field) override + { + if constexpr (HasTemporalOperator) + { + cls_.temporalOperation(field); + } + } + + // virtual fvcc::VolumeField* volumeField() override { return cls_.volumeField(); } + + virtual void build(const Input& input) override + { + // FIXME + // cls_.build(input); + } + + virtual bool evaluated() override + { + // FIXME + // return cls_.evaluated(); + } + + /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ + Operator::Type getType() const override { return cls_.getType(); } + + const Executor& exec() const override { return cls_.exec(); } + + // std::size_t nCells() const override { return cls_.nCells(); } + + void setField(std::shared_ptr> field) override + { + // FIXME + // cls_.setField(field); + } + + /* @brief get the associated coefficient for this term */ + virtual Coeff& getCoefficient() override + { + // FIXME + // return cls_.getCoefficient(); + } + + /* @brief get the associated coefficient for this term */ + virtual Coeff getCoefficient() const override + { + // FIXME + // return cls_.getCoefficient(); + } + + // The Prototype Design Pattern + std::unique_ptr clone() const override + { + return std::make_unique(*this); + } + + T cls_; + }; + + std::unique_ptr model_; +}; + + +auto operator*(scalar scale, const Operator& lhs) +{ + Operator result = lhs; + result.getCoefficient() *= scale; + return result; +} + +// add multiply operator to Operator +auto operator*(Field scale, const Operator& lhs) +{ + Operator result = lhs; + // FIXME + // if (!result.getCoefficient().useSpan) + // { + // // allocate the scaling field to avoid deallocation + // result.setField(std::make_shared>(scale)); + // } + // else + // { + // result.getCoefficient() *= scale; + // } + return result; +} + +// template +template +Operator operator*(ScaleFunction scaleFunc, const Operator& lhs) +{ + Operator result = lhs; + // FIXME + // if (!result.getCoefficient().useSpan) + // { + // result.setField(std::make_shared>(result.exec(), result.nCells(), 1.0)); + // } + // map(result.exec(), result.getCoefficient().values, scaleFunc); + return result; +} + +} // namespace NeoFOAM::DSL diff --git a/include/NeoFOAM/core/dictionary.hpp b/include/NeoFOAM/core/dictionary.hpp index cd06b2dc9..94cec83fe 100644 --- a/include/NeoFOAM/core/dictionary.hpp +++ b/include/NeoFOAM/core/dictionary.hpp @@ -162,6 +162,12 @@ class Dictionary */ const std::unordered_map& getMap() const; + /** + * @brief Checks whether the dictionary is empty + * @return A bool indicating if the dictionary is empty + */ + bool empty() const { return data_.empty(); } + private: std::unordered_map data_; diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp index 63fcd57aa..9709f0746 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp @@ -8,7 +8,7 @@ #include "NeoFOAM/mesh/unstructured.hpp" #include "NeoFOAM/finiteVolume/cellCentred.hpp" -#include "NeoFOAM/DSL/eqnTerm.hpp" +#include "NeoFOAM/DSL/operator.hpp" #include "NeoFOAM/DSL/eqnSystem.hpp" #include diff --git a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp index d2b4ca994..a43d204d0 100644 --- a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp +++ b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp @@ -33,7 +33,6 @@ void computeDiv( size_t nInternalFaces = mesh.nInternalFaces(); const auto surfV = mesh.cellVolumes().span(); - // check if the executor is GPU if (std::holds_alternative(exec)) { @@ -51,7 +50,6 @@ void computeDiv( surfDivPhi[own] += valueOwn; } - for (size_t celli = 0; celli < mesh.nCells(); celli++) { surfDivPhi[celli] *= 1 / surfV[celli]; diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp index b67d42cae..08ce009f2 100644 --- a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp +++ b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp @@ -20,7 +20,7 @@ ForwardEuler::ForwardEuler(const dsl::EqnSystem& eqnSystem, const Dictionary& di void ForwardEuler::solve() { std::cout << "Solving using Forward Euler" << std::endl; - scalar dt = eqnSystem_.dt; + scalar dt = eqnSystem_.getDt(); fvcc::VolumeField* refField = eqnSystem_.volumeField(); // Field Phi(eqnSystem_.exec(), eqnSystem_.nCells()); // NeoFOAM::fill(Phi, 0.0); diff --git a/test/dsl/CMakeLists.txt b/test/dsl/CMakeLists.txt index 06ec5792d..5616fabe1 100644 --- a/test/dsl/CMakeLists.txt +++ b/test/dsl/CMakeLists.txt @@ -2,4 +2,6 @@ # SPDX-FileCopyrightText: 2024 NeoFOAM authors neofoam_unit_test(coeff) +neofoam_unit_test(operator) + # FIXME neofoam_unit_test(dsl) diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp index 1d3cbd0c1..da2ced419 100644 --- a/test/dsl/coeff.cpp +++ b/test/dsl/coeff.cpp @@ -12,6 +12,7 @@ using Field = NeoFOAM::Field; using Coeff = NeoFOAM::DSL::Coeff; + namespace detail = NeoFOAM::DSL::detail; @@ -114,7 +115,4 @@ TEST_CASE("Coeff") } } - - - } diff --git a/test/dsl/dsl.cpp b/test/dsl/dsl.cpp index 0aa1d02e7..48fafa000 100644 --- a/test/dsl/dsl.cpp +++ b/test/dsl/dsl.cpp @@ -64,7 +64,6 @@ class Divergence dsl::EqnTerm::Type getType() const { return termType_; } - const NeoFOAM::Executor& exec() const { return exec_; } const std::size_t nCells() const { return nCells_; } diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp new file mode 100644 index 000000000..12d4c831a --- /dev/null +++ b/test/dsl/operator.cpp @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create + // a custom main +#include +#include +#include +#include + +#include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/DSL/coeff.hpp" +#include "NeoFOAM/DSL/operator.hpp" + +using Field = NeoFOAM::Field; +using Coeff = NeoFOAM::DSL::Coeff; +using Operator = NeoFOAM::DSL::Operator; +using OperatorMixin = NeoFOAM::DSL::OperatorMixin; +using Executor = NeoFOAM::Executor; +using VolumeField = fvcc::VolumeField; +namespace fvcc = NeoFOAM::finiteVolume::cellCentred; + +/* A dummy implementation of a Operator + * following the Operator interface */ +class Dummy : public OperatorMixin +{ + +public: + + Dummy(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} + + void explicitOperation(Field& source, NeoFOAM::scalar scale) + { + auto sourceField = source.span(); + NeoFOAM::parallelFor( + source.exec(), + {0, source.size()}, + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } + ); + } + + const VolumeField& volumeField() const { return field_; } + + VolumeField& volumeField() { return field_; } + + Operator::Type getType() const { return Operator::Type::Explicit; } + +private: + + VolumeField& field_; +}; + +TEST_CASE("Operator") +{ + NeoFOAM::Executor exec = GENERATE( + NeoFOAM::Executor(NeoFOAM::SerialExecutor {}), + NeoFOAM::Executor(NeoFOAM::CPUExecutor {}), + NeoFOAM::Executor(NeoFOAM::GPUExecutor {}) + ); + + std::string execName = std::visit([](auto e) { return e.print(); }, exec); + + auto mesh = NeoFOAM::createSingleCellMesh(exec); + + SECTION("Operator creation on " + execName) + { + + Field fA(exec, 3, 2.0); + + std::vector> bcs {}; + auto vf = VolumeField(exec, mesh, bcs); + auto b = Dummy(exec, vf); + } + + SECTION("Supports Coefficients" + execName) + { + + std::vector> bcs {}; + auto vf = VolumeField(exec, mesh, bcs); + + Field fA(exec, 3, 2.0); + Field fB(exec, 3, 3.0); + + auto b = Dummy(exec, &fA); + + auto c = 2 * Dummy(exec, &fA); + auto d = fB * Dummy(exec, &fA); + auto e = Coeff(-3, fB) * Dummy(exec, &fA); + + auto coeffc = c.getCoefficient(); + auto coeffd = d.getCoefficient(); + auto coeffE = e.getCoefficient(); + } +} diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp index e276213f1..b73083fd8 100644 --- a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp +++ b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp @@ -10,9 +10,7 @@ #include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" - - -#include "NeoFOAM/DSL/eqnTerm.hpp" +#include "NeoFOAM/DSL/operator.hpp" #include "NeoFOAM/DSL/eqnSystem.hpp" @@ -35,7 +33,7 @@ class Divergence ); } - dsl::EqnTerm::Type getType() const { return termType_; } + dsl::Operator::Type getType() const { return termType_; } fvcc::VolumeField* volumeField() const { return nullptr; } @@ -43,17 +41,17 @@ class Divergence std::size_t nCells() const { return nCells_; } - dsl::EqnTerm::Type termType_; + dsl::Operator::Type termType_; NeoFOAM::Executor exec_; std::size_t nCells_; }; -class TimeTerm +class TimeOperator { public: - std::string display() const { return "TimeTerm"; } + std::string display() const { return "TimeOperator"; } void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) { @@ -65,7 +63,7 @@ class TimeTerm ); } - dsl::EqnTerm::Type getType() const { return termType_; } + dsl::Operator::Type getType() const { return termType_; } fvcc::VolumeField* volumeField() const { return nullptr; } @@ -73,7 +71,7 @@ class TimeTerm std::size_t nCells() const { return nCells_; } - dsl::EqnTerm::Type termType_; + dsl::Operator::Type termType_; const NeoFOAM::Executor exec_; std::size_t nCells_; }; @@ -87,11 +85,11 @@ TEST_CASE("TimeIntegration") NeoFOAM::Dictionary dict; dict.insert("type", std::string("forwardEuler")); - dsl::EqnTerm divTerm = Divergence(dsl::EqnTerm::Type::Explicit, exec, 1); + dsl::Operator divOperator = Divergence(dsl::Operator::Type::Explicit, exec, 1); - dsl::EqnTerm ddtTerm = TimeTerm(dsl::EqnTerm::Type::Temporal, exec, 1); + dsl::Operator ddtOperator = TimeOperator(dsl::Operator::Type::Temporal, exec, 1); - dsl::EqnSystem eqnSys = ddtTerm + divTerm; + dsl::EqnSystem eqnSys = ddtOperator + divOperator; fvcc::TimeIntegration timeIntergrator(eqnSys, dict); } From 2a9c309960149b7fa558e2eab14d89ce46409774 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 16:49:19 +0200 Subject: [PATCH 29/63] refactor constructors --- include/NeoFOAM/fields/domainField.hpp | 4 +-- .../cellCentred/fields/geometricField.hpp | 27 +++++++++++++++++-- .../cellCentred/fields/surfaceField.hpp | 21 +++++++++++++-- .../cellCentred/fields/volumeField.hpp | 19 ++++++++++++- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/include/NeoFOAM/fields/domainField.hpp b/include/NeoFOAM/fields/domainField.hpp index a92d2fb08..905f28382 100644 --- a/include/NeoFOAM/fields/domainField.hpp +++ b/include/NeoFOAM/fields/domainField.hpp @@ -55,7 +55,7 @@ class DomainField {} - DomainField(const ::NeoFOAM::DomainField& rhs) + DomainField(const DomainField& rhs) : exec_(rhs.exec_), internalField_(rhs.internalField_), boundaryFields_(rhs.boundaryFields_) {} @@ -66,7 +66,7 @@ class DomainField {} - DomainField& operator=(const ::NeoFOAM::DomainField& rhs) + DomainField& operator=(const DomainField& rhs) { internalField_ = rhs.internalField_; boundaryFields_ = rhs.boundaryFields_; diff --git a/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp b/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp index 53b68a47d..c02ee804a 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp @@ -36,11 +36,34 @@ class GeometricFieldMixin * @param field The domain field object. */ GeometricFieldMixin( - const Executor& exec, const UnstructuredMesh& mesh, const DomainField& field + const Executor& exec, + const UnstructuredMesh& mesh, + const DomainField& domainField ) - : exec_(exec), mesh_(mesh), field_(field) + : exec_(exec), mesh_(mesh), field_(domainField) {} + /** + * @brief Constructor for GeometricFieldMixin. + * + * @param exec The executor object. + * @param mesh The unstructured mesh object. + * @param field The domain field object. + */ + GeometricFieldMixin( + const Executor& exec, + const UnstructuredMesh& mesh, + const Field& internalField, + const BoundaryFields& boundaryFields + ) + : exec_(exec), mesh_(mesh), field_({exec, internalField, boundaryFields}) + { + if (mesh.nCells() != internalField.size()) + { + NF_ERROR_EXIT("Inconsistent size of mesh and internal field detected"); + } + } + /** * @brief Returns a const reference to the internal field. * diff --git a/include/NeoFOAM/finiteVolume/cellCentred/fields/surfaceField.hpp b/include/NeoFOAM/finiteVolume/cellCentred/fields/surfaceField.hpp index 64ad685b7..200bbd18c 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/fields/surfaceField.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/fields/surfaceField.hpp @@ -55,13 +55,30 @@ class SurfaceField : public GeometricFieldMixin SurfaceField( const Executor& exec, const UnstructuredMesh& mesh, - const Field& internalField, + const DomainField& domainField, const std::vector>& boundaryConditions ) - : GeometricFieldMixin(exec, mesh, {exec, mesh, internalField}), + : GeometricFieldMixin(exec, mesh, domainField), boundaryConditions_(boundaryConditions) {} + /* @brief Constructor for a surfaceField with a given internal field + * + * @param exec The executor + * @param mesh The underlying mesh + * @param internalField the underlying internal field + * @param boundaryConditions a vector of boundary conditions + */ + SurfaceField( + const Executor& exec, + const UnstructuredMesh& mesh, + const Field& internalField, + const BoundaryFields& boundaryFields, + const std::vector>& boundaryConditions + ) + : GeometricFieldMixin(exec, mesh, {exec, mesh, internalField, boundaryFields}), + boundaryConditions_(boundaryConditions) + {} SurfaceField(const SurfaceField& other) : GeometricFieldMixin(other), boundaryConditions_(other.boundaryConditions_) diff --git a/include/NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp b/include/NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp index ad590f425..f9ba40463 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp @@ -46,6 +46,22 @@ class VolumeField : public GeometricFieldMixin boundaryConditions_(boundaryConditions) {} + /* @brief Constructor for a VolumeField with a given internal field + * + * @param mesh The underlying mesh + * @param internalField the underlying internal field + * @param boundaryConditions a vector of boundary conditions + */ + VolumeField( + const Executor& exec, + const UnstructuredMesh& mesh, + const DomainField& domainField, + const std::vector>& boundaryConditions + ) + : GeometricFieldMixin(exec, mesh, domainField), + boundaryConditions_(boundaryConditions) + {} + /* @brief Constructor for a VolumeField with a given internal field * * @param mesh The underlying mesh @@ -56,9 +72,10 @@ class VolumeField : public GeometricFieldMixin const Executor& exec, const UnstructuredMesh& mesh, const Field& internalField, + const BoundaryFields& boundaryFields, const std::vector>& boundaryConditions ) - : GeometricFieldMixin(exec, mesh, {exec, mesh, internalField}), + : GeometricFieldMixin(exec, mesh, internalField, boundaryFields), boundaryConditions_(boundaryConditions) {} From 9f01abb73ec789934647652ba2bde3aff0e9c42a Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sat, 5 Oct 2024 08:30:14 +0200 Subject: [PATCH 30/63] wip add tests --- include/NeoFOAM/DSL/operator.hpp | 12 ++-------- test/dsl/operator.cpp | 23 +++++++++---------- .../timeIntegration/timeIntegration.cpp | 13 ++++++----- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index 48cfc6535..4586f6c3b 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -255,18 +255,10 @@ class Operator } /* @brief get the associated coefficient for this term */ - virtual Coeff& getCoefficient() override - { - // FIXME - // return cls_.getCoefficient(); - } + virtual Coeff& getCoefficient() override { return cls_.getCoefficient(); } /* @brief get the associated coefficient for this term */ - virtual Coeff getCoefficient() const override - { - // FIXME - // return cls_.getCoefficient(); - } + virtual Coeff getCoefficient() const override { return cls_.getCoefficient(); } // The Prototype Design Pattern std::unique_ptr clone() const override diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp index 12d4c831a..f9df8ec3b 100644 --- a/test/dsl/operator.cpp +++ b/test/dsl/operator.cpp @@ -17,6 +17,7 @@ using Operator = NeoFOAM::DSL::Operator; using OperatorMixin = NeoFOAM::DSL::OperatorMixin; using Executor = NeoFOAM::Executor; using VolumeField = fvcc::VolumeField; +using BoundaryFields = NeoFOAM::BoundaryFields; namespace fvcc = NeoFOAM::finiteVolume::cellCentred; /* A dummy implementation of a Operator @@ -63,28 +64,26 @@ TEST_CASE("Operator") SECTION("Operator creation on " + execName) { - - Field fA(exec, 3, 2.0); + Field fA(exec, 1, 2.0); + BoundaryFields bf(exec, mesh.nBoundaryFaces(), mesh.nBoundaries()); std::vector> bcs {}; - auto vf = VolumeField(exec, mesh, bcs); + auto vf = VolumeField(exec, mesh, fA, bf, bcs); auto b = Dummy(exec, vf); } SECTION("Supports Coefficients" + execName) { - std::vector> bcs {}; - auto vf = VolumeField(exec, mesh, bcs); - - Field fA(exec, 3, 2.0); - Field fB(exec, 3, 3.0); - auto b = Dummy(exec, &fA); + Field fA(exec, 1, 2.0); + Field fB(exec, 1, 2.0); + BoundaryFields bf(exec, mesh.nBoundaryFaces(), mesh.nBoundaries()); + auto vf = VolumeField(exec, mesh, fA, bf, bcs); - auto c = 2 * Dummy(exec, &fA); - auto d = fB * Dummy(exec, &fA); - auto e = Coeff(-3, fB) * Dummy(exec, &fA); + auto c = 2 * Dummy(exec, vf); + auto d = fB * Dummy(exec, vf); + auto e = Coeff(-3, fB) * Dummy(exec, vf); auto coeffc = c.getCoefficient(); auto coeffd = d.getCoefficient(); diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp index b73083fd8..b1f3b64ce 100644 --- a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp +++ b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp @@ -13,10 +13,9 @@ #include "NeoFOAM/DSL/operator.hpp" #include "NeoFOAM/DSL/eqnSystem.hpp" - namespace dsl = NeoFOAM::DSL; -class Divergence +class Divergence : public NeoFOAM::DSL::OperatorMixin { public: @@ -42,7 +41,9 @@ class Divergence std::size_t nCells() const { return nCells_; } dsl::Operator::Type termType_; + NeoFOAM::Executor exec_; + std::size_t nCells_; }; @@ -85,11 +86,11 @@ TEST_CASE("TimeIntegration") NeoFOAM::Dictionary dict; dict.insert("type", std::string("forwardEuler")); - dsl::Operator divOperator = Divergence(dsl::Operator::Type::Explicit, exec, 1); + // dsl::Operator divOperator = Divergence(dsl::Operator::Type::Explicit, exec, 1); - dsl::Operator ddtOperator = TimeOperator(dsl::Operator::Type::Temporal, exec, 1); + // dsl::Operator ddtOperator = TimeOperator(dsl::Operator::Type::Temporal, exec, 1); - dsl::EqnSystem eqnSys = ddtOperator + divOperator; + // dsl::EqnSystem eqnSys = ddtOperator + divOperator; - fvcc::TimeIntegration timeIntergrator(eqnSys, dict); + // fvcc::TimeIntegration timeIntergrator(eqnSys, dict); } From ba1a68f65901759599503d81b6944f6f5320b0bf Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:25:16 +0200 Subject: [PATCH 31/63] rename input/add further operator tests --- include/NeoFOAM/DSL/operator.hpp | 109 ++++++++---------- .../NeoFOAM/core/{inputs.hpp => input.hpp} | 0 test/core/CMakeLists.txt | 2 +- test/core/{inputs.cpp => input.cpp} | 2 +- test/dsl/operator.cpp | 31 ++++- 5 files changed, 74 insertions(+), 70 deletions(-) rename include/NeoFOAM/core/{inputs.hpp => input.hpp} (100%) rename test/core/{inputs.cpp => input.cpp} (98%) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index 4586f6c3b..ded92a29a 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -12,7 +12,7 @@ #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" #include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" -#include "NeoFOAM/core/inputs.hpp" +#include "NeoFOAM/core/input.hpp" #include "NeoFOAM/DSL/coeff.hpp" @@ -55,13 +55,6 @@ class OperatorMixin virtual ~OperatorMixin() = default; - // void setField(const Field> field) - // { - // field_ = field; - // // FIXME - // // getCoefficient() = Coeff(field_->span(), getCoefficient().value); - // } - const Executor& exec() const { return exec_; } Coeff& getCoefficient() { return coeffs_; } @@ -72,6 +65,9 @@ class OperatorMixin bool& evaluated() { return evaluated_; } + /* @brief Given an input this function reads required coeffs */ + void build(const Input& input) {} + // // const Field* field() { return field_; } @@ -142,14 +138,13 @@ class Operator /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ Operator::Type getType() const { return model_->getType(); } - void setField(std::shared_ptr> field) { model_->setField(field); } - Coeff& getCoefficient() { return model_->getCoefficient(); } Coeff getCoefficient() const { return model_->getCoefficient(); } - bool evaluated() { return model_->evaluated(); } + bool evaluated() const { return model_->evaluated(); } + /* @brief Given an input this function reads required coeffs */ void build(const Input& input) { model_->build(input); } const Executor& exec() const { return model_->exec(); } @@ -176,15 +171,14 @@ class Operator virtual void temporalOperation(Field& field) = 0; + /* @brief Given an input this function reads required coeffs */ virtual void build(const Input& input) = 0; - virtual bool evaluated() = 0; + virtual bool evaluated() const = 0; /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ virtual Operator::Type getType() const = 0; - virtual void setField(std::shared_ptr> field) = 0; - /* @brief get the associated coefficient for this term */ virtual Coeff& getCoefficient() = 0; @@ -202,63 +196,52 @@ class Operator }; // Templated derived class to implement the type-specific behavior - template + template struct OperatorModel : OperatorConcept { - OperatorModel(T cls) : cls_(std::move(cls)) {} + /* @brief build with concrete operator */ + OperatorModel(ConcreteOperatorType concreteOp) : concreteOp_(std::move(concreteOp)) {} std::string display() const override - { /*return cls_.display();*/ + { /*return concreteOp_.display();*/ } virtual void explicitOperation(Field& source) override { - if constexpr (HasExplicitOperator) + if constexpr (HasExplicitOperator) { - cls_.explicitOperation(source); + concreteOp_.explicitOperation(source); } } virtual void temporalOperation(Field& field) override { - if constexpr (HasTemporalOperator) + if constexpr (HasTemporalOperator) { - cls_.temporalOperation(field); + concreteOp_.temporalOperation(field); } } - // virtual fvcc::VolumeField* volumeField() override { return cls_.volumeField(); } + // virtual fvcc::VolumeField* volumeField() override { return + // concreteOp_.volumeField(); } - virtual void build(const Input& input) override - { - // FIXME - // cls_.build(input); - } + /* @brief Given an input this function reads required coeffs */ + virtual void build(const Input& input) override { concreteOp_.build(input); } - virtual bool evaluated() override - { - // FIXME - // return cls_.evaluated(); - } + virtual bool evaluated() const override { return concreteOp_.evaluated(); } /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ - Operator::Type getType() const override { return cls_.getType(); } + Operator::Type getType() const override { return concreteOp_.getType(); } - const Executor& exec() const override { return cls_.exec(); } + const Executor& exec() const override { return concreteOp_.exec(); } - // std::size_t nCells() const override { return cls_.nCells(); } - - void setField(std::shared_ptr> field) override - { - // FIXME - // cls_.setField(field); - } + // std::size_t nCells() const override { return concreteOp_.nCells(); } /* @brief get the associated coefficient for this term */ - virtual Coeff& getCoefficient() override { return cls_.getCoefficient(); } + virtual Coeff& getCoefficient() override { return concreteOp_.getCoefficient(); } /* @brief get the associated coefficient for this term */ - virtual Coeff getCoefficient() const override { return cls_.getCoefficient(); } + virtual Coeff getCoefficient() const override { return concreteOp_.getCoefficient(); } // The Prototype Design Pattern std::unique_ptr clone() const override @@ -266,43 +249,41 @@ class Operator return std::make_unique(*this); } - T cls_; + ConcreteOperatorType concreteOp_; }; std::unique_ptr model_; }; -auto operator*(scalar scale, const Operator& lhs) +auto operator*(scalar scalarCoeff, const Operator& rhs) { - Operator result = lhs; - result.getCoefficient() *= scale; + Operator result = rhs; + result.getCoefficient() *= scalarCoeff; return result; } -// add multiply operator to Operator -auto operator*(Field scale, const Operator& lhs) +auto operator*(const Field& coeffField, const Operator& rhs) { - Operator result = lhs; - // FIXME - // if (!result.getCoefficient().useSpan) - // { - // // allocate the scaling field to avoid deallocation - // result.setField(std::make_shared>(scale)); - // } - // else - // { - // result.getCoefficient() *= scale; - // } + Operator result = rhs; + result.getCoefficient() *= Coeff(coeffField); + return result; +} + +auto operator*(const Coeff& coeff, const Operator& rhs) +{ + Operator result = rhs; + result.getCoefficient() *= coeff; return result; } -// template -template -Operator operator*(ScaleFunction scaleFunc, const Operator& lhs) +template + requires std::invocable +Operator operator*(CoeffFunction coeffFunc, const Operator& lhs) { + // TODO implement + NF_ERROR_EXIT("Not implemented"); Operator result = lhs; - // FIXME // if (!result.getCoefficient().useSpan) // { // result.setField(std::make_shared>(result.exec(), result.nCells(), 1.0)); diff --git a/include/NeoFOAM/core/inputs.hpp b/include/NeoFOAM/core/input.hpp similarity index 100% rename from include/NeoFOAM/core/inputs.hpp rename to include/NeoFOAM/core/input.hpp diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index 4bdb9b185..7c57a79ab 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -6,7 +6,7 @@ add_subdirectory(primitives) neofoam_unit_test(dictionary) neofoam_unit_test(tokenList) -neofoam_unit_test(inputs) +neofoam_unit_test(input) neofoam_unit_test(executor) neofoam_unit_test(parallelAlgorithms) diff --git a/test/core/inputs.cpp b/test/core/input.cpp similarity index 98% rename from test/core/inputs.cpp rename to test/core/input.cpp index 5d9a86e54..2bef240fb 100644 --- a/test/core/inputs.cpp +++ b/test/core/input.cpp @@ -7,7 +7,7 @@ #include #include -#include "NeoFOAM/core/inputs.hpp" +#include "NeoFOAM/core/input.hpp" #include "NeoFOAM/core/primitives/label.hpp" #include "NeoFOAM/core/primitives/scalar.hpp" diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp index f9df8ec3b..1dc236ace 100644 --- a/test/dsl/operator.cpp +++ b/test/dsl/operator.cpp @@ -29,13 +29,15 @@ class Dummy : public OperatorMixin Dummy(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} - void explicitOperation(Field& source, NeoFOAM::scalar scale) + void explicitOperation(Field& source) { - auto sourceField = source.span(); + auto sourceSpan = source.span(); + auto fieldSpan = field_.internalField().span(); + auto coeff = getCoefficient(); NeoFOAM::parallelFor( source.exec(), - {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } + source.range(), + KOKKOS_LAMBDA(const size_t i) { sourceSpan[i] += coeff[i] * fieldSpan[i]; } ); } @@ -88,5 +90,26 @@ TEST_CASE("Operator") auto coeffc = c.getCoefficient(); auto coeffd = d.getCoefficient(); auto coeffE = e.getCoefficient(); + + REQUIRE(c.evaluated() == false); + REQUIRE(d.evaluated() == false); + REQUIRE(e.evaluated() == false); + + Field source(exec, 1, 2.0); + c.explicitOperation(source); + + // 2 += 2 * 2 + auto hostSourceC = source.copyToHost(); + REQUIRE(hostSourceC.span()[0] == 6.0); + + // 6 += 2 * 2 + d.explicitOperation(source); + auto hostSourceD = source.copyToHost(); + REQUIRE(hostSourceD.span()[0] == 10.0); + + // 10 += - 6 * 2 + e.explicitOperation(source); + auto hostSourceE = source.copyToHost(); + REQUIRE(hostSourceE.span()[0] == -2.0); } } From 627bf9009033f4b46cea7ab29f25de4bb65f019c Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:40:07 +0200 Subject: [PATCH 32/63] add getName() --- include/NeoFOAM/DSL/operator.hpp | 18 +++++------------- test/dsl/operator.cpp | 4 ++++ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index ded92a29a..ed0d44dc2 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -149,10 +149,6 @@ class Operator const Executor& exec() const { return model_->exec(); } - // std::size_t nCells() const { return model_->nCells(); } - - // fvcc::VolumeField* volumeField() { return model_->volumeField(); } - private: @@ -165,7 +161,6 @@ class Operator { virtual ~OperatorConcept() = default; - virtual std::string display() const = 0; virtual void explicitOperation(Field& source) = 0; @@ -176,6 +171,9 @@ class Operator virtual bool evaluated() const = 0; + /* returns the name of the operator */ + virtual std::string getName() const = 0; + /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ virtual Operator::Type getType() const = 0; @@ -187,8 +185,6 @@ class Operator virtual const Executor& exec() const = 0; - // virtual std::size_t nCells() const = 0; - // virtual fvcc::VolumeField* volumeField() = 0; // The Prototype Design Pattern @@ -202,9 +198,8 @@ class Operator /* @brief build with concrete operator */ OperatorModel(ConcreteOperatorType concreteOp) : concreteOp_(std::move(concreteOp)) {} - std::string display() const override - { /*return concreteOp_.display();*/ - } + /* returns the name of the operator */ + std::string getName() const override { return concreteOp_.getName(); } virtual void explicitOperation(Field& source) override { @@ -222,9 +217,6 @@ class Operator } } - // virtual fvcc::VolumeField* volumeField() override { return - // concreteOp_.volumeField(); } - /* @brief Given an input this function reads required coeffs */ virtual void build(const Input& input) override { concreteOp_.build(input); } diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp index 1dc236ace..b1783f19f 100644 --- a/test/dsl/operator.cpp +++ b/test/dsl/operator.cpp @@ -41,6 +41,8 @@ class Dummy : public OperatorMixin ); } + std::string getName() const { return "Dummy"; } + const VolumeField& volumeField() const { return field_; } VolumeField& volumeField() { return field_; } @@ -72,6 +74,8 @@ TEST_CASE("Operator") std::vector> bcs {}; auto vf = VolumeField(exec, mesh, fA, bf, bcs); auto b = Dummy(exec, vf); + + REQUIRE(b.getName() == "Dummy"); } SECTION("Supports Coefficients" + execName) From 62f2fc5323d48f80e572334716aa54a543a73573 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:42:30 +0200 Subject: [PATCH 33/63] fix format --- test/dsl/coeff.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp index da2ced419..e7c33958e 100644 --- a/test/dsl/coeff.cpp +++ b/test/dsl/coeff.cpp @@ -101,7 +101,7 @@ TEST_CASE("Coeff") { NeoFOAM::Field fieldA(exec, size, 0.0); NeoFOAM::Field fieldB(exec, size, 1.0); - Coeff coeff {-5.0,fieldB}; + Coeff coeff {-5.0, fieldB}; { NeoFOAM::parallelFor( fieldA, KOKKOS_LAMBDA(const size_t i) { return coeff[i] + 2.0; } @@ -113,6 +113,5 @@ TEST_CASE("Coeff") REQUIRE(hostFieldA[1] == -3.0); REQUIRE(hostFieldA[2] == -3.0); } - } } From f9e82e8b7eeb682418a49b926cd3864bc37069b0 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:52:23 +0200 Subject: [PATCH 34/63] add getName function --- include/NeoFOAM/DSL/operator.hpp | 3 +-- test/dsl/operator.cpp | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index ed0d44dc2..cd4d98698 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -68,7 +68,7 @@ class OperatorMixin /* @brief Given an input this function reads required coeffs */ void build(const Input& input) {} - // + // NOTE // const Field* field() { return field_; } protected: @@ -77,7 +77,6 @@ class OperatorMixin // NOTE unfortunately does not work // std::optional&> field_; - // const Field* field_; Coeff coeffs_; diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp index b1783f19f..1d299aec5 100644 --- a/test/dsl/operator.cpp +++ b/test/dsl/operator.cpp @@ -76,6 +76,7 @@ TEST_CASE("Operator") auto b = Dummy(exec, vf); REQUIRE(b.getName() == "Dummy"); + REQUIRE(b.getType() == Operator::Type::Explicit); } SECTION("Supports Coefficients" + execName) From 7111a82a3f0528f90866c97f7ee88282ef1c19cf Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:58:26 +0200 Subject: [PATCH 35/63] remove evaluated --- include/NeoFOAM/DSL/operator.hpp | 14 +------------- test/dsl/operator.cpp | 4 ---- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index cd4d98698..3f3aea508 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -48,7 +48,7 @@ class OperatorMixin public: - OperatorMixin(const Executor exec) : exec_(exec), coeffs_(), evaluated_(false) {}; + OperatorMixin(const Executor exec) : exec_(exec), coeffs_() {}; // OperatorMixin(const Executor exec, const Field* field) // : exec_(exec), field_(field), coeffs_(), evaluated_(false) {}; @@ -61,10 +61,6 @@ class OperatorMixin const Coeff& getCoefficient() const { return coeffs_; } - bool evaluated() const { return evaluated_; } - - bool& evaluated() { return evaluated_; } - /* @brief Given an input this function reads required coeffs */ void build(const Input& input) {} @@ -80,8 +76,6 @@ class OperatorMixin // const Field* field_; Coeff coeffs_; - - bool evaluated_; }; @@ -141,8 +135,6 @@ class Operator Coeff getCoefficient() const { return model_->getCoefficient(); } - bool evaluated() const { return model_->evaluated(); } - /* @brief Given an input this function reads required coeffs */ void build(const Input& input) { model_->build(input); } @@ -168,8 +160,6 @@ class Operator /* @brief Given an input this function reads required coeffs */ virtual void build(const Input& input) = 0; - virtual bool evaluated() const = 0; - /* returns the name of the operator */ virtual std::string getName() const = 0; @@ -219,8 +209,6 @@ class Operator /* @brief Given an input this function reads required coeffs */ virtual void build(const Input& input) override { concreteOp_.build(input); } - virtual bool evaluated() const override { return concreteOp_.evaluated(); } - /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ Operator::Type getType() const override { return concreteOp_.getType(); } diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp index 1d299aec5..ec8870b0a 100644 --- a/test/dsl/operator.cpp +++ b/test/dsl/operator.cpp @@ -96,10 +96,6 @@ TEST_CASE("Operator") auto coeffd = d.getCoefficient(); auto coeffE = e.getCoefficient(); - REQUIRE(c.evaluated() == false); - REQUIRE(d.evaluated() == false); - REQUIRE(e.evaluated() == false); - Field source(exec, 1, 2.0); c.explicitOperation(source); From 135b9181e10f24c78d2ee32b0218d744a8f4f69b Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 13:00:27 +0200 Subject: [PATCH 36/63] remove field and nCells --- include/NeoFOAM/DSL/operator.hpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index 3f3aea508..9a6738bc8 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -50,9 +50,6 @@ class OperatorMixin OperatorMixin(const Executor exec) : exec_(exec), coeffs_() {}; - // OperatorMixin(const Executor exec, const Field* field) - // : exec_(exec), field_(field), coeffs_(), evaluated_(false) {}; - virtual ~OperatorMixin() = default; const Executor& exec() const { return exec_; } @@ -64,17 +61,10 @@ class OperatorMixin /* @brief Given an input this function reads required coeffs */ void build(const Input& input) {} - // NOTE - // const Field* field() { return field_; } - protected: const Executor exec_; //!< Executor associated with the field. (CPU, GPU, openMP, etc.) - // NOTE unfortunately does not work - // std::optional&> field_; - // const Field* field_; - Coeff coeffs_; }; @@ -174,8 +164,6 @@ class Operator virtual const Executor& exec() const = 0; - // virtual fvcc::VolumeField* volumeField() = 0; - // The Prototype Design Pattern virtual std::unique_ptr clone() const = 0; }; @@ -214,8 +202,6 @@ class Operator const Executor& exec() const override { return concreteOp_.exec(); } - // std::size_t nCells() const override { return concreteOp_.nCells(); } - /* @brief get the associated coefficient for this term */ virtual Coeff& getCoefficient() override { return concreteOp_.getCoefficient(); } From 281137ef8f865af1aa74b94291db6f36fef7736b Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 13:10:41 +0200 Subject: [PATCH 37/63] refactor operator= --- include/NeoFOAM/DSL/operator.hpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index 9a6738bc8..f1feff8cf 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -100,19 +100,14 @@ class Operator Operator(Operator&& eqnOperator) : model_ {std::move(eqnOperator.model_)} {} + // TODO needed? Operator& operator=(const Operator& eqnOperator) { model_ = eqnOperator.model_->clone(); return *this; } - Operator& operator=(Operator&& eqnOperator) - { - model_ = std::move(eqnOperator.model_); - return *this; - } - - // std::string display() const { return model_->display(); } + Operator& operator=(Operator&& eqnOperator) { return this->operator=(eqnOperator); } void explicitOperation(Field& source) { model_->explicitOperation(source); } @@ -128,6 +123,7 @@ class Operator /* @brief Given an input this function reads required coeffs */ void build(const Input& input) { model_->build(input); } + /* @brief Get the executor */ const Executor& exec() const { return model_->exec(); } @@ -135,14 +131,11 @@ class Operator /* @brief Base class defining the concept of a term. This effectively * defines what functions need to be implemented by a concrete Operator implementation - * - * * */ struct OperatorConcept { virtual ~OperatorConcept() = default; - virtual void explicitOperation(Field& source) = 0; virtual void temporalOperation(Field& field) = 0; @@ -162,6 +155,7 @@ class Operator /* @brief get the associated coefficient for this term */ virtual Coeff getCoefficient() const = 0; + /* @brief Get the executor */ virtual const Executor& exec() const = 0; // The Prototype Design Pattern @@ -200,6 +194,7 @@ class Operator /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ Operator::Type getType() const override { return concreteOp_.getType(); } + /* @brief Get the executor */ const Executor& exec() const override { return concreteOp_.exec(); } /* @brief get the associated coefficient for this term */ From 7516cc348e7d766aa0f670effd952185ab1347e9 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 13:11:05 +0200 Subject: [PATCH 38/63] remove operator= --- include/NeoFOAM/DSL/operator.hpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index f1feff8cf..8ac92d543 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -100,15 +100,6 @@ class Operator Operator(Operator&& eqnOperator) : model_ {std::move(eqnOperator.model_)} {} - // TODO needed? - Operator& operator=(const Operator& eqnOperator) - { - model_ = eqnOperator.model_->clone(); - return *this; - } - - Operator& operator=(Operator&& eqnOperator) { return this->operator=(eqnOperator); } - void explicitOperation(Field& source) { model_->explicitOperation(source); } void temporalOperation(Field& field) { model_->temporalOperation(field); } From d376d2794f1f0563d877779d849e68576fdd0309 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 14:26:01 +0200 Subject: [PATCH 39/63] renamed EqnSystem->Equation --- .../DSL/{eqnSystem.hpp => equation.hpp} | 26 +- .../timeIntegration/forwardEuler.hpp | 2 +- .../timeIntegration/timeIntegration.hpp | 11 +- .../timeIntegration/forwardEuler.cpp | 2 +- test/dsl/CMakeLists.txt | 3 +- test/dsl/common.hpp | 61 ++++ test/dsl/dsl.cpp | 276 ------------------ test/dsl/equation.cpp | 271 +++++++++++++++++ test/dsl/operator.cpp | 52 +--- .../timeIntegration/timeIntegration.cpp | 4 +- 10 files changed, 356 insertions(+), 352 deletions(-) rename include/NeoFOAM/DSL/{eqnSystem.hpp => equation.hpp} (87%) create mode 100644 test/dsl/common.hpp delete mode 100644 test/dsl/dsl.cpp create mode 100644 test/dsl/equation.cpp diff --git a/include/NeoFOAM/DSL/eqnSystem.hpp b/include/NeoFOAM/DSL/equation.hpp similarity index 87% rename from include/NeoFOAM/DSL/eqnSystem.hpp rename to include/NeoFOAM/DSL/equation.hpp index ae34351e9..71380340a 100644 --- a/include/NeoFOAM/DSL/eqnSystem.hpp +++ b/include/NeoFOAM/DSL/equation.hpp @@ -15,11 +15,11 @@ namespace NeoFOAM::DSL { -class EqnSystem +class Equation { public: - EqnSystem(const NeoFOAM::Executor& exec, std::size_t nCells) + Equation(const NeoFOAM::Executor& exec, std::size_t nCells) : exec_(exec), nCells_(nCells), temporalOperators_(), implicitOperators_(), explicitOperators_(), volumeField_(nullptr) {} @@ -51,7 +51,7 @@ class EqnSystem } } - void addSystem(const EqnSystem& eqnSys) + void addSystem(const Equation& eqnSys) { for (auto& Operator : eqnSys.temporalOperators_) { @@ -140,30 +140,30 @@ class EqnSystem fvcc::VolumeField* volumeField_; }; -EqnSystem operator+(EqnSystem lhs, const EqnSystem& rhs) +Equation operator+(Equation lhs, const Equation& rhs) { lhs.addSystem(rhs); return lhs; } -EqnSystem operator+(EqnSystem lhs, const Operator& rhs) +Equation operator+(Equation lhs, const Operator& rhs) { lhs.addOperator(rhs); return lhs; } -EqnSystem operator+(const Operator& lhs, const Operator& rhs) +Equation operator+(const Operator& lhs, const Operator& rhs) { NF_ERROR_EXIT("Not implemented."); - // EqnSystem eqnSys(lhs.exec(), lhs.nCells()); + // Equation eqnSys(lhs.exec(), lhs.nCells()); // eqnSys.addOperator(lhs); // eqnSys.addOperator(rhs); // return eqnSys; } -EqnSystem operator*(NeoFOAM::scalar scale, const EqnSystem& es) +Equation operator*(NeoFOAM::scalar scale, const Equation& es) { - EqnSystem results(es.exec(), es.nCells()); + Equation results(es.exec(), es.nCells()); for (const auto& Operator : es.temporalOperators()) { results.addOperator(scale * Operator); @@ -179,22 +179,22 @@ EqnSystem operator*(NeoFOAM::scalar scale, const EqnSystem& es) return results; } -EqnSystem operator-(EqnSystem lhs, const EqnSystem& rhs) +Equation operator-(Equation lhs, const Equation& rhs) { lhs.addSystem(-1.0 * rhs); return lhs; } -EqnSystem operator-(EqnSystem lhs, const Operator& rhs) +Equation operator-(Equation lhs, const Operator& rhs) { lhs.addOperator(-1.0 * rhs); return lhs; } -EqnSystem operator-(const Operator& lhs, const Operator& rhs) +Equation operator-(const Operator& lhs, const Operator& rhs) { NF_ERROR_EXIT("Not implemented."); - // EqnSystem results(lhs.exec(), lhs.nCells()); + // Equation results(lhs.exec(), lhs.nCells()); // results.addOperator(lhs); // results.addOperator(-1.0 * rhs); // return results; diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp index 1509044b6..d27505611 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp @@ -20,7 +20,7 @@ class ForwardEuler : public TimeIntegrationFactory::Register public: - ForwardEuler(const dsl::EqnSystem& eqnSystem, const Dictionary& dict); + ForwardEuler(const DSL::Equation& eqnSystem, const Dictionary& dict); static std::string name() { return "forwardEuler"; } diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp index 9709f0746..483f2b8e7 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp @@ -9,7 +9,7 @@ #include "NeoFOAM/finiteVolume/cellCentred.hpp" #include "NeoFOAM/DSL/operator.hpp" -#include "NeoFOAM/DSL/eqnSystem.hpp" +#include "NeoFOAM/DSL/equation.hpp" #include @@ -21,14 +21,14 @@ namespace NeoFOAM::finiteVolume::cellCentred class TimeIntegrationFactory : public NeoFOAM::RuntimeSelectionFactory< TimeIntegrationFactory, - Parameters> + Parameters> { public: static std::string name() { return "timeIntegrationFactory"; } - TimeIntegrationFactory(const dsl::EqnSystem& eqnSystem, const Dictionary& dict) + TimeIntegrationFactory(const dsl::Equation& eqnSystem, const Dictionary& dict) : eqnSystem_(eqnSystem), dict_(dict) {} @@ -41,7 +41,8 @@ class TimeIntegrationFactory : protected: - dsl::EqnSystem eqnSystem_; + DSL::Equation eqnSystem_; + const Dictionary& dict_; }; @@ -56,7 +57,7 @@ class TimeIntegration TimeIntegration(TimeIntegration&& timeIntegrate) : timeIntegrateStrategy_(std::move(timeIntegrate.timeIntegrateStrategy_)) {}; - TimeIntegration(const dsl::EqnSystem& eqnSystem, const Dictionary& dict) + TimeIntegration(const DSL::Equation& eqnSystem, const Dictionary& dict) : timeIntegrateStrategy_( TimeIntegrationFactory::create(dict.get("type"), eqnSystem, dict) ) {}; diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp index 08ce009f2..1b6c0e740 100644 --- a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp +++ b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp @@ -11,7 +11,7 @@ namespace NeoFOAM::finiteVolume::cellCentred { -ForwardEuler::ForwardEuler(const dsl::EqnSystem& eqnSystem, const Dictionary& dict) +ForwardEuler::ForwardEuler(const dsl::Equation& eqnSystem, const Dictionary& dict) : TimeIntegrationFactory::Register(eqnSystem, dict) { // Constructor diff --git a/test/dsl/CMakeLists.txt b/test/dsl/CMakeLists.txt index 5616fabe1..4935deff8 100644 --- a/test/dsl/CMakeLists.txt +++ b/test/dsl/CMakeLists.txt @@ -3,5 +3,4 @@ neofoam_unit_test(coeff) neofoam_unit_test(operator) - -# FIXME neofoam_unit_test(dsl) +neofoam_unit_test(equation) diff --git a/test/dsl/common.hpp b/test/dsl/common.hpp new file mode 100644 index 000000000..8e4a5bb58 --- /dev/null +++ b/test/dsl/common.hpp @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create + // a custom main +#include +#include +#include +#include + +#include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/DSL/coeff.hpp" +#include "NeoFOAM/DSL/operator.hpp" + +using Field = NeoFOAM::Field; +using Coeff = NeoFOAM::DSL::Coeff; +using Operator = NeoFOAM::DSL::Operator; +using OperatorMixin = NeoFOAM::DSL::OperatorMixin; +using Executor = NeoFOAM::Executor; +using VolumeField = fvcc::VolumeField; +using BoundaryFields = NeoFOAM::BoundaryFields; +namespace fvcc = NeoFOAM::finiteVolume::cellCentred; + +/* A dummy implementation of a Operator + * following the Operator interface */ +class Dummy : public OperatorMixin +{ + +public: + + Dummy(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} + + void explicitOperation(Field& source) + { + auto sourceSpan = source.span(); + auto fieldSpan = field_.internalField().span(); + auto coeff = getCoefficient(); + NeoFOAM::parallelFor( + source.exec(), + source.range(), + KOKKOS_LAMBDA(const size_t i) { sourceSpan[i] += coeff[i] * fieldSpan[i]; } + ); + } + + std::string getName() const { return "Dummy"; } + + const VolumeField& volumeField() const { return field_; } + + VolumeField& volumeField() { return field_; } + + Operator::Type getType() const { return Operator::Type::Explicit; } + +private: + + VolumeField& field_; +}; + +NeoFOAM::scalar getField(const NeoFOAM::Field& source) +{ + auto sourceField = source.copyToHost(); + return sourceField.span()[0]; +} diff --git a/test/dsl/dsl.cpp b/test/dsl/dsl.cpp deleted file mode 100644 index 48fafa000..000000000 --- a/test/dsl/dsl.cpp +++ /dev/null @@ -1,276 +0,0 @@ -// SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors -#define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create - // a custom main -#include -#include -#include -#include - -#include "NeoFOAM/DSL/eqnTerm.hpp" -#include "NeoFOAM/DSL/eqnSystem.hpp" - - -namespace dsl = NeoFOAM::DSL; -namespace fvcc = NeoFOAM::finiteVolume::cellCentred; - -class Laplacian -{ - -public: - - std::string display() const { return "Laplacian"; } - - void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) - { - auto sourceField = source.span(); - NeoFOAM::parallelFor( - source.exec(), - {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } - ); - } - - dsl::EqnTerm::Type getType() const { return termType_; } - - const NeoFOAM::Executor& exec() const { return exec_; } - - const std::size_t nCells() const { return nCells_; } - - fvcc::VolumeField* volumeField() { return nullptr; } - - dsl::EqnTerm::Type termType_; - - const NeoFOAM::Executor exec_; - const std::size_t nCells_; -}; - -class Divergence -{ - -public: - - std::string display() const { return "Divergence"; } - - void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) - { - auto sourceField = source.span(); - NeoFOAM::parallelFor( - source.exec(), - {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } - ); - } - - dsl::EqnTerm::Type getType() const { return termType_; } - - const NeoFOAM::Executor& exec() const { return exec_; } - - const std::size_t nCells() const { return nCells_; } - - fvcc::VolumeField* volumeField() { return nullptr; } - - dsl::EqnTerm::Type termType_; - - const NeoFOAM::Executor exec_; - const std::size_t nCells_; -}; - -NeoFOAM::scalar getField(const NeoFOAM::Field& source) -{ - auto sourceField = source.copyToHost(); - return sourceField.span()[0]; -} - -TEST_CASE("DSL") -{ - auto exec = NeoFOAM::SerialExecutor(); - dsl::EqnTerm lapTerm = Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1); - - REQUIRE("Laplacian" == lapTerm.display()); - - dsl::EqnTerm divTerm = Divergence(dsl::EqnTerm::Type::Explicit, exec, 1); - - REQUIRE("Divergence" == divTerm.display()); - { - NeoFOAM::Field source(exec, 1); - NeoFOAM::fill(source, 0.0); - - lapTerm.explicitOperation(source); - divTerm.explicitOperation(source); - - REQUIRE(getField(source) == 2.0); - } - - { - dsl::EqnSystem eqnSys = lapTerm + divTerm; - REQUIRE(eqnSys.size() == 2); - REQUIRE(getField(eqnSys.explicitOperation()) == 2); - } - BENCHMARK("Creation from EqnTerm") - { - dsl::EqnSystem eqnSys = lapTerm + divTerm; - return eqnSys; - }; - - { - dsl::EqnSystem eqnSys(lapTerm + lapTerm + divTerm + divTerm); - REQUIRE(eqnSys.size() == 4); - REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); - } - BENCHMARK("Creation from multiple terms") - { - dsl::EqnSystem eqnSys2(lapTerm + lapTerm + divTerm + divTerm); - return eqnSys2; - }; - - { - dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); - REQUIRE(eqnSys.size() == 2); - REQUIRE(getField(eqnSys.explicitOperation()) == 2.0); - } - BENCHMARK("Creation from term and temporary term") - { - dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); - return eqnSys; - }; - - { - dsl::EqnSystem eqnSys = lapTerm - divTerm; - REQUIRE(eqnSys.size() == 2); - REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); - } - - { - dsl::EqnSystem eqnSys(lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); - REQUIRE(eqnSys.size() == 2); - REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); - } - - { - dsl::EqnSystem eqnSys(lapTerm - lapTerm - divTerm - divTerm); - REQUIRE(eqnSys.size() == 4); - REQUIRE(getField(eqnSys.explicitOperation()) == -2.0); - } - - { - dsl::EqnSystem eqnSys( - lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm - + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - dsl::EqnSystem eqnSys2( - lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm - + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - REQUIRE(eqnSys.size() == 4); - REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); - dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; - REQUIRE(combinedEqnSys.size() == 8); - REQUIRE(getField(combinedEqnSys.explicitOperation()) == 8.0); - } - BENCHMARK("Creation from term and temporary term") - { - dsl::EqnSystem eqnSys( - lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm - + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - dsl::EqnSystem eqnSys2( - lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm - + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; - return combinedEqnSys; - }; - - { - dsl::EqnSystem eqnSys( - lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - divTerm - - Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - dsl::EqnSystem eqnSys2( - lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - divTerm - - Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - REQUIRE(eqnSys.size() == 4); - REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); - REQUIRE(eqnSys2.size() == 4); - REQUIRE(getField(eqnSys2.explicitOperation()) == -2.0); - - SECTION("multiplying eqnSys by 2") - { - dsl::EqnSystem multiplyEqnSys = 2.0 * eqnSys2; - REQUIRE(multiplyEqnSys.size() == 4); - REQUIRE(getField(multiplyEqnSys.explicitOperation()) == -4.0); - } - - SECTION("adding eqnSys to eqnSys2") - { - dsl::EqnSystem addEqnSys = eqnSys2 + eqnSys; - REQUIRE(addEqnSys.size() == 8); - REQUIRE(getField(addEqnSys.explicitOperation()) == -2.0); - } - SECTION("subtracting eqnSys from eqnSys2") - { - std::cout << "subtracting eqnSys from eqnSys2" << std::endl; - dsl::EqnSystem subtractEqnSys = eqnSys - eqnSys2; - REQUIRE(subtractEqnSys.size() == 8); - REQUIRE(getField(subtractEqnSys.explicitOperation()) == 2.0); - } - } - // profiling - // with different number of terms - BENCHMARK("Creation from 2 terms") - { - dsl::EqnSystem eqnSys(divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); - - return eqnSys; - }; - - BENCHMARK("Creation from 4 terms") - { - dsl::EqnSystem eqnSys( - divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - - return eqnSys; - }; - - BENCHMARK("Creation from 8 terms") - { - dsl::EqnSystem eqnSys( - divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - - return eqnSys; - }; - - BENCHMARK("Creation from 16 terms") - { - dsl::EqnSystem eqnSys( - divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - ); - - return eqnSys; - }; -} diff --git a/test/dsl/equation.cpp b/test/dsl/equation.cpp new file mode 100644 index 000000000..14d7dae00 --- /dev/null +++ b/test/dsl/equation.cpp @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create + // a custom main +#include "common.hpp" +#include "NeoFOAM/DSL/equation.hpp" + +// class Laplacian +// { + +// public: + +// std::string display() const { return "Laplacian"; } + +// void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) +// { +// auto sourceField = source.span(); +// NeoFOAM::parallelFor( +// source.exec(), +// {0, source.size()}, +// KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } +// ); +// } + +// dsl::EqnTerm::Type getType() const { return termType_; } + +// const NeoFOAM::Executor& exec() const { return exec_; } + +// const std::size_t nCells() const { return nCells_; } + +// fvcc::VolumeField* volumeField() { return nullptr; } + +// dsl::EqnTerm::Type termType_; + +// const NeoFOAM::Executor exec_; +// const std::size_t nCells_; +// }; + +// class Divergence +// { + +// public: + +// std::string display() const { return "Divergence"; } + +// void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) +// { +// auto sourceField = source.span(); +// NeoFOAM::parallelFor( +// source.exec(), +// {0, source.size()}, +// KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } +// ); +// } + +// dsl::EqnTerm::Type getType() const { return termType_; } + +// const NeoFOAM::Executor& exec() const { return exec_; } + +// const std::size_t nCells() const { return nCells_; } + +// fvcc::VolumeField* volumeField() { return nullptr; } + +// dsl::EqnTerm::Type termType_; + +// const NeoFOAM::Executor exec_; +// const std::size_t nCells_; +// }; + +using Equation = NeoFOAM::DSL::Equation; + +TEST_CASE("Equation") +{ + NeoFOAM::Executor exec = GENERATE( + NeoFOAM::Executor(NeoFOAM::SerialExecutor {}), + NeoFOAM::Executor(NeoFOAM::CPUExecutor {}), + NeoFOAM::Executor(NeoFOAM::GPUExecutor {}) + ); + + std::string execName = std::visit([](auto e) { return e.print(); }, exec); + auto mesh = NeoFOAM::createSingleCellMesh(exec); + + Field fA(exec, 1, 2.0); + BoundaryFields bf(exec, mesh.nBoundaryFaces(), mesh.nBoundaries()); + + std::vector> bcs {}; + auto vf = VolumeField(exec, mesh, fA, bf, bcs); + auto fB = Field(exec, 1, 4.0); + + auto a = Dummy(exec, vf); + auto b = Dummy(exec, vf); + + SECTION("Create from operators " + execName) + { + auto eqnA = a + b; + auto eqnB = fB * Dummy(exec, vf) + 2 * Dummy(exec, vf); + + REQUIRE(eqnA.size() == 2); + REQUIRE(eqnB.size() == 2); + + REQUIRE(getField(eqnA.explicitOperation()) == 4); + REQUIRE(getField(eqnB.explicitOperation()) == 12); + } + + // BENCHMARK("Creation from EqnTerm") + // { + // dsl::EqnSystem eqnSys = lapTerm + divTerm; + // return eqnSys; + // }; + + // { + // dsl::EqnSystem eqnSys(lapTerm + lapTerm + divTerm + divTerm); + // REQUIRE(eqnSys.size() == 4); + // REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); + // } + // BENCHMARK("Creation from multiple terms") + // { + // dsl::EqnSystem eqnSys2(lapTerm + lapTerm + divTerm + divTerm); + // return eqnSys2; + // }; + + // { + // dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); + // REQUIRE(eqnSys.size() == 2); + // REQUIRE(getField(eqnSys.explicitOperation()) == 2.0); + // } + // BENCHMARK("Creation from term and temporary term") + // { + // dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); + // return eqnSys; + // }; + + // { + // dsl::EqnSystem eqnSys = lapTerm - divTerm; + // REQUIRE(eqnSys.size() == 2); + // REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); + // } + + // { + // dsl::EqnSystem eqnSys(lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); + // REQUIRE(eqnSys.size() == 2); + // REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); + // } + + // { + // dsl::EqnSystem eqnSys(lapTerm - lapTerm - divTerm - divTerm); + // REQUIRE(eqnSys.size() == 4); + // REQUIRE(getField(eqnSys.explicitOperation()) == -2.0); + // } + + // { + // dsl::EqnSystem eqnSys( + // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm + // + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + // dsl::EqnSystem eqnSys2( + // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm + // + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + // REQUIRE(eqnSys.size() == 4); + // REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); + // dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; + // REQUIRE(combinedEqnSys.size() == 8); + // REQUIRE(getField(combinedEqnSys.explicitOperation()) == 8.0); + // } + // BENCHMARK("Creation from term and temporary term") + // { + // dsl::EqnSystem eqnSys( + // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm + // + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + // dsl::EqnSystem eqnSys2( + // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm + // + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + // dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; + // return combinedEqnSys; + // }; + + // { + // dsl::EqnSystem eqnSys( + // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - divTerm + // - Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + // dsl::EqnSystem eqnSys2( + // lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - divTerm + // - Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + // REQUIRE(eqnSys.size() == 4); + // REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); + // REQUIRE(eqnSys2.size() == 4); + // REQUIRE(getField(eqnSys2.explicitOperation()) == -2.0); + + // SECTION("multiplying eqnSys by 2") + // { + // dsl::EqnSystem multiplyEqnSys = 2.0 * eqnSys2; + // REQUIRE(multiplyEqnSys.size() == 4); + // REQUIRE(getField(multiplyEqnSys.explicitOperation()) == -4.0); + // } + + // SECTION("adding eqnSys to eqnSys2") + // { + // dsl::EqnSystem addEqnSys = eqnSys2 + eqnSys; + // REQUIRE(addEqnSys.size() == 8); + // REQUIRE(getField(addEqnSys.explicitOperation()) == -2.0); + // } + // SECTION("subtracting eqnSys from eqnSys2") + // { + // std::cout << "subtracting eqnSys from eqnSys2" << std::endl; + // dsl::EqnSystem subtractEqnSys = eqnSys - eqnSys2; + // REQUIRE(subtractEqnSys.size() == 8); + // REQUIRE(getField(subtractEqnSys.explicitOperation()) == 2.0); + // } + // } + // // profiling + // // with different number of terms + // BENCHMARK("Creation from 2 terms") + // { + // dsl::EqnSystem eqnSys(divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); + + // return eqnSys; + // }; + + // BENCHMARK("Creation from 4 terms") + // { + // dsl::EqnSystem eqnSys( + // divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + + // return eqnSys; + // }; + + // BENCHMARK("Creation from 8 terms") + // { + // dsl::EqnSystem eqnSys( + // divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + + // return eqnSys; + // }; + + // BENCHMARK("Creation from 16 terms") + // { + // dsl::EqnSystem eqnSys( + // divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + // ); + + // return eqnSys; + // }; +} diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp index ec8870b0a..b48c4a1ee 100644 --- a/test/dsl/operator.cpp +++ b/test/dsl/operator.cpp @@ -2,57 +2,7 @@ // SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors #define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create // a custom main -#include -#include -#include -#include - -#include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/DSL/coeff.hpp" -#include "NeoFOAM/DSL/operator.hpp" - -using Field = NeoFOAM::Field; -using Coeff = NeoFOAM::DSL::Coeff; -using Operator = NeoFOAM::DSL::Operator; -using OperatorMixin = NeoFOAM::DSL::OperatorMixin; -using Executor = NeoFOAM::Executor; -using VolumeField = fvcc::VolumeField; -using BoundaryFields = NeoFOAM::BoundaryFields; -namespace fvcc = NeoFOAM::finiteVolume::cellCentred; - -/* A dummy implementation of a Operator - * following the Operator interface */ -class Dummy : public OperatorMixin -{ - -public: - - Dummy(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} - - void explicitOperation(Field& source) - { - auto sourceSpan = source.span(); - auto fieldSpan = field_.internalField().span(); - auto coeff = getCoefficient(); - NeoFOAM::parallelFor( - source.exec(), - source.range(), - KOKKOS_LAMBDA(const size_t i) { sourceSpan[i] += coeff[i] * fieldSpan[i]; } - ); - } - - std::string getName() const { return "Dummy"; } - - const VolumeField& volumeField() const { return field_; } - - VolumeField& volumeField() { return field_; } - - Operator::Type getType() const { return Operator::Type::Explicit; } - -private: - - VolumeField& field_; -}; +#include "common.hpp" TEST_CASE("Operator") { diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp index b1f3b64ce..95a259cae 100644 --- a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp +++ b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp @@ -7,11 +7,9 @@ #include #include -#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" -#include "NeoFOAM/DSL/operator.hpp" -#include "NeoFOAM/DSL/eqnSystem.hpp" +#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" namespace dsl = NeoFOAM::DSL; From 13905d197d47acd47aca767667744e9369faa0be Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 17:21:15 +0200 Subject: [PATCH 40/63] mark explicitOperation as const --- include/NeoFOAM/DSL/operator.hpp | 14 +++++++++++--- test/dsl/common.hpp | 4 +++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp index 8ac92d543..64480b7f8 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/DSL/operator.hpp @@ -100,7 +100,7 @@ class Operator Operator(Operator&& eqnOperator) : model_ {std::move(eqnOperator.model_)} {} - void explicitOperation(Field& source) { model_->explicitOperation(source); } + void explicitOperation(Field& source) const { model_->explicitOperation(source); } void temporalOperation(Field& field) { model_->temporalOperation(field); } @@ -111,6 +111,9 @@ class Operator Coeff getCoefficient() const { return model_->getCoefficient(); } + /* get the corresponding field size over which the operator operates */ + size_t getSize() const { return model_->getSize(); } + /* @brief Given an input this function reads required coeffs */ void build(const Input& input) { model_->build(input); } @@ -127,7 +130,7 @@ class Operator { virtual ~OperatorConcept() = default; - virtual void explicitOperation(Field& source) = 0; + virtual void explicitOperation(Field& source) const = 0; virtual void temporalOperation(Field& field) = 0; @@ -140,6 +143,8 @@ class Operator /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ virtual Operator::Type getType() const = 0; + virtual size_t getSize() const = 0; + /* @brief get the associated coefficient for this term */ virtual Coeff& getCoefficient() = 0; @@ -163,7 +168,7 @@ class Operator /* returns the name of the operator */ std::string getName() const override { return concreteOp_.getName(); } - virtual void explicitOperation(Field& source) override + virtual void explicitOperation(Field& source) const override { if constexpr (HasExplicitOperator) { @@ -194,6 +199,9 @@ class Operator /* @brief get the associated coefficient for this term */ virtual Coeff getCoefficient() const override { return concreteOp_.getCoefficient(); } + /* @brief get the associated coefficient for this term */ + virtual size_t getSize() const override { return concreteOp_.getSize(); } + // The Prototype Design Pattern std::unique_ptr clone() const override { diff --git a/test/dsl/common.hpp b/test/dsl/common.hpp index 8e4a5bb58..434c78e7f 100644 --- a/test/dsl/common.hpp +++ b/test/dsl/common.hpp @@ -29,7 +29,7 @@ class Dummy : public OperatorMixin Dummy(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} - void explicitOperation(Field& source) + void explicitOperation(Field& source) const { auto sourceSpan = source.span(); auto fieldSpan = field_.internalField().span(); @@ -49,6 +49,8 @@ class Dummy : public OperatorMixin Operator::Type getType() const { return Operator::Type::Explicit; } + size_t getSize() const { return field_.internalField().size(); } + private: VolumeField& field_; From b5bc333ea886844840c26a197bb5325eb3fc37f2 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 17:22:06 +0200 Subject: [PATCH 41/63] add overload for explicitOperation --- include/NeoFOAM/DSL/equation.hpp | 60 ++++---- test/dsl/equation.cpp | 240 ++----------------------------- 2 files changed, 43 insertions(+), 257 deletions(-) diff --git a/include/NeoFOAM/DSL/equation.hpp b/include/NeoFOAM/DSL/equation.hpp index 71380340a..27d64dd83 100644 --- a/include/NeoFOAM/DSL/equation.hpp +++ b/include/NeoFOAM/DSL/equation.hpp @@ -19,15 +19,21 @@ class Equation { public: - Equation(const NeoFOAM::Executor& exec, std::size_t nCells) + Equation(const Executor& exec, std::size_t nCells) : exec_(exec), nCells_(nCells), temporalOperators_(), implicitOperators_(), explicitOperators_(), volumeField_(nullptr) {} - NeoFOAM::Field explicitOperation() + /* @brief perform all explicit operation and accumulate the result */ + Field explicitOperation() const + { + Field source(exec_, nCells_, 0.0); + return explicitOperation(source); + } + + /* @brief perform all explicit operation and accumulate the result */ + Field explicitOperation(Field& source) const { - NeoFOAM::Field source(exec_, nCells_); - NeoFOAM::fill(source, 0.0); for (auto& Operator : explicitOperators_) { Operator.explicitOperation(source); @@ -51,17 +57,17 @@ class Equation } } - void addSystem(const Equation& eqnSys) + void addEquation(const Equation& equation) { - for (auto& Operator : eqnSys.temporalOperators_) + for (auto& Operator : equation.temporalOperators_) { temporalOperators_.push_back(Operator); } - for (auto& Operator : eqnSys.implicitOperators_) + for (auto& Operator : equation.implicitOperators_) { implicitOperators_.push_back(Operator); } - for (auto& Operator : eqnSys.explicitOperators_) + for (auto& Operator : equation.explicitOperators_) { explicitOperators_.push_back(Operator); } @@ -75,14 +81,17 @@ class Equation } if (temporalOperators_.size() > 0) { + NF_ERROR_EXIT("Not implemented."); // integrate equations in time } else { + NF_ERROR_EXIT("Not implemented."); // solve sparse matrix system } } + /* @brief getter for the total number of terms in the equation */ size_t size() const { return temporalOperators_.size() + implicitOperators_.size() + explicitOperators_.size(); @@ -101,13 +110,13 @@ class Equation std::vector& explicitOperators() { return explicitOperators_; } - const NeoFOAM::Executor& exec() const { return exec_; } + const Executor& exec() const { return exec_; } const std::size_t nCells() const { return nCells_; } scalar getDt() const { return dt_; } - fvcc::VolumeField* volumeField() + fvcc::VolumeField* volumeField() { if (temporalOperators_.size() == 0 && implicitOperators_.size() == 0) { @@ -128,21 +137,21 @@ class Equation return volumeField_; } - NeoFOAM::scalar dt_ = 0; + scalar dt_ = 0; private: - const NeoFOAM::Executor exec_; + const Executor exec_; const std::size_t nCells_; std::vector temporalOperators_; std::vector implicitOperators_; std::vector explicitOperators_; - fvcc::VolumeField* volumeField_; + fvcc::VolumeField* volumeField_; }; Equation operator+(Equation lhs, const Equation& rhs) { - lhs.addSystem(rhs); + lhs.addEquation(rhs); return lhs; } @@ -154,14 +163,13 @@ Equation operator+(Equation lhs, const Operator& rhs) Equation operator+(const Operator& lhs, const Operator& rhs) { - NF_ERROR_EXIT("Not implemented."); - // Equation eqnSys(lhs.exec(), lhs.nCells()); - // eqnSys.addOperator(lhs); - // eqnSys.addOperator(rhs); - // return eqnSys; + Equation equation(lhs.exec(), lhs.getSize()); + equation.addOperator(lhs); + equation.addOperator(rhs); + return equation; } -Equation operator*(NeoFOAM::scalar scale, const Equation& es) +Equation operator*(scalar scale, const Equation& es) { Equation results(es.exec(), es.nCells()); for (const auto& Operator : es.temporalOperators()) @@ -181,7 +189,7 @@ Equation operator*(NeoFOAM::scalar scale, const Equation& es) Equation operator-(Equation lhs, const Equation& rhs) { - lhs.addSystem(-1.0 * rhs); + lhs.addEquation(-1.0 * rhs); return lhs; } @@ -193,12 +201,10 @@ Equation operator-(Equation lhs, const Operator& rhs) Equation operator-(const Operator& lhs, const Operator& rhs) { - NF_ERROR_EXIT("Not implemented."); - // Equation results(lhs.exec(), lhs.nCells()); - // results.addOperator(lhs); - // results.addOperator(-1.0 * rhs); - // return results; + Equation equation(lhs.exec(), lhs.getSize()); + equation.addOperator(lhs); + equation.addOperator(Coeff(-1) * rhs); + return equation; } - } // namespace NeoFOAM::DSL diff --git a/test/dsl/equation.cpp b/test/dsl/equation.cpp index 14d7dae00..11d917a71 100644 --- a/test/dsl/equation.cpp +++ b/test/dsl/equation.cpp @@ -5,68 +5,6 @@ #include "common.hpp" #include "NeoFOAM/DSL/equation.hpp" -// class Laplacian -// { - -// public: - -// std::string display() const { return "Laplacian"; } - -// void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) -// { -// auto sourceField = source.span(); -// NeoFOAM::parallelFor( -// source.exec(), -// {0, source.size()}, -// KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } -// ); -// } - -// dsl::EqnTerm::Type getType() const { return termType_; } - -// const NeoFOAM::Executor& exec() const { return exec_; } - -// const std::size_t nCells() const { return nCells_; } - -// fvcc::VolumeField* volumeField() { return nullptr; } - -// dsl::EqnTerm::Type termType_; - -// const NeoFOAM::Executor exec_; -// const std::size_t nCells_; -// }; - -// class Divergence -// { - -// public: - -// std::string display() const { return "Divergence"; } - -// void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) -// { -// auto sourceField = source.span(); -// NeoFOAM::parallelFor( -// source.exec(), -// {0, source.size()}, -// KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } -// ); -// } - -// dsl::EqnTerm::Type getType() const { return termType_; } - -// const NeoFOAM::Executor& exec() const { return exec_; } - -// const std::size_t nCells() const { return nCells_; } - -// fvcc::VolumeField* volumeField() { return nullptr; } - -// dsl::EqnTerm::Type termType_; - -// const NeoFOAM::Executor exec_; -// const std::size_t nCells_; -// }; - using Equation = NeoFOAM::DSL::Equation; TEST_CASE("Equation") @@ -90,182 +28,24 @@ TEST_CASE("Equation") auto a = Dummy(exec, vf); auto b = Dummy(exec, vf); - SECTION("Create from operators " + execName) + SECTION("Create equation and perform explicitOperation on " + execName) { auto eqnA = a + b; auto eqnB = fB * Dummy(exec, vf) + 2 * Dummy(exec, vf); + auto eqnC = Equation(2 * a - b); + auto eqnD = 3 * (2 * a - b); + auto eqnE = (2 * a - b) + (2 * a - b); + auto eqnF = (2 * a - b) - (2 * a - b); REQUIRE(eqnA.size() == 2); REQUIRE(eqnB.size() == 2); + REQUIRE(eqnC.size() == 2); REQUIRE(getField(eqnA.explicitOperation()) == 4); REQUIRE(getField(eqnB.explicitOperation()) == 12); + REQUIRE(getField(eqnC.explicitOperation()) == 2); + REQUIRE(getField(eqnD.explicitOperation()) == 6); + REQUIRE(getField(eqnE.explicitOperation()) == 4); + REQUIRE(getField(eqnF.explicitOperation()) == 0); } - - // BENCHMARK("Creation from EqnTerm") - // { - // dsl::EqnSystem eqnSys = lapTerm + divTerm; - // return eqnSys; - // }; - - // { - // dsl::EqnSystem eqnSys(lapTerm + lapTerm + divTerm + divTerm); - // REQUIRE(eqnSys.size() == 4); - // REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); - // } - // BENCHMARK("Creation from multiple terms") - // { - // dsl::EqnSystem eqnSys2(lapTerm + lapTerm + divTerm + divTerm); - // return eqnSys2; - // }; - - // { - // dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); - // REQUIRE(eqnSys.size() == 2); - // REQUIRE(getField(eqnSys.explicitOperation()) == 2.0); - // } - // BENCHMARK("Creation from term and temporary term") - // { - // dsl::EqnSystem eqnSys(lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); - // return eqnSys; - // }; - - // { - // dsl::EqnSystem eqnSys = lapTerm - divTerm; - // REQUIRE(eqnSys.size() == 2); - // REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); - // } - - // { - // dsl::EqnSystem eqnSys(lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); - // REQUIRE(eqnSys.size() == 2); - // REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); - // } - - // { - // dsl::EqnSystem eqnSys(lapTerm - lapTerm - divTerm - divTerm); - // REQUIRE(eqnSys.size() == 4); - // REQUIRE(getField(eqnSys.explicitOperation()) == -2.0); - // } - - // { - // dsl::EqnSystem eqnSys( - // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm - // + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - // dsl::EqnSystem eqnSys2( - // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm - // + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - // REQUIRE(eqnSys.size() == 4); - // REQUIRE(getField(eqnSys.explicitOperation()) == 4.0); - // dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; - // REQUIRE(combinedEqnSys.size() == 8); - // REQUIRE(getField(combinedEqnSys.explicitOperation()) == 8.0); - // } - // BENCHMARK("Creation from term and temporary term") - // { - // dsl::EqnSystem eqnSys( - // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm - // + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - // dsl::EqnSystem eqnSys2( - // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) + divTerm - // + Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - // dsl::EqnSystem combinedEqnSys = eqnSys + eqnSys2; - // return combinedEqnSys; - // }; - - // { - // dsl::EqnSystem eqnSys( - // lapTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - divTerm - // - Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - // dsl::EqnSystem eqnSys2( - // lapTerm - Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - divTerm - // - Divergence(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - // REQUIRE(eqnSys.size() == 4); - // REQUIRE(getField(eqnSys.explicitOperation()) == 0.0); - // REQUIRE(eqnSys2.size() == 4); - // REQUIRE(getField(eqnSys2.explicitOperation()) == -2.0); - - // SECTION("multiplying eqnSys by 2") - // { - // dsl::EqnSystem multiplyEqnSys = 2.0 * eqnSys2; - // REQUIRE(multiplyEqnSys.size() == 4); - // REQUIRE(getField(multiplyEqnSys.explicitOperation()) == -4.0); - // } - - // SECTION("adding eqnSys to eqnSys2") - // { - // dsl::EqnSystem addEqnSys = eqnSys2 + eqnSys; - // REQUIRE(addEqnSys.size() == 8); - // REQUIRE(getField(addEqnSys.explicitOperation()) == -2.0); - // } - // SECTION("subtracting eqnSys from eqnSys2") - // { - // std::cout << "subtracting eqnSys from eqnSys2" << std::endl; - // dsl::EqnSystem subtractEqnSys = eqnSys - eqnSys2; - // REQUIRE(subtractEqnSys.size() == 8); - // REQUIRE(getField(subtractEqnSys.explicitOperation()) == 2.0); - // } - // } - // // profiling - // // with different number of terms - // BENCHMARK("Creation from 2 terms") - // { - // dsl::EqnSystem eqnSys(divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1)); - - // return eqnSys; - // }; - - // BENCHMARK("Creation from 4 terms") - // { - // dsl::EqnSystem eqnSys( - // divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - - // return eqnSys; - // }; - - // BENCHMARK("Creation from 8 terms") - // { - // dsl::EqnSystem eqnSys( - // divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - - // return eqnSys; - // }; - - // BENCHMARK("Creation from 16 terms") - // { - // dsl::EqnSystem eqnSys( - // divTerm + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // + Laplacian(dsl::EqnTerm::Type::Explicit, exec, 1) - // ); - - // return eqnSys; - // }; } From 9c8aa79d04e8d97f427529d2f2e6eaef92d0ffb1 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 17:40:17 +0200 Subject: [PATCH 42/63] remove volumeField for now --- include/NeoFOAM/DSL/equation.hpp | 28 ++++--------------- .../timeIntegration/forwardEuler.cpp | 6 ++-- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/include/NeoFOAM/DSL/equation.hpp b/include/NeoFOAM/DSL/equation.hpp index 27d64dd83..87c2f6b01 100644 --- a/include/NeoFOAM/DSL/equation.hpp +++ b/include/NeoFOAM/DSL/equation.hpp @@ -21,7 +21,7 @@ class Equation Equation(const Executor& exec, std::size_t nCells) : exec_(exec), nCells_(nCells), temporalOperators_(), implicitOperators_(), - explicitOperators_(), volumeField_(nullptr) + explicitOperators_() {} /* @brief perform all explicit operation and accumulate the result */ @@ -116,37 +116,19 @@ class Equation scalar getDt() const { return dt_; } - fvcc::VolumeField* volumeField() - { - if (temporalOperators_.size() == 0 && implicitOperators_.size() == 0) - { - NF_ERROR_EXIT("No temporal or implicit terms to solve."); - } - if (temporalOperators_.size() > 0) - { - // FIXME - NF_ERROR_EXIT("Not implemented."); - // volumeField_ = temporalOperators_[0].volumeField(); - } - else - { - // FIXME - NF_ERROR_EXIT("Not implemented."); - // volumeField_ = implicitOperators_[0].volumeField(); - } - return volumeField_; - } - scalar dt_ = 0; private: const Executor exec_; + const std::size_t nCells_; + std::vector temporalOperators_; + std::vector implicitOperators_; + std::vector explicitOperators_; - fvcc::VolumeField* volumeField_; }; Equation operator+(Equation lhs, const Equation& rhs) diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp index 1b6c0e740..8e80367ba 100644 --- a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp +++ b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp @@ -21,7 +21,7 @@ void ForwardEuler::solve() { std::cout << "Solving using Forward Euler" << std::endl; scalar dt = eqnSystem_.getDt(); - fvcc::VolumeField* refField = eqnSystem_.volumeField(); + // fvcc::VolumeField* refField = eqnSystem_.volumeField(); // Field Phi(eqnSystem_.exec(), eqnSystem_.nCells()); // NeoFOAM::fill(Phi, 0.0); Field source = eqnSystem_.explicitOperation(); @@ -31,8 +31,8 @@ void ForwardEuler::solve() // eqnTerm.temporalOperation(Phi); // } // Phi += source*dt; - refField->internalField() -= source * dt; - refField->correctBoundaryConditions(); + // refField->internalField() -= source * dt; + // refField->correctBoundaryConditions(); // check if execturo is GPU if (std::holds_alternative(eqnSystem_.exec())) From e0098fcfc5d63da73385ef85163a0a30fdb2879a Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Thu, 10 Oct 2024 17:06:04 +0200 Subject: [PATCH 43/63] update class names --- doc/DSL/{eqnSystem.rst => equation.rst} | 35 +++++++++++---------- doc/DSL/index.rst | 6 ++-- doc/DSL/{eqnTerm.rst => operator.rst} | 41 ++++++++++++------------- 3 files changed, 41 insertions(+), 41 deletions(-) rename doc/DSL/{eqnSystem.rst => equation.rst} (55%) rename doc/DSL/{eqnTerm.rst => operator.rst} (58%) diff --git a/doc/DSL/eqnSystem.rst b/doc/DSL/equation.rst similarity index 55% rename from doc/DSL/eqnSystem.rst rename to doc/DSL/equation.rst index 2b865381f..1a059d01b 100644 --- a/doc/DSL/eqnSystem.rst +++ b/doc/DSL/equation.rst @@ -1,8 +1,9 @@ -EqnSystem +Equation --------- -The `EqnSystem` template class in NeoFOAM holds, manages, builds and solves the expressed/programmed equation and its core responsibilities lie in the answering of the following questions: +The `Equation` class in NeoFOAM holds, manages, builds and solves the expressed/programmed equation. +Its core responsibility lie in the answering of the following questions: - How to discretize the spatial terms? - In OpenFOAM this information is provided in **fvSchemes** @@ -12,22 +13,22 @@ The `EqnSystem` template class in NeoFOAM holds, manages, builds and solves the - In OpenFOAM this information is provided in **fvSolution** The main difference between NeoFOAM and OpenFOAM is that the DSL is evaluated lazily, i.e. evaluation is not performed on construction by default. -Since, the evaluation is not tied to the construction but rather delayde, other numerical integration strategies (e.g. RK methods or even substepping within an the equation) are possible. +Since, the evaluation is not tied to the construction but rather delayed, other numerical integration strategies (e.g. RK methods or even sub-stepping within an the equation) are possible. -To implement lazy evaluation, the `EqnSystem` stores 3 vectors: +To implement lazy evaluation, the `Equation` stores 3 vectors: .. mermaid:: classDiagram - class EqnTerm { + class Operator { +explicitOperation(...) +implicitOperation(...) } - class DivEqnTerm { + class DivOperator { +explicitOperation(...) +implicitOperation(...) } - class TemporalEqnTerm { + class TemporalOperator { +explicitOperation(...) +implicitOperation(...) } @@ -35,15 +36,15 @@ To implement lazy evaluation, the `EqnSystem` stores 3 vectors: +explicitOperation(...) +implicitOperation(...) } - class EqnSystem { - +temporalTerms_: vector~EqnTerm~ - +implicitTerms_: vector~EqnTerm~ - +explicitTerms_: vector~EqnTerm~ + class Equation { + +temporalTerms_: vector~Operator~ + +implicitTerms_: vector~Operator~ + +explicitTerms_: vector~Operator~ } - EqnTerm <|-- DivEqnTerm - EqnTerm <|-- TemporalEqnTerm - EqnTerm <|-- Others - EqnSystem <|-- EqnTerm + Operator <|-- DivOperator + Operator <|-- TemporalOperator + Operator <|-- Others + Equation <|-- Operator -Thus, an `EqnSystem` consists of multiple `EqnTerms` which are either explicit, implicit, or temporal. -Consequently, addition, subtraction, and scaling with a field needs to be handled by the `EqnTerm`. +Thus, an `Equation` consists of multiple `Operators` which are either explicit, implicit, or temporal. +Consequently, addition, subtraction, and scaling with a field needs to be handled by the `Operator`. diff --git a/doc/DSL/index.rst b/doc/DSL/index.rst index a193a40ed..840f7712f 100644 --- a/doc/DSL/index.rst +++ b/doc/DSL/index.rst @@ -46,7 +46,7 @@ The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adop .. code-block:: cpp - dsl::EqnSystem UEqn + dsl::Equation UEqn ( fvcc::impOp::ddt(U) + fvcc::impOp::div(phi, U) @@ -67,5 +67,5 @@ After the system is assembled or solved, it provides access to the linear system :maxdepth: 2 :glob: - eqnSystem.rst - eqnTerm.rst + equation.rst + operator.rst diff --git a/doc/DSL/eqnTerm.rst b/doc/DSL/operator.rst similarity index 58% rename from doc/DSL/eqnTerm.rst rename to doc/DSL/operator.rst index c9ddc2e66..30c0d3c15 100644 --- a/doc/DSL/eqnTerm.rst +++ b/doc/DSL/operator.rst @@ -1,44 +1,43 @@ -EqnTerm +Operator ======= -The template `EqnTerm` represents a term in an equation and can be instantiated with different value types. -An `EqnTerm` is either explicit, implicit or temporal, and needs to be scalable by a scalar value or a further field. -The `EqnTerm` implementation uses Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: - +The `Operator` class represents a term in an equation and can be instantiated with different value types. +An `Operator` is either explicit, implicit or temporal, and can be scalable by a an additional coefficient, for example a scalar value or a further field. +The `Operator` implementation uses Type Erasure (more details `[1] `_ `[2] `_ `[3] `_) to achieve polymorphism without inheritance. Consequently, the class needs only to implement the interface which is used in the DSL and which is shown in the below example: Example: .. code-block:: cpp - NeoFOAM::DSL::EqnTerm divTerm = - Divergence(NeoFOAM::DSL::EqnTerm::Type::Explicit, exec, ...); + NeoFOAM::DSL::Operator divTerm = + Divergence(NeoFOAM::DSL::Operator::Type::Explicit, exec, ...); - NeoFOAM::DSL::EqnTerm ddtTerm = - TimeTerm(NeoFOAM::DSL::EqnTerm::Type::Temporal, exec, ..); + NeoFOAM::DSL::Operator ddtTerm = + TimeTerm(NeoFOAM::DSL::Operator::Type::Temporal, exec, ..); -To fit the specification of the EqnSystem (storage in a vector), the EqnTerm needs to be able to be scaled: +To fit the specification of the EqnSystem (storage in a vector), the Operator needs to be able to be scaled: .. code-block:: cpp NeoFOAM::Field scalingField(exec, nCells, 2.0); auto sF = scalingField.span(); - dsl::EqnTerm customTerm = - CustomTerm(dsl::EqnTerm::Type::Explicit, exec, nCells, 1.0); + dsl::Operator customTerm = + CustomTerm(dsl::Operator::Type::Explicit, exec, nCells, 1.0); auto constantScaledTerm = 2.0 * customTerm; // A constant scaling factor of 2 for the term. auto fieldScaledTerm = scalingField * customTerm; // scalingField is used to scale the term. - // EqnTerm also supports a similar syntax as OpenFOAM + // Operator also supports a similar syntax as OpenFOAM auto multiScaledTerm = (scale + scale + scale + scale) * customTerm; - // EqnTerm also supports the use of a lambda as scaling function to reduce the number of temporaries generated + // Operator also supports the use of a lambda as scaling function to reduce the number of temporaries generated auto lambdaScaledTerm = (KOKKOS_LAMBDA(const NeoFOAM::size_t i) { return sF[i] + sF[i] + sF[i] + sF[i]; }) * customTerm; -To add a user-defined `EqnTerm`, a new derived class must be created, inheriting from `EqnTermMixin`, - and provide the definitions of the below virtual functions that are required for the `EqnTerm` interface: +To add a user-defined `Operator`, a new derived class must be created, inheriting from `OperatorMixin`, + and provide the definitions of the below virtual functions that are required for the `Operator` interface: - build: build the term - explicitOperation: perform the explicit operation @@ -53,7 +52,7 @@ An example is given below: .. code-block:: cpp - class CustomEqnTerm : public dsl::EqnTermMixin + class CustomOperator : public dsl::OperatorMixin { public: @@ -75,7 +74,7 @@ An example is given below: void explicitOperation(NeoFOAM::Field& source) { NeoFOAM::scalar setValue = value; - // scaleField is defined in EqnTermMixin + // scaleField is defined in OperatorMixin // and accounts for the scaling of the terms // and considers scaling by fields and scalars auto scale = scaleField(); @@ -88,7 +87,7 @@ An example is given below: } // other helper functions - dsl::EqnTerm::Type getType() const { return termType_; } + dsl::Operator::Type getType() const { return termType_; } const NeoFOAM::Executor& exec() const { return exec_; } @@ -96,7 +95,7 @@ An example is given below: fvcc::VolumeField* volumeField() { return nullptr; } - dsl::EqnTerm::Type termType_; + dsl::Operator::Type termType_; const NeoFOAM::Executor exec_; @@ -104,7 +103,7 @@ An example is given below: NeoFOAM::scalar value = 1.0; }; -The required scaling of the term is handle by the `scaleField` function, provided by `EqnTermMixin`. The `scaleField` function returns the 'ScalingField' class that is used to scale by fields and scalars. +The required scaling of the term is handle by the `scaleField` function, provided by `OperatorMixin`. The `scaleField` function returns the 'ScalingField' class that is used to scale by fields and scalars. .. code-block:: cpp From 852a433e0a5500661ff2292863cbce037f88ef17 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 8 Oct 2024 17:45:40 +0200 Subject: [PATCH 44/63] wip refactor timeintegration --- .../cellCentred/timeIntegration/forwardEuler.hpp | 7 +++---- .../timeIntegration/timeIntegration.hpp | 14 +++++--------- .../timeIntegration/timeIntegration.cpp | 4 +++- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp index d27505611..3d8b24e96 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp @@ -1,20 +1,20 @@ // SPDX-License-Identifier: MIT +// // SPDX-FileCopyrightText: 2023 NeoFOAM authors #pragma once +#include + #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/core/executor/executor.hpp" #include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" #include "NeoFOAM/mesh/unstructured.hpp" -#include - namespace NeoFOAM::finiteVolume::cellCentred { - class ForwardEuler : public TimeIntegrationFactory::Register { @@ -28,7 +28,6 @@ class ForwardEuler : public TimeIntegrationFactory::Register static std::string schema() { return "none"; } - void solve() override; std::unique_ptr clone() const override; diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp index 483f2b8e7..b6d7cc8e5 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp @@ -13,26 +13,24 @@ #include -namespace dsl = NeoFOAM::DSL; - -namespace NeoFOAM::finiteVolume::cellCentred +namespace NeoFOAM { class TimeIntegrationFactory : - public NeoFOAM::RuntimeSelectionFactory< + public RuntimeSelectionFactory< TimeIntegrationFactory, - Parameters> + Parameters> { public: static std::string name() { return "timeIntegrationFactory"; } - TimeIntegrationFactory(const dsl::Equation& eqnSystem, const Dictionary& dict) + TimeIntegrationFactory(const DSL::Equation& eqnSystem, const Dictionary& dict) : eqnSystem_(eqnSystem), dict_(dict) {} - virtual ~TimeIntegrationFactory() {} // Virtual destructor + virtual ~TimeIntegrationFactory() {} virtual void solve() = 0; // Pure virtual function for solving @@ -62,12 +60,10 @@ class TimeIntegration TimeIntegrationFactory::create(dict.get("type"), eqnSystem, dict) ) {}; - void solve() { timeIntegrateStrategy_->solve(); } private: - std::unique_ptr timeIntegrateStrategy_; }; diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp index 95a259cae..85bb623d6 100644 --- a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp +++ b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp @@ -3,10 +3,10 @@ #define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create // a custom main -#include #include #include +#include "common.hpp" #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" #include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" @@ -71,7 +71,9 @@ class TimeOperator std::size_t nCells() const { return nCells_; } dsl::Operator::Type termType_; + const NeoFOAM::Executor exec_; + std::size_t nCells_; }; From a3d2d4f6a56ccbfd1d07b69304f9b63428e24f2c Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 11 Oct 2024 10:39:32 +0200 Subject: [PATCH 45/63] reorganize, change DSL->dsl, move timeIntegration to dsl --- include/NeoFOAM/{DSL => dsl}/coeff.hpp | 6 +++--- include/NeoFOAM/{DSL => dsl}/equation.hpp | 6 +++--- include/NeoFOAM/{DSL => dsl}/operator.hpp | 18 +++++++----------- .../timeIntegration/forwardEuler.hpp | 7 ++----- .../timeIntegration/timeIntegration.hpp | 13 ++++++------- src/CMakeLists.txt | 2 +- .../timeIntegration/forwardEuler.cpp | 3 +-- test/CMakeLists.txt | 3 ++- test/dsl/coeff.cpp | 6 +++--- test/dsl/common.hpp | 14 ++++++++------ test/dsl/equation.cpp | 4 ++-- .../timeIntegration/CMakeLists.txt | 0 .../timeIntegration/timeIntegration.cpp | 0 test/finiteVolume/CMakeLists.txt | 1 - 14 files changed, 38 insertions(+), 45 deletions(-) rename include/NeoFOAM/{DSL => dsl}/coeff.hpp (97%) rename include/NeoFOAM/{DSL => dsl}/equation.hpp (98%) rename include/NeoFOAM/{DSL => dsl}/operator.hpp (95%) rename include/NeoFOAM/{finiteVolume/cellCentred => dsl}/timeIntegration/forwardEuler.hpp (72%) rename include/NeoFOAM/{finiteVolume/cellCentred => dsl}/timeIntegration/timeIntegration.hpp (83%) rename src/{finiteVolume/cellCentred => dsl}/timeIntegration/forwardEuler.cpp (90%) rename test/{finiteVolume/cellCentred => dsl}/timeIntegration/CMakeLists.txt (100%) rename test/{finiteVolume/cellCentred => dsl}/timeIntegration/timeIntegration.cpp (100%) diff --git a/include/NeoFOAM/DSL/coeff.hpp b/include/NeoFOAM/dsl/coeff.hpp similarity index 97% rename from include/NeoFOAM/DSL/coeff.hpp rename to include/NeoFOAM/dsl/coeff.hpp index d2b2a6623..cd91ecdb7 100644 --- a/include/NeoFOAM/DSL/coeff.hpp +++ b/include/NeoFOAM/dsl/coeff.hpp @@ -2,12 +2,12 @@ // SPDX-FileCopyrightText: 2023 NeoFOAM authors #pragma once -namespace NeoFOAM::DSL +namespace NeoFOAM::dsl { /** * @class Coeff - * @brief A class that represents a coefficient for the NeoFOAM DSL. + * @brief A class that represents a coefficient for the NeoFOAM dsl. * * This class stores a single scalar coefficient and optionally span of values. * It is used to delay the evaluation of a scalar multiplication with a field to @@ -107,4 +107,4 @@ inline Coeff operator*(const Coeff& lhs, const Coeff& rhs) return result; } -} // namespace NeoFOAM::DSL +} // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/DSL/equation.hpp b/include/NeoFOAM/dsl/equation.hpp similarity index 98% rename from include/NeoFOAM/DSL/equation.hpp rename to include/NeoFOAM/dsl/equation.hpp index 87c2f6b01..86ee0109d 100644 --- a/include/NeoFOAM/DSL/equation.hpp +++ b/include/NeoFOAM/dsl/equation.hpp @@ -9,10 +9,10 @@ #include "NeoFOAM/core/primitives/scalar.hpp" #include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/DSL/operator.hpp" +#include "NeoFOAM/dsl/operator.hpp" #include "NeoFOAM/core/error.hpp" -namespace NeoFOAM::DSL +namespace NeoFOAM::dsl { class Equation @@ -189,4 +189,4 @@ Equation operator-(const Operator& lhs, const Operator& rhs) return equation; } -} // namespace NeoFOAM::DSL +} // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/dsl/operator.hpp similarity index 95% rename from include/NeoFOAM/DSL/operator.hpp rename to include/NeoFOAM/dsl/operator.hpp index 64480b7f8..8392a8591 100644 --- a/include/NeoFOAM/DSL/operator.hpp +++ b/include/NeoFOAM/dsl/operator.hpp @@ -10,15 +10,11 @@ #include "NeoFOAM/core/primitives/scalar.hpp" #include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/core/parallelAlgorithms.hpp" -#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" #include "NeoFOAM/core/input.hpp" -#include "NeoFOAM/DSL/coeff.hpp" +#include "NeoFOAM/dsl/coeff.hpp" -namespace fvcc = NeoFOAM::finiteVolume::cellCentred; - -namespace NeoFOAM::DSL +namespace NeoFOAM::dsl { template @@ -38,10 +34,10 @@ concept HasExplicitOperator = requires(T t) { /* @class OperatorMixin * @brief A mixin class to represent simplify implementations of concrete operators - * in NeoFOAMs DSL + * in NeoFOAMs dsl * * - * @ingroup DSL + * @ingroup dsl */ class OperatorMixin { @@ -70,7 +66,7 @@ class OperatorMixin /* @class Operator - * @brief A class to represent a operator in NeoFOAMs DSL + * @brief A class to represent a operator in NeoFOAMs dsl * * The design here is based on the type erasure design pattern * see https://www.youtube.com/watch?v=4eeESJQk-mw @@ -79,7 +75,7 @@ class OperatorMixin * of Operators e.g Divergence, Laplacian, etc can be stored in a vector of * Operators * - * @ingroup DSL + * @ingroup dsl */ class Operator { @@ -251,4 +247,4 @@ Operator operator*(CoeffFunction coeffFunc, const Operator& lhs) return result; } -} // namespace NeoFOAM::DSL +} // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp similarity index 72% rename from include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp rename to include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp index 3d8b24e96..b5879fa3a 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp @@ -7,10 +7,7 @@ #include #include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/core/executor/executor.hpp" -#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" -#include "NeoFOAM/mesh/unstructured.hpp" - +#include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" namespace NeoFOAM::finiteVolume::cellCentred { @@ -20,7 +17,7 @@ class ForwardEuler : public TimeIntegrationFactory::Register public: - ForwardEuler(const DSL::Equation& eqnSystem, const Dictionary& dict); + ForwardEuler(const dsl::Equation& eqnSystem, const Dictionary& dict); static std::string name() { return "forwardEuler"; } diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp similarity index 83% rename from include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp rename to include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp index b6d7cc8e5..890875efa 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp @@ -7,9 +7,8 @@ #include "NeoFOAM/core/executor/executor.hpp" #include "NeoFOAM/mesh/unstructured.hpp" #include "NeoFOAM/finiteVolume/cellCentred.hpp" - -#include "NeoFOAM/DSL/operator.hpp" -#include "NeoFOAM/DSL/equation.hpp" +#include "NeoFOAM/dsl/operator.hpp" +#include "NeoFOAM/dsl/equation.hpp" #include @@ -19,14 +18,14 @@ namespace NeoFOAM class TimeIntegrationFactory : public RuntimeSelectionFactory< TimeIntegrationFactory, - Parameters> + Parameters> { public: static std::string name() { return "timeIntegrationFactory"; } - TimeIntegrationFactory(const DSL::Equation& eqnSystem, const Dictionary& dict) + TimeIntegrationFactory(const dsl::Equation& eqnSystem, const Dictionary& dict) : eqnSystem_(eqnSystem), dict_(dict) {} @@ -39,7 +38,7 @@ class TimeIntegrationFactory : protected: - DSL::Equation eqnSystem_; + dsl::Equation eqnSystem_; const Dictionary& dict_; }; @@ -55,7 +54,7 @@ class TimeIntegration TimeIntegration(TimeIntegration&& timeIntegrate) : timeIntegrateStrategy_(std::move(timeIntegrate.timeIntegrateStrategy_)) {}; - TimeIntegration(const DSL::Equation& eqnSystem, const Dictionary& dict) + TimeIntegration(const dsl::Equation& eqnSystem, const Dictionary& dict) : timeIntegrateStrategy_( TimeIntegrationFactory::create(dict.get("type"), eqnSystem, dict) ) {}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 86bf09ce3..13fbdd2ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,7 +30,7 @@ target_sources( "finiteVolume/cellCentred/operators/gaussGreenDiv.cpp" "finiteVolume/cellCentred/interpolation/linear.cpp" "finiteVolume/cellCentred/interpolation/upwind.cpp" - "finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp") + "dsl/timeIntegration/forwardEuler.cpp") include(${CMAKE_SOURCE_DIR}/cmake/Sanitizer.cmake) enable_sanitizers( diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/dsl/timeIntegration/forwardEuler.cpp similarity index 90% rename from src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp rename to src/dsl/timeIntegration/forwardEuler.cpp index 8e80367ba..4d21498b9 100644 --- a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp +++ b/src/dsl/timeIntegration/forwardEuler.cpp @@ -3,9 +3,8 @@ #include -#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp" +#include "NeoFOAM/dsl/timeIntegration/forwardEuler.hpp" #include "NeoFOAM/core/error.hpp" -#include "NeoFOAM/core/parallelAlgorithms.hpp" namespace NeoFOAM::finiteVolume::cellCentred { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 80d8ffdce..25609aff4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,7 +6,8 @@ list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras) # has to be first since it adds the main target add_subdirectory(catch2) -# This function creates unit tests. It allows the following keywords: +# include "NeoFOAM/core/parallelAlgorithms.hpp" This function creates unit tests. It allows the +# following keywords: # # * MPI_SIZE: the number of MPI processors to be used, defaults to 1 if not set # * COMMAND: the test command (same behavior as for CMake's add_test), defaults to the test name diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp index e7c33958e..583fcbd18 100644 --- a/test/dsl/coeff.cpp +++ b/test/dsl/coeff.cpp @@ -8,12 +8,12 @@ #include #include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/DSL/coeff.hpp" +#include "NeoFOAM/dsl/coeff.hpp" using Field = NeoFOAM::Field; -using Coeff = NeoFOAM::DSL::Coeff; +using Coeff = NeoFOAM::dsl::Coeff; -namespace detail = NeoFOAM::DSL::detail; +namespace detail = NeoFOAM::dsl::detail; TEST_CASE("Coeff") diff --git a/test/dsl/common.hpp b/test/dsl/common.hpp index 434c78e7f..ede411279 100644 --- a/test/dsl/common.hpp +++ b/test/dsl/common.hpp @@ -8,17 +8,19 @@ #include #include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/DSL/coeff.hpp" -#include "NeoFOAM/DSL/operator.hpp" +#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" +#include "NeoFOAM/dsl/coeff.hpp" +#include "NeoFOAM/dsl/operator.hpp" + +namespace fvcc = NeoFOAM::finiteVolume::cellCentred; using Field = NeoFOAM::Field; -using Coeff = NeoFOAM::DSL::Coeff; -using Operator = NeoFOAM::DSL::Operator; -using OperatorMixin = NeoFOAM::DSL::OperatorMixin; +using Coeff = NeoFOAM::dsl::Coeff; +using Operator = NeoFOAM::dsl::Operator; +using OperatorMixin = NeoFOAM::dsl::OperatorMixin; using Executor = NeoFOAM::Executor; using VolumeField = fvcc::VolumeField; using BoundaryFields = NeoFOAM::BoundaryFields; -namespace fvcc = NeoFOAM::finiteVolume::cellCentred; /* A dummy implementation of a Operator * following the Operator interface */ diff --git a/test/dsl/equation.cpp b/test/dsl/equation.cpp index 11d917a71..42d818ae1 100644 --- a/test/dsl/equation.cpp +++ b/test/dsl/equation.cpp @@ -3,9 +3,9 @@ #define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create // a custom main #include "common.hpp" -#include "NeoFOAM/DSL/equation.hpp" +#include "NeoFOAM/dsl/equation.hpp" -using Equation = NeoFOAM::DSL::Equation; +using Equation = NeoFOAM::dsl::Equation; TEST_CASE("Equation") { diff --git a/test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt b/test/dsl/timeIntegration/CMakeLists.txt similarity index 100% rename from test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt rename to test/dsl/timeIntegration/CMakeLists.txt diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp similarity index 100% rename from test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp rename to test/dsl/timeIntegration/timeIntegration.cpp diff --git a/test/finiteVolume/CMakeLists.txt b/test/finiteVolume/CMakeLists.txt index 7213b6f5a..564d38f7b 100644 --- a/test/finiteVolume/CMakeLists.txt +++ b/test/finiteVolume/CMakeLists.txt @@ -4,4 +4,3 @@ add_subdirectory(cellCentred/fields) add_subdirectory(cellCentred/boundary) add_subdirectory(cellCentred/interpolation) -add_subdirectory(cellCentred/timeIntegration) From a9bf558237d7700e8e43d0ec79785def82af60f4 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 11 Oct 2024 10:49:17 +0200 Subject: [PATCH 46/63] fix warnings, clean NeoFOAM:: in test --- include/NeoFOAM/dsl/equation.hpp | 2 +- include/NeoFOAM/dsl/operator.hpp | 2 +- include/NeoFOAM/fields/field.hpp | 2 +- test/dsl/coeff.cpp | 8 ++------ test/dsl/operator.cpp | 6 +++--- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/include/NeoFOAM/dsl/equation.hpp b/include/NeoFOAM/dsl/equation.hpp index 86ee0109d..f734e7cb4 100644 --- a/include/NeoFOAM/dsl/equation.hpp +++ b/include/NeoFOAM/dsl/equation.hpp @@ -112,7 +112,7 @@ class Equation const Executor& exec() const { return exec_; } - const std::size_t nCells() const { return nCells_; } + std::size_t nCells() const { return nCells_; } scalar getDt() const { return dt_; } diff --git a/include/NeoFOAM/dsl/operator.hpp b/include/NeoFOAM/dsl/operator.hpp index 8392a8591..3848e59c6 100644 --- a/include/NeoFOAM/dsl/operator.hpp +++ b/include/NeoFOAM/dsl/operator.hpp @@ -55,7 +55,7 @@ class OperatorMixin const Coeff& getCoefficient() const { return coeffs_; } /* @brief Given an input this function reads required coeffs */ - void build(const Input& input) {} + void build([[maybe_unused]] const Input& input) {} protected: diff --git a/include/NeoFOAM/fields/field.hpp b/include/NeoFOAM/fields/field.hpp index c5e02ab51..39e6baa85 100644 --- a/include/NeoFOAM/fields/field.hpp +++ b/include/NeoFOAM/fields/field.hpp @@ -79,7 +79,7 @@ class Field { void* ptr = nullptr; std::visit( - [this, &ptr, size](const auto& concreteExec) + [&ptr, size](const auto& concreteExec) { ptr = concreteExec.alloc(size * sizeof(ValueType)); }, exec_ ); diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp index 583fcbd18..5a8ad335a 100644 --- a/test/dsl/coeff.cpp +++ b/test/dsl/coeff.cpp @@ -62,8 +62,8 @@ TEST_CASE("Coeff") { size_t size = 3; - NeoFOAM::Field fieldA(exec, size, 0.0); - NeoFOAM::Field fieldB(exec, size, 1.0); + Field fieldA(exec, size, 0.0); + Field fieldB(exec, size, 1.0); SECTION("span") { @@ -82,8 +82,6 @@ TEST_CASE("Coeff") SECTION("scalar") { - NeoFOAM::Field fieldA(exec, size, 0.0); - Coeff coeff = Coeff(2.0); { NeoFOAM::parallelFor( @@ -99,8 +97,6 @@ TEST_CASE("Coeff") SECTION("span and scalar") { - NeoFOAM::Field fieldA(exec, size, 0.0); - NeoFOAM::Field fieldB(exec, size, 1.0); Coeff coeff {-5.0, fieldB}; { NeoFOAM::parallelFor( diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp index b48c4a1ee..e9b731240 100644 --- a/test/dsl/operator.cpp +++ b/test/dsl/operator.cpp @@ -42,9 +42,9 @@ TEST_CASE("Operator") auto d = fB * Dummy(exec, vf); auto e = Coeff(-3, fB) * Dummy(exec, vf); - auto coeffc = c.getCoefficient(); - auto coeffd = d.getCoefficient(); - auto coeffE = e.getCoefficient(); + [[maybe_unused]] auto coeffC = c.getCoefficient(); + [[maybe_unused]] auto coeffD = d.getCoefficient(); + [[maybe_unused]] auto coeffE = e.getCoefficient(); Field source(exec, 1, 2.0); c.explicitOperation(source); From 50f6c7c466850dacf712c02a4114dace7ac18bdc Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 11 Oct 2024 20:39:40 +0200 Subject: [PATCH 47/63] wip time integration --- include/NeoFOAM/dsl/equation.hpp | 15 ++- .../dsl/timeIntegration/forwardEuler.hpp | 43 +++++++-- .../dsl/timeIntegration/timeIntegration.hpp | 45 +++++---- src/dsl/timeIntegration/forwardEuler.cpp | 37 -------- test/dsl/CMakeLists.txt | 2 + test/dsl/timeIntegration/timeIntegration.cpp | 91 +++++++++---------- 6 files changed, 114 insertions(+), 119 deletions(-) diff --git a/include/NeoFOAM/dsl/equation.hpp b/include/NeoFOAM/dsl/equation.hpp index f734e7cb4..b076bd2bc 100644 --- a/include/NeoFOAM/dsl/equation.hpp +++ b/include/NeoFOAM/dsl/equation.hpp @@ -10,11 +10,17 @@ #include "NeoFOAM/core/primitives/scalar.hpp" #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/dsl/operator.hpp" +// TODO redundant name +#include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" #include "NeoFOAM/core/error.hpp" +#include "NeoFOAM/dsl/timeIntegration/forwardEuler.hpp" +#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" + namespace NeoFOAM::dsl { + class Equation { public: @@ -73,7 +79,8 @@ class Equation } } - void solve() + template + void solve(SolutionFieldType& solution, const Dictionary& solverProperties) { if (temporalOperators_.size() == 0 && implicitOperators_.size() == 0) { @@ -81,8 +88,10 @@ class Equation } if (temporalOperators_.size() > 0) { - NF_ERROR_EXIT("Not implemented."); // integrate equations in time + TimeIntegration> + timeIntegrator(solverProperties.subDict("ddtSchemes")); + // timeIntegrator.solve(solution, solverProperties); } else { @@ -189,4 +198,6 @@ Equation operator-(const Operator& lhs, const Operator& rhs) return equation; } +template class ForwardEuler>; + } // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp index b5879fa3a..7aa74a527 100644 --- a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp @@ -9,25 +9,56 @@ #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" -namespace NeoFOAM::finiteVolume::cellCentred +namespace NeoFOAM::dsl { -class ForwardEuler : public TimeIntegrationFactory::Register +template +class ForwardEuler : + public TimeIntegrationFactory::template Register< + ForwardEuler> { public: - ForwardEuler(const dsl::Equation& eqnSystem, const Dictionary& dict); + using Base = TimeIntegrationFactory::template Register< + ForwardEuler>; + + ForwardEuler(const Dictionary& dict) : Base(dict) {} static std::string name() { return "forwardEuler"; } - static std::string doc() { return "forwardEuler timeIntegration"; } + static std::string doc() { return "first order time integration method"; } static std::string schema() { return "none"; } - void solve() override; + virtual void solve(EquationType& eqn, SolutionType& sol) const override + { + scalar dt = eqn.getDt(); + // fvcc::VolumeField* refField = eqnSystem_.volumeField(); + // Field Phi(eqnSystem_.exec(), eqnSystem_.nCells()); + // NeoFOAM::fill(Phi, 0.0); + // Field source = eqn.explicitOperation(); + + // for (auto& eqnTerm : eqnSystem_.temporalTerms()) + // { + // eqnTerm.temporalOperation(Phi); + // } + // Phi += source*dt; + // refField->internalField() -= source * dt; + // refField->correctBoundaryConditions(); - std::unique_ptr clone() const override; + // check if execturo is GPU + // if (std::holds_alternative(eqnSystem_.exec())) + // { + // Kokkos::fence(); + // } + }; + + std::unique_ptr> clone() const override + { + return std::make_unique(*this); + } }; + } // namespace NeoFOAM diff --git a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp index 890875efa..ba847a36a 100644 --- a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp @@ -3,67 +3,64 @@ #pragma once +#include + #include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/core/executor/executor.hpp" -#include "NeoFOAM/mesh/unstructured.hpp" #include "NeoFOAM/finiteVolume/cellCentred.hpp" -#include "NeoFOAM/dsl/operator.hpp" -#include "NeoFOAM/dsl/equation.hpp" - -#include namespace NeoFOAM { +/* @class Factory class to create time integration method by a given name + */ +template class TimeIntegrationFactory : public RuntimeSelectionFactory< - TimeIntegrationFactory, - Parameters> + TimeIntegrationFactory, + Parameters> { public: static std::string name() { return "timeIntegrationFactory"; } - TimeIntegrationFactory(const dsl::Equation& eqnSystem, const Dictionary& dict) - : eqnSystem_(eqnSystem), dict_(dict) - {} + TimeIntegrationFactory(const Dictionary& dict) : dict_(dict) {} virtual ~TimeIntegrationFactory() {} - virtual void solve() = 0; // Pure virtual function for solving + virtual void + solve(EquationType& eqn, SolutionType& sol) const = 0; // Pure virtual function for solving // Pure virtual function for cloning virtual std::unique_ptr clone() const = 0; protected: - dsl::Equation eqnSystem_; - const Dictionary& dict_; }; +template class TimeIntegration { public: - TimeIntegration(const TimeIntegration& timeIntegrate) - : timeIntegrateStrategy_(timeIntegrate.timeIntegrateStrategy_->clone()) {}; + TimeIntegration(const TimeIntegration& timeIntegrator) + : timeIntegratorStrategy_(timeIntegrator.timeIntegratorStrategy_->clone()) {}; - TimeIntegration(TimeIntegration&& timeIntegrate) - : timeIntegrateStrategy_(std::move(timeIntegrate.timeIntegrateStrategy_)) {}; + TimeIntegration(TimeIntegration&& timeIntegrator) + : timeIntegratorStrategy_(std::move(timeIntegrator.timeIntegratorStrategy_)) {}; - TimeIntegration(const dsl::Equation& eqnSystem, const Dictionary& dict) - : timeIntegrateStrategy_( - TimeIntegrationFactory::create(dict.get("type"), eqnSystem, dict) - ) {}; + TimeIntegration(const Dictionary& dict) + : timeIntegratorStrategy_(TimeIntegrationFactory::create( + dict.get("type"), dict + )) {}; - void solve() { timeIntegrateStrategy_->solve(); } + void solve(EquationType& eqn, SolutionType& sol) { timeIntegratorStrategy_->solve(eqn, sol); } private: - std::unique_ptr timeIntegrateStrategy_; + std::unique_ptr> timeIntegratorStrategy_; }; diff --git a/src/dsl/timeIntegration/forwardEuler.cpp b/src/dsl/timeIntegration/forwardEuler.cpp index 4d21498b9..926604b36 100644 --- a/src/dsl/timeIntegration/forwardEuler.cpp +++ b/src/dsl/timeIntegration/forwardEuler.cpp @@ -8,41 +8,4 @@ namespace NeoFOAM::finiteVolume::cellCentred { - - -ForwardEuler::ForwardEuler(const dsl::Equation& eqnSystem, const Dictionary& dict) - : TimeIntegrationFactory::Register(eqnSystem, dict) -{ - // Constructor -} - -void ForwardEuler::solve() -{ - std::cout << "Solving using Forward Euler" << std::endl; - scalar dt = eqnSystem_.getDt(); - // fvcc::VolumeField* refField = eqnSystem_.volumeField(); - // Field Phi(eqnSystem_.exec(), eqnSystem_.nCells()); - // NeoFOAM::fill(Phi, 0.0); - Field source = eqnSystem_.explicitOperation(); - - // for (auto& eqnTerm : eqnSystem_.temporalTerms()) - // { - // eqnTerm.temporalOperation(Phi); - // } - // Phi += source*dt; - // refField->internalField() -= source * dt; - // refField->correctBoundaryConditions(); - - // check if execturo is GPU - if (std::holds_alternative(eqnSystem_.exec())) - { - Kokkos::fence(); - } -} - -std::unique_ptr ForwardEuler::clone() const -{ - return std::make_unique(*this); -} - } // namespace NeoFOAM diff --git a/test/dsl/CMakeLists.txt b/test/dsl/CMakeLists.txt index 4935deff8..eb0ba3b98 100644 --- a/test/dsl/CMakeLists.txt +++ b/test/dsl/CMakeLists.txt @@ -4,3 +4,5 @@ neofoam_unit_test(coeff) neofoam_unit_test(operator) neofoam_unit_test(equation) + +add_subdirectory(timeIntegration) diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index 85bb623d6..7e85fa643 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -6,19 +6,23 @@ #include #include -#include "common.hpp" +#include "../common.hpp" + #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" -#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" - -namespace dsl = NeoFOAM::DSL; +#include "NeoFOAM/dsl/equation.hpp" +#include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" -class Divergence : public NeoFOAM::DSL::OperatorMixin +class TimeOperator : public OperatorMixin { public: - std::string display() const { return "Divergence"; } + TimeOperator(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} + + std::string getName() const { return "TimeOperator"; } + + Operator::Type getType() const { return Operator::Type::Temporal; } void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) { @@ -26,71 +30,58 @@ class Divergence : public NeoFOAM::DSL::OperatorMixin NeoFOAM::parallelFor( source.exec(), {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1 * scale; } ); } - dsl::Operator::Type getType() const { return termType_; } - - fvcc::VolumeField* volumeField() const { return nullptr; } + VolumeField& volumeField() const { return field_; } - const NeoFOAM::Executor& exec() const { return exec_; } + size_t getSize() const { return field_.internalField().size(); } - std::size_t nCells() const { return nCells_; } + const Executor& exec() const { return exec_; } - dsl::Operator::Type termType_; - - NeoFOAM::Executor exec_; + const Executor exec_; std::size_t nCells_; -}; - -class TimeOperator -{ - -public: - - std::string display() const { return "TimeOperator"; } - - void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) - { - auto sourceField = source.span(); - NeoFOAM::parallelFor( - source.exec(), - {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1 * scale; } - ); - } - dsl::Operator::Type getType() const { return termType_; } + VolumeField& field_; +}; - fvcc::VolumeField* volumeField() const { return nullptr; } - const NeoFOAM::Executor& exec() const { return exec_; } +TEST_CASE("TimeIntegration") +{ + NeoFOAM::Executor exec = GENERATE( + NeoFOAM::Executor(NeoFOAM::SerialExecutor {}), + NeoFOAM::Executor(NeoFOAM::CPUExecutor {}), + NeoFOAM::Executor(NeoFOAM::GPUExecutor {}) + ); - std::size_t nCells() const { return nCells_; } + std::string execName = std::visit([](auto e) { return e.print(); }, exec); + auto mesh = NeoFOAM::createSingleCellMesh(exec); - dsl::Operator::Type termType_; + Field fA(exec, 1, 2.0); + BoundaryFields bf(exec, mesh.nBoundaryFaces(), mesh.nBoundaries()); - const NeoFOAM::Executor exec_; + std::vector> bcs {}; + auto vf = VolumeField(exec, mesh, fA, bf, bcs); + auto fB = Field(exec, 1, 4.0); - std::size_t nCells_; -}; + NeoFOAM::Dictionary dict, subDict; + subDict.insert("type", std::string("forwardEuler")); + dict.insert("ddtSchemes", subDict); -TEST_CASE("TimeIntegration") -{ - auto exec = NeoFOAM::SerialExecutor(); - namespace fvcc = NeoFOAM::finiteVolume::cellCentred; + auto dummy = Dummy(exec, vf); - NeoFOAM::Dictionary dict; - dict.insert("type", std::string("forwardEuler")); + SECTION("Create equation and perform explicitOperation on " + execName) + { - // dsl::Operator divOperator = Divergence(dsl::Operator::Type::Explicit, exec, 1); + Operator ddtOperator = TimeOperator(exec, vf); - // dsl::Operator ddtOperator = TimeOperator(dsl::Operator::Type::Temporal, exec, 1); + auto eqn = ddtOperator + dummy; - // dsl::EqnSystem eqnSys = ddtOperator + divOperator; + eqn.solve(vf, dict); + } // fvcc::TimeIntegration timeIntergrator(eqnSys, dict); } From c5d5c6a746d1a5fb0b4dacaa316729d6504c0436 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sat, 12 Oct 2024 15:51:06 +0200 Subject: [PATCH 48/63] use and test dedicated ddt operator --- include/NeoFOAM/dsl/timeIntegration/ddt.hpp | 49 +++++++++++++++++++ .../dsl/timeIntegration/timeIntegration.hpp | 8 +-- test/dsl/timeIntegration/timeIntegration.cpp | 39 +-------------- 3 files changed, 55 insertions(+), 41 deletions(-) create mode 100644 include/NeoFOAM/dsl/timeIntegration/ddt.hpp diff --git a/include/NeoFOAM/dsl/timeIntegration/ddt.hpp b/include/NeoFOAM/dsl/timeIntegration/ddt.hpp new file mode 100644 index 000000000..483797a6e --- /dev/null +++ b/include/NeoFOAM/dsl/timeIntegration/ddt.hpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +// +// SPDX-FileCopyrightText: 2023 NeoFOAM authors + +#pragma once + +#include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/finiteVolume/cellCentred.hpp" +#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" + +namespace NeoFOAM::dsl::temporal +{ + +class Ddt : public OperatorMixin +{ + +public: + + Ddt(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} + + std::string getName() const { return "TimeOperator"; } + + Operator::Type getType() const { return Operator::Type::Temporal; } + + void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) + { + auto sourceField = source.span(); + NeoFOAM::parallelFor( + source.exec(), + {0, source.size()}, + KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1 * scale; } + ); + } + + VolumeField& volumeField() const { return field_; } + + size_t getSize() const { return field_.internalField().size(); } + + const Executor& exec() const { return exec_; } + + const Executor exec_; + + std::size_t nCells_; + + VolumeField& field_; +}; + + +} // namespace NeoFOAM diff --git a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp index ba847a36a..3f938ec4e 100644 --- a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp @@ -1,4 +1,5 @@ // SPDX-License-Identifier: MIT +// // SPDX-FileCopyrightText: 2023 NeoFOAM authors #pragma once @@ -8,10 +9,11 @@ #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/finiteVolume/cellCentred.hpp" -namespace NeoFOAM +namespace NeoFOAM::dsl { /* @class Factory class to create time integration method by a given name + * using NeoFOAMs runTimeFactory mechanism */ template class TimeIntegrationFactory : @@ -62,6 +64,4 @@ class TimeIntegration std::unique_ptr> timeIntegratorStrategy_; }; - - -} // namespace NeoFOAM +} // namespace NeoFOAM::dsl diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index 7e85fa643..f84e2c0ea 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -11,41 +11,7 @@ #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" #include "NeoFOAM/dsl/equation.hpp" -#include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" - -class TimeOperator : public OperatorMixin -{ - -public: - - TimeOperator(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} - - std::string getName() const { return "TimeOperator"; } - - Operator::Type getType() const { return Operator::Type::Temporal; } - - void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) - { - auto sourceField = source.span(); - NeoFOAM::parallelFor( - source.exec(), - {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1 * scale; } - ); - } - - VolumeField& volumeField() const { return field_; } - - size_t getSize() const { return field_.internalField().size(); } - - const Executor& exec() const { return exec_; } - - const Executor exec_; - - std::size_t nCells_; - - VolumeField& field_; -}; +#include "NeoFOAM/dsl/timeIntegration/ddt.hpp" TEST_CASE("TimeIntegration") @@ -75,8 +41,7 @@ TEST_CASE("TimeIntegration") SECTION("Create equation and perform explicitOperation on " + execName) { - - Operator ddtOperator = TimeOperator(exec, vf); + Operator ddtOperator = NeoFOAM::dsl::temporal::Ddt(exec, vf); auto eqn = ddtOperator + dummy; From 51df98e8b9bb3f8192d2af329a3d8a118f9b73d8 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sun, 13 Oct 2024 10:19:02 +0200 Subject: [PATCH 49/63] add free solve function --- include/NeoFOAM/dsl/equation.hpp | 18 ++++++++++++++++++ .../dsl/timeIntegration/timeIntegration.hpp | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/include/NeoFOAM/dsl/equation.hpp b/include/NeoFOAM/dsl/equation.hpp index b076bd2bc..3f4182e75 100644 --- a/include/NeoFOAM/dsl/equation.hpp +++ b/include/NeoFOAM/dsl/equation.hpp @@ -198,6 +198,24 @@ Equation operator-(const Operator& lhs, const Operator& rhs) return equation; } +/* @brief free function to solve an equation + * + * @param eqn - Equation to solve + * @param solutionField - Field for which the equation is to be solved + * @param fvSchemes - Dictionary containing spatial operator and time integration properties + * @param fvSolution - Dictionary containing linear solver properties + */ +template +void solve( + const Equation& eqn, + FieldType& solutionField, + const Dictionary& schemesDict, + const Dictionary& solutionDict +) +{ + eqn.solve(solutionField, schemesDict); +} + template class ForwardEuler>; } // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp index 3f938ec4e..b6b136df0 100644 --- a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp @@ -41,6 +41,12 @@ class TimeIntegrationFactory : const Dictionary& dict_; }; +/* @class Factory class to create time integration method by a given name + * using NeoFOAMs runTimeFactory mechanism + * + * @tparam EquationType Injects the type of equation for into the solve method + * @tparam SolutionType Type of the solution field eg, volumeField or just a plain Field + */ template class TimeIntegration { @@ -64,4 +70,5 @@ class TimeIntegration std::unique_ptr> timeIntegratorStrategy_; }; + } // namespace NeoFOAM::dsl From 34fc503e410431dfcfd3ab03c688465f3b3d8912 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 14 Oct 2024 12:02:58 +0200 Subject: [PATCH 50/63] improve error message for non matching executors --- include/NeoFOAM/fields/field.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/NeoFOAM/fields/field.hpp b/include/NeoFOAM/fields/field.hpp index 39e6baa85..133a09e85 100644 --- a/include/NeoFOAM/fields/field.hpp +++ b/include/NeoFOAM/fields/field.hpp @@ -413,7 +413,13 @@ class Field void validateOtherField(const Field& rhs) const { NF_DEBUG_ASSERT(size() == rhs.size(), "Fields are not the same size."); - NF_DEBUG_ASSERT(exec() == rhs.exec(), "Executors are not the same."); + + std::string execName = std::visit([](auto e) { return e.print(); }, exec()); + std::string rhsExecName = std::visit([](auto e) { return e.print(); }, rhs.exec()); + NF_DEBUG_ASSERT( + exec() == rhs.exec(), + "Executors: " + execName + " and " + rhsExecName + " are not the same" + ); } }; From ecfeac708c1844dac69b65a1c7b93349a15c14dc Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 14 Oct 2024 12:03:33 +0200 Subject: [PATCH 51/63] add size() getter --- .../finiteVolume/cellCentred/fields/geometricField.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp b/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp index c02ee804a..d2fb1dea4 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp @@ -78,6 +78,13 @@ class GeometricFieldMixin */ Field& internalField() { return field_.internalField(); } + /** + * @brief Returns the size of the internal field + * + * @return The size of the internal field + */ + size_t size() const { return field_.internalField().size(); } + /** * @brief Returns a const reference to the boundary field. * From f1020945ce76ae8a2581c6a637b39703c8f7da93 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 14 Oct 2024 12:04:10 +0200 Subject: [PATCH 52/63] make exec() method final --- include/NeoFOAM/dsl/operator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/NeoFOAM/dsl/operator.hpp b/include/NeoFOAM/dsl/operator.hpp index 3848e59c6..d6a9b5c02 100644 --- a/include/NeoFOAM/dsl/operator.hpp +++ b/include/NeoFOAM/dsl/operator.hpp @@ -48,7 +48,7 @@ class OperatorMixin virtual ~OperatorMixin() = default; - const Executor& exec() const { return exec_; } + virtual const Executor& exec() const final { return exec_; } Coeff& getCoefficient() { return coeffs_; } From e5f5a957d7cc5b4dd4076dc17c91acb99513ebab Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 14 Oct 2024 12:05:18 +0200 Subject: [PATCH 53/63] add time setter/getter, docstrings, pass dictionaries --- include/NeoFOAM/dsl/equation.hpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/include/NeoFOAM/dsl/equation.hpp b/include/NeoFOAM/dsl/equation.hpp index 3f4182e75..7121cbc99 100644 --- a/include/NeoFOAM/dsl/equation.hpp +++ b/include/NeoFOAM/dsl/equation.hpp @@ -79,8 +79,16 @@ class Equation } } + /* @brief solve an equation + * + * @param solutionField - Field for which the equation is to be solved + * @param fvSchemes - Dictionary containing spatial operator and time integration properties + * @param fvSolution - Dictionary containing linear solver properties + * @tparam FieldType - type of the underlying field, e.g. VolumeField or plain Field + */ template - void solve(SolutionFieldType& solution, const Dictionary& solverProperties) + void + solve(SolutionFieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution) { if (temporalOperators_.size() == 0 && implicitOperators_.size() == 0) { @@ -90,8 +98,8 @@ class Equation { // integrate equations in time TimeIntegration> - timeIntegrator(solverProperties.subDict("ddtSchemes")); - // timeIntegrator.solve(solution, solverProperties); + timeIntegrator(fvSchemes.subDict("ddtSchemes")); + timeIntegrator.solve(*this, solution); } else { @@ -125,10 +133,13 @@ class Equation scalar getDt() const { return dt_; } - scalar dt_ = 0; + void setDt(scalar dt) { dt_ = dt; } + private: + scalar dt_ = 0; + const Executor exec_; const std::size_t nCells_; @@ -204,6 +215,7 @@ Equation operator-(const Operator& lhs, const Operator& rhs) * @param solutionField - Field for which the equation is to be solved * @param fvSchemes - Dictionary containing spatial operator and time integration properties * @param fvSolution - Dictionary containing linear solver properties + * @tparam FieldType - type of the underlying field, e.g. VolumeField or plain Field */ template void solve( @@ -213,7 +225,7 @@ void solve( const Dictionary& solutionDict ) { - eqn.solve(solutionField, schemesDict); + eqn.solve(solutionField, schemesDict, solutionDict); } template class ForwardEuler>; From 38a97a22acf589262d334d26c501659db260d59a Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 14 Oct 2024 12:05:48 +0200 Subject: [PATCH 54/63] improve simple time integration test --- include/NeoFOAM/dsl/timeIntegration/ddt.hpp | 21 +++++++++------- .../dsl/timeIntegration/forwardEuler.hpp | 18 +++++++------- test/dsl/timeIntegration/timeIntegration.cpp | 24 ++++++++++++------- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/include/NeoFOAM/dsl/timeIntegration/ddt.hpp b/include/NeoFOAM/dsl/timeIntegration/ddt.hpp index 483797a6e..ac5d5de4e 100644 --- a/include/NeoFOAM/dsl/timeIntegration/ddt.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/ddt.hpp @@ -22,25 +22,30 @@ class Ddt : public OperatorMixin Operator::Type getType() const { return Operator::Type::Temporal; } - void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) + void explicitOperation(Field& source, scalar scale) { auto sourceField = source.span(); - NeoFOAM::parallelFor( + parallelFor( source.exec(), - {0, source.size()}, + source.range(), KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1 * scale; } ); } + void temporalOperation(Field& phi) + { + auto phiSpan = phi.span(); + auto fieldSpan = field_.internalField().span(); + parallelFor( + phi.exec(), phi.range(), KOKKOS_LAMBDA(const size_t i) { fieldSpan[i] += phiSpan[i]; } + ); + } + VolumeField& volumeField() const { return field_; } size_t getSize() const { return field_.internalField().size(); } - const Executor& exec() const { return exec_; } - - const Executor exec_; - - std::size_t nCells_; +private: VolumeField& field_; }; diff --git a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp index 7aa74a527..5692936fa 100644 --- a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp @@ -34,20 +34,18 @@ class ForwardEuler : virtual void solve(EquationType& eqn, SolutionType& sol) const override { scalar dt = eqn.getDt(); - // fvcc::VolumeField* refField = eqnSystem_.volumeField(); - // Field Phi(eqnSystem_.exec(), eqnSystem_.nCells()); - // NeoFOAM::fill(Phi, 0.0); - // Field source = eqn.explicitOperation(); + Field phi(sol.exec(), sol.size(), 0.0); + Field source = eqn.explicitOperation(); - // for (auto& eqnTerm : eqnSystem_.temporalTerms()) + // phi += source*dt; + // for (auto& op : eqn.temporalOperators()) // { - // eqnTerm.temporalOperation(Phi); + // op.temporalOperation(phi); // } - // Phi += source*dt; - // refField->internalField() -= source * dt; - // refField->correctBoundaryConditions(); + sol.internalField() -= source * dt; + sol.correctBoundaryConditions(); - // check if execturo is GPU + // check if executor is GPU // if (std::holds_alternative(eqnSystem_.exec())) // { // Kokkos::fence(); diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index f84e2c0ea..eb0287af0 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -25,28 +25,34 @@ TEST_CASE("TimeIntegration") std::string execName = std::visit([](auto e) { return e.print(); }, exec); auto mesh = NeoFOAM::createSingleCellMesh(exec); + NeoFOAM::Dictionary fvSchemes; + NeoFOAM::Dictionary ddtSchemes; + ddtSchemes.insert("type", std::string("forwardEuler")); + fvSchemes.insert("ddtSchemes", ddtSchemes); + NeoFOAM::Dictionary fvSolution; + Field fA(exec, 1, 2.0); BoundaryFields bf(exec, mesh.nBoundaryFaces(), mesh.nBoundaries()); std::vector> bcs {}; auto vf = VolumeField(exec, mesh, fA, bf, bcs); - auto fB = Field(exec, 1, 4.0); - - - NeoFOAM::Dictionary dict, subDict; - subDict.insert("type", std::string("forwardEuler")); - dict.insert("ddtSchemes", subDict); - - auto dummy = Dummy(exec, vf); SECTION("Create equation and perform explicitOperation on " + execName) { + auto dummy = Dummy(exec, vf); Operator ddtOperator = NeoFOAM::dsl::temporal::Ddt(exec, vf); + // ddt(U) = f auto eqn = ddtOperator + dummy; + eqn.setDt(2.0); - eqn.solve(vf, dict); + // int(ddt(U)) + f = 0 + // (U^1-U^0)/dt = -f + // U^1 = - f * dt + U^0, where dt = 2, f=1, U^0=2.0 -> U^1=-2.0 + eqn.solve(vf, fvSchemes, fvSolution); + REQUIRE(getField(vf.internalField()) == -2.0); } + // auto fB = Field(exec, 1, 4.0); // fvcc::TimeIntegration timeIntergrator(eqnSys, dict); } From 41acd45ce38234478b61302c0631cf08a80e4880 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Wed, 16 Oct 2024 09:15:58 +0200 Subject: [PATCH 55/63] remove EquationType template argument --- include/NeoFOAM/dsl/equation.hpp | 13 ++++-------- .../dsl/timeIntegration/forwardEuler.hpp | 13 ++++++------ .../dsl/timeIntegration/timeIntegration.hpp | 20 +++++++++---------- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/include/NeoFOAM/dsl/equation.hpp b/include/NeoFOAM/dsl/equation.hpp index 7121cbc99..4c99e60e3 100644 --- a/include/NeoFOAM/dsl/equation.hpp +++ b/include/NeoFOAM/dsl/equation.hpp @@ -10,11 +10,8 @@ #include "NeoFOAM/core/primitives/scalar.hpp" #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/dsl/operator.hpp" -// TODO redundant name -#include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" #include "NeoFOAM/core/error.hpp" -#include "NeoFOAM/dsl/timeIntegration/forwardEuler.hpp" #include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" namespace NeoFOAM::dsl @@ -96,10 +93,10 @@ class Equation } if (temporalOperators_.size() > 0) { - // integrate equations in time - TimeIntegration> - timeIntegrator(fvSchemes.subDict("ddtSchemes")); - timeIntegrator.solve(*this, solution); + // // integrate equations in time + // TimeIntegration> + // timeIntegrator(fvSchemes.subDict("ddtSchemes")); + // timeIntegrator.solve(*this, solution); } else { @@ -228,6 +225,4 @@ void solve( eqn.solve(solutionField, schemesDict, solutionDict); } -template class ForwardEuler>; - } // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp index 5692936fa..7737ff80d 100644 --- a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp @@ -12,16 +12,15 @@ namespace NeoFOAM::dsl { -template +template class ForwardEuler : - public TimeIntegrationFactory::template Register< - ForwardEuler> + public TimeIntegrationFactory::template Register> { public: - using Base = TimeIntegrationFactory::template Register< - ForwardEuler>; + using Base = + TimeIntegrationFactory::template Register>; ForwardEuler(const Dictionary& dict) : Base(dict) {} @@ -31,7 +30,7 @@ class ForwardEuler : static std::string schema() { return "none"; } - virtual void solve(EquationType& eqn, SolutionType& sol) const override + virtual void solve(Equation& eqn, SolutionType& sol) const override { scalar dt = eqn.getDt(); Field phi(sol.exec(), sol.size(), 0.0); @@ -52,7 +51,7 @@ class ForwardEuler : // } }; - std::unique_ptr> clone() const override + std::unique_ptr> clone() const override { return std::make_unique(*this); } diff --git a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp index b6b136df0..e14198bea 100644 --- a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp @@ -8,6 +8,7 @@ #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/finiteVolume/cellCentred.hpp" +#include "NeoFOAM/dsl/equation.hpp" namespace NeoFOAM::dsl { @@ -15,10 +16,10 @@ namespace NeoFOAM::dsl /* @class Factory class to create time integration method by a given name * using NeoFOAMs runTimeFactory mechanism */ -template +template class TimeIntegrationFactory : public RuntimeSelectionFactory< - TimeIntegrationFactory, + TimeIntegrationFactory, Parameters> { @@ -31,7 +32,7 @@ class TimeIntegrationFactory : virtual ~TimeIntegrationFactory() {} virtual void - solve(EquationType& eqn, SolutionType& sol) const = 0; // Pure virtual function for solving + solve(Equation& eqn, SolutionType& sol) const = 0; // Pure virtual function for solving // Pure virtual function for cloning virtual std::unique_ptr clone() const = 0; @@ -44,10 +45,9 @@ class TimeIntegrationFactory : /* @class Factory class to create time integration method by a given name * using NeoFOAMs runTimeFactory mechanism * - * @tparam EquationType Injects the type of equation for into the solve method * @tparam SolutionType Type of the solution field eg, volumeField or just a plain Field */ -template +template class TimeIntegration { @@ -60,15 +60,15 @@ class TimeIntegration : timeIntegratorStrategy_(std::move(timeIntegrator.timeIntegratorStrategy_)) {}; TimeIntegration(const Dictionary& dict) - : timeIntegratorStrategy_(TimeIntegrationFactory::create( - dict.get("type"), dict - )) {}; + : timeIntegratorStrategy_( + TimeIntegrationFactory::create(dict.get("type"), dict) + ) {}; - void solve(EquationType& eqn, SolutionType& sol) { timeIntegratorStrategy_->solve(eqn, sol); } + void solve(Equation& eqn, SolutionType& sol) { timeIntegratorStrategy_->integrate(eqn, sol); } private: - std::unique_ptr> timeIntegratorStrategy_; + std::unique_ptr> timeIntegratorStrategy_; }; } // namespace NeoFOAM::dsl From 83be03af42dacb2157506e13026717d858d21842 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Wed, 16 Oct 2024 09:32:24 +0200 Subject: [PATCH 56/63] move solve out of equation --- include/NeoFOAM/dsl/equation.hpp | 39 --------------- include/NeoFOAM/dsl/solver.hpp | 49 +++++++++++++++++++ .../dsl/timeIntegration/forwardEuler.hpp | 3 ++ .../dsl/timeIntegration/timeIntegration.hpp | 3 +- test/dsl/timeIntegration/timeIntegration.cpp | 4 +- 5 files changed, 56 insertions(+), 42 deletions(-) create mode 100644 include/NeoFOAM/dsl/solver.hpp diff --git a/include/NeoFOAM/dsl/equation.hpp b/include/NeoFOAM/dsl/equation.hpp index 4c99e60e3..eaea39762 100644 --- a/include/NeoFOAM/dsl/equation.hpp +++ b/include/NeoFOAM/dsl/equation.hpp @@ -76,34 +76,6 @@ class Equation } } - /* @brief solve an equation - * - * @param solutionField - Field for which the equation is to be solved - * @param fvSchemes - Dictionary containing spatial operator and time integration properties - * @param fvSolution - Dictionary containing linear solver properties - * @tparam FieldType - type of the underlying field, e.g. VolumeField or plain Field - */ - template - void - solve(SolutionFieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution) - { - if (temporalOperators_.size() == 0 && implicitOperators_.size() == 0) - { - NF_ERROR_EXIT("No temporal or implicit terms to solve."); - } - if (temporalOperators_.size() > 0) - { - // // integrate equations in time - // TimeIntegration> - // timeIntegrator(fvSchemes.subDict("ddtSchemes")); - // timeIntegrator.solve(*this, solution); - } - else - { - NF_ERROR_EXIT("Not implemented."); - // solve sparse matrix system - } - } /* @brief getter for the total number of terms in the equation */ size_t size() const @@ -132,7 +104,6 @@ class Equation void setDt(scalar dt) { dt_ = dt; } - private: scalar dt_ = 0; @@ -214,15 +185,5 @@ Equation operator-(const Operator& lhs, const Operator& rhs) * @param fvSolution - Dictionary containing linear solver properties * @tparam FieldType - type of the underlying field, e.g. VolumeField or plain Field */ -template -void solve( - const Equation& eqn, - FieldType& solutionField, - const Dictionary& schemesDict, - const Dictionary& solutionDict -) -{ - eqn.solve(solutionField, schemesDict, solutionDict); -} } // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/dsl/solver.hpp b/include/NeoFOAM/dsl/solver.hpp new file mode 100644 index 000000000..052100225 --- /dev/null +++ b/include/NeoFOAM/dsl/solver.hpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors +#pragma once + +#include +#include +#include +#include +#include + +#include "NeoFOAM/core/primitives/scalar.hpp" +#include "NeoFOAM/fields/field.hpp" +#include "NeoFOAM/core/input.hpp" +#include "NeoFOAM/dsl/equation.hpp" +#include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" + + +namespace NeoFOAM::dsl +{ +template +void solve( + Equation& eqn, FieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution +) +{ + /* @brief solve an equation + * + * @param solutionField - Field for which the equation is to be solved + * @param fvSchemes - Dictionary containing spatial operator and time integration properties + * @param fvSolution - Dictionary containing linear solver properties + * @tparam FieldType - type of the underlying field, e.g. VolumeField or plain Field + */ + if (eqn.temporalOperators().size() == 0 && eqn.implicitOperators().size() == 0) + { + NF_ERROR_EXIT("No temporal or implicit terms to solve."); + } + if (eqn.temporalOperators().size() > 0) + { + // integrate equations in time + TimeIntegration timeIntegrator(fvSchemes.subDict("ddtSchemes")); + timeIntegrator.solve(eqn, solution); + } + else + { + NF_ERROR_EXIT("Not implemented."); + // solve sparse matrix system + } +} + +} // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp index 7737ff80d..5b7c3f200 100644 --- a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp @@ -57,5 +57,8 @@ class ForwardEuler : } }; +// unfortunately needs explicit instantiation +template class ForwardEuler>; + } // namespace NeoFOAM diff --git a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp index e14198bea..f92a396b7 100644 --- a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp @@ -64,11 +64,12 @@ class TimeIntegration TimeIntegrationFactory::create(dict.get("type"), dict) ) {}; - void solve(Equation& eqn, SolutionType& sol) { timeIntegratorStrategy_->integrate(eqn, sol); } + void solve(Equation& eqn, SolutionType& sol) { timeIntegratorStrategy_->solve(eqn, sol); } private: std::unique_ptr> timeIntegratorStrategy_; }; + } // namespace NeoFOAM::dsl diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index eb0287af0..62154fc4b 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -10,7 +10,7 @@ #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" -#include "NeoFOAM/dsl/equation.hpp" +#include "NeoFOAM/dsl/solver.hpp" #include "NeoFOAM/dsl/timeIntegration/ddt.hpp" @@ -49,7 +49,7 @@ TEST_CASE("TimeIntegration") // int(ddt(U)) + f = 0 // (U^1-U^0)/dt = -f // U^1 = - f * dt + U^0, where dt = 2, f=1, U^0=2.0 -> U^1=-2.0 - eqn.solve(vf, fvSchemes, fvSolution); + solve(eqn, vf, fvSchemes, fvSolution); REQUIRE(getField(vf.internalField()) == -2.0); } From 08a2fa875f6f73424bba2518051e2e5886dde70a Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 18 Oct 2024 08:38:29 +0200 Subject: [PATCH 57/63] rename Equation -> Expression --- .../dsl/{equation.hpp => expression.hpp} | 32 +++++++++---------- include/NeoFOAM/dsl/solver.hpp | 4 +-- .../dsl/timeIntegration/forwardEuler.hpp | 2 +- .../dsl/timeIntegration/timeIntegration.hpp | 6 ++-- test/dsl/CMakeLists.txt | 2 +- test/dsl/{equation.cpp => expression.cpp} | 8 ++--- 6 files changed, 27 insertions(+), 27 deletions(-) rename include/NeoFOAM/dsl/{equation.hpp => expression.hpp} (84%) rename test/dsl/{equation.cpp => expression.cpp} (91%) diff --git a/include/NeoFOAM/dsl/equation.hpp b/include/NeoFOAM/dsl/expression.hpp similarity index 84% rename from include/NeoFOAM/dsl/equation.hpp rename to include/NeoFOAM/dsl/expression.hpp index eaea39762..d75709381 100644 --- a/include/NeoFOAM/dsl/equation.hpp +++ b/include/NeoFOAM/dsl/expression.hpp @@ -18,11 +18,11 @@ namespace NeoFOAM::dsl { -class Equation +class Expression { public: - Equation(const Executor& exec, std::size_t nCells) + Expression(const Executor& exec, std::size_t nCells) : exec_(exec), nCells_(nCells), temporalOperators_(), implicitOperators_(), explicitOperators_() {} @@ -60,7 +60,7 @@ class Equation } } - void addEquation(const Equation& equation) + void addExpression(const Expression& equation) { for (auto& Operator : equation.temporalOperators_) { @@ -119,29 +119,29 @@ class Equation std::vector explicitOperators_; }; -Equation operator+(Equation lhs, const Equation& rhs) +Expression operator+(Expression lhs, const Expression& rhs) { - lhs.addEquation(rhs); + lhs.addExpression(rhs); return lhs; } -Equation operator+(Equation lhs, const Operator& rhs) +Expression operator+(Expression lhs, const Operator& rhs) { lhs.addOperator(rhs); return lhs; } -Equation operator+(const Operator& lhs, const Operator& rhs) +Expression operator+(const Operator& lhs, const Operator& rhs) { - Equation equation(lhs.exec(), lhs.getSize()); + Expression equation(lhs.exec(), lhs.getSize()); equation.addOperator(lhs); equation.addOperator(rhs); return equation; } -Equation operator*(scalar scale, const Equation& es) +Expression operator*(scalar scale, const Expression& es) { - Equation results(es.exec(), es.nCells()); + Expression results(es.exec(), es.nCells()); for (const auto& Operator : es.temporalOperators()) { results.addOperator(scale * Operator); @@ -157,21 +157,21 @@ Equation operator*(scalar scale, const Equation& es) return results; } -Equation operator-(Equation lhs, const Equation& rhs) +Expression operator-(Expression lhs, const Expression& rhs) { - lhs.addEquation(-1.0 * rhs); + lhs.addExpression(-1.0 * rhs); return lhs; } -Equation operator-(Equation lhs, const Operator& rhs) +Expression operator-(Expression lhs, const Operator& rhs) { lhs.addOperator(-1.0 * rhs); return lhs; } -Equation operator-(const Operator& lhs, const Operator& rhs) +Expression operator-(const Operator& lhs, const Operator& rhs) { - Equation equation(lhs.exec(), lhs.getSize()); + Expression equation(lhs.exec(), lhs.getSize()); equation.addOperator(lhs); equation.addOperator(Coeff(-1) * rhs); return equation; @@ -179,7 +179,7 @@ Equation operator-(const Operator& lhs, const Operator& rhs) /* @brief free function to solve an equation * - * @param eqn - Equation to solve + * @param eqn - Expression to solve * @param solutionField - Field for which the equation is to be solved * @param fvSchemes - Dictionary containing spatial operator and time integration properties * @param fvSolution - Dictionary containing linear solver properties diff --git a/include/NeoFOAM/dsl/solver.hpp b/include/NeoFOAM/dsl/solver.hpp index 052100225..647720b7d 100644 --- a/include/NeoFOAM/dsl/solver.hpp +++ b/include/NeoFOAM/dsl/solver.hpp @@ -11,7 +11,7 @@ #include "NeoFOAM/core/primitives/scalar.hpp" #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/core/input.hpp" -#include "NeoFOAM/dsl/equation.hpp" +#include "NeoFOAM/dsl/expression.hpp" #include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" @@ -19,7 +19,7 @@ namespace NeoFOAM::dsl { template void solve( - Equation& eqn, FieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution + Expression& eqn, FieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution ) { /* @brief solve an equation diff --git a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp index 5b7c3f200..144e94028 100644 --- a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp @@ -30,7 +30,7 @@ class ForwardEuler : static std::string schema() { return "none"; } - virtual void solve(Equation& eqn, SolutionType& sol) const override + virtual void solve(Expression& eqn, SolutionType& sol) const override { scalar dt = eqn.getDt(); Field phi(sol.exec(), sol.size(), 0.0); diff --git a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp index f92a396b7..3c08c2562 100644 --- a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp @@ -8,7 +8,7 @@ #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/finiteVolume/cellCentred.hpp" -#include "NeoFOAM/dsl/equation.hpp" +#include "NeoFOAM/dsl/expression.hpp" namespace NeoFOAM::dsl { @@ -32,7 +32,7 @@ class TimeIntegrationFactory : virtual ~TimeIntegrationFactory() {} virtual void - solve(Equation& eqn, SolutionType& sol) const = 0; // Pure virtual function for solving + solve(Expression& eqn, SolutionType& sol) const = 0; // Pure virtual function for solving // Pure virtual function for cloning virtual std::unique_ptr clone() const = 0; @@ -64,7 +64,7 @@ class TimeIntegration TimeIntegrationFactory::create(dict.get("type"), dict) ) {}; - void solve(Equation& eqn, SolutionType& sol) { timeIntegratorStrategy_->solve(eqn, sol); } + void solve(Expression& eqn, SolutionType& sol) { timeIntegratorStrategy_->solve(eqn, sol); } private: diff --git a/test/dsl/CMakeLists.txt b/test/dsl/CMakeLists.txt index eb0ba3b98..c0b7c92f2 100644 --- a/test/dsl/CMakeLists.txt +++ b/test/dsl/CMakeLists.txt @@ -3,6 +3,6 @@ neofoam_unit_test(coeff) neofoam_unit_test(operator) -neofoam_unit_test(equation) +neofoam_unit_test(expression) add_subdirectory(timeIntegration) diff --git a/test/dsl/equation.cpp b/test/dsl/expression.cpp similarity index 91% rename from test/dsl/equation.cpp rename to test/dsl/expression.cpp index 42d818ae1..853896a9e 100644 --- a/test/dsl/equation.cpp +++ b/test/dsl/expression.cpp @@ -3,11 +3,11 @@ #define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create // a custom main #include "common.hpp" -#include "NeoFOAM/dsl/equation.hpp" +#include "NeoFOAM/dsl/expression.hpp" -using Equation = NeoFOAM::dsl::Equation; +using Expression = NeoFOAM::dsl::Expression; -TEST_CASE("Equation") +TEST_CASE("Expression") { NeoFOAM::Executor exec = GENERATE( NeoFOAM::Executor(NeoFOAM::SerialExecutor {}), @@ -32,7 +32,7 @@ TEST_CASE("Equation") { auto eqnA = a + b; auto eqnB = fB * Dummy(exec, vf) + 2 * Dummy(exec, vf); - auto eqnC = Equation(2 * a - b); + auto eqnC = Expression(2 * a - b); auto eqnD = 3 * (2 * a - b); auto eqnE = (2 * a - b) + (2 * a - b); auto eqnF = (2 * a - b) - (2 * a - b); From a61ec619803bd3d273526ae92593596725f1ccf0 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 18 Oct 2024 08:59:37 +0200 Subject: [PATCH 58/63] reorganize structure --- include/NeoFOAM/dsl/{timeIntegration => }/ddt.hpp | 0 include/NeoFOAM/dsl/solver.hpp | 2 +- include/NeoFOAM/{dsl => }/timeIntegration/forwardEuler.hpp | 2 +- include/NeoFOAM/{dsl => }/timeIntegration/timeIntegration.hpp | 0 src/dsl/timeIntegration/forwardEuler.cpp | 2 +- test/dsl/timeIntegration/timeIntegration.cpp | 2 +- 6 files changed, 4 insertions(+), 4 deletions(-) rename include/NeoFOAM/dsl/{timeIntegration => }/ddt.hpp (100%) rename include/NeoFOAM/{dsl => }/timeIntegration/forwardEuler.hpp (96%) rename include/NeoFOAM/{dsl => }/timeIntegration/timeIntegration.hpp (100%) diff --git a/include/NeoFOAM/dsl/timeIntegration/ddt.hpp b/include/NeoFOAM/dsl/ddt.hpp similarity index 100% rename from include/NeoFOAM/dsl/timeIntegration/ddt.hpp rename to include/NeoFOAM/dsl/ddt.hpp diff --git a/include/NeoFOAM/dsl/solver.hpp b/include/NeoFOAM/dsl/solver.hpp index 647720b7d..65679e946 100644 --- a/include/NeoFOAM/dsl/solver.hpp +++ b/include/NeoFOAM/dsl/solver.hpp @@ -12,7 +12,7 @@ #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/core/input.hpp" #include "NeoFOAM/dsl/expression.hpp" -#include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" +#include "NeoFOAM/timeIntegration/timeIntegration.hpp" namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/timeIntegration/forwardEuler.hpp similarity index 96% rename from include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp rename to include/NeoFOAM/timeIntegration/forwardEuler.hpp index 144e94028..c778654d7 100644 --- a/include/NeoFOAM/dsl/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/timeIntegration/forwardEuler.hpp @@ -7,7 +7,7 @@ #include #include "NeoFOAM/fields/field.hpp" -#include "NeoFOAM/dsl/timeIntegration/timeIntegration.hpp" +#include "NeoFOAM/timeIntegration/timeIntegration.hpp" namespace NeoFOAM::dsl { diff --git a/include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/timeIntegration/timeIntegration.hpp similarity index 100% rename from include/NeoFOAM/dsl/timeIntegration/timeIntegration.hpp rename to include/NeoFOAM/timeIntegration/timeIntegration.hpp diff --git a/src/dsl/timeIntegration/forwardEuler.cpp b/src/dsl/timeIntegration/forwardEuler.cpp index 926604b36..c57ef64c4 100644 --- a/src/dsl/timeIntegration/forwardEuler.cpp +++ b/src/dsl/timeIntegration/forwardEuler.cpp @@ -3,7 +3,7 @@ #include -#include "NeoFOAM/dsl/timeIntegration/forwardEuler.hpp" +#include "NeoFOAM/timeIntegration/forwardEuler.hpp" #include "NeoFOAM/core/error.hpp" namespace NeoFOAM::finiteVolume::cellCentred diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index 62154fc4b..9c2c96aa1 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -11,7 +11,7 @@ #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" #include "NeoFOAM/dsl/solver.hpp" -#include "NeoFOAM/dsl/timeIntegration/ddt.hpp" +#include "NeoFOAM/dsl/ddt.hpp" TEST_CASE("TimeIntegration") From ee0f1c0357b5104c05525726fe339b16f6ae293f Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 21 Oct 2024 17:46:31 +0200 Subject: [PATCH 59/63] Apply suggestions from code review Co-authored-by: bevanwsjones --- include/NeoFOAM/dsl/expression.hpp | 8 ------- include/NeoFOAM/dsl/solver.hpp | 22 ++++++++++---------- include/NeoFOAM/fields/field.hpp | 2 +- test/CMakeLists.txt | 2 +- test/dsl/timeIntegration/timeIntegration.cpp | 2 +- 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/include/NeoFOAM/dsl/expression.hpp b/include/NeoFOAM/dsl/expression.hpp index d75709381..23a9a7b76 100644 --- a/include/NeoFOAM/dsl/expression.hpp +++ b/include/NeoFOAM/dsl/expression.hpp @@ -177,13 +177,5 @@ Expression operator-(const Operator& lhs, const Operator& rhs) return equation; } -/* @brief free function to solve an equation - * - * @param eqn - Expression to solve - * @param solutionField - Field for which the equation is to be solved - * @param fvSchemes - Dictionary containing spatial operator and time integration properties - * @param fvSolution - Dictionary containing linear solver properties - * @tparam FieldType - type of the underlying field, e.g. VolumeField or plain Field - */ } // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/dsl/solver.hpp b/include/NeoFOAM/dsl/solver.hpp index 65679e946..6846de636 100644 --- a/include/NeoFOAM/dsl/solver.hpp +++ b/include/NeoFOAM/dsl/solver.hpp @@ -17,27 +17,27 @@ namespace NeoFOAM::dsl { -template -void solve( - Expression& eqn, FieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution -) -{ - /* @brief solve an equation + /* @brief solve an expresion * - * @param solutionField - Field for which the equation is to be solved + * @param exp - Expression which is to be solved/updated. + * @param solution - Solution field, where the solution will be 'written to'. * @param fvSchemes - Dictionary containing spatial operator and time integration properties * @param fvSolution - Dictionary containing linear solver properties - * @tparam FieldType - type of the underlying field, e.g. VolumeField or plain Field */ - if (eqn.temporalOperators().size() == 0 && eqn.implicitOperators().size() == 0) +template +void solve( + Expression& exp, FieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution +) +{ + if (exp.temporalOperators().size() == 0 && exp.implicitOperators().size() == 0) { NF_ERROR_EXIT("No temporal or implicit terms to solve."); } - if (eqn.temporalOperators().size() > 0) + if (exp.temporalOperators().size() > 0) { // integrate equations in time TimeIntegration timeIntegrator(fvSchemes.subDict("ddtSchemes")); - timeIntegrator.solve(eqn, solution); + timeIntegrator.solve(exp, solution); } else { diff --git a/include/NeoFOAM/fields/field.hpp b/include/NeoFOAM/fields/field.hpp index 133a09e85..fd5ffd691 100644 --- a/include/NeoFOAM/fields/field.hpp +++ b/include/NeoFOAM/fields/field.hpp @@ -418,7 +418,7 @@ class Field std::string rhsExecName = std::visit([](auto e) { return e.print(); }, rhs.exec()); NF_DEBUG_ASSERT( exec() == rhs.exec(), - "Executors: " + execName + " and " + rhsExecName + " are not the same" + "Executors: " + execName + " and " + rhsExecName + " are not the same." ); } }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 25609aff4..a0dbcffef 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,7 +6,7 @@ list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras) # has to be first since it adds the main target add_subdirectory(catch2) -# include "NeoFOAM/core/parallelAlgorithms.hpp" This function creates unit tests. It allows the +# include "NeoFOAM/core/parallelAlgorithms.hpp" This function creates unit tests. It provides the # following keywords: # # * MPI_SIZE: the number of MPI processors to be used, defaults to 1 if not set diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index 9c2c96aa1..772d840a2 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -37,7 +37,7 @@ TEST_CASE("TimeIntegration") std::vector> bcs {}; auto vf = VolumeField(exec, mesh, fA, bf, bcs); - SECTION("Create equation and perform explicitOperation on " + execName) + SECTION("Create expression and perform explicitOperation on " + execName) { auto dummy = Dummy(exec, vf); Operator ddtOperator = NeoFOAM::dsl::temporal::Ddt(exec, vf); From 1e08f07b47da88742e857aeaab30756ed0cae4b7 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 25 Oct 2024 09:31:22 +0200 Subject: [PATCH 60/63] require field in OperatorMixin --- include/NeoFOAM/dsl/ddt.hpp | 39 ++++----- include/NeoFOAM/dsl/expression.hpp | 39 ++++----- include/NeoFOAM/dsl/operator.hpp | 85 ++++++++++--------- include/NeoFOAM/dsl/solver.hpp | 15 ++-- .../NeoFOAM/timeIntegration/forwardEuler.hpp | 20 ++--- test/dsl/common.hpp | 16 +--- test/dsl/expression.cpp | 21 ++--- test/dsl/operator.cpp | 8 +- test/dsl/timeIntegration/timeIntegration.cpp | 5 +- 9 files changed, 114 insertions(+), 134 deletions(-) diff --git a/include/NeoFOAM/dsl/ddt.hpp b/include/NeoFOAM/dsl/ddt.hpp index ac5d5de4e..e7a801a89 100644 --- a/include/NeoFOAM/dsl/ddt.hpp +++ b/include/NeoFOAM/dsl/ddt.hpp @@ -11,43 +11,36 @@ namespace NeoFOAM::dsl::temporal { -class Ddt : public OperatorMixin + +// TODO add free factory function +template +class Ddt : public OperatorMixin { public: - Ddt(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} + Ddt(FieldType& field) : OperatorMixin(field.exec(), field, Operator::Type::Temporal) + {} std::string getName() const { return "TimeOperator"; } - Operator::Type getType() const { return Operator::Type::Temporal; } - void explicitOperation(Field& source, scalar scale) { - auto sourceField = source.span(); - parallelFor( - source.exec(), - source.range(), - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1 * scale; } - ); - } - - void temporalOperation(Field& phi) - { - auto phiSpan = phi.span(); - auto fieldSpan = field_.internalField().span(); - parallelFor( - phi.exec(), phi.range(), KOKKOS_LAMBDA(const size_t i) { fieldSpan[i] += phiSpan[i]; } - ); + NF_ERROR_EXIT("Not implemented"); } - VolumeField& volumeField() const { return field_; } - - size_t getSize() const { return field_.internalField().size(); } + void implicitOperation(Field& phi) { NF_ERROR_EXIT("Not implemented"); } private: +}; - VolumeField& field_; +// see +// https://github.com/exasim-project/NeoFOAM/blob/dsl/operatorIntergration/include/NeoFOAM/finiteVolume/cellCentred/operators/explicitOperators/expOp.hpp + +template +Ddt ddt(FieldType& in) +{ + return Ddt(in); }; diff --git a/include/NeoFOAM/dsl/expression.hpp b/include/NeoFOAM/dsl/expression.hpp index 23a9a7b76..f63a0705e 100644 --- a/include/NeoFOAM/dsl/expression.hpp +++ b/include/NeoFOAM/dsl/expression.hpp @@ -22,15 +22,14 @@ class Expression { public: - Expression(const Executor& exec, std::size_t nCells) - : exec_(exec), nCells_(nCells), temporalOperators_(), implicitOperators_(), - explicitOperators_() + Expression(const Executor& exec) + : exec_(exec), temporalOperators_(), implicitOperators_(), explicitOperators_() {} /* @brief perform all explicit operation and accumulate the result */ - Field explicitOperation() const + Field explicitOperation(size_t nCells) const { - Field source(exec_, nCells_, 0.0); + Field source(exec_, nCells, 0.0); return explicitOperation(source); } @@ -98,8 +97,6 @@ class Expression const Executor& exec() const { return exec_; } - std::size_t nCells() const { return nCells_; } - scalar getDt() const { return dt_; } void setDt(scalar dt) { dt_ = dt; } @@ -110,8 +107,6 @@ class Expression const Executor exec_; - const std::size_t nCells_; - std::vector temporalOperators_; std::vector implicitOperators_; @@ -133,28 +128,28 @@ Expression operator+(Expression lhs, const Operator& rhs) Expression operator+(const Operator& lhs, const Operator& rhs) { - Expression equation(lhs.exec(), lhs.getSize()); - equation.addOperator(lhs); - equation.addOperator(rhs); - return equation; + Expression expr(lhs.exec()); + expr.addOperator(lhs); + expr.addOperator(rhs); + return expr; } Expression operator*(scalar scale, const Expression& es) { - Expression results(es.exec(), es.nCells()); + Expression expr(es.exec()); for (const auto& Operator : es.temporalOperators()) { - results.addOperator(scale * Operator); + expr.addOperator(scale * Operator); } for (const auto& Operator : es.implicitOperators()) { - results.addOperator(scale * Operator); + expr.addOperator(scale * Operator); } for (const auto& Operator : es.explicitOperators()) { - results.addOperator(scale * Operator); + expr.addOperator(scale * Operator); } - return results; + return expr; } Expression operator-(Expression lhs, const Expression& rhs) @@ -171,10 +166,10 @@ Expression operator-(Expression lhs, const Operator& rhs) Expression operator-(const Operator& lhs, const Operator& rhs) { - Expression equation(lhs.exec(), lhs.getSize()); - equation.addOperator(lhs); - equation.addOperator(Coeff(-1) * rhs); - return equation; + Expression expr(lhs.exec()); + expr.addOperator(lhs); + expr.addOperator(Coeff(-1) * rhs); + return expr; } diff --git a/include/NeoFOAM/dsl/operator.hpp b/include/NeoFOAM/dsl/operator.hpp index d6a9b5c02..2092a1715 100644 --- a/include/NeoFOAM/dsl/operator.hpp +++ b/include/NeoFOAM/dsl/operator.hpp @@ -12,7 +12,7 @@ #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/core/input.hpp" #include "NeoFOAM/dsl/coeff.hpp" - +#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" namespace NeoFOAM::dsl { @@ -31,40 +31,6 @@ concept HasExplicitOperator = requires(T t) { } -> std::same_as; // Adjust return type and arguments as needed }; - -/* @class OperatorMixin - * @brief A mixin class to represent simplify implementations of concrete operators - * in NeoFOAMs dsl - * - * - * @ingroup dsl - */ -class OperatorMixin -{ - -public: - - OperatorMixin(const Executor exec) : exec_(exec), coeffs_() {}; - - virtual ~OperatorMixin() = default; - - virtual const Executor& exec() const final { return exec_; } - - Coeff& getCoefficient() { return coeffs_; } - - const Coeff& getCoefficient() const { return coeffs_; } - - /* @brief Given an input this function reads required coeffs */ - void build([[maybe_unused]] const Input& input) {} - -protected: - - const Executor exec_; //!< Executor associated with the field. (CPU, GPU, openMP, etc.) - - Coeff coeffs_; -}; - - /* @class Operator * @brief A class to represent a operator in NeoFOAMs dsl * @@ -108,7 +74,7 @@ class Operator Coeff getCoefficient() const { return model_->getCoefficient(); } /* get the corresponding field size over which the operator operates */ - size_t getSize() const { return model_->getSize(); } + // size_t getSize() const { return model_->getSize(); } /* @brief Given an input this function reads required coeffs */ void build(const Input& input) { model_->build(input); } @@ -139,7 +105,7 @@ class Operator /* returns the fundamental type of an operator, ie explicit, implicit, temporal */ virtual Operator::Type getType() const = 0; - virtual size_t getSize() const = 0; + // virtual size_t getSize() const = 0; /* @brief get the associated coefficient for this term */ virtual Coeff& getCoefficient() = 0; @@ -196,7 +162,7 @@ class Operator virtual Coeff getCoefficient() const override { return concreteOp_.getCoefficient(); } /* @brief get the associated coefficient for this term */ - virtual size_t getSize() const override { return concreteOp_.getSize(); } + // virtual size_t getSize() const override { return concreteOp_.getSize(); } // The Prototype Design Pattern std::unique_ptr clone() const override @@ -247,4 +213,47 @@ Operator operator*(CoeffFunction coeffFunc, const Operator& lhs) return result; } +/* @class OperatorMixin + * @brief A mixin class to represent simplify implementations of concrete operators + * in NeoFOAMs dsl + * + * + * @ingroup dsl + */ +template +class OperatorMixin +{ + +public: + + OperatorMixin(const Executor exec, FieldType& field, Operator::Type type) + : exec_(exec), coeffs_(), field_(field), type_(type) {}; + + Operator::Type getType() const { return type_; } + + virtual ~OperatorMixin() = default; + + virtual const Executor& exec() const final { return exec_; } + + Coeff& getCoefficient() { return coeffs_; } + + const Coeff& getCoefficient() const { return coeffs_; } + + FieldType& getField() { return field_; } + + const FieldType& getField() const { return field_; } + + /* @brief Given an input this function reads required coeffs */ + void build([[maybe_unused]] const Input& input) {} + +protected: + + const Executor exec_; //!< Executor associated with the field. (CPU, GPU, openMP, etc.) + + Coeff coeffs_; + + FieldType& field_; + + Operator::Type type_; +}; } // namespace NeoFOAM::dsl diff --git a/include/NeoFOAM/dsl/solver.hpp b/include/NeoFOAM/dsl/solver.hpp index 6846de636..f2df40f04 100644 --- a/include/NeoFOAM/dsl/solver.hpp +++ b/include/NeoFOAM/dsl/solver.hpp @@ -17,13 +17,14 @@ namespace NeoFOAM::dsl { - /* @brief solve an expresion - * - * @param exp - Expression which is to be solved/updated. - * @param solution - Solution field, where the solution will be 'written to'. - * @param fvSchemes - Dictionary containing spatial operator and time integration properties - * @param fvSolution - Dictionary containing linear solver properties - */ + +/* @brief solve an expression + * + * @param exp - Expression which is to be solved/updated. + * @param solution - Solution field, where the solution will be 'written to'. + * @param fvSchemes - Dictionary containing spatial operator and time integration properties + * @param fvSolution - Dictionary containing linear solver properties + */ template void solve( Expression& exp, FieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution diff --git a/include/NeoFOAM/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/timeIntegration/forwardEuler.hpp index c778654d7..c8ce788bf 100644 --- a/include/NeoFOAM/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/timeIntegration/forwardEuler.hpp @@ -32,23 +32,17 @@ class ForwardEuler : virtual void solve(Expression& eqn, SolutionType& sol) const override { - scalar dt = eqn.getDt(); - Field phi(sol.exec(), sol.size(), 0.0); - Field source = eqn.explicitOperation(); - - // phi += source*dt; - // for (auto& op : eqn.temporalOperators()) - // { - // op.temporalOperation(phi); - // } + auto dt = eqn.getDt(); + auto source = eqn.explicitOperation(sol.size()); + sol.internalField() -= source * dt; sol.correctBoundaryConditions(); // check if executor is GPU - // if (std::holds_alternative(eqnSystem_.exec())) - // { - // Kokkos::fence(); - // } + if (std::holds_alternative(eqn.exec())) + { + Kokkos::fence(); + } }; std::unique_ptr> clone() const override diff --git a/test/dsl/common.hpp b/test/dsl/common.hpp index ede411279..7a7115905 100644 --- a/test/dsl/common.hpp +++ b/test/dsl/common.hpp @@ -17,9 +17,9 @@ namespace fvcc = NeoFOAM::finiteVolume::cellCentred; using Field = NeoFOAM::Field; using Coeff = NeoFOAM::dsl::Coeff; using Operator = NeoFOAM::dsl::Operator; -using OperatorMixin = NeoFOAM::dsl::OperatorMixin; using Executor = NeoFOAM::Executor; using VolumeField = fvcc::VolumeField; +using OperatorMixin = NeoFOAM::dsl::OperatorMixin; using BoundaryFields = NeoFOAM::BoundaryFields; /* A dummy implementation of a Operator @@ -29,7 +29,7 @@ class Dummy : public OperatorMixin public: - Dummy(const Executor& exec, VolumeField& field) : OperatorMixin(exec), field_(field) {} + Dummy(VolumeField& field) : OperatorMixin(field.exec(), field, Operator::Type::Explicit) {} void explicitOperation(Field& source) const { @@ -44,18 +44,6 @@ class Dummy : public OperatorMixin } std::string getName() const { return "Dummy"; } - - const VolumeField& volumeField() const { return field_; } - - VolumeField& volumeField() { return field_; } - - Operator::Type getType() const { return Operator::Type::Explicit; } - - size_t getSize() const { return field_.internalField().size(); } - -private: - - VolumeField& field_; }; NeoFOAM::scalar getField(const NeoFOAM::Field& source) diff --git a/test/dsl/expression.cpp b/test/dsl/expression.cpp index 853896a9e..c1d509e36 100644 --- a/test/dsl/expression.cpp +++ b/test/dsl/expression.cpp @@ -18,20 +18,21 @@ TEST_CASE("Expression") std::string execName = std::visit([](auto e) { return e.print(); }, exec); auto mesh = NeoFOAM::createSingleCellMesh(exec); - Field fA(exec, 1, 2.0); + const size_t size {1}; + Field fA(exec, size, 2.0); BoundaryFields bf(exec, mesh.nBoundaryFaces(), mesh.nBoundaries()); std::vector> bcs {}; auto vf = VolumeField(exec, mesh, fA, bf, bcs); auto fB = Field(exec, 1, 4.0); - auto a = Dummy(exec, vf); - auto b = Dummy(exec, vf); + auto a = Dummy(vf); + auto b = Dummy(vf); SECTION("Create equation and perform explicitOperation on " + execName) { auto eqnA = a + b; - auto eqnB = fB * Dummy(exec, vf) + 2 * Dummy(exec, vf); + auto eqnB = fB * Dummy(vf) + 2 * Dummy(vf); auto eqnC = Expression(2 * a - b); auto eqnD = 3 * (2 * a - b); auto eqnE = (2 * a - b) + (2 * a - b); @@ -41,11 +42,11 @@ TEST_CASE("Expression") REQUIRE(eqnB.size() == 2); REQUIRE(eqnC.size() == 2); - REQUIRE(getField(eqnA.explicitOperation()) == 4); - REQUIRE(getField(eqnB.explicitOperation()) == 12); - REQUIRE(getField(eqnC.explicitOperation()) == 2); - REQUIRE(getField(eqnD.explicitOperation()) == 6); - REQUIRE(getField(eqnE.explicitOperation()) == 4); - REQUIRE(getField(eqnF.explicitOperation()) == 0); + REQUIRE(getField(eqnA.explicitOperation(size)) == 4); + REQUIRE(getField(eqnB.explicitOperation(size)) == 12); + REQUIRE(getField(eqnC.explicitOperation(size)) == 2); + REQUIRE(getField(eqnD.explicitOperation(size)) == 6); + REQUIRE(getField(eqnE.explicitOperation(size)) == 4); + REQUIRE(getField(eqnF.explicitOperation(size)) == 0); } } diff --git a/test/dsl/operator.cpp b/test/dsl/operator.cpp index e9b731240..5203aa9c9 100644 --- a/test/dsl/operator.cpp +++ b/test/dsl/operator.cpp @@ -23,7 +23,7 @@ TEST_CASE("Operator") std::vector> bcs {}; auto vf = VolumeField(exec, mesh, fA, bf, bcs); - auto b = Dummy(exec, vf); + auto b = Dummy(vf); REQUIRE(b.getName() == "Dummy"); REQUIRE(b.getType() == Operator::Type::Explicit); @@ -38,9 +38,9 @@ TEST_CASE("Operator") BoundaryFields bf(exec, mesh.nBoundaryFaces(), mesh.nBoundaries()); auto vf = VolumeField(exec, mesh, fA, bf, bcs); - auto c = 2 * Dummy(exec, vf); - auto d = fB * Dummy(exec, vf); - auto e = Coeff(-3, fB) * Dummy(exec, vf); + auto c = 2 * Dummy(vf); + auto d = fB * Dummy(vf); + auto e = Coeff(-3, fB) * Dummy(vf); [[maybe_unused]] auto coeffC = c.getCoefficient(); [[maybe_unused]] auto coeffD = d.getCoefficient(); diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index 772d840a2..dcb8db942 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -13,7 +13,6 @@ #include "NeoFOAM/dsl/solver.hpp" #include "NeoFOAM/dsl/ddt.hpp" - TEST_CASE("TimeIntegration") { NeoFOAM::Executor exec = GENERATE( @@ -39,8 +38,8 @@ TEST_CASE("TimeIntegration") SECTION("Create expression and perform explicitOperation on " + execName) { - auto dummy = Dummy(exec, vf); - Operator ddtOperator = NeoFOAM::dsl::temporal::Ddt(exec, vf); + auto dummy = Dummy(vf); + Operator ddtOperator = NeoFOAM::dsl::temporal::ddt(vf); // ddt(U) = f auto eqn = ddtOperator + dummy; From 399358218f5b083bc59467431d02ecaec23c2233 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 25 Oct 2024 09:44:47 +0200 Subject: [PATCH 61/63] remove dt from equation, fix warnings --- include/NeoFOAM/dsl/ddt.hpp | 7 +++++-- include/NeoFOAM/dsl/expression.hpp | 6 ------ include/NeoFOAM/dsl/solver.hpp | 9 +++++++-- include/NeoFOAM/timeIntegration/forwardEuler.hpp | 3 +-- include/NeoFOAM/timeIntegration/timeIntegration.hpp | 9 ++++++--- test/dsl/timeIntegration/timeIntegration.cpp | 7 ++----- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/include/NeoFOAM/dsl/ddt.hpp b/include/NeoFOAM/dsl/ddt.hpp index e7a801a89..06a4b5ba3 100644 --- a/include/NeoFOAM/dsl/ddt.hpp +++ b/include/NeoFOAM/dsl/ddt.hpp @@ -24,12 +24,15 @@ class Ddt : public OperatorMixin std::string getName() const { return "TimeOperator"; } - void explicitOperation(Field& source, scalar scale) + void explicitOperation([[maybe_unused]] Field& source, [[maybe_unused]] scalar scale) { NF_ERROR_EXIT("Not implemented"); } - void implicitOperation(Field& phi) { NF_ERROR_EXIT("Not implemented"); } + void implicitOperation([[maybe_unused]] Field& phi) + { + NF_ERROR_EXIT("Not implemented"); + } private: }; diff --git a/include/NeoFOAM/dsl/expression.hpp b/include/NeoFOAM/dsl/expression.hpp index f63a0705e..90808f1d2 100644 --- a/include/NeoFOAM/dsl/expression.hpp +++ b/include/NeoFOAM/dsl/expression.hpp @@ -97,14 +97,8 @@ class Expression const Executor& exec() const { return exec_; } - scalar getDt() const { return dt_; } - - void setDt(scalar dt) { dt_ = dt; } - private: - scalar dt_ = 0; - const Executor exec_; std::vector temporalOperators_; diff --git a/include/NeoFOAM/dsl/solver.hpp b/include/NeoFOAM/dsl/solver.hpp index f2df40f04..2f84fe57b 100644 --- a/include/NeoFOAM/dsl/solver.hpp +++ b/include/NeoFOAM/dsl/solver.hpp @@ -22,12 +22,17 @@ namespace NeoFOAM::dsl * * @param exp - Expression which is to be solved/updated. * @param solution - Solution field, where the solution will be 'written to'. + * @param dt - time step for the temporal integration * @param fvSchemes - Dictionary containing spatial operator and time integration properties * @param fvSolution - Dictionary containing linear solver properties */ template void solve( - Expression& exp, FieldType& solution, const Dictionary& fvSchemes, const Dictionary& fvSolution + Expression& exp, + FieldType& solution, + scalar dt, + [[maybe_unused]] const Dictionary& fvSchemes, + [[maybe_unused]] const Dictionary& fvSolution ) { if (exp.temporalOperators().size() == 0 && exp.implicitOperators().size() == 0) @@ -38,7 +43,7 @@ void solve( { // integrate equations in time TimeIntegration timeIntegrator(fvSchemes.subDict("ddtSchemes")); - timeIntegrator.solve(exp, solution); + timeIntegrator.solve(exp, solution, dt); } else { diff --git a/include/NeoFOAM/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/timeIntegration/forwardEuler.hpp index c8ce788bf..6fdd9b7d1 100644 --- a/include/NeoFOAM/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/timeIntegration/forwardEuler.hpp @@ -30,9 +30,8 @@ class ForwardEuler : static std::string schema() { return "none"; } - virtual void solve(Expression& eqn, SolutionType& sol) const override + virtual void solve(Expression& eqn, SolutionType& sol, scalar dt) const override { - auto dt = eqn.getDt(); auto source = eqn.explicitOperation(sol.size()); sol.internalField() -= source * dt; diff --git a/include/NeoFOAM/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/timeIntegration/timeIntegration.hpp index 3c08c2562..6d2a3a4fe 100644 --- a/include/NeoFOAM/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/timeIntegration/timeIntegration.hpp @@ -31,8 +31,8 @@ class TimeIntegrationFactory : virtual ~TimeIntegrationFactory() {} - virtual void - solve(Expression& eqn, SolutionType& sol) const = 0; // Pure virtual function for solving + virtual void solve(Expression& eqn, SolutionType& sol, scalar dt) + const = 0; // Pure virtual function for solving // Pure virtual function for cloning virtual std::unique_ptr clone() const = 0; @@ -64,7 +64,10 @@ class TimeIntegration TimeIntegrationFactory::create(dict.get("type"), dict) ) {}; - void solve(Expression& eqn, SolutionType& sol) { timeIntegratorStrategy_->solve(eqn, sol); } + void solve(Expression& eqn, SolutionType& sol, scalar dt) + { + timeIntegratorStrategy_->solve(eqn, sol, dt); + } private: diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index dcb8db942..31959653f 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -43,15 +43,12 @@ TEST_CASE("TimeIntegration") // ddt(U) = f auto eqn = ddtOperator + dummy; - eqn.setDt(2.0); + double dt {2.0}; // int(ddt(U)) + f = 0 // (U^1-U^0)/dt = -f // U^1 = - f * dt + U^0, where dt = 2, f=1, U^0=2.0 -> U^1=-2.0 - solve(eqn, vf, fvSchemes, fvSolution); + solve(eqn, vf, dt, fvSchemes, fvSolution); REQUIRE(getField(vf.internalField()) == -2.0); } - - // auto fB = Field(exec, 1, 4.0); - // fvcc::TimeIntegration timeIntergrator(eqnSys, dict); } From ce14d1937161bcb9523d8ba44ee69e0fec3cf80a Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 25 Oct 2024 10:01:00 +0200 Subject: [PATCH 62/63] remove unused file, rename timeIntegrationFactory->timeIntegrationBase --- include/NeoFOAM/dsl/operator.hpp | 2 +- include/NeoFOAM/timeIntegration/forwardEuler.hpp | 9 ++++----- .../NeoFOAM/timeIntegration/timeIntegration.hpp | 16 +++++++--------- src/CMakeLists.txt | 3 +-- src/dsl/timeIntegration/forwardEuler.cpp | 11 ----------- 5 files changed, 13 insertions(+), 28 deletions(-) delete mode 100644 src/dsl/timeIntegration/forwardEuler.cpp diff --git a/include/NeoFOAM/dsl/operator.hpp b/include/NeoFOAM/dsl/operator.hpp index 2092a1715..345432fa9 100644 --- a/include/NeoFOAM/dsl/operator.hpp +++ b/include/NeoFOAM/dsl/operator.hpp @@ -200,7 +200,7 @@ auto operator*(const Coeff& coeff, const Operator& rhs) template requires std::invocable -Operator operator*(CoeffFunction coeffFunc, const Operator& lhs) +Operator operator*([[maybe_unused]] CoeffFunction coeffFunc, const Operator& lhs) { // TODO implement NF_ERROR_EXIT("Not implemented"); diff --git a/include/NeoFOAM/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/timeIntegration/forwardEuler.hpp index 6fdd9b7d1..0dda395a1 100644 --- a/include/NeoFOAM/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/timeIntegration/forwardEuler.hpp @@ -14,13 +14,12 @@ namespace NeoFOAM::dsl template class ForwardEuler : - public TimeIntegrationFactory::template Register> + public TimeIntegratorBase::template Register> { public: - using Base = - TimeIntegrationFactory::template Register>; + using Base = TimeIntegratorBase::template Register>; ForwardEuler(const Dictionary& dict) : Base(dict) {} @@ -30,7 +29,7 @@ class ForwardEuler : static std::string schema() { return "none"; } - virtual void solve(Expression& eqn, SolutionType& sol, scalar dt) const override + void solve(Expression& eqn, SolutionType& sol, scalar dt) const override { auto source = eqn.explicitOperation(sol.size()); @@ -44,7 +43,7 @@ class ForwardEuler : } }; - std::unique_ptr> clone() const override + std::unique_ptr> clone() const override { return std::make_unique(*this); } diff --git a/include/NeoFOAM/timeIntegration/timeIntegration.hpp b/include/NeoFOAM/timeIntegration/timeIntegration.hpp index 6d2a3a4fe..89b1feff9 100644 --- a/include/NeoFOAM/timeIntegration/timeIntegration.hpp +++ b/include/NeoFOAM/timeIntegration/timeIntegration.hpp @@ -17,25 +17,23 @@ namespace NeoFOAM::dsl * using NeoFOAMs runTimeFactory mechanism */ template -class TimeIntegrationFactory : - public RuntimeSelectionFactory< - TimeIntegrationFactory, - Parameters> +class TimeIntegratorBase : + public RuntimeSelectionFactory, Parameters> { public: static std::string name() { return "timeIntegrationFactory"; } - TimeIntegrationFactory(const Dictionary& dict) : dict_(dict) {} + TimeIntegratorBase(const Dictionary& dict) : dict_(dict) {} - virtual ~TimeIntegrationFactory() {} + virtual ~TimeIntegratorBase() {} virtual void solve(Expression& eqn, SolutionType& sol, scalar dt) const = 0; // Pure virtual function for solving // Pure virtual function for cloning - virtual std::unique_ptr clone() const = 0; + virtual std::unique_ptr clone() const = 0; protected: @@ -61,7 +59,7 @@ class TimeIntegration TimeIntegration(const Dictionary& dict) : timeIntegratorStrategy_( - TimeIntegrationFactory::create(dict.get("type"), dict) + TimeIntegratorBase::create(dict.get("type"), dict) ) {}; void solve(Expression& eqn, SolutionType& sol, scalar dt) @@ -71,7 +69,7 @@ class TimeIntegration private: - std::unique_ptr> timeIntegratorStrategy_; + std::unique_ptr> timeIntegratorStrategy_; }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 13fbdd2ab..e7399cd8a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,8 +29,7 @@ target_sources( "finiteVolume/cellCentred/operators/gaussGreenGrad.cpp" "finiteVolume/cellCentred/operators/gaussGreenDiv.cpp" "finiteVolume/cellCentred/interpolation/linear.cpp" - "finiteVolume/cellCentred/interpolation/upwind.cpp" - "dsl/timeIntegration/forwardEuler.cpp") + "finiteVolume/cellCentred/interpolation/upwind.cpp") include(${CMAKE_SOURCE_DIR}/cmake/Sanitizer.cmake) enable_sanitizers( diff --git a/src/dsl/timeIntegration/forwardEuler.cpp b/src/dsl/timeIntegration/forwardEuler.cpp deleted file mode 100644 index c57ef64c4..000000000 --- a/src/dsl/timeIntegration/forwardEuler.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2023 NeoFOAM authors - -#include - -#include "NeoFOAM/timeIntegration/forwardEuler.hpp" -#include "NeoFOAM/core/error.hpp" - -namespace NeoFOAM::finiteVolume::cellCentred -{ -} // namespace NeoFOAM From adb378fe26392353f7080832feee5d3005f1cf81 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 25 Oct 2024 10:55:52 +0200 Subject: [PATCH 63/63] fixup --- test/dsl/coeff.cpp | 1 + test/dsl/timeIntegration/timeIntegration.cpp | 1 + test/finiteVolume/CMakeLists.txt | 1 - .../timeIntegration/CMakeLists.txt | 4 - .../timeIntegration/timeIntegration.cpp | 94 ------------------- 5 files changed, 2 insertions(+), 99 deletions(-) delete mode 100644 test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt delete mode 100644 test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp diff --git a/test/dsl/coeff.cpp b/test/dsl/coeff.cpp index 7a3dd0c3a..f945a00ae 100644 --- a/test/dsl/coeff.cpp +++ b/test/dsl/coeff.cpp @@ -12,6 +12,7 @@ using Field = NeoFOAM::Field; using Coeff = NeoFOAM::dsl::Coeff; +using namespace NeoFOAM::dsl; TEST_CASE("Coeff") diff --git a/test/dsl/timeIntegration/timeIntegration.cpp b/test/dsl/timeIntegration/timeIntegration.cpp index 31959653f..4abb44e66 100644 --- a/test/dsl/timeIntegration/timeIntegration.cpp +++ b/test/dsl/timeIntegration/timeIntegration.cpp @@ -10,6 +10,7 @@ #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" +#include "NeoFOAM/timeIntegration/forwardEuler.hpp" #include "NeoFOAM/dsl/solver.hpp" #include "NeoFOAM/dsl/ddt.hpp" diff --git a/test/finiteVolume/CMakeLists.txt b/test/finiteVolume/CMakeLists.txt index 7213b6f5a..564d38f7b 100644 --- a/test/finiteVolume/CMakeLists.txt +++ b/test/finiteVolume/CMakeLists.txt @@ -4,4 +4,3 @@ add_subdirectory(cellCentred/fields) add_subdirectory(cellCentred/boundary) add_subdirectory(cellCentred/interpolation) -add_subdirectory(cellCentred/timeIntegration) diff --git a/test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt b/test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt deleted file mode 100644 index fd05e4245..000000000 --- a/test/finiteVolume/cellCentred/timeIntegration/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: Unlicense -# SPDX-FileCopyrightText: 2024 NeoFOAM authors - -neofoam_unit_test(timeIntegration) diff --git a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp b/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp deleted file mode 100644 index 95a259cae..000000000 --- a/test/finiteVolume/cellCentred/timeIntegration/timeIntegration.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2024 NeoFOAM authors - -#define CATCH_CONFIG_RUNNER // Define this before including catch.hpp to create - // a custom main -#include -#include -#include - -#include "NeoFOAM/core/dictionary.hpp" -#include "NeoFOAM/core/parallelAlgorithms.hpp" -#include "NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp" - -namespace dsl = NeoFOAM::DSL; - -class Divergence : public NeoFOAM::DSL::OperatorMixin -{ - -public: - - std::string display() const { return "Divergence"; } - - void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) - { - auto sourceField = source.span(); - NeoFOAM::parallelFor( - source.exec(), - {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1.0 * scale; } - ); - } - - dsl::Operator::Type getType() const { return termType_; } - - fvcc::VolumeField* volumeField() const { return nullptr; } - - const NeoFOAM::Executor& exec() const { return exec_; } - - std::size_t nCells() const { return nCells_; } - - dsl::Operator::Type termType_; - - NeoFOAM::Executor exec_; - - std::size_t nCells_; -}; - -class TimeOperator -{ - -public: - - std::string display() const { return "TimeOperator"; } - - void explicitOperation(NeoFOAM::Field& source, NeoFOAM::scalar scale) - { - auto sourceField = source.span(); - NeoFOAM::parallelFor( - source.exec(), - {0, source.size()}, - KOKKOS_LAMBDA(const size_t i) { sourceField[i] += 1 * scale; } - ); - } - - dsl::Operator::Type getType() const { return termType_; } - - fvcc::VolumeField* volumeField() const { return nullptr; } - - const NeoFOAM::Executor& exec() const { return exec_; } - - std::size_t nCells() const { return nCells_; } - - dsl::Operator::Type termType_; - const NeoFOAM::Executor exec_; - std::size_t nCells_; -}; - - -TEST_CASE("TimeIntegration") -{ - auto exec = NeoFOAM::SerialExecutor(); - namespace fvcc = NeoFOAM::finiteVolume::cellCentred; - - NeoFOAM::Dictionary dict; - dict.insert("type", std::string("forwardEuler")); - - // dsl::Operator divOperator = Divergence(dsl::Operator::Type::Explicit, exec, 1); - - // dsl::Operator ddtOperator = TimeOperator(dsl::Operator::Type::Temporal, exec, 1); - - // dsl::EqnSystem eqnSys = ddtOperator + divOperator; - - // fvcc::TimeIntegration timeIntergrator(eqnSys, dict); -}