Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
LegacyVtkWriter.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
18
19#include "shambase/endian.hpp"
20#include "shambase/memory.hpp"
22#include "shambase/string.hpp"
23#include "shambase/time.hpp"
27#include "shambackends/vec.hpp"
28#include "shamcomm/io.hpp"
33#include <fstream>
34#include <sstream>
35#include <string>
36
37namespace shamrock {
38 namespace details {
39
40 template<class T>
41 using repr_t = typename shambase::VectorProperties<T>::component_type;
42
43 template<class T>
44 static constexpr u32 repr_count = shambase::VectorProperties<T>::dimension;
45
46 template<class RT, class T>
47 inline void write_buffer_vtktype(
48 MPI_File fh,
49 sycl::buffer<T> &buf,
50 u32 len,
51 u32 sum_len,
52 bool device_alloc,
53 u64 &file_head_ptr) {
54 StackEntry stack_loc{};
55
56 if (len == 0) {
58 "Cannot call this function with null buffer length");
59 }
60
61 const u32 new_cnt = len * repr_count<T>;
62 const u32 new_cnt_sum = sum_len * repr_count<T>;
63
64 shamlog_debug_mpi_ln("VTK write", new_cnt, new_cnt_sum);
65
66 sycl::queue &q = shamsys::instance::get_compute_queue();
67
68 sycl::buffer<RT> buf_w = shamrock::details::to_vtk_buf_type<RT>(q, buf, len);
69
70 RT *usm_buf;
71 if (device_alloc) {
72
73 usm_buf = sycl::malloc_device<RT>(new_cnt, q);
74
75 auto ev = q.submit([&](sycl::handler &cgh) {
76 sycl::accessor acc_buf{buf_w, cgh, sycl::read_only};
77 RT *ptr = usm_buf;
78 cgh.parallel_for(sycl::range<1>{new_cnt}, [=](sycl::item<1> i) {
79 ptr[i] = (acc_buf[i]);
80 });
81 });
82 ev.wait(); // TODO wait for the event only when doing MPI calls
83
84 } else {
85 usm_buf = sycl::malloc_host<RT>(new_cnt, q);
86
87 {
88 sycl::host_accessor acc_buf{buf_w, sycl::read_only};
89 for (u32 i = 0; i < new_cnt; i++) {
90 usm_buf[i] = (acc_buf[i]);
91 }
92 }
93 }
94
95 shamlog_debug_mpi_ln("VTK write", new_cnt);
96
98 fh, usm_buf, new_cnt, new_cnt_sum, file_head_ptr);
99
100 sycl::free(usm_buf, q);
101 }
102
103 template<class RT, class T>
104 inline void write_buffer_vtktype_no_buf(
105 MPI_File fh, u32 sum_len, bool device_alloc, u64 &file_head_ptr) {
106 StackEntry stack_loc{};
107
108 const u32 new_cnt_sum = sum_len * repr_count<T>;
109
110 shamlog_debug_mpi_ln("VTK write", new_cnt_sum);
111
112 sycl::queue &q = shamsys::instance::get_compute_queue();
113
114 shamalgs::collective::viewed_write_all_fetch_known_total_size<RT>(
115 fh, nullptr, 0, new_cnt_sum, file_head_ptr);
116 }
117 } // namespace details
118
119 enum DataSetTypes { UnstructuredGrid };
120
121 class LegacyVtkWriter {
122 MPI_File mfile{};
123 std::string fname;
124 bool binary;
125
126 u64 file_head_ptr;
127
128 shambase::Timer timer;
129
130 private:
131 inline void head_write(std::string s) {
132 shamalgs::collective::write_header_raw(mfile, s, file_head_ptr);
133 }
134
135 template<class T>
136 inline void write_buf(sycl::buffer<T> &buf, u32 len, u32 sum_len) {
137 if constexpr (shambase::VectorProperties<T>::is_float_based) {
138 details::write_buffer_vtktype<f32>(mfile, buf, len, sum_len, false, file_head_ptr);
139 } else if constexpr (shambase::VectorProperties<T>::is_int_based) {
140 details::write_buffer_vtktype<i32>(mfile, buf, len, sum_len, false, file_head_ptr);
141 } else if constexpr (shambase::VectorProperties<T>::is_uint_based) {
142 details::write_buffer_vtktype<i32>(mfile, buf, len, sum_len, false, file_head_ptr);
143 }
144 }
145
146 template<class T>
147 inline void write_buf_no_buf(u32 sum_len) {
148 if constexpr (shambase::VectorProperties<T>::is_float_based) {
149 details::write_buffer_vtktype_no_buf<f32, T>(mfile, sum_len, false, file_head_ptr);
150 } else if constexpr (shambase::VectorProperties<T>::is_int_based) {
151 details::write_buffer_vtktype_no_buf<i32, T>(mfile, sum_len, false, file_head_ptr);
152 } else if constexpr (shambase::VectorProperties<T>::is_uint_based) {
153 details::write_buffer_vtktype_no_buf<i32, T>(mfile, sum_len, false, file_head_ptr);
154 }
155 }
156
157 template<class T>
158 inline std::string get_buf_type_name() {
159 if constexpr (shambase::VectorProperties<T>::is_float_based) {
160 return "float";
161 } else if constexpr (shambase::VectorProperties<T>::is_int_based) {
162 return "int";
163 } else if constexpr (shambase::VectorProperties<T>::is_uint_based) {
164 return "int";
165 } else {
166 return "unknown";
167 }
168 }
169
170 u64 points_count;
171 bool has_written_points = false;
172
173 u64 cells_count;
174 bool has_written_cells = false;
175
176 public:
177 inline LegacyVtkWriter(std::string fname, bool binary, DataSetTypes type)
178 : fname(fname), binary(binary), file_head_ptr(0_u64) {
179
180 StackEntry stack_loc{};
181
182 timer.start();
183
184 shamlog_debug_ln("VtkWriter", "opening :", fname);
185
186 if (fname.find(".vtk") == std::string::npos) {
188 "the extension should be .vtk");
189 }
190
191 shamcomm::open_reset_file(mfile, fname);
192
193 std::stringstream ss;
194
195 if (binary) {
196 ss << ("# vtk DataFile Version 4.2\nvtk output\nBINARY\n");
197 } else {
198 ss << ("# vtk DataFile Version 4.2\nvtk output\nASCII\n");
199 }
200
201 if (type == UnstructuredGrid) {
202 ss << ("DATASET UNSTRUCTURED_GRID");
203 } else {
204 throw shambase::make_except_with_loc<std::invalid_argument>("unknown dataset type");
205 }
206
207 std::string write_str = ss.str();
208
209 head_write(write_str);
210 }
211
212 template<class T>
213 void write_points(sycl::buffer<sycl::vec<T, 3>> &buf, u32 len) {
214 StackEntry stack_loc{};
215
216 shamlog_debug_mpi_ln("VTK write", "write_points");
217
218 u32 sum_len = shamalgs::collective::allreduce_sum(len);
219
220 std::stringstream ss;
221 ss << "\n\nPOINTS ";
222 ss << sum_len;
223 ss << " " << get_buf_type_name<sycl::vec<T, 3>>();
224 ss << "\n";
225
226 head_write(ss.str());
227
228 write_buf(buf, len, sum_len);
229
230 has_written_points = true;
231 points_count = sum_len;
232 }
233
234 template<class T>
235 void write_points_no_buf() {
236 StackEntry stack_loc{};
237
238 shamlog_debug_mpi_ln("VTK write", "write_points no buf");
239
240 u32 sum_len = shamalgs::collective::allreduce_sum(0);
241
242 std::stringstream ss;
243 ss << "\n\nPOINTS ";
244 ss << sum_len;
245 ss << " " << get_buf_type_name<sycl::vec<T, 3>>();
246 ss << "\n";
247
248 head_write(ss.str());
249
250 write_buf_no_buf<T>(sum_len);
251
252 has_written_points = true;
253 points_count = sum_len;
254 }
255
256 template<class T>
257 void write_points(std::unique_ptr<sycl::buffer<sycl::vec<T, 3>>> &buf, u32 len) {
258 if (len > 0) {
259 write_points(shambase::get_check_ref(buf), len);
260 } else {
261 write_points_no_buf<T>();
262 }
263 }
264
265 template<class T>
266 void write_voxel_cells(
267 sycl::buffer<sycl::vec<T, 3>> &buf_min,
268 sycl::buffer<sycl::vec<T, 3>> &buf_max,
269 u32 len) {
270
271 sycl::buffer<sycl::vec<T, 3>> pos_points(len * 8);
272
273 auto view = shamalgs::collective::fetch_view(len);
274 u32 sum_len = view.total_byte_count;
275 u32 len_offset = view.head_offset;
276
277 shamsys::instance::get_compute_queue().submit([&](sycl::handler &cgh) {
278 sycl::accessor acc_min{buf_min, cgh, sycl::read_only};
279 sycl::accessor acc_max{buf_max, cgh, sycl::read_only};
280
281 sycl::accessor acc_points{pos_points, cgh, sycl::write_only, sycl::no_init};
282
283 cgh.parallel_for(sycl::range<1>{len}, [=](sycl::item<1> id) {
284 u32 idx = id.get_linear_id() * 8;
285
286 sycl::vec<T, 3> pmin = acc_min[id];
287 sycl::vec<T, 3> pmax = acc_max[id];
288
289 acc_points[idx + 0] = pmin;
290 acc_points[idx + 1] = {pmax.x(), pmin.y(), pmin.z()};
291 acc_points[idx + 2] = {pmin.x(), pmax.y(), pmin.z()};
292 acc_points[idx + 3] = {pmax.x(), pmax.y(), pmin.z()};
293 acc_points[idx + 4] = {pmin.x(), pmin.y(), pmax.z()};
294 acc_points[idx + 5] = {pmax.x(), pmin.y(), pmax.z()};
295 acc_points[idx + 6] = {pmin.x(), pmax.y(), pmax.z()};
296 acc_points[idx + 7] = pmax;
297 });
298 });
299
300 write_points(pos_points, len * 8);
301
302 std::stringstream ss;
303 ss << "\n\nCELLS ";
304 ss << sum_len;
305 ss << " " << sum_len * 9;
306 ss << "\n";
307 head_write(ss.str());
308
309 sycl::buffer<i32> idx_cells(len * 9);
310 sycl::buffer<i32> type_cell(len);
311
312 shamsys::instance::get_compute_queue().submit([&](sycl::handler &cgh) {
313 sycl::accessor idxs{idx_cells, cgh, sycl::write_only, sycl::no_init};
314 sycl::accessor cellt{type_cell, cgh, sycl::write_only, sycl::no_init};
315
316 u32 idp_off = len_offset * 8;
317
318 cgh.parallel_for(sycl::range<1>{len}, [=](sycl::item<1> item) {
319 u32 idp = item.get_linear_id() * 8;
320 u32 idx = item.get_linear_id() * 9;
321
322 idxs[idx + 0] = 8;
323 idxs[idx + 1] = idp_off + idp + 0;
324 idxs[idx + 2] = idp_off + idp + 1;
325 idxs[idx + 3] = idp_off + idp + 2;
326 idxs[idx + 4] = idp_off + idp + 3;
327 idxs[idx + 5] = idp_off + idp + 4;
328 idxs[idx + 6] = idp_off + idp + 5;
329 idxs[idx + 7] = idp_off + idp + 6;
330 idxs[idx + 8] = idp_off + idp + 7;
331
332 cellt[item] = 11;
333 });
334 });
335
336 write_buf(idx_cells, len * 9, sum_len * 9);
337
338 std::stringstream ss2;
339 ss2 << "\n\nCELL_TYPES ";
340 ss2 << sum_len;
341 ss2 << "\n";
342 head_write(ss2.str());
343
344 write_buf(type_cell, len, sum_len);
345
346 cells_count = sum_len;
347 has_written_cells = true;
348 }
349
350 void add_point_data_section() {
351
352 if (!has_written_points) {
354 "no points had been written");
355 }
356
357 std::stringstream ss;
358 ss << "\n\nPOINT_DATA ";
359 ss << points_count;
360
361 head_write(ss.str());
362 }
363
364 void add_cell_data_section() {
365
366 if (!has_written_cells) {
368 "no cells had been written");
369 }
370
371 std::stringstream ss;
372 ss << "\n\nCELL_DATA ";
373 ss << cells_count;
374
375 head_write(ss.str());
376 }
377
378 void add_field_data_section(u32 num_field) {
379
380 if (!has_written_points) {
382 "no points had been written");
383 }
384
385 std::stringstream ss;
386 ss << "\nFIELD FieldData ";
387 ss << num_field;
388
389 head_write(ss.str());
390 }
391
392 template<class T>
393 void write_field(std::string name, sycl::buffer<T> &buf, u32 len) {
394
395 u32 sum_len = shamalgs::collective::allreduce_sum(len);
396
397 std::stringstream ss;
398 ss << "\n" << name;
399 ss << " " << details::repr_count<T>;
400 ss << " " << sum_len;
401 ss << " " << get_buf_type_name<T>();
402 ss << "\n";
403 head_write(ss.str());
404
405 write_buf(buf, len, sum_len);
406 }
407
408 template<class T>
409 void write_field_no_buf(std::string name) {
410
411 u32 sum_len = shamalgs::collective::allreduce_sum(0);
412
413 std::stringstream ss;
414 ss << "\n" << name;
415 ss << " " << details::repr_count<T>;
416 ss << " " << sum_len;
417 ss << " " << get_buf_type_name<T>();
418 ss << "\n";
419 head_write(ss.str());
420
421 write_buf_no_buf<T>(sum_len);
422 }
423
424 template<class T>
425 void write_field(std::string name, std::unique_ptr<sycl::buffer<T>> &buf, u32 len) {
426 if (len > 0) {
427 sycl::buffer<T> &buf_ref = shambase::get_check_ref(buf);
428 if (buf_ref.size() < len) {
430 "the buffer is smaller than expected write field size\n buf size = {}, "
431 "cnt = {}",
432 buf_ref.size(),
433 len));
434 }
435 write_field(name, buf_ref, len);
436 } else {
437 write_field_no_buf<T>(name);
438 }
439 }
440
441 inline ~LegacyVtkWriter() {
442 shamlog_debug_mpi_ln("LegacyVtkWriter", "calling : shamcomm::mpi::File_close");
444 timer.stop();
445
446 if (shamcomm::world_rank() == 0) {
448 "VTK Dump",
449 sham::format(
450 "dump to {}\n - took {}, bandwidth = {}/s",
451 fname,
452 timer.get_time_str(),
453 shambase::readable_sizeof(file_head_ptr / timer.elapsed_sec())));
454 }
455 }
456
457 LegacyVtkWriter(const LegacyVtkWriter &) = delete;
458 LegacyVtkWriter &operator=(const LegacyVtkWriter &) = delete;
459 LegacyVtkWriter(LegacyVtkWriter &&other)
460 : mfile(other.mfile), fname(std::move(other.fname)), binary(other.binary),
461 file_head_ptr(other.file_head_ptr), points_count(other.points_count),
462 has_written_points(other.has_written_points), cells_count(other.cells_count),
463 has_written_cells(other.has_written_cells) {} // move constructor
464 LegacyVtkWriter &operator=(LegacyVtkWriter &&other) = delete; // move assignment
465 };
466} // namespace shamrock
This header does the MPI include and wrap MPI calls.
Header file describing a Node Instance.
sycl::queue & get_compute_queue(u32 id=0)
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
Class Timer measures the time elapsed since the timer was started.
Definition Timer.hpp:36
std::string readable_sizeof(double size)
given a sizeof value return a readble string Example : readable_sizeof(1e9) -> "1....
Definition string.hpp:80
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
T & get_check_ref(const std::unique_ptr< T > &ptr, SourceLocation loc=SourceLocation())
Takes a std::unique_ptr and returns a reference to the object it holds. It throws a std::runtime_erro...
Definition memory.hpp:112
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
void open_reset_file(MPI_File &fh, const std::string &fname)
Open a MPI file and remove its content.
Definition io.cpp:24
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
Definition worldInfo.cpp:41
namespace for the main framework
Definition __init__.py:1
void write_header_raw(MPI_File fh, std::string s, u64 &file_head_ptr)
Writes a string to a file using MPI and updates the file head pointer.
Definition io.hpp:96
void viewed_write_all_fetch_known_total_size(MPI_File fh, T *ptr_data, u64 data_cnt, u64 total_cnt, u64 &file_head_ptr)
Writes data to an MPI file in a collective manner and updates the file head pointer.
Definition io.hpp:69
void info_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:132
This file contains the definition for the stacktrace related functionality.
shambase::details::BasicStackEntry StackEntry
Alias for shambase::details::BasicStackEntry.
void File_close(MPI_File *fh)
MPI wrapper for MPI_File_close.
Definition wrapper.cpp:307