-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #151 from exasim-project/impl/scalingField
Implementation of operator coefficient handler
- Loading branch information
Showing
8 changed files
with
239 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
|
||
} | ||
|
||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters