Skip to content

Commit

Permalink
Merge pull request #151 from exasim-project/impl/scalingField
Browse files Browse the repository at this point in the history
Implementation of operator coefficient handler
  • Loading branch information
HenningScheufler authored Oct 6, 2024
2 parents d2109e7 + e2af6cd commit 7377af8
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 14 deletions.
110 changes: 110 additions & 0 deletions include/NeoFOAM/DSL/coeff.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// 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<scalar>& field)
: coeff_(coeff), span_(field.span()), hasSpan_(true)
{}

Coeff(const Field<scalar>& 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<const scalar> 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<const scalar> 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<scalar>& 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
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ class GaussGreenDiv
div(VolumeField<scalar>& divPhi, const SurfaceField<scalar>& faceFlux, VolumeField<scalar>& phi
);

void
div(Field<scalar>& divPhi, const SurfaceField<scalar>& faceFlux, VolumeField<scalar>& phi
);
void div(Field<scalar>& divPhi, const SurfaceField<scalar>& faceFlux, VolumeField<scalar>& phi);

private:

Expand Down
3 changes: 2 additions & 1 deletion src/finiteVolume/cellCentred/operators/gaussGreenDiv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ void computeDiv(
const auto exec = phi.exec();
SurfaceField<scalar> phif(exec, mesh, createCalculatedBCs<scalar>(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();

Expand Down
4 changes: 2 additions & 2 deletions src/finiteVolume/cellCentred/timeIntegration/forwardEuler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<NeoFOAM::GPUExecutor>(eqnSystem_.exec()))
{
Kokkos::fence();
Kokkos::fence();
}
}

Expand Down
3 changes: 2 additions & 1 deletion test/dsl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
120 changes: 120 additions & 0 deletions test/dsl/coeff.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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 <catch2/catch_session.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators_all.hpp>
#include <catch2/benchmark/catch_benchmark.hpp>

#include "NeoFOAM/fields/field.hpp"
#include "NeoFOAM/DSL/coeff.hpp"

using Field = NeoFOAM::Field<NeoFOAM::scalar>;
using Coeff = NeoFOAM::DSL::Coeff;
namespace detail = NeoFOAM::DSL::detail;


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};
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;
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;
detail::toField(f, res);
auto hostResF = res.copyToHost();
REQUIRE(hostResF.data()[0] == 12.0);
REQUIRE(hostResF.data()[1] == 12.0);
REQUIRE(hostResF.data()[2] == 12.0);
}

SECTION("evaluation in parallelFor" + execName)
{
size_t size = 3;

NeoFOAM::Field<NeoFOAM::scalar> fieldA(exec, size, 0.0);
NeoFOAM::Field<NeoFOAM::scalar> 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<NeoFOAM::scalar> 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<NeoFOAM::scalar> fieldA(exec, size, 0.0);
NeoFOAM::Field<NeoFOAM::scalar> 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);
}

}



}
4 changes: 2 additions & 2 deletions test/dsl/dsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ class Divergence

NeoFOAM::scalar getField(const NeoFOAM::Field<NeoFOAM::scalar>& source)
{
auto sourceField = source.copyToHost().span();
return sourceField[0];
auto sourceField = source.copyToHost();
return sourceField.span()[0];
}

TEST_CASE("DSL")
Expand Down
5 changes: 0 additions & 5 deletions test/fields/field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,17 +274,12 @@ TEST_CASE("getSpans")
NeoFOAM::Executor(NeoFOAM::GPUExecutor {})
);


NeoFOAM::Field<NeoFOAM::scalar> a(exec, 3, 1.0);
NeoFOAM::Field<NeoFOAM::scalar> b(exec, 3, 2.0);
NeoFOAM::Field<NeoFOAM::scalar> 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]; }
);
Expand Down

0 comments on commit 7377af8

Please sign in to comment.