Improvements for hermitespline interpolation#3298
Conversation
For FCI we need to be able to access "random" data from the adjacent slices. If they are split in x-direction, this requires some tricky communication pattern. It can be used like this: ``` // Create object GlobalField3DAccess fci_comm(thismesh); // let it know what data points will be required: // where IndG3D is an index in the global field, which would be the // normal Ind3D if there would be only one proc. fci_comm.get(IndG3D(i, ny, nz)); // If all index have been added, the communication pattern will be // established. This has to be called by all processors in parallel fci_comm.setup() // Once the data for a given field is needed, it needs to be // communicated: GlobalField3DAccessInstance global_data = fci_comm.communicate(f3d); // and can be accessed like this BoutReal data = global_data[IndG3D(i, ny, nz)]; // ny and nz in the IndG3D are always optional. ```
If they are two instances of the same template, this allows to have an if in the inner loop that can be optimised out.
lower_bound takes into account the data is sorted
Ensures we all ways check for monotonicity
Tags were different for sender and receiver
Otherwise mpi might wait for the wrong request.
to avoid confusion whether the offsets are for sending or receiving
Using a local set for each thread ensures we do not need a mutex for adding data, at the cost of having to merge the different sets later.
We want to skip sending if there is no data for this process ...
The result needs to be well understood, as the indices are a mix of local and global indices, as we need to access non-local data.
06f3890 to
424136b
Compare
I have added some docs.
I improved the naming
I extended on the templating. Now all versions are templated.
I added an interface to the mesh, to do the mapping. If you think this should be reproduced here, I would need to know how you intend to do it. All comments addressed, ready for re-review 👍 |
| #endif | ||
|
|
||
| namespace { | ||
| enum class implementation_type { new_weights, petsc, legacy }; |
There was a problem hiding this comment.
warning: enum 'implementation_type' uses a larger base type ('int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size [performance-enum-size]
enum class implementation_type { new_weights, petsc, legacy };
^| PE_XIND = MYPE % NXPE; | ||
| PE_ZIND = 0; | ||
|
|
||
| ASSERT2(MYPE == getProcIndex(PE_XIND, PE_YIND, PE_ZIND)); |
There was a problem hiding this comment.
warning: no header providing "ASSERT2" is directly included [misc-include-cleaner]
ASSERT2(MYPE == getProcIndex(PE_XIND, PE_YIND, PE_ZIND));
^| } | ||
| } | ||
|
|
||
| int BoutMesh::getProcIndex(int X, int Y, int Z) { return Y * NXPE + X; } |
There was a problem hiding this comment.
warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
| int BoutMesh::getProcIndex(int X, int Y, int Z) { return Y * NXPE + X; } | |
| int BoutMesh::getProcIndex(int X, int Y, int Z) { return (Y * NXPE) + X; } |
| } | ||
| } | ||
|
|
||
| int BoutMesh::getProcIndex(int X, int Y, int Z) { return Y * NXPE + X; } |
There was a problem hiding this comment.
warning: method 'getProcIndex' can be made const [readability-make-member-function-const]
| int BoutMesh::getProcIndex(int X, int Y, int Z) { return Y * NXPE + X; } | |
| int BoutMesh::getProcIndex(int X, int Y, int Z) const { return Y * NXPE + X; } |
| } | ||
| } | ||
|
|
||
| int BoutMesh::getProcIndex(int X, int Y, int Z) { return Y * NXPE + X; } |
There was a problem hiding this comment.
warning: out-of-line definition of 'getProcIndex' does not match any declaration in 'BoutMesh' [clang-diagnostic-error]
int BoutMesh::getProcIndex(int X, int Y, int Z) { return Y * NXPE + X; }
^Additional context
src/mesh/impls/bout/boutmesh.hxx:18: BoutMesh defined here
class BoutMesh : public Mesh {
^src/mesh/impls/bout/boutmesh.hxx:65: member declaration does not match because it is const qualified
int getProcIndex(int X, int Y, int Z) const override;
^| #endif | ||
| if constexpr (monotonic) { | ||
| const auto gind = | ||
| gf3daccess->xyzg(i_corn, y + y_offset + y_global_offset, k_corner(x, y, z)); |
There was a problem hiding this comment.
warning: no member named 'xyzg' in 'GlobalField3DAccess' [clang-diagnostic-error]
gf3daccess->xyzg(i_corn, y + y_offset + y_global_offset, k_corner(x, y, z));
^| const BoutMask& mask, | ||
| const std::string& region) { | ||
| setMask(mask); | ||
| calcWeights(delta_x, delta_z, region); |
There was a problem hiding this comment.
warning: no viable conversion from 'const std::string' (aka 'const basic_string') to 'const BoutMask' [clang-diagnostic-error]
calcWeights(delta_x, delta_z, region);
^Additional context
src/mesh/interpolation/hermite_spline_xz.cxx:535: in instantiation of member function 'XZHermiteSplineBase<true, (anonymous namespace)::implementation_type::new_weights>::calcWeights' requested here
template class XZHermiteSplineBase<true, implementation_type::new_weights>;
^include/bout/mask.hxx:47: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const std::string' (aka 'const basic_string') to 'const BoutMask &' for 1st argument
class BoutMask {
^include/bout/mask.hxx:47: candidate constructor (the implicit move constructor) not viable: no known conversion from 'const std::string' (aka 'const basic_string') to 'BoutMask &&' for 1st argument
class BoutMask {
^include/bout/mask.hxx:55: explicit constructor is not a candidate
explicit BoutMask(const Mesh& mesh, bool value = false)
^include/bout/mask.hxx:57: explicit constructor is not a candidate
explicit BoutMask(const Mesh* mesh = nullptr, bool value = false)
^/usr/include/c++/15/bits/basic_string.h:1035: candidate function
operator __sv_type() const noexcept
^include/bout/interpolation_xz.hxx:209: passing argument to parameter 'mask' here
void calcWeights(const Field3D& delta_x, const Field3D& delta_z, const BoutMask& mask,
^| f_interp[iyp] += newWeights[w * 4 + 3][i] * f[ic.zp(2).xp(w - 1)]; | ||
|
|
||
| if constexpr (imp_type == implementation_type::petsc) { | ||
| BoutReal* ptr; |
There was a problem hiding this comment.
warning: variable 'ptr' is not initialized [cppcoreguidelines-init-variables]
| BoutReal* ptr; | |
| BoutReal* ptr = nullptr; |
|
|
||
| if constexpr (imp_type == implementation_type::petsc) { | ||
| BoutReal* ptr; | ||
| const BoutReal* cptr; |
There was a problem hiding this comment.
warning: variable 'cptr' is not initialized [cppcoreguidelines-init-variables]
| const BoutReal* cptr; | |
| const BoutReal* cptr = nullptr; |
| if constexpr (monotonic) { | ||
| const auto iyp = i; | ||
| const auto i = iyp.ym(y_offset); | ||
| const auto corners = {(*gf)[IndG3D(g3dinds[i][0])], (*gf)[IndG3D(g3dinds[i][1])], |
There was a problem hiding this comment.
warning: no header providing "IndG3D" is directly included [misc-include-cleaner]
const auto corners = {(*gf)[IndG3D(g3dinds[i][0])], (*gf)[IndG3D(g3dinds[i][1])],
^88827de to
cabf678
Compare
| } | ||
| } | ||
|
|
||
| int BoutMesh::getProcIndex(int X, int Y, int Z) const { return Y * NXPE + X; } |
There was a problem hiding this comment.
warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]
| int BoutMesh::getProcIndex(int X, int Y, int Z) const { return Y * NXPE + X; } | |
| int BoutMesh::getProcIndex(int X, int Y, int Z) const { return (Y * NXPE) + X; } |
| } | ||
| } | ||
|
|
||
| int BoutMesh::getProcIndex(int X, int Y, int Z) const { return Y * NXPE + X; } |
There was a problem hiding this comment.
warning: parameter 'Z' is unused [misc-unused-parameters]
| int BoutMesh::getProcIndex(int X, int Y, int Z) const { return Y * NXPE + X; } | |
| int BoutMesh::getProcIndex(int X, int Y, int /*Z*/) const { return Y * NXPE + X; } |
| } | ||
| } | ||
|
|
||
| int BoutMesh::getProcIndex(int X, int Y, int Z) const { return Y * NXPE + X; } |
There was a problem hiding this comment.
warning: unused parameter 'Z' [clang-diagnostic-unused-parameter]
int BoutMesh::getProcIndex(int X, int Y, int Z) const { return Y * NXPE + X; }
^| if (localmesh->getNXPE() > 1) { | ||
| throw BoutException("Require PETSc for MPI splitting in X"); | ||
| if constexpr (imp_type == implementation_type::petsc) { | ||
| petsclib = new PetscLib( |
There was a problem hiding this comment.
warning: no header providing "PetscLib" is directly included [misc-include-cleaner]
src/mesh/interpolation/hermite_spline_xz.cxx:31:
+ #include "bout/petsclib.hxx"| const BoutMask& mask, | ||
| const std::string& region) { | ||
| setMask(mask); | ||
| calcWeights(delta_x, delta_z, region); |
There was a problem hiding this comment.
warning: no viable conversion from 'const std::string' (aka 'const basic_string') to 'const BoutMask' [clang-diagnostic-error]
calcWeights(delta_x, delta_z, region);
^Additional context
src/mesh/interpolation/hermite_spline_xz.cxx:537: in instantiation of member function 'XZHermiteSplineBase<true, (anonymous namespace)::implementation_type::new_weights>::calcWeights' requested here
template class XZHermiteSplineBase<true, implementation_type::new_weights>;
^include/bout/mask.hxx:47: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const std::string' (aka 'const basic_string') to 'const BoutMask &' for 1st argument
class BoutMask {
^include/bout/mask.hxx:47: candidate constructor (the implicit move constructor) not viable: no known conversion from 'const std::string' (aka 'const basic_string') to 'BoutMask &&' for 1st argument
class BoutMask {
^include/bout/mask.hxx:55: explicit constructor is not a candidate
explicit BoutMask(const Mesh& mesh, bool value = false)
^include/bout/mask.hxx:57: explicit constructor is not a candidate
explicit BoutMask(const Mesh* mesh = nullptr, bool value = false)
^/usr/include/c++/15/bits/basic_string.h:1035: candidate function
operator __sv_type() const noexcept
^include/bout/interpolation_xz.hxx:209: passing argument to parameter 'mask' here
void calcWeights(const Field3D& delta_x, const Field3D& delta_z, const BoutMask& mask,
^| const auto piy = global2local_y.convert(gind.y()); | ||
| const auto piz = global2local_z.convert(gind.z()); | ||
| ASSERT3(piz.proc == 0); | ||
| toGet[mesh.getProcIndex(pix.proc, piy.index, piz.index)].push_back( |
There was a problem hiding this comment.
warning: no member named 'index' in 'fci_comm::ProcLocal' [clang-diagnostic-error]
toGet[mesh.getProcIndex(pix.proc, piy.index, piz.index)].push_back(
^| int offset = 0; | ||
| for (const auto& get : toGet) { | ||
| getOffsets.push_back(offset); | ||
| offset += get.size(); |
There was a problem hiding this comment.
warning: narrowing conversion from 'size_type' (aka 'unsigned long') to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
offset += get.size();
^| getOffsets.push_back(offset); | ||
| } | ||
| for (const auto id : ids) { | ||
| const IndG3D gind{id, global2local_y.getGlobalWith(), global2local_z.getGlobalWith()}; |
There was a problem hiding this comment.
warning: use of undeclared identifier 'global2local_y' [clang-diagnostic-error]
const IndG3D gind{id, global2local_y.getGlobalWith(), global2local_z.getGlobalWith()};
^| for (const auto id : ids) { | ||
| const IndG3D gind{id, global2local_y.getGlobalWith(), global2local_z.getGlobalWith()}; | ||
| const auto pix = global2local_x.convert(gind.x()); | ||
| const auto piy = global2local_y.convert(gind.y()); |
There was a problem hiding this comment.
warning: use of undeclared identifier 'global2local_y' [clang-diagnostic-error]
const auto piy = global2local_y.convert(gind.y());
^| const auto piy = global2local_y.convert(gind.y()); | ||
| const auto piz = global2local_z.convert(gind.z()); | ||
| ASSERT3(piz.proc == 0); | ||
| const auto proc = mesh.getProcIndex(pix.proc, piy.index, piz.index); |
There was a problem hiding this comment.
warning: member reference type 'Mesh *' is a pointer; did you mean to use '->'? [clang-diagnostic-error]
| const auto proc = mesh.getProcIndex(pix.proc, piy.index, piz.index); | |
| const auto proc = mesh->getProcIndex(pix.proc, piy.index, piz.index); |
fd92807 to
6bd15d2
Compare
| continue; | ||
| } | ||
| auto ret = MPI_Irecv(data.data() + getOffsets[proc], toGet[proc].size(), MPI_DOUBLE, | ||
| proc, 666, comm, reqs.data() + cnt1); |
There was a problem hiding this comment.
warning: narrowing conversion from 'size_t' (aka 'unsigned long') to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
proc, 666, comm, reqs.data() + cnt1);
^| for (auto i : toSend[proc]) { | ||
| sendBuffer[cnt++] = f[Ind3D(i)]; | ||
| } | ||
| auto ret = MPI_Send(start, toSend[proc].size(), MPI_DOUBLE, proc, 666, comm); |
There was a problem hiding this comment.
warning: narrowing conversion from 'size_t' (aka 'unsigned long') to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
auto ret = MPI_Send(start, toSend[proc].size(), MPI_DOUBLE, proc, 666, comm);
^| for (auto i : toSend[proc]) { | ||
| sendBuffer[cnt++] = f[Ind3D(i)]; | ||
| } | ||
| auto ret = MPI_Send(start, toSend[proc].size(), MPI_DOUBLE, proc, 666, comm); |
There was a problem hiding this comment.
warning: narrowing conversion from 'size_type' (aka 'unsigned long') to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
auto ret = MPI_Send(start, toSend[proc].size(), MPI_DOUBLE, proc, 666, comm);
^| auto it = std::lower_bound(vec.begin(), vec.end(), tofind); | ||
| ASSERT3(it != vec.end()); | ||
| ASSERT3(*it == tofind); | ||
| mapping[id] = std::distance(vec.begin(), it) + getOffsets[proc]; |
There was a problem hiding this comment.
warning: narrowing conversion from 'typename iterator_traits<__gnu_cxx::__normal_iterator<const int *, std::vector<int, std::allocator>>>::difference_type' (aka 'long') to signed type 'mapped_type' (aka 'int') is implementation-defined [bugprone-narrowing-conversions]
mapping[id] = std::distance(vec.begin(), it) + getOffsets[proc];
^| auto it = std::lower_bound(vec.begin(), vec.end(), tofind); | ||
| ASSERT3(it != vec.end()); | ||
| ASSERT3(*it == tofind); | ||
| mapping[id] = std::distance(vec.begin(), it) + getOffsets[proc]; |
There was a problem hiding this comment.
warning: no header providing "std::distance" is directly included [misc-include-cleaner]
src/mesh/parallel/fci_comm.cxx:33:
- #include <mpi.h>
+ #include <iterator>
+ #include <mpi.h>| fci_comm::GlobalToLocal1D global2local_z; | ||
|
|
||
| public: | ||
| fci_comm::XYZ2Ind<Ind3D> xyzlocal; |
There was a problem hiding this comment.
warning: member variable 'xyzlocal' has public visibility [cppcoreguidelines-non-private-member-variables-in-classes]
fci_comm::XYZ2Ind<Ind3D> xyzlocal;
^|
|
||
| public: | ||
| fci_comm::XYZ2Ind<Ind3D> xyzlocal; | ||
| fci_comm::XYZ2Ind<IndG3D> xyzglobal; |
There was a problem hiding this comment.
warning: member variable 'xyzglobal' has public visibility [cppcoreguidelines-non-private-member-variables-in-classes]
fci_comm::XYZ2Ind<IndG3D> xyzglobal;
^Also, the indices should all start at 0
Includes X-splitting also for monotonichermitespline and more.