Skip to content

Commit 64a9c9b

Browse files
committed
docs
refs wording additions from review wording some work
1 parent 06931a0 commit 64a9c9b

File tree

5 files changed

+85
-47
lines changed

5 files changed

+85
-47
lines changed

docs/website/01_framework/dirichletBCs.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,25 @@ The interface of `#!cpp Ikarus::DirichletValues` is represented by the following
2424
Ikarus::DirichletValues dirichletValues2(basis); // (1)!
2525
void fixBoundaryDOFs(f); // (2)!
2626
void fixDOFs(f); // (3)!
27-
void fixIthDOF(i); // (4)!
27+
void setSingleDOF(i, bool flag); // (4)!
2828
const auto& basis() const; // (5)!
2929
bool isConstrained(std::size_t i) const; // (6)!
3030
auto fixedDOFsize() const; // (7)!
3131
auto size() const ; // (8)!
32+
auto reset(); // (9)!
3233
```
3334
3435
1. Create class by inserting a global basis, [@sander2020dune] Chapter 10.
3536
2. Accepts a functor to fix boundary degrees of freedom. `f` is a functor that will be called with the boolean vector of fixed boundary.
3637
degrees of freedom and the usual arguments of `Dune::Functions::forEachBoundaryDOF`, as defined on page 388 of the Dune
3738
[@sander2020dune] book.
3839
3. A more general version of `fixBoundaryDOFs`. Here, a functor is to be provided that accepts a basis and the corresponding boolean
39-
4. A function that helps to fix the $i$-th degree of freedom
40+
4. A function that helps to fix or unfix the $i$-th degree of freedom
4041
vector considering the Dirichlet degrees of freedom.
4142
5. Returns the underlying basis.
4243
6. Indicates whether the degree of freedom `i` is fixed.
4344
7. Returns the number of fixed degrees of freedom.
4445
8. Returns the number of all dirichlet degrees of freedom.
46+
9. Resets the whole container
4547
4648
\bibliography

ikarus/python/dirichletvalues/dirichletvalues.hh

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@
2424
// PYBIND11_MAKE_OPAQUE(std::vector<bool>);
2525
namespace Ikarus::Python {
2626

27-
template <class DirichletValues, typename CppVisitor>
28-
void forwardCorrectFunction(DirichletValues& dirichletValues, const pybind11::function& functor,
29-
CppVisitor&& cppFunction) {
27+
template <class DirichletValues>
28+
void forwardCorrectFunction(DirichletValues& dirichletValues, const pybind11::function& functor, auto&& cppFunction) {
3029
using Basis = typename DirichletValues::Basis;
3130
using Intersection = typename Basis::GridView::Intersection;
3231
using BackendType = typename DirichletValues::BackendType;
@@ -46,24 +45,24 @@ void forwardCorrectFunction(DirichletValues& dirichletValues, const pybind11::fu
4645
size_t numParams = pybind11::len(result);
4746

4847
if (numParams == 2) {
49-
auto& function = functor.template cast<const FixBoundaryDOFsWithGlobalIndexFunction>();
50-
auto lambda = [&](BackendType& vec, const MultiIndex& indexGlobal) {
48+
auto function = functor.template cast<const FixBoundaryDOFsWithGlobalIndexFunction>();
49+
auto lambda = [&](BackendType& vec, const MultiIndex& indexGlobal) {
5150
// we explicitly only allow flat indices
5251
function(vec.vector(), indexGlobal[0]);
5352
};
5453
cppFunction(lambda);
5554

5655
} else if (numParams == 3) {
57-
auto& function = functor.template cast<const FixBoundaryDOFsWithLocalViewFunction>();
58-
auto lambda = [&](BackendType& vec, int localIndex, auto& lv) {
56+
auto function = functor.template cast<const FixBoundaryDOFsWithLocalViewFunction>();
57+
auto lambda = [&](BackendType& vec, int localIndex, auto& lv) {
5958
auto lvWrapper = LocalViewWrapper(lv.rootLocalView());
6059
function(vec.vector(), localIndex, lvWrapper);
6160
};
6261
cppFunction(lambda);
6362

6463
} else if (numParams == 4) {
65-
auto& function = functor.template cast<const FixBoundaryDOFsWithIntersectionFunction>();
66-
auto lambda = [&](BackendType& vec, int localIndex, auto& lv, const Intersection& intersection) {
64+
auto function = functor.template cast<const FixBoundaryDOFsWithIntersectionFunction>();
65+
auto lambda = [&](BackendType& vec, int localIndex, auto& lv, const Intersection& intersection) {
6766
auto lvWrapper = LocalViewWrapper(lv.rootLocalView());
6867
function(vec.vector(), localIndex, lvWrapper, intersection);
6968
};
@@ -80,15 +79,21 @@ void forwardCorrectFunction(DirichletValues& dirichletValues, const pybind11::fu
8079
* This function registers Python bindings for a DirichletValues class, allowing it to be used in Python scripts.
8180
* The registered class will have an initializer that takes a `Basis` object. It exposes several member functions to
8281
* Python:
83-
* - `fixBoundaryDOFs(f)`: Fixes boundary degrees of freedom. This function can be overloaded with the following
84-
* arguments:
85-
* - using a user-defined function `f`.
86-
* - using a user-defined function `f` with a `LocalView` argument.
87-
* - using a user-defined function `f` with `LocalView` and `Intersection` arguments.
88-
* - `fixDOFs(f)`: Fixes boundary degrees of freedom using a user-defined function `f` with the boolean vector and
89-
* the basis as arguments.
90-
* - - `fixBoundaryDOFsOfSubSpaceBasis(f)`: Same implementation but you can pass a index of a child basis of a Power
91-
* Basis
82+
* - `fixBoundaryDOFs(f)`: Fixes boundary degrees of freedom using a user-defined function `f` than can be called
83+
* with the following arguments:
84+
* - with the boolean vector and the global index.
85+
* - with the boolean vector, the local index and the `LocalView`.
86+
* - with the boolean vector, the local index, the `LocalView` and the `Intersection`.
87+
* - `fixDOFs(f)`: Fixes boundary degrees of freedom using a user-defined function `f` with the basis and the boolean
88+
* vector as arguments.
89+
* - `setSingleDOF(i, flag: bool): Fixes or unfixes DOF with index i
90+
* - `isConstrained(i)`: Checks whether index i is constrained
91+
* - `reset()`: Resets the whole container
92+
*
93+
* The following properties can be accessed:
94+
* - `container`: the underlying container of dirichlet flags (as a const reference)
95+
* - `size`: the size of the underlying basis
96+
* - `fixedDOFsize`: the amount of DOFs currently fixed
9297
*
9398
* \tparam DirichletValues The DirichletValues class to be registered.
9499
* \tparam options Variadic template parameters for additional options when defining the Python class.
@@ -120,12 +125,12 @@ void registerDirichletValues(pybind11::handle scope, pybind11::class_<DirichletV
120125

121126
cls.def(pybind11::init([](const Basis& basis) { return new DirichletValues(basis); }), pybind11::keep_alive<1, 2>());
122127

123-
cls.def_property_readonly("container", &DirichletValues::container);
128+
cls.def_property_readonly("container", &DirichletValues::container, pybind11::return_value_policy::reference);
124129
cls.def_property_readonly("size", &DirichletValues::size);
125130
cls.def_property_readonly("fixedDOFsize", &DirichletValues::fixedDOFsize);
126131
cls.def("isConstrained", [](DirichletValues& self, std::size_t i) -> bool { return self.isConstrained(i); });
127-
128-
cls.def("fixIthDOF", [](DirichletValues& self, std::size_t i) { self.fixIthDOF(MultiIndex(std::array{i})); });
132+
cls.def("setSingleDOF", [](DirichletValues& self, std::size_t i, bool flag) { self.setSingleDOF(i, flag); });
133+
cls.def("reset", &DirichletValues::reset);
129134

130135
cls.def("fixDOFs",
131136
[](DirichletValues& self, const std::function<void(const Basis&, Eigen::Ref<Eigen::VectorX<bool>>)>& f) {

ikarus/python/test/testdirichletvalues.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import debug_info
55

6-
debug_info.unsetDebugFlags()
6+
debug_info.setDebugFlags()
77

88
import ikarus as iks
99
import dune.grid
@@ -42,7 +42,7 @@ def fixOneIndex(vec, globalIndex):
4242
# This is equivalent to values[0] == True, but this syntax is discouraged by PEP
4343
assert dirichletValues.container[0]
4444

45-
# Note that the result of localView.index(localIndex) is a multiIndex even for a flat basis, the localIndex appears to be a int
45+
# Note that the result of localView.index(localIndex) is a multiIndex even for a flat basis, the localIndex is an int
4646
def fixAnotherIndexWithLocalView(vec, localIndex, localView):
4747
if localView.index(localIndex) == [4]:
4848
vec[localView.index(localIndex)] = True
@@ -52,7 +52,9 @@ def fixAnotherIndexWithLocalView(vec, localIndex, localView):
5252
assert isinstance(localView.index(localIndex)[0], int)
5353

5454
dirichletValues.fixBoundaryDOFs(fixAnotherIndexWithLocalView)
55-
assert sum(dirichletValues.container) == 2
55+
container = dirichletValues.container
56+
57+
assert sum(container) == 2
5658
assert dirichletValues.fixedDOFsize == 2
5759

5860
def fixTopSide(vec, localIndex, localView, intersection):
@@ -69,6 +71,9 @@ def fixTopSide(vec, localIndex, localView, intersection):
6971
indicesPerDirection: int = (math.sqrt(grid.size(0)) + 1) * 2
7072
assert dirichletValues.fixedDOFsize == 2 + indicesPerDirection
7173

74+
# This checks whether container is a reference
75+
assert sum(container) == dirichletValues.fixedDOFsize
76+
7277
# Test Subbasis
7378
dirichletValues2 = iks.dirichletValues(basis)
7479

@@ -81,11 +86,18 @@ def fixTopSide(vec, localIndex, localView, intersection):
8186
dirichletValues2.fixBoundaryDOFs(fixTopSide, 1)
8287
assert dirichletValues2.fixedDOFsize == 2 + indicesPerDirection
8388

84-
dirichletValues2.fixIthDOF(1)
89+
dirichletValues2.setSingleDOF(1, True)
8590
assert dirichletValues2.fixedDOFsize == 2 + indicesPerDirection + 1
8691
assert dirichletValues2.container[1]
8792
assert dirichletValues2.isConstrained(1)
88-
93+
94+
dirichletValues2.setSingleDOF(1, False)
95+
assert dirichletValues2.fixedDOFsize == 2 + indicesPerDirection
96+
assert not dirichletValues2.isConstrained(1)
97+
98+
dirichletValues2.reset()
99+
assert dirichletValues2.fixedDOFsize == 0
100+
assert sum(dirichletValues2.container) == 0
89101

90102

91103
if __name__ == "__main__":

ikarus/utils/dirichletvalues.hh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,21 @@ public:
104104
* \brief Fixes (set boolean value to true) a specific degree of freedom
105105
*
106106
* \param i An index indicating the DOF number to be fixed
107+
* \param flag Boolean indicating whether the DOF should fixed or not
107108
*/
108-
void fixIthDOF(typename Basis::MultiIndex i) { dirichletFlagsBackend_[i] = true; }
109+
template <typename MultiIndex>
110+
requires(not std::integral<MultiIndex>)
111+
void setSingleDOF(const MultiIndex i, bool flag) {
112+
dirichletFlagsBackend_[i] = flag;
113+
}
109114

110115
/**
111-
* \brief Unfixes (set boolean value to false) a specific degree of freedom
116+
* \brief Fixes (set boolean value to true) a specific degree of freedom
112117
*
113118
* \param i An index indicating the DOF number to be fixed
119+
* \param flag Boolean indicating whether the DOF should fixed or not
114120
*/
115-
void unfixIthDOF(typename Basis::MultiIndex i) { dirichletFlagsBackend_[i] = false; }
121+
void setSingleDOF(std::size_t i, bool flag) { dirichletFlags_[i] = flag; }
116122

117123
/**
118124
* \brief Resets all degrees of freedom

tests/src/testdirichletvalue.cpp

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// SPDX-License-Identifier: LGPL-3.0-or-later
33
#include <config.h>
44

5-
#include "testhelpers.hh"
6-
75
#include <vector>
86

97
#include <dune/common/float_cmp.hh>
@@ -44,22 +42,23 @@ static auto dirichletBCTest() {
4442
using namespace Dune::Functions::BasisFactory;
4543
auto basis = Ikarus::makeBasis(gridView, power<2>(lagrange<1>()));
4644

47-
auto basisP = std::make_shared<const decltype(basis)>(basis);
45+
auto basisP = std::make_shared<const decltype(basis)>(basis);
46+
auto flatBasis = basisP->flat();
4847

49-
Ikarus::DirichletValues dirichletValues1(basisP->flat());
48+
Ikarus::DirichletValues dirichletValues1(flatBasis);
5049
dirichletValues1.fixDOFs([](auto& basis_, auto& dirichFlags) {
5150
Dune::Functions::forEachBoundaryDOF(basis_, [&](auto&& indexGlobal) { dirichFlags[indexGlobal] = true; });
5251
});
5352

54-
Ikarus::DirichletValues dirichletValues2(basisP->flat());
53+
Ikarus::DirichletValues dirichletValues2(flatBasis);
5554
dirichletValues2.fixBoundaryDOFs([](auto& dirichFlags, auto&& indexGlobal) { dirichFlags[indexGlobal] = true; });
5655

57-
for (std::size_t i = 0; i < basisP->flat().size(); ++i)
56+
for (std::size_t i = 0; i < flatBasis.size(); ++i)
5857
t.check(dirichletValues1.isConstrained(i) == dirichletValues2.isConstrained(i))
5958
<< "Different dirichlet value creations didn't provide the same result. Index: i=" << i;
6059

6160
auto testSubSpaceBasis = [&](auto&& tree1, auto&& tree2) {
62-
Ikarus::DirichletValues dirichletValues_SSB(basisP->flat());
61+
Ikarus::DirichletValues dirichletValues_SSB(flatBasis);
6362
dirichletValues_SSB.fixBoundaryDOFs([](auto& dirichFlags, auto&& indexGlobal) { dirichFlags[indexGlobal] = true; },
6463
tree1);
6564

@@ -94,10 +93,10 @@ static auto dirichletBCTest() {
9493
if (intersection.geometry().center()[0] > 4 - 1e-8)
9594
dirichletFlags[localView.index(localIndex)] = true;
9695
};
97-
Ikarus::DirichletValues dirichletValues5(basisP->flat());
96+
Ikarus::DirichletValues dirichletValues5(flatBasis);
9897
dirichletValues5.fixBoundaryDOFs(fixLambda);
9998

100-
Ikarus::DirichletValues dirichletValues_SSB2(basisP->flat());
99+
Ikarus::DirichletValues dirichletValues_SSB2(flatBasis);
101100
dirichletValues_SSB2.fixBoundaryDOFs(fixLambda, treePath0);
102101

103102
t.check(dirichletValues5.fixedDOFsize() == dirichletValues_SSB2.fixedDOFsize() * 2)
@@ -113,15 +112,13 @@ static auto dirichletBCTest() {
113112
<< dirichletValues_SSB2.fixedDOFsize() << ", where as the full basis has " << dirichletValues5.fixedDOFsize()
114113
<< " fixed DOFs";
115114

116-
for (std::size_t i = 0; i < basisP->flat().size(); ++i)
115+
for (std::size_t i = 0; i < flatBasis.size(); ++i)
117116
t.check(dirichletValues_SSB2.isConstrained(i) == dirichletValues5.isConstrained(i))
118117
<< "Different dirichlet value creations with subspace basis didn't provide the same result as with full basis. "
119118
"Index: i="
120119
<< i;
121120

122-
auto sum = [](const auto& container_) {
123-
return std::accumulate(container_.begin(), container_.end(), 0, std::plus());
124-
};
121+
auto sum = [](const auto& container_) { return std::accumulate(container_.begin(), container_.end(), 0); };
125122
auto manual_sum = [](const auto& dv) {
126123
int sum = 0;
127124
for (auto i : Dune::range(dv.size()))
@@ -130,6 +127,18 @@ static auto dirichletBCTest() {
130127
return sum;
131128
};
132129

130+
// Fix non-boundaryDOFs
131+
// Ikarus::DirichletValues dirichletValues6(flatBasis);
132+
// dirichletValues6.fixDOFs([](const auto& basis, auto& dirichletFlags) {
133+
// Dune::Functions::forEachBoundaryDOF(basis, [&](auto&& localIndex, auto&& localView, auto&& intersection) {
134+
// dirichletFlags[localView.index(localIndex)] = true;
135+
// });
136+
// });
137+
138+
// t.check(dirichletValues6.fixedDOFsize() == flatBasis.size())
139+
// << "All Dofs should be fixed but only " << dirichletValues6.fixedDOFsize() << "out of " << flatBasis.size()
140+
// << "are fixed";
141+
133142
// Test container
134143
auto& container = dirichletValues2.container();
135144
static_assert(std::is_reference_v<decltype(container)>, "container should be a reference");
@@ -143,17 +152,21 @@ static auto dirichletBCTest() {
143152
t.check(sumManual == sumPre)
144153
<< "Summing over container should yield the same amount of fixed DOFs then checking manually";
145154

146-
dirichletValues2.unfixIthDOF({1});
155+
dirichletValues2.setSingleDOF(decltype(flatBasis)::MultiIndex{1}, false);
147156
t.check(sum(container) == sumPre - 1) << "The sum of fixed DOFs should be one less then after unfixing one";
148157

149158
t.check(manual_sum(dirichletValues2) == sumPre - 1)
150159
<< "Summing over container should yield the same amount of fixed DOFs then checking manually";
151160

161+
dirichletValues2.setSingleDOF(2, false);
162+
t.check(sum(container) == sumPre - 2) << "The sum of fixed DOFs should be two less then after unfixing two";
163+
152164
// Reset
153165
dirichletValues2.reset();
154166
t.check(sum(container) == 0) << "After resetting container should have only false entries";
155-
t.check(manual_sum(dirichletValues2) == 0) << "After resetting all DOFs should be false";
167+
t.check(manual_sum(dirichletValues2) == 0) << "After resetting, all DOFs should be false";
156168

169+
// Inhomogenious Boundary Conditions
157170
auto inhomogeneousDisplacement = []<typename T>(const auto& globalCoord, const T& lambda) {
158171
Eigen::Vector<T, 2> localInhomogeneous;
159172
if (globalCoord[0] > 4 - 1e-8) {
@@ -251,7 +264,7 @@ static auto dirichletBCTest() {
251264
(std::abs(nodalPos[i][1]) < tol) or (std::abs(nodalPos[i][1] - Ly) < tol))
252265
for (auto fixedDirection = 0; fixedDirection < 2; ++fixedDirection) {
253266
auto fixIndex = localView.index(localView.tree().child(fixedDirection).localIndex(i));
254-
dirichletValues4.fixIthDOF(fixIndex);
267+
dirichletValues4.setSingleDOF(fixIndex, true);
255268
}
256269
}
257270

0 commit comments

Comments
 (0)