OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
DirichletPlaneWriter.h
Go to the documentation of this file.
1//
2// Class DirichletPlaneWriter
3// Writes interpolated potential values on a 2D dirichlet plane to ASCII files.
4//
5// Copyright (c) 2026, Paul Scherrer Institut
6// All rights reserved
7//
8// This file is part of OPAL.
9//
10// OPAL is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// You should have received a copy of the GNU General Public License
16// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
17//
18
19#ifndef OPAL_DIRICHLET_PLANE_WRITER_H
20#define OPAL_DIRICHLET_PLANE_WRITER_H
21
22#include <Kokkos_Core.hpp>
23
24#include <algorithm>
25#include <cmath>
26#include <cstddef>
27#include <filesystem>
28#include <string>
29#include <vector>
30
32
40public:
42 double mean = 0.0;
43 double variance = 0.0;
44 std::size_t sampleCount = 0;
45 };
46
48 explicit DirichletPlaneWriter(const std::string& outputDirectory);
49
51 void writePlane(
52 long long step, double time, double zPlane, const std::vector<double>& xCoords,
53 const std::vector<double>& yCoords, const std::vector<double>& phiValues,
54 std::size_t nx, std::size_t ny, const std::string& solveTag);
55
72 template <typename FieldType>
74 long long step, double time, double zPlane, const FieldType& field,
75 const std::string& solveTag);
76
77private:
78 std::filesystem::path outputDirectory_m;
79};
80
81template <typename FieldType>
83 long long step, double time, double zPlane, const FieldType& field,
84 const std::string& solveTag) {
85 const auto lDom = field.getLayout().getLocalNDIndex();
86 const int nghost = field.getNghost();
87 const auto spacing = field.get_mesh().getMeshSpacing();
88 const auto origin = field.get_mesh().getOrigin();
89
90 if (spacing[0] <= 0.0 || spacing[1] <= 0.0 || spacing[2] <= 0.0) {
91 throw OpalException(
92 "DirichletPlaneWriter::dumpInterpolatedPlane",
93 "Mesh spacing must be positive in all dimensions.");
94 }
95
96 const int nxOwned = lDom[0].length();
97 const int nyOwned = lDom[1].length();
98 const int nzOwned = lDom[2].length();
99 if (nxOwned <= 0 || nyOwned <= 0 || nzOwned <= 0) {
100 return PlaneDiagnostics{};
101 }
102
103 const std::size_t nx = static_cast<std::size_t>(nxOwned);
104 const std::size_t ny = static_cast<std::size_t>(nyOwned);
105
106 const int kMinGlobal = lDom[2].first();
107 const int kMaxGlobal = lDom[2].last();
108
109 const double kFloatRaw = (zPlane - origin[2]) / spacing[2] - 0.5;
110 const double kFloat = std::min(
111 std::max(kFloatRaw, static_cast<double>(kMinGlobal)), static_cast<double>(kMaxGlobal));
112
113 int k0Global = static_cast<int>(std::floor(kFloat));
114 int k1Global = k0Global + 1;
115 k0Global = std::max(kMinGlobal, std::min(k0Global, kMaxGlobal));
116 k1Global = std::max(kMinGlobal, std::min(k1Global, kMaxGlobal));
117
118 const double alpha = (k1Global == k0Global) ? 0.0 : (kFloat - static_cast<double>(k0Global));
119
120 const int k0Local = k0Global - lDom[2].first() + nghost;
121 const int k1Local = k1Global - lDom[2].first() + nghost;
122
123 using exec_space = typename FieldType::execution_space;
124 using mem_space = typename FieldType::view_type::memory_space;
125
126 const std::size_t nxy = nx * ny;
127 Kokkos::View<double**, mem_space> planeDevice("dirichlet_plane", nx, ny);
128 auto fieldView = field.getView();
129
130 Kokkos::parallel_for(
131 "DirichletPlaneWriter::interpolatePlane", Kokkos::RangePolicy<exec_space>(0, nxy),
132 KOKKOS_LAMBDA(const std::size_t idx) {
133 const std::size_t ii = idx / ny;
134 const std::size_t jj = idx - ii * ny;
135
136 const int iLocal = static_cast<int>(ii) + nghost;
137 const int jLocal = static_cast<int>(jj) + nghost;
138
139 const double phi0 = fieldView(iLocal, jLocal, k0Local);
140 const double phi1 = fieldView(iLocal, jLocal, k1Local);
141 planeDevice(ii, jj) = (1.0 - alpha) * phi0 + alpha * phi1;
142 });
143
144 double sum = 0.0;
145 Kokkos::parallel_reduce(
146 "DirichletPlaneWriter::sumPlane", Kokkos::RangePolicy<exec_space>(0, nxy),
147 KOKKOS_LAMBDA(const std::size_t idx, double& acc) {
148 const std::size_t ii = idx / ny;
149 const std::size_t jj = idx - ii * ny;
150 acc += planeDevice(ii, jj);
151 },
152 sum);
153
154 double sumSq = 0.0;
155 Kokkos::parallel_reduce(
156 "DirichletPlaneWriter::sumSqPlane", Kokkos::RangePolicy<exec_space>(0, nxy),
157 KOKKOS_LAMBDA(const std::size_t idx, double& acc) {
158 const std::size_t ii = idx / ny;
159 const std::size_t jj = idx - ii * ny;
160 const double v = planeDevice(ii, jj);
161 acc += v * v;
162 },
163 sumSq);
164
165 auto planeHost = Kokkos::create_mirror_view(planeDevice);
166 Kokkos::deep_copy(planeHost, planeDevice);
167
168 std::vector<double> xCoords(nx, 0.0);
169 std::vector<double> yCoords(ny, 0.0);
170 std::vector<double> phiValues(nxy, 0.0);
171
172 for (std::size_t i = 0; i < nx; ++i) {
173 const int iGlobal = lDom[0].first() + static_cast<int>(i);
174 xCoords[i] = origin[0] + (static_cast<double>(iGlobal) + 0.5) * spacing[0];
175 }
176 for (std::size_t j = 0; j < ny; ++j) {
177 const int jGlobal = lDom[1].first() + static_cast<int>(j);
178 yCoords[j] = origin[1] + (static_cast<double>(jGlobal) + 0.5) * spacing[1];
179 }
180
181 for (std::size_t i = 0; i < nx; ++i) {
182 for (std::size_t j = 0; j < ny; ++j) {
183 phiValues[i * ny + j] = planeHost(i, j);
184 }
185 }
186
187 writePlane(step, time, zPlane, xCoords, yCoords, phiValues, nx, ny, solveTag);
188
189 PlaneDiagnostics diagnostics;
190 diagnostics.sampleCount = nxy;
191 diagnostics.mean = sum / static_cast<double>(nxy);
192 diagnostics.variance = sumSq / static_cast<double>(nxy) - diagnostics.mean * diagnostics.mean;
193 if (diagnostics.variance < 0.0) {
194 diagnostics.variance = 0.0;
195 }
196 return diagnostics;
197}
198
199#endif // OPAL_DIRICHLET_PLANE_WRITER_H
Writes dirichlet-plane potential snapshots to ASCII files.
PlaneDiagnostics dumpInterpolatedPlane(long long step, double time, double zPlane, const FieldType &field, const std::string &solveTag)
Interpolate a z-plane from a 3D field on device and write it to disk.
std::filesystem::path outputDirectory_m
void writePlane(long long step, double time, double zPlane, const std::vector< double > &xCoords, const std::vector< double > &yCoords, const std::vector< double > &phiValues, std::size_t nx, std::size_t ny, const std::string &solveTag)
Write one plane snapshot.