From d888bde8c6f41bad81a48a764ec773d11ed34e07 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Wed, 4 Sep 2024 20:52:07 +0200 Subject: [PATCH 001/127] 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 002/127] 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 003/127] 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 004/127] 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 005/127] 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 006/127] 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 007/127] 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 008/127] 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 009/127] 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 010/127] 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 011/127] 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 012/127] 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 013/127] 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 014/127] 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 015/127] 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 016/127] 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 017/127] 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 018/127] 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 019/127] 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 020/127] 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 021/127] 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 022/127] 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 023/127] 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 024/127] 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 025/127] 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 026/127] 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 027/127] 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 028/127] 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 029/127] 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 030/127] 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 031/127] 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 032/127] 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 033/127] 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 034/127] 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 035/127] 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 036/127] 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 037/127] 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 038/127] 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 039/127] 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 040/127] 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 041/127] 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 042/127] 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 043/127] 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 044/127] 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 045/127] 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 046/127] 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 5441e7290acc13193581b688825e97928c8578bf Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Wed, 24 Jul 2024 18:26:14 +0200 Subject: [PATCH 047/127] 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 79294ea76f608d6076410f0583a169d508d281da Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Thu, 25 Jul 2024 11:33:14 +0200 Subject: [PATCH 048/127] 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 f125c11941250b4569ecf47eb22feaeb167cd505 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Thu, 25 Jul 2024 12:22:04 +0200 Subject: [PATCH 049/127] 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 34d39e564..792d72901 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,7 +27,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") if(NEOFOAM_ENABLE_MPI_SUPPORT) target_sources(NeoFOAM PRIVATE "core/mpi/halfDuplexCommBuffer.cpp" 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 cb58d6b7c963ded38fbf71c1e3d87484a48f2054 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Thu, 25 Jul 2024 17:28:51 +0200 Subject: [PATCH 050/127] 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 624748a029aadff73deaacb11bc7d91842f1725d Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Thu, 25 Jul 2024 17:29:39 +0200 Subject: [PATCH 051/127] 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 f4837db047a63978c1654e4570fc02d03c32bd15 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Thu, 11 Jul 2024 22:01:11 +0200 Subject: [PATCH 052/127] 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 99fc3eb17aae2da25e87a261778142ee8c95462c Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Fri, 26 Jul 2024 12:30:19 +0200 Subject: [PATCH 053/127] 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 b9dfe10911fe92d6419ebd28dffdf2e11c039a7e Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Fri, 26 Jul 2024 12:31:39 +0200 Subject: [PATCH 054/127] 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 48518a5b1c172bb2612ad9118ec2e80f0532693b Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Fri, 26 Jul 2024 17:33:20 +0200 Subject: [PATCH 055/127] 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 74c2a3fad0cd67a16bc3245cb00f5a898a7faf90 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Sat, 10 Aug 2024 13:09:28 +0200 Subject: [PATCH 056/127] 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 dc12ab0acaf2ebc42d92bf61d32d293fe29e516f Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 13:25:50 +0200 Subject: [PATCH 057/127] 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 387f95f2a62f5d0c177c53aa1a16a77211b650fc Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 14:01:07 +0200 Subject: [PATCH 058/127] 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 dac0c54fbc771deac96b201e0055b3f19b69bd66 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 09:15:44 +0200 Subject: [PATCH 059/127] 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 d89202c516cae511c6faba96f02ff839b830aae4 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 09:23:43 +0200 Subject: [PATCH 060/127] 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 28ceb8025812c8b85aa47d4399badc2d95df31ce Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 13:46:26 +0200 Subject: [PATCH 061/127] 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 b837006703146c5cf2a5012dac3fc7c43df1c040 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Sun, 6 Oct 2024 10:37:08 +0200 Subject: [PATCH 062/127] 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 a415f6dccbd3d843d061f3ffe4e83b12a4eb3f04 Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Sun, 6 Oct 2024 10:38:10 +0200 Subject: [PATCH 063/127] 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 f9b8453748a1b60a5a08831ab5e5a9da36c652cd Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 14:37:53 +0200 Subject: [PATCH 064/127] 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 d85c1ceef2d0d90a9f06a31a12c0967935c95668 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 4 Oct 2024 16:49:19 +0200 Subject: [PATCH 065/127] 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 06120b131044353c4bb3e991b8516d2c22357ff5 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sat, 5 Oct 2024 08:30:14 +0200 Subject: [PATCH 066/127] 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 2457021d66b25c85d57dbefc393f0b2633089738 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:25:16 +0200 Subject: [PATCH 067/127] 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 e8bb2c689..55de3363d 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -9,7 +9,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 fe1cee0faf6fe0d431631387ffbfa58c05dee94b Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:40:07 +0200 Subject: [PATCH 068/127] 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 250935fb5e7a1c91889514fc444438c1d95d8464 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:42:30 +0200 Subject: [PATCH 069/127] 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 d6c55126b2bc5856bd5d286e1a68edcc9143ee33 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:52:23 +0200 Subject: [PATCH 070/127] 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 9415cf782d4b26f816974abd7d201221de14db48 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 12:58:26 +0200 Subject: [PATCH 071/127] 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 8df98b1d34cf06b5123ebd486b4ddfb7d4249a57 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 13:00:27 +0200 Subject: [PATCH 072/127] 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 cb2484b94cd450b46f147b29e30a4dda821e3793 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 13:10:41 +0200 Subject: [PATCH 073/127] 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 a436a8b8291b63c8277b9792d9cb8dbba86bb7d1 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 13:11:05 +0200 Subject: [PATCH 074/127] 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 663e9e5c7b88b4e128952cd159cdacb9c7900396 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 14:26:01 +0200 Subject: [PATCH 075/127] 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 e42845b2d8c23d594feb014c7a14d4ea5e19cd46 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 17:21:15 +0200 Subject: [PATCH 076/127] 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 3a1b7a17e696988252e6fc9f1674b858e5bbf6b4 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 17:22:06 +0200 Subject: [PATCH 077/127] 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 0127c97f9630eeca77f3841be4d98655131b8dc3 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 7 Oct 2024 17:40:17 +0200 Subject: [PATCH 078/127] 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 d229c29a42cb5c86122a96dec6e442f1af94cc4f Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Wed, 4 Sep 2024 20:52:07 +0200 Subject: [PATCH 079/127] add documentation --- doc/conf.py | 1 + doc/finiteVolume/DSL.rst | 4 - doc/finiteVolume/cellCentred/DSL.rst | 230 +++++++++++++++++++++++++ doc/finiteVolume/cellCentred/index.rst | 1 - 4 files changed, 231 insertions(+), 5 deletions(-) delete mode 100644 doc/finiteVolume/DSL.rst create mode 100644 doc/finiteVolume/cellCentred/DSL.rst 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 98038965c9ec2d1b4199b985f63eede5f83885bb Mon Sep 17 00:00:00 2001 From: Henning Scheufler Date: Wed, 4 Sep 2024 21:46:24 +0200 Subject: [PATCH 080/127] 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 3534aea35d0326ffa9dc76b799964b5cb077b97c 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 081/127] 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 0c9eed2c7379fda5745fb66e2f22bf0107258ab6 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sun, 29 Sep 2024 20:23:07 +0200 Subject: [PATCH 082/127] 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 9c1648f0693057b0e6cbf32de7e220711124e698 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 11:27:06 +0200 Subject: [PATCH 083/127] 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 1ee7a415f..32948d06b 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 feb8ce2cd2754c6f428c477da6d42e8e513c3c5d Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 11:33:40 +0200 Subject: [PATCH 084/127] 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 32948d06b..1f9c680d4 100644 --- a/.github/workflows/build_doc.yaml +++ b/.github/workflows/build_doc.yaml @@ -48,6 +48,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 daf3a13981bc374faad86925dc9c713fdd436422 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 12:41:04 +0200 Subject: [PATCH 085/127] 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 9b9fbf7aeb715f721d6fc01b843ba15f9e8d4c4b Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 12:49:56 +0200 Subject: [PATCH 086/127] 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 39626927b29912d5e96c6e19913ddc1b2eac3295 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 12:54:35 +0200 Subject: [PATCH 087/127] 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 c0996f9b4834cbb5e4aabe7b0cc2d0a928408679 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Mon, 30 Sep 2024 12:59:38 +0200 Subject: [PATCH 088/127] 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 6436f3f3bb26286a5a42713c2e4a5714a2a71a85 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Thu, 10 Oct 2024 17:06:04 +0200 Subject: [PATCH 089/127] 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 50f6c7c466850dacf712c02a4114dace7ac18bdc Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 11 Oct 2024 20:39:40 +0200 Subject: [PATCH 090/127] 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 091/127] 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 092/127] 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 093/127] 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 094/127] 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 095/127] 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 096/127] 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 097/127] 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 098/127] 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 099/127] 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 100/127] 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 101/127] 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 102/127] 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 103/127] 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 104/127] 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 105/127] 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 106/127] 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); -} From 701da67798a608ea84777ff0f720e3f776fbdb49 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Fri, 25 Oct 2024 15:43:30 +0200 Subject: [PATCH 107/127] add missing mermaid package --- doc/requirements.txt | 1 + scripts/package.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 scripts/package.py diff --git a/doc/requirements.txt b/doc/requirements.txt index a49f2dc6c..f7520c582 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -2,3 +2,4 @@ sphinx sphinx-sitemap furo breathe +sphinxcontrib-mermaid diff --git a/scripts/package.py b/scripts/package.py new file mode 100644 index 000000000..d69f8e89c --- /dev/null +++ b/scripts/package.py @@ -0,0 +1,21 @@ +# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other +# Spack Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: MIT + +from spack.package import * + +class Neofoam(CMakePackage): + """NeoFOAM is a WIP prototype of a modern CFD core.""" + + homepage = "https://github.com/exasim-project/NeoFOAM" + git = homepage + + # maintainers("github_user1", "github_user2") + + license("UNKNOWN", checked_by="github_user1") + + version("develop", branch="main") + + depends_on("mpi") + depends_on("kokkos@4.3.0") From ea8cbbef0c43b90e1dca222c148dc74b45f63f4a Mon Sep 17 00:00:00 2001 From: bevanwsjones Date: Sun, 27 Oct 2024 10:54:53 +0100 Subject: [PATCH 108/127] - Removed old include/NeoFOAM/DSL --- include/NeoFOAM/DSL/coeff.hpp | 110 ------------- include/NeoFOAM/DSL/equation.hpp | 192 ----------------------- include/NeoFOAM/DSL/operator.hpp | 254 ------------------------------- 3 files changed, 556 deletions(-) delete mode 100644 include/NeoFOAM/DSL/coeff.hpp delete mode 100644 include/NeoFOAM/DSL/equation.hpp delete mode 100644 include/NeoFOAM/DSL/operator.hpp diff --git a/include/NeoFOAM/DSL/coeff.hpp b/include/NeoFOAM/DSL/coeff.hpp deleted file mode 100644 index d2b2a6623..000000000 --- a/include/NeoFOAM/DSL/coeff.hpp +++ /dev/null @@ -1,110 +0,0 @@ -// 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_; } - - bool hasSpan() { return hasSpan_; } - - std::span span() { return span_; } - - Coeff& operator*=(scalar rhs) - { - coeff_ *= rhs; - return *this; - } - - 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_; -}; - - -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; - result *= rhs; - return result; -} - -} // namespace NeoFOAM::DSL diff --git a/include/NeoFOAM/DSL/equation.hpp b/include/NeoFOAM/DSL/equation.hpp deleted file mode 100644 index 87c2f6b01..000000000 --- a/include/NeoFOAM/DSL/equation.hpp +++ /dev/null @@ -1,192 +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/DSL/operator.hpp" -#include "NeoFOAM/core/error.hpp" - -namespace NeoFOAM::DSL -{ - -class Equation -{ -public: - - Equation(const Executor& exec, std::size_t nCells) - : exec_(exec), nCells_(nCells), temporalOperators_(), implicitOperators_(), - explicitOperators_() - {} - - /* @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 - { - for (auto& Operator : explicitOperators_) - { - Operator.explicitOperation(source); - } - return source; - } - - void addOperator(const Operator& Operator) - { - switch (Operator.getType()) - { - case Operator::Type::Temporal: - temporalOperators_.push_back(Operator); - break; - case Operator::Type::Implicit: - implicitOperators_.push_back(Operator); - break; - case Operator::Type::Explicit: - explicitOperators_.push_back(Operator); - break; - } - } - - void addEquation(const Equation& equation) - { - for (auto& Operator : equation.temporalOperators_) - { - temporalOperators_.push_back(Operator); - } - for (auto& Operator : equation.implicitOperators_) - { - implicitOperators_.push_back(Operator); - } - for (auto& Operator : equation.explicitOperators_) - { - explicitOperators_.push_back(Operator); - } - } - - void solve() - { - if (temporalOperators_.size() == 0 && implicitOperators_.size() == 0) - { - NF_ERROR_EXIT("No temporal or implicit terms to solve."); - } - 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(); - } - - // getters - const std::vector& temporalOperators() const { return temporalOperators_; } - - const std::vector& implicitOperators() const { return implicitOperators_; } - - const std::vector& explicitOperators() const { return explicitOperators_; } - - std::vector& temporalOperators() { return temporalOperators_; } - - std::vector& implicitOperators() { return implicitOperators_; } - - std::vector& explicitOperators() { return explicitOperators_; } - - const Executor& exec() const { return exec_; } - - const std::size_t nCells() const { return nCells_; } - - scalar getDt() const { return dt_; } - - scalar dt_ = 0; - -private: - - const Executor exec_; - - const std::size_t nCells_; - - std::vector temporalOperators_; - - std::vector implicitOperators_; - - std::vector explicitOperators_; -}; - -Equation operator+(Equation lhs, const Equation& rhs) -{ - lhs.addEquation(rhs); - return lhs; -} - -Equation operator+(Equation lhs, const Operator& rhs) -{ - lhs.addOperator(rhs); - return lhs; -} - -Equation operator+(const Operator& lhs, const Operator& rhs) -{ - Equation equation(lhs.exec(), lhs.getSize()); - equation.addOperator(lhs); - equation.addOperator(rhs); - return equation; -} - -Equation operator*(scalar scale, const Equation& es) -{ - Equation results(es.exec(), es.nCells()); - for (const auto& Operator : es.temporalOperators()) - { - results.addOperator(scale * Operator); - } - for (const auto& Operator : es.implicitOperators()) - { - results.addOperator(scale * Operator); - } - for (const auto& Operator : es.explicitOperators()) - { - results.addOperator(scale * Operator); - } - return results; -} - -Equation operator-(Equation lhs, const Equation& rhs) -{ - lhs.addEquation(-1.0 * rhs); - return lhs; -} - -Equation operator-(Equation lhs, const Operator& rhs) -{ - lhs.addOperator(-1.0 * rhs); - return lhs; -} - -Equation operator-(const Operator& lhs, const Operator& rhs) -{ - Equation equation(lhs.exec(), lhs.getSize()); - equation.addOperator(lhs); - equation.addOperator(Coeff(-1) * rhs); - return equation; -} - -} // namespace NeoFOAM::DSL diff --git a/include/NeoFOAM/DSL/operator.hpp b/include/NeoFOAM/DSL/operator.hpp deleted file mode 100644 index 64480b7f8..000000000 --- a/include/NeoFOAM/DSL/operator.hpp +++ /dev/null @@ -1,254 +0,0 @@ -// 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/input.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_() {}; - - virtual ~OperatorMixin() = default; - - const Executor& exec() const { return exec_; } - - Coeff& getCoefficient() { return coeffs_; } - - const Coeff& getCoefficient() const { return coeffs_; } - - /* @brief Given an input this function reads required coeffs */ - void build(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 - * - * 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_)} {} - - void explicitOperation(Field& source) const { 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(); } - - Coeff& getCoefficient() { return model_->getCoefficient(); } - - 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); } - - /* @brief Get the executor */ - const Executor& exec() const { return model_->exec(); } - - -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 void explicitOperation(Field& source) const = 0; - - virtual void temporalOperation(Field& field) = 0; - - /* @brief Given an input this function reads required coeffs */ - virtual void build(const Input& input) = 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; - - virtual size_t getSize() const = 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; - - /* @brief Get the executor */ - virtual const Executor& exec() const = 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 - { - /* @brief build with concrete operator */ - OperatorModel(ConcreteOperatorType concreteOp) : concreteOp_(std::move(concreteOp)) {} - - /* returns the name of the operator */ - std::string getName() const override { return concreteOp_.getName(); } - - virtual void explicitOperation(Field& source) const override - { - if constexpr (HasExplicitOperator) - { - concreteOp_.explicitOperation(source); - } - } - - virtual void temporalOperation(Field& field) override - { - if constexpr (HasTemporalOperator) - { - concreteOp_.temporalOperation(field); - } - } - - /* @brief Given an input this function reads required coeffs */ - virtual void build(const Input& input) override { concreteOp_.build(input); } - - /* 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 */ - virtual Coeff& getCoefficient() override { return concreteOp_.getCoefficient(); } - - /* @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 - { - return std::make_unique(*this); - } - - ConcreteOperatorType concreteOp_; - }; - - std::unique_ptr model_; -}; - - -auto operator*(scalar scalarCoeff, const Operator& rhs) -{ - Operator result = rhs; - result.getCoefficient() *= scalarCoeff; - return result; -} - -auto operator*(const Field& coeffField, const Operator& rhs) -{ - 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 - requires std::invocable -Operator operator*(CoeffFunction coeffFunc, const Operator& lhs) -{ - // TODO implement - NF_ERROR_EXIT("Not implemented"); - Operator result = lhs; - // 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 From ffd01e7a624dfb6801644dbd7e023e9a70578557 Mon Sep 17 00:00:00 2001 From: bevanwsjones Date: Sun, 27 Oct 2024 10:57:21 +0100 Subject: [PATCH 109/127] - removed finiteVolume time integration, which was based on DSL. --- .../timeIntegration/forwardEuler.hpp | 37 --------- .../timeIntegration/timeIntegration.hpp | 75 ------------------- src/CMakeLists.txt | 3 +- .../timeIntegration/forwardEuler.cpp | 49 ------------ 4 files changed, 1 insertion(+), 163 deletions(-) delete mode 100644 include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp delete mode 100644 include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp delete mode 100644 src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp diff --git a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp deleted file mode 100644 index d27505611..000000000 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/forwardEuler.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// 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 - - -namespace NeoFOAM::finiteVolume::cellCentred -{ - - -class ForwardEuler : public TimeIntegrationFactory::Register -{ - -public: - - ForwardEuler(const DSL::Equation& 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 deleted file mode 100644 index 483f2b8e7..000000000 --- a/include/NeoFOAM/finiteVolume/cellCentred/timeIntegration/timeIntegration.hpp +++ /dev/null @@ -1,75 +0,0 @@ -// 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/operator.hpp" -#include "NeoFOAM/DSL/equation.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::Equation& 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::Equation 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::Equation& 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 792d72901..34d39e564 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,8 +27,7 @@ target_sources( "finiteVolume/cellCentred/operators/gaussGreenGrad.cpp" "finiteVolume/cellCentred/operators/gaussGreenDiv.cpp" "finiteVolume/cellCentred/interpolation/linear.cpp" - "finiteVolume/cellCentred/interpolation/upwind.cpp" - "finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp") + "finiteVolume/cellCentred/interpolation/upwind.cpp") if(NEOFOAM_ENABLE_MPI_SUPPORT) target_sources(NeoFOAM PRIVATE "core/mpi/halfDuplexCommBuffer.cpp" diff --git a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp b/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp deleted file mode 100644 index 8e80367ba..000000000 --- a/src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// 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::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 From 95dc8f27a10d12375f514d58ab13c3d8090e2679 Mon Sep 17 00:00:00 2001 From: bevanwsjones Date: Sun, 27 Oct 2024 11:03:22 +0100 Subject: [PATCH 110/127] - Updated DSL->dsl change to docs --- doc/basics/fields.rst | 4 ++-- doc/{DSL => dsl}/equation.rst | 0 doc/{DSL => dsl}/index.rst | 0 doc/{DSL => dsl}/operator.rst | 8 ++++---- doc/finiteVolume/cellCentred/index.rst | 1 - doc/index.rst | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) rename doc/{DSL => dsl}/equation.rst (100%) rename doc/{DSL => dsl}/index.rst (100%) rename doc/{DSL => dsl}/operator.rst (94%) diff --git a/doc/basics/fields.rst b/doc/basics/fields.rst index c183955bb..44b44ad19 100644 --- a/doc/basics/fields.rst +++ b/doc/basics/fields.rst @@ -9,7 +9,7 @@ Fields Cell Centered Fields ^^^^^^^^^^^^^^^^^^^^ -The ``VolumeField`` stores the field values at cell centers and along boundaries, providing essential data for constructing the DSL (Domain Specific Language). This functionality also includes access to mesh data, integrating closely with the computational framework. +The ``VolumeField`` stores the field values at cell centers and along boundaries, providing essential data for constructing the Domain Specific Language (DSL). This functionality also includes access to mesh data, integrating closely with the computational framework. ``DomainField`` acts as the fundamental data container within this structure, offering both read and write to the ``internalField`` and ``boundaryFields`` provided by the ``DomainField``. The ``correctBoundaryConditions`` member function updates the field's boundary conditions, which are specified at construction. It does not hold the data but rather modifies the ``DomainField`` or ``BoundaryField`` container. @@ -26,7 +26,7 @@ Functionally, ``fvccVolField`` parallels several OpenFOAM classes such as ``volS Face Centered fields ^^^^^^^^^^^^^^^^^^^^ -The ``SurfaceField`` class stores the field values interpreted as face centers values. Additionally, it stores boundaries for the corresponding boundary conditions. This provides essential data for constructing the DSL (Domain Specific Language). The functionality also includes access to mesh data, integrating closely with the computational framework. +The ``SurfaceField`` class stores the field values interpreted as face centers values. Additionally, it stores boundaries for the corresponding boundary conditions. This provides essential data for constructing the DSL. The functionality also includes access to mesh data, integrating closely with the computational framework. ``DomainField`` acts as the fundamental data container within this structure, offering both read and to the ``internalField`` and ``boundaryField`` provided by the ``DomainField``. The ``correctBoundaryConditions`` member function updates field's boundary conditions, which are specified at construction. It does not hold the data, but modify the ``DomainField`` or ``BoundaryField`` container. diff --git a/doc/DSL/equation.rst b/doc/dsl/equation.rst similarity index 100% rename from doc/DSL/equation.rst rename to doc/dsl/equation.rst diff --git a/doc/DSL/index.rst b/doc/dsl/index.rst similarity index 100% rename from doc/DSL/index.rst rename to doc/dsl/index.rst diff --git a/doc/DSL/operator.rst b/doc/dsl/operator.rst similarity index 94% rename from doc/DSL/operator.rst rename to doc/dsl/operator.rst index 30c0d3c15..a56f2527c 100644 --- a/doc/DSL/operator.rst +++ b/doc/dsl/operator.rst @@ -9,11 +9,11 @@ The `Operator` implementation uses Type Erasure (more details `[1] divTerm = - Divergence(NeoFOAM::DSL::Operator::Type::Explicit, exec, ...); + NeoFOAM::dsl::Operator divTerm = + Divergence(NeoFOAM::dsl::Operator::Type::Explicit, exec, ...); - NeoFOAM::DSL::Operator ddtTerm = - TimeTerm(NeoFOAM::DSL::Operator::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 Operator needs to be able to be scaled: diff --git a/doc/finiteVolume/cellCentred/index.rst b/doc/finiteVolume/cellCentred/index.rst index 16b862c1e..c8c37828f 100644 --- a/doc/finiteVolume/cellCentred/index.rst +++ b/doc/finiteVolume/cellCentred/index.rst @@ -8,7 +8,6 @@ cellCenteredFiniteVolume :maxdepth: 2 :glob: - DSL.rst boundaryConditions.rst operators.rst stencil.rst diff --git a/doc/index.rst b/doc/index.rst index af18c2ae6..243b96f9e 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -26,7 +26,7 @@ Table of Contents contributing basics/index finiteVolume/cellCentred/index - DSL/index + dsl/index api/index Compatibility with OpenFOAM From 5ce7bb8874aa7b50b3e7d5426c015f8006f873f0 Mon Sep 17 00:00:00 2001 From: bevanwsjones Date: Sun, 27 Oct 2024 11:04:18 +0100 Subject: [PATCH 111/127] - Removed equation test (replaced by expression test). - Cleaned CMakeLists file. --- src/CMakeLists.txt | 1 - test/dsl/equation.cpp | 51 ------------------------------------------- 2 files changed, 52 deletions(-) delete mode 100644 test/dsl/equation.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 34d39e564..bebd717ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Unlicense # SPDX-FileCopyrightText: 2023 NeoFOAM authors -# add_subdirectory(DSL) add_library(NeoFOAM SHARED) diff --git a/test/dsl/equation.cpp b/test/dsl/equation.cpp deleted file mode 100644 index 11d917a71..000000000 --- a/test/dsl/equation.cpp +++ /dev/null @@ -1,51 +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 "common.hpp" -#include "NeoFOAM/DSL/equation.hpp" - -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 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); - } -} From 747e334ee19f84a8c482e9a6e9a36fff3e535002 Mon Sep 17 00:00:00 2001 From: bevanwsjones Date: Sun, 27 Oct 2024 11:08:14 +0100 Subject: [PATCH 112/127] - Added trailing white space to CMakeLists.txt in test/dsl --- test/dsl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dsl/CMakeLists.txt b/test/dsl/CMakeLists.txt index 419310dd5..c0b7c92f2 100644 --- a/test/dsl/CMakeLists.txt +++ b/test/dsl/CMakeLists.txt @@ -5,4 +5,4 @@ neofoam_unit_test(coeff) neofoam_unit_test(operator) neofoam_unit_test(expression) -add_subdirectory(timeIntegration) \ No newline at end of file +add_subdirectory(timeIntegration) From 0581b6f1cf93b1ce3daac2dba9ea630b1d5fa5ac Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sat, 2 Nov 2024 10:14:18 +0100 Subject: [PATCH 113/127] wip fix unused #include --- include/NeoFOAM/core/demangle.hpp | 12 +++++++----- include/NeoFOAM/core/dictionary.hpp | 2 -- include/NeoFOAM/core/executor/CPUExecutor.hpp | 1 - include/NeoFOAM/core/executor/GPUExecutor.hpp | 1 - include/NeoFOAM/core/executor/serialExecutor.hpp | 1 - .../cellCentred/interpolation/linear.hpp | 2 +- .../cellCentred/operators/gaussGreenGrad.hpp | 2 -- .../cellCentred/stencil/basicGeometryScheme.hpp | 3 --- include/NeoFOAM/mesh/unstructured/boundaryMesh.hpp | 1 - .../NeoFOAM/mesh/unstructured/unstructuredMesh.hpp | 4 ---- src/core/demangle.cpp | 3 +++ src/core/dictionary.cpp | 5 ++++- src/core/primitives/vector.cpp | 2 -- .../cellCentred/interpolation/linear.cpp | 1 - src/mesh/unstructured/unstructuredMesh.cpp | 3 +++ 15 files changed, 18 insertions(+), 25 deletions(-) diff --git a/include/NeoFOAM/core/demangle.hpp b/include/NeoFOAM/core/demangle.hpp index 818d2202d..17018d3fd 100644 --- a/include/NeoFOAM/core/demangle.hpp +++ b/include/NeoFOAM/core/demangle.hpp @@ -1,11 +1,13 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2024 NeoFOAM authors + #pragma once -// TODO For WIN builds, needs to be ifdef'ed out. -#include -#include -#include -#include + +#include // for bad_any_cast +#include // for operator<<, basic_ostream, cerr, endl, ostream +#include // for operator<<, string +#include // for type_info + namespace NeoFOAM { diff --git a/include/NeoFOAM/core/dictionary.hpp b/include/NeoFOAM/core/dictionary.hpp index 94cec83fe..f7230ae73 100644 --- a/include/NeoFOAM/core/dictionary.hpp +++ b/include/NeoFOAM/core/dictionary.hpp @@ -5,11 +5,9 @@ #include #include #include -#include #include #include "NeoFOAM/core/demangle.hpp" -#include "NeoFOAM/core/error.hpp" namespace NeoFOAM { diff --git a/include/NeoFOAM/core/executor/CPUExecutor.hpp b/include/NeoFOAM/core/executor/CPUExecutor.hpp index 36e0bc255..fe60439ee 100644 --- a/include/NeoFOAM/core/executor/CPUExecutor.hpp +++ b/include/NeoFOAM/core/executor/CPUExecutor.hpp @@ -3,7 +3,6 @@ #pragma once #include -#include namespace NeoFOAM { diff --git a/include/NeoFOAM/core/executor/GPUExecutor.hpp b/include/NeoFOAM/core/executor/GPUExecutor.hpp index d98ac974e..7ef88a0e1 100644 --- a/include/NeoFOAM/core/executor/GPUExecutor.hpp +++ b/include/NeoFOAM/core/executor/GPUExecutor.hpp @@ -3,7 +3,6 @@ #pragma once #include -#include namespace NeoFOAM { diff --git a/include/NeoFOAM/core/executor/serialExecutor.hpp b/include/NeoFOAM/core/executor/serialExecutor.hpp index b68cfe960..c2e7b9248 100644 --- a/include/NeoFOAM/core/executor/serialExecutor.hpp +++ b/include/NeoFOAM/core/executor/serialExecutor.hpp @@ -3,7 +3,6 @@ #pragma once #include -#include namespace NeoFOAM { diff --git a/include/NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp b/include/NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp index 1bce8bc7e..6f75c317c 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp @@ -6,8 +6,8 @@ #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/core/executor/executor.hpp" #include "NeoFOAM/finiteVolume/cellCentred/interpolation/surfaceInterpolation.hpp" -#include "NeoFOAM/mesh/unstructured.hpp" #include "NeoFOAM/finiteVolume/cellCentred/stencil/geometryScheme.hpp" +#include "NeoFOAM/mesh/unstructured.hpp" #include diff --git a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp index 117f155f0..ae0c7a07d 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp @@ -3,8 +3,6 @@ #pragma once -#include - #include #include "NeoFOAM/fields/field.hpp" diff --git a/include/NeoFOAM/finiteVolume/cellCentred/stencil/basicGeometryScheme.hpp b/include/NeoFOAM/finiteVolume/cellCentred/stencil/basicGeometryScheme.hpp index 640ca4d95..cb57879e0 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/stencil/basicGeometryScheme.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/stencil/basicGeometryScheme.hpp @@ -3,11 +3,8 @@ #pragma once -#include "NeoFOAM/core/primitives/vector.hpp" #include "NeoFOAM/core/primitives/scalar.hpp" -#include "NeoFOAM/core/primitives/label.hpp" #include "NeoFOAM/core/executor/executor.hpp" -#include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/finiteVolume/cellCentred/stencil/geometryScheme.hpp" namespace NeoFOAM::finiteVolume::cellCentred diff --git a/include/NeoFOAM/mesh/unstructured/boundaryMesh.hpp b/include/NeoFOAM/mesh/unstructured/boundaryMesh.hpp index eb5a91db4..32c10a624 100644 --- a/include/NeoFOAM/mesh/unstructured/boundaryMesh.hpp +++ b/include/NeoFOAM/mesh/unstructured/boundaryMesh.hpp @@ -2,7 +2,6 @@ // SPDX-FileCopyrightText: 2023 NeoFOAM authors #pragma once -#include #include #include "NeoFOAM/core/primitives/label.hpp" diff --git a/include/NeoFOAM/mesh/unstructured/unstructuredMesh.hpp b/include/NeoFOAM/mesh/unstructured/unstructuredMesh.hpp index 7644daac5..d6ccdfd3e 100644 --- a/include/NeoFOAM/mesh/unstructured/unstructuredMesh.hpp +++ b/include/NeoFOAM/mesh/unstructured/unstructuredMesh.hpp @@ -3,10 +3,6 @@ #pragma once -#include -#include - -#include "NeoFOAM/core/primitives/vector.hpp" #include "NeoFOAM/fields/fieldTypeDefs.hpp" #include "NeoFOAM/mesh/unstructured/boundaryMesh.hpp" #include "NeoFOAM/finiteVolume/cellCentred/stencil/stencilDataBase.hpp" diff --git a/src/core/demangle.cpp b/src/core/demangle.cpp index 9f605c79e..ec699810d 100644 --- a/src/core/demangle.cpp +++ b/src/core/demangle.cpp @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2024 NeoFOAM authors +#include // for __cxa_demangle +#include // for free + #include "NeoFOAM/core/demangle.hpp" diff --git a/src/core/dictionary.cpp b/src/core/dictionary.cpp index e5a8297d7..fb1abb0b1 100644 --- a/src/core/dictionary.cpp +++ b/src/core/dictionary.cpp @@ -1,9 +1,11 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 NeoFOAM authors +#include +#include // for operator<<, basic_ostream, endl, cerr, ostream + #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/error.hpp" -#include namespace NeoFOAM { @@ -13,6 +15,7 @@ void logOutRange( const std::unordered_map& data ) { + // TODO use NeoFOAM error here std::cerr << "Key not found: " << key << " \n" << "available keys are: \n" << std::accumulate( diff --git a/src/core/primitives/vector.cpp b/src/core/primitives/vector.cpp index 60b8054eb..7e7bbab28 100644 --- a/src/core/primitives/vector.cpp +++ b/src/core/primitives/vector.cpp @@ -1,9 +1,7 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 NeoFOAM authors - #include "NeoFOAM/core/primitives/vector.hpp" -#include "NeoFOAM/core/primitives/scalar.hpp" namespace NeoFOAM { diff --git a/src/finiteVolume/cellCentred/interpolation/linear.cpp b/src/finiteVolume/cellCentred/interpolation/linear.cpp index eb0c9de64..bc057cd62 100644 --- a/src/finiteVolume/cellCentred/interpolation/linear.cpp +++ b/src/finiteVolume/cellCentred/interpolation/linear.cpp @@ -4,7 +4,6 @@ #include #include "NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp" -#include "NeoFOAM/core/error.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" namespace NeoFOAM::finiteVolume::cellCentred diff --git a/src/mesh/unstructured/unstructuredMesh.cpp b/src/mesh/unstructured/unstructuredMesh.cpp index 1410e667a..f56542781 100644 --- a/src/mesh/unstructured/unstructuredMesh.cpp +++ b/src/mesh/unstructured/unstructuredMesh.cpp @@ -3,6 +3,9 @@ #include "NeoFOAM/mesh/unstructured/unstructuredMesh.hpp" +#include "NeoFOAM/core/primitives/vector.hpp" // for Vector + + namespace NeoFOAM { From 1ffb7269ddfe1f427b93d469ae8a7465fee06477 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sat, 2 Nov 2024 10:43:33 +0100 Subject: [PATCH 114/127] format files --- include/NeoFOAM/core/demangle.hpp | 8 ++++---- src/core/demangle.cpp | 4 ++-- src/core/dictionary.cpp | 2 +- src/mesh/unstructured/unstructuredMesh.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/NeoFOAM/core/demangle.hpp b/include/NeoFOAM/core/demangle.hpp index 17018d3fd..afc450037 100644 --- a/include/NeoFOAM/core/demangle.hpp +++ b/include/NeoFOAM/core/demangle.hpp @@ -3,10 +3,10 @@ #pragma once -#include // for bad_any_cast -#include // for operator<<, basic_ostream, cerr, endl, ostream -#include // for operator<<, string -#include // for type_info +#include // for bad_any_cast +#include // for operator<<, basic_ostream, cerr, endl, ostream +#include // for operator<<, string +#include // for type_info namespace NeoFOAM { diff --git a/src/core/demangle.cpp b/src/core/demangle.cpp index ec699810d..1d1309ae9 100644 --- a/src/core/demangle.cpp +++ b/src/core/demangle.cpp @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2024 NeoFOAM authors -#include // for __cxa_demangle -#include // for free +#include // for __cxa_demangle +#include // for free #include "NeoFOAM/core/demangle.hpp" diff --git a/src/core/dictionary.cpp b/src/core/dictionary.cpp index fb1abb0b1..9ab0124ce 100644 --- a/src/core/dictionary.cpp +++ b/src/core/dictionary.cpp @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2023 NeoFOAM authors #include -#include // for operator<<, basic_ostream, endl, cerr, ostream +#include // for operator<<, basic_ostream, endl, cerr, ostream #include "NeoFOAM/core/dictionary.hpp" #include "NeoFOAM/core/error.hpp" diff --git a/src/mesh/unstructured/unstructuredMesh.cpp b/src/mesh/unstructured/unstructuredMesh.cpp index f56542781..d6f86855a 100644 --- a/src/mesh/unstructured/unstructuredMesh.cpp +++ b/src/mesh/unstructured/unstructuredMesh.cpp @@ -3,7 +3,7 @@ #include "NeoFOAM/mesh/unstructured/unstructuredMesh.hpp" -#include "NeoFOAM/core/primitives/vector.hpp" // for Vector +#include "NeoFOAM/core/primitives/vector.hpp" // for Vector namespace NeoFOAM From 08221c3057ddc4f593f5dae5cb73bb8cd1623aa2 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Sat, 2 Nov 2024 11:07:20 +0100 Subject: [PATCH 115/127] wip fix unused #include --- include/NeoFOAM/core/executor/CPUExecutor.hpp | 2 +- include/NeoFOAM/core/primitives/vector.hpp | 3 ++- src/CMakeLists.txt | 1 - src/core/kokkos.cpp | 16 ---------------- .../cellCentred/operators/gaussGreenDiv.cpp | 3 --- .../cellCentred/operators/gaussGreenGrad.cpp | 2 -- 6 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 src/core/kokkos.cpp diff --git a/include/NeoFOAM/core/executor/CPUExecutor.hpp b/include/NeoFOAM/core/executor/CPUExecutor.hpp index fe60439ee..c51362fe8 100644 --- a/include/NeoFOAM/core/executor/CPUExecutor.hpp +++ b/include/NeoFOAM/core/executor/CPUExecutor.hpp @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2023 NeoFOAM authors #pragma once -#include +#include // IWYU pragma: keep namespace NeoFOAM { diff --git a/include/NeoFOAM/core/primitives/vector.hpp b/include/NeoFOAM/core/primitives/vector.hpp index 9d6f7133a..1843adefd 100644 --- a/include/NeoFOAM/core/primitives/vector.hpp +++ b/include/NeoFOAM/core/primitives/vector.hpp @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 NeoFOAM authors + #pragma once -#include +#include // IWYU pragma: keep #include "NeoFOAM/core/primitives/scalar.hpp" #include "NeoFOAM/core/primitives/label.hpp" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bebd717ff..8d8136c33 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,7 +12,6 @@ target_sources( "core/dictionary.cpp" "core/demangle.cpp" "core/tokenList.cpp" - "core/kokkos.cpp" "executor/CPUExecutor.cpp" "executor/GPUExecutor.cpp" "executor/serialExecutor.cpp" diff --git a/src/core/kokkos.cpp b/src/core/kokkos.cpp deleted file mode 100644 index 577935344..000000000 --- a/src/core/kokkos.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -// SPDX-FileCopyrightText: 2023 NeoFOAM authors - -#include - -namespace NeoFOAM -{ - -struct HelloWorld -{ - KOKKOS_INLINE_FUNCTION - void operator()(const int i) const { printf("Hello from i = %i\n", i); } -}; - -void foo() { Kokkos::parallel_for("HelloWorld", 15, HelloWorld()); } -} // namespace NeoFOAM diff --git a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp index a43d204d0..85e0ef570 100644 --- a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp +++ b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 NeoFOAM authors -#include - #include "NeoFOAM/core/parallelAlgorithms.hpp" #include "NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenDiv.hpp" -#include "NeoFOAM/finiteVolume/cellCentred/stencil/geometryScheme.hpp" namespace NeoFOAM::finiteVolume::cellCentred { diff --git a/src/finiteVolume/cellCentred/operators/gaussGreenGrad.cpp b/src/finiteVolume/cellCentred/operators/gaussGreenGrad.cpp index e29026822..94bd88873 100644 --- a/src/finiteVolume/cellCentred/operators/gaussGreenGrad.cpp +++ b/src/finiteVolume/cellCentred/operators/gaussGreenGrad.cpp @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 NeoFOAM authors -#include - #include "NeoFOAM/finiteVolume/cellCentred/operators/gaussGreenGrad.hpp" #include "NeoFOAM/finiteVolume/cellCentred/interpolation/linear.hpp" #include "NeoFOAM/core/parallelAlgorithms.hpp" From 1b9c574e61f6a133b93e8d232ef0a66ca6664986 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 09:53:02 +0100 Subject: [PATCH 116/127] fix docstrings --- include/NeoFOAM/dsl/ddt.hpp | 4 ---- include/NeoFOAM/dsl/operator.hpp | 3 +-- .../finiteVolume/cellCentred/fields/geometricField.hpp | 5 +++-- .../NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp | 6 ++++-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/NeoFOAM/dsl/ddt.hpp b/include/NeoFOAM/dsl/ddt.hpp index 06a4b5ba3..4c7ec842b 100644 --- a/include/NeoFOAM/dsl/ddt.hpp +++ b/include/NeoFOAM/dsl/ddt.hpp @@ -11,8 +11,6 @@ namespace NeoFOAM::dsl::temporal { - -// TODO add free factory function template class Ddt : public OperatorMixin { @@ -39,12 +37,10 @@ class Ddt : public OperatorMixin // 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); }; - } // namespace NeoFOAM diff --git a/include/NeoFOAM/dsl/operator.hpp b/include/NeoFOAM/dsl/operator.hpp index 345432fa9..78b3a3360 100644 --- a/include/NeoFOAM/dsl/operator.hpp +++ b/include/NeoFOAM/dsl/operator.hpp @@ -214,10 +214,9 @@ Operator operator*([[maybe_unused]] CoeffFunction coeffFunc, const Operator& lhs } /* @class OperatorMixin - * @brief A mixin class to represent simplify implementations of concrete operators + * @brief A mixin class to simplify implementations of concrete operators * in NeoFOAMs dsl * - * * @ingroup dsl */ template diff --git a/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp b/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp index d2fb1dea4..7e22c8fb1 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/fields/geometricField.hpp @@ -33,7 +33,7 @@ class GeometricFieldMixin * * @param exec The executor object. * @param mesh The unstructured mesh object. - * @param field The domain field object. + * @param domainField The domain field object. */ GeometricFieldMixin( const Executor& exec, @@ -48,7 +48,8 @@ class GeometricFieldMixin * * @param exec The executor object. * @param mesh The unstructured mesh object. - * @param field The domain field object. + * @param internalField The internal field object. + * @param boundaryFields The boundary field object. */ GeometricFieldMixin( const Executor& exec, diff --git a/include/NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp b/include/NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp index f9ba40463..3e834d470 100644 --- a/include/NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp +++ b/include/NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp @@ -49,7 +49,8 @@ class VolumeField : public GeometricFieldMixin /* @brief Constructor for a VolumeField with a given internal field * * @param mesh The underlying mesh - * @param internalField the underlying internal field + * @param domainField the underlying domain field i.e. combination of internal and boundary + * fields * @param boundaryConditions a vector of boundary conditions */ VolumeField( @@ -62,10 +63,11 @@ class VolumeField : public GeometricFieldMixin boundaryConditions_(boundaryConditions) {} - /* @brief Constructor for a VolumeField with a given internal field + /* @brief Constructor for a VolumeField with a given internal and boundary field * * @param mesh The underlying mesh * @param internalField the underlying internal field + * @param boundaryFields the underlying boundary data fields * @param boundaryConditions a vector of boundary conditions */ VolumeField( From a8ca05d008ddcb0e8eea5dd9b8d24a5bd2a9577f Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 09:56:58 +0100 Subject: [PATCH 117/127] remove unused headers --- include/NeoFOAM/dsl/expression.hpp | 1 - include/NeoFOAM/timeIntegration/forwardEuler.hpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/include/NeoFOAM/dsl/expression.hpp b/include/NeoFOAM/dsl/expression.hpp index 90808f1d2..996df349e 100644 --- a/include/NeoFOAM/dsl/expression.hpp +++ b/include/NeoFOAM/dsl/expression.hpp @@ -2,7 +2,6 @@ // SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors #pragma once -#include #include #include #include diff --git a/include/NeoFOAM/timeIntegration/forwardEuler.hpp b/include/NeoFOAM/timeIntegration/forwardEuler.hpp index 0dda395a1..a02d48e46 100644 --- a/include/NeoFOAM/timeIntegration/forwardEuler.hpp +++ b/include/NeoFOAM/timeIntegration/forwardEuler.hpp @@ -4,8 +4,6 @@ #pragma once -#include - #include "NeoFOAM/fields/field.hpp" #include "NeoFOAM/timeIntegration/timeIntegration.hpp" From 0ba618aca6436b7c3adc22fe0480007f24073709 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 10:06:45 +0100 Subject: [PATCH 118/127] add [[nodiscard]] --- include/NeoFOAM/dsl/expression.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/NeoFOAM/dsl/expression.hpp b/include/NeoFOAM/dsl/expression.hpp index 996df349e..a7e732640 100644 --- a/include/NeoFOAM/dsl/expression.hpp +++ b/include/NeoFOAM/dsl/expression.hpp @@ -107,19 +107,19 @@ class Expression std::vector explicitOperators_; }; -Expression operator+(Expression lhs, const Expression& rhs) +[[nodiscard]] Expression operator+(Expression lhs, const Expression& rhs) { lhs.addExpression(rhs); return lhs; } -Expression operator+(Expression lhs, const Operator& rhs) +[[nodiscard]] Expression operator+(Expression lhs, const Operator& rhs) { lhs.addOperator(rhs); return lhs; } -Expression operator+(const Operator& lhs, const Operator& rhs) +[[nodiscard]] Expression operator+(const Operator& lhs, const Operator& rhs) { Expression expr(lhs.exec()); expr.addOperator(lhs); @@ -127,7 +127,7 @@ Expression operator+(const Operator& lhs, const Operator& rhs) return expr; } -Expression operator*(scalar scale, const Expression& es) +[[nodiscard]] Expression operator*(scalar scale, const Expression& es) { Expression expr(es.exec()); for (const auto& Operator : es.temporalOperators()) @@ -145,19 +145,19 @@ Expression operator*(scalar scale, const Expression& es) return expr; } -Expression operator-(Expression lhs, const Expression& rhs) +[[nodiscard]] Expression operator-(Expression lhs, const Expression& rhs) { lhs.addExpression(-1.0 * rhs); return lhs; } -Expression operator-(Expression lhs, const Operator& rhs) +[[nodiscard]] Expression operator-(Expression lhs, const Operator& rhs) { lhs.addOperator(-1.0 * rhs); return lhs; } -Expression operator-(const Operator& lhs, const Operator& rhs) +[[nodiscard]] Expression operator-(const Operator& lhs, const Operator& rhs) { Expression expr(lhs.exec()); expr.addOperator(lhs); From 8d9b954054d35a400de139113a2d13736662e634 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 10:19:29 +0100 Subject: [PATCH 119/127] fix warnings --- .../cellCentred/operators/gaussGreenDiv.cpp | 15 +++++++-------- src/mesh/unstructured/unstructuredMesh.cpp | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp index 85e0ef570..89d16448f 100644 --- a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp +++ b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp @@ -36,13 +36,13 @@ void computeDiv( for (size_t i = 0; i < nInternalFaces; i++) { scalar flux = surfFaceFlux[i] * surfPhif[i]; - surfDivPhi[surfOwner[i]] += flux; - surfDivPhi[surfNeighbour[i]] -= flux; + surfDivPhi[static_cast(surfOwner[i])] += flux; + surfDivPhi[static_cast(surfNeighbour[i])] -= flux; } for (size_t i = nInternalFaces; i < surfPhif.size(); i++) { - int32_t own = surfFaceCells[i - nInternalFaces]; + auto own = static_cast(surfFaceCells[i - nInternalFaces]); scalar valueOwn = surfFaceFlux[i] * surfPhif[i]; surfDivPhi[own] += valueOwn; } @@ -59,8 +59,8 @@ void computeDiv( {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); + Kokkos::atomic_add(&surfDivPhi[static_cast(surfOwner[i])], flux); + Kokkos::atomic_sub(&surfDivPhi[static_cast(surfNeighbour[i])], flux); } ); @@ -68,7 +68,7 @@ void computeDiv( exec, {nInternalFaces, surfPhif.size()}, KOKKOS_LAMBDA(const size_t i) { - int32_t own = surfFaceCells[i - nInternalFaces]; + auto own = static_cast(surfFaceCells[i - nInternalFaces]); scalar valueOwn = surfFaceFlux[i] * surfPhif[i]; Kokkos::atomic_add(&surfDivPhi[own], valueOwn); } @@ -85,7 +85,7 @@ void computeDiv( void computeDiv( const SurfaceField& faceFlux, const VolumeField& phi, - const SurfaceInterpolation& surfInterp, + [[maybe_unused]] const SurfaceInterpolation& surfInterp, Field& divPhi ) { @@ -105,7 +105,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)) { diff --git a/src/mesh/unstructured/unstructuredMesh.cpp b/src/mesh/unstructured/unstructuredMesh.cpp index d6f86855a..51e529e7e 100644 --- a/src/mesh/unstructured/unstructuredMesh.cpp +++ b/src/mesh/unstructured/unstructuredMesh.cpp @@ -93,7 +93,7 @@ UnstructuredMesh createSingleCellMesh(const Executor exec) ); return UnstructuredMesh( {exec, {{0, 0, 0}, {0, 1, 0}, {1, 1, 0}, {1, 0, 0}}}, // points, - {exec, {1}}, // cellVolumes + {exec, 1}, // cellVolumes {exec, {{0.5, 0.5, 0.0}}}, // cellCentres faceAreasVectors, faceCentresVectors, From 34deb2168fab85f674bf3b39df27a8f31e347a23 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 10:26:30 +0100 Subject: [PATCH 120/127] update documentatioin --- doc/dsl/equation.rst | 14 +++++++------- doc/dsl/index.rst | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/dsl/equation.rst b/doc/dsl/equation.rst index 1a059d01b..ea02c56b2 100644 --- a/doc/dsl/equation.rst +++ b/doc/dsl/equation.rst @@ -1,9 +1,9 @@ -Equation +Expression --------- -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: +The `Expression` class in NeoFOAM holds a set of operators to express an expression and ultimately helps to formulate equations. +Its core responsibility lies in the answering of the following questions: - How to discretize the spatial terms? - In OpenFOAM this information is provided in **fvSchemes** @@ -15,7 +15,7 @@ Its core responsibility lie in the answering of the following questions: 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 delayed, other numerical integration strategies (e.g. RK methods or even sub-stepping within an the equation) are possible. -To implement lazy evaluation, the `Equation` stores 3 vectors: +To implement lazy evaluation, the `Expression` stores 3 vectors: .. mermaid:: @@ -36,7 +36,7 @@ To implement lazy evaluation, the `Equation` stores 3 vectors: +explicitOperation(...) +implicitOperation(...) } - class Equation { + class Expression { +temporalTerms_: vector~Operator~ +implicitTerms_: vector~Operator~ +explicitTerms_: vector~Operator~ @@ -44,7 +44,7 @@ To implement lazy evaluation, the `Equation` stores 3 vectors: Operator <|-- DivOperator Operator <|-- TemporalOperator Operator <|-- Others - Equation <|-- Operator + Expression <|-- Operator -Thus, an `Equation` consists of multiple `Operators` which are either explicit, implicit, or temporal. +Thus, an `Expression` 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 840f7712f..9ad9fdf79 100644 --- a/doc/dsl/index.rst +++ b/doc/dsl/index.rst @@ -3,8 +3,8 @@ 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. +The concept of a Domain Specific Language (DSL) allows to 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, while 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: From c995f6277b66bd589653d983d0f967ce9d7d22ec Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 10:27:57 +0100 Subject: [PATCH 121/127] update docstring --- include/NeoFOAM/dsl/ddt.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/NeoFOAM/dsl/ddt.hpp b/include/NeoFOAM/dsl/ddt.hpp index 4c7ec842b..57f41cb2d 100644 --- a/include/NeoFOAM/dsl/ddt.hpp +++ b/include/NeoFOAM/dsl/ddt.hpp @@ -35,8 +35,7 @@ class Ddt : public OperatorMixin private: }; -// see -// https://github.com/exasim-project/NeoFOAM/blob/dsl/operatorIntergration/include/NeoFOAM/finiteVolume/cellCentred/operators/explicitOperators/expOp.hpp +/* @brief factory function to create a Ddt term as ddt() */ template Ddt ddt(FieldType& in) { From f4c2e975b195f4b3c8a5e3e19099657d2725a890 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 10:29:21 +0100 Subject: [PATCH 122/127] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c4050cc2..7fa0274b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # Version 0.1.0 (unreleased) -- Implement a DSL interface []() +- Implement a basic DSL interface [#102](https://github.com/exasim-project/NeoFOAM/pull/102) - 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 d270cf3070676b97b298e0b590ba05d047b24a3b Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 10:34:30 +0100 Subject: [PATCH 123/127] clean-up --- include/NeoFOAM/dsl/ddt.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/NeoFOAM/dsl/ddt.hpp b/include/NeoFOAM/dsl/ddt.hpp index 57f41cb2d..fda1de19c 100644 --- a/include/NeoFOAM/dsl/ddt.hpp +++ b/include/NeoFOAM/dsl/ddt.hpp @@ -31,8 +31,6 @@ class Ddt : public OperatorMixin { NF_ERROR_EXIT("Not implemented"); } - -private: }; /* @brief factory function to create a Ddt term as ddt() */ From d1c25adb69be4e33a0b0c2665b4ece1513aee62e Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 10:35:58 +0100 Subject: [PATCH 124/127] clean-up --- include/NeoFOAM/dsl/operator.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/NeoFOAM/dsl/operator.hpp b/include/NeoFOAM/dsl/operator.hpp index 78b3a3360..cd19db332 100644 --- a/include/NeoFOAM/dsl/operator.hpp +++ b/include/NeoFOAM/dsl/operator.hpp @@ -73,9 +73,6 @@ 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); } @@ -105,8 +102,6 @@ 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; @@ -161,9 +156,6 @@ 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 { From df8fc573636397fa7a9c4a17d456b21b70363d77 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 10:58:16 +0100 Subject: [PATCH 125/127] update documentation --- doc/dsl/index.rst | 14 +++++++------- doc/dsl/operator.rst | 18 ++---------------- include/NeoFOAM/dsl/expression.hpp | 2 -- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/doc/dsl/index.rst b/doc/dsl/index.rst index 9ad9fdf79..5086aaead 100644 --- a/doc/dsl/index.rst +++ b/doc/dsl/index.rst @@ -30,7 +30,8 @@ To solve the continuity equation in OpenFOAM with the PISO or SIMPLE algorithm, 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 + - individual terms are eagerly evaluated, resulting in unnecessary use of temporaries + - the sparse matrix is always an 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: @@ -39,7 +40,7 @@ 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 use of standard matrix formats 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: @@ -48,12 +49,12 @@ The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adop dsl::Equation UEqn ( - fvcc::impOp::ddt(U) - + fvcc::impOp::div(phi, U) - - fvcc::impOp::laplacian(nu, U) + dsl::temporal::ddt(U) + + dsl::implicit::div(phi, U) + - dsl::implicit::laplacian(nu, U) ) - solve(UEqn == -fvcc::expOp::grad(p)); + solve(UEqn == -dsl::explicit::grad(p), U, fvSchemes, fvSolution); In contrast to OpenFOAM, here the majority of the work is done in the solve step. @@ -62,7 +63,6 @@ After the system is assembled or solved, it provides access to the linear system - .. toctree:: :maxdepth: 2 :glob: diff --git a/doc/dsl/operator.rst b/doc/dsl/operator.rst index a56f2527c..73294ae97 100644 --- a/doc/dsl/operator.rst +++ b/doc/dsl/operator.rst @@ -3,7 +3,7 @@ Operator 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. +An `Operator` is either explicit, implicit or temporal, and can be scalable by 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: @@ -42,10 +42,8 @@ To add a user-defined `Operator`, a new derived class must be created, inheritin - 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: @@ -103,16 +101,4 @@ An example is given below: NeoFOAM::scalar value = 1.0; }; -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 - - 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; } - - } +The required scaling of the term is handled by the `Coeff` type which can be retrieved by the `getCoefficient` function of `Operator`. diff --git a/include/NeoFOAM/dsl/expression.hpp b/include/NeoFOAM/dsl/expression.hpp index a7e732640..ac2e2ef68 100644 --- a/include/NeoFOAM/dsl/expression.hpp +++ b/include/NeoFOAM/dsl/expression.hpp @@ -11,8 +11,6 @@ #include "NeoFOAM/dsl/operator.hpp" #include "NeoFOAM/core/error.hpp" -#include "NeoFOAM/finiteVolume/cellCentred/fields/volumeField.hpp" - namespace NeoFOAM::dsl { From 5eeb6faaaed5d607d7ed4939e971e282c08615ca Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 11:17:17 +0100 Subject: [PATCH 126/127] fix interpolation --- src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp index 89d16448f..b2ac722d3 100644 --- a/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp +++ b/src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp @@ -93,8 +93,10 @@ void computeDiv( const auto exec = phi.exec(); SurfaceField phif(exec, mesh, createCalculatedBCs(mesh)); const auto surfFaceCells = mesh.boundaryMesh().faceCells().span(); - // FIXME not implemented - // surfInterp.interpolate(phif, faceFlux, phi); + + // TODO check if copy can be avoided + auto faceFluxCopy = SurfaceField(faceFlux); + surfInterp.interpolate(phif, phi, faceFluxCopy); auto surfDivPhi = divPhi.span(); From 05e94dbfccf5112302f75c53c1ba88771b889019 Mon Sep 17 00:00:00 2001 From: Gregor Olenik Date: Tue, 26 Nov 2024 11:17:45 +0100 Subject: [PATCH 127/127] update documentation --- doc/dsl/index.rst | 2 +- doc/dsl/operator.rst | 55 +------------------------------------------- 2 files changed, 2 insertions(+), 55 deletions(-) diff --git a/doc/dsl/index.rst b/doc/dsl/index.rst index 5086aaead..586bf2c46 100644 --- a/doc/dsl/index.rst +++ b/doc/dsl/index.rst @@ -57,7 +57,7 @@ The NeoFOAM DSL is designed as drop in replacement for OpenFOAM DSL and the adop solve(UEqn == -dsl::explicit::grad(p), U, fvSchemes, fvSolution); -In contrast to OpenFOAM, here the majority of the work is done in the solve step. +In contrast to OpenFOAM, the matrix assembly is deferred till the solve step. Hence the majority of the computational work is performed during 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. diff --git a/doc/dsl/operator.rst b/doc/dsl/operator.rst index 73294ae97..12adb5780 100644 --- a/doc/dsl/operator.rst +++ b/doc/dsl/operator.rst @@ -46,59 +46,6 @@ To add a user-defined `Operator`, a new derived class must be created, inheritin - exec: get the executor - volumeField: get the volume field -An example is given below: - -.. code-block:: cpp - - class CustomOperator : public dsl::OperatorMixin - { - - 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 OperatorMixin - // 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::Operator::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::Operator::Type termType_; - - - const NeoFOAM::Executor exec_; - std::size_t nCells_; - NeoFOAM::scalar value = 1.0; - }; +An example can be found in `test/dsl/operator.cpp`. The required scaling of the term is handled by the `Coeff` type which can be retrieved by the `getCoefficient` function of `Operator`.