Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implementation of operator coefficient handler #151

Merged
merged 7 commits into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Collaborator

Choose a reason for hiding this comment

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

The coeff would be used inside the Operator and the cases of multiplying two coeff should Not excist

{
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
Loading