ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
EKinWalberlaImpl.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022-2026 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <blockforest/communication/UniformBufferedScheme.h>
23#include <field/AddToStorage.h>
24#include <field/FlagField.h>
25#include <field/FlagUID.h>
26#include <field/GhostLayerField.h>
27#include <field/communication/PackInfo.h>
28#include <field/iterators/IteratorMacros.h>
29#include <field/vtk/FlagFieldCellFilter.h>
30#include <field/vtk/VTKWriter.h>
31#include <stencil/D3Q27.h>
32#include <waLBerlaDefinitions.h>
33#if defined(__CUDACC__) and defined(WALBERLA_BUILD_WITH_CUDA)
34#include <gpu/AddGPUFieldToStorage.h>
35#include <gpu/communication/MemcpyPackInfo.h>
36#include <gpu/communication/UniformGPUScheme.h>
37#endif
38
39#include "../BoundaryHandling.hpp"
40#include "../BoundaryPackInfo.hpp"
41#include "../utils/boundary.hpp"
42#include "../utils/types_conversion.hpp"
43#include "ek_kernels.hpp"
44#if defined(__CUDACC__) and defined(WALBERLA_BUILD_WITH_CUDA)
45#include "ek_kernels.cuh"
46#endif
47
54
55#include <utils/Vector.hpp>
56
57#include <cstddef>
58#include <cstdint>
59#include <iterator>
60#include <memory>
61#include <optional>
62#include <ranges>
63#include <stdexcept>
64#include <string>
65#include <type_traits>
66#include <variant>
67#include <vector>
68
69namespace walberla {
70
71/** @brief Class that runs and controls the EK on waLBerla. */
72template <std::size_t FluxCount = 13, typename FloatType = double,
75#if not defined(WALBERLA_BUILD_WITH_CUDA)
76 static_assert(Architecture != lbmpy::Arch::GPU,
77 "waLBerla was compiled without CUDA support");
78#endif
79 using ContinuityKernel =
81 using DiffusiveFluxKernelUnthermalized =
82 typename detail::KernelTrait<FloatType,
83 Architecture>::DiffusiveFluxKernel;
84 using DiffusiveFluxKernelThermalized = typename detail::KernelTrait<
85 FloatType, Architecture>::DiffusiveFluxKernelThermalized;
86 using AdvectiveFluxKernel =
87 typename detail::KernelTrait<FloatType,
88 Architecture>::AdvectiveFluxKernel;
89 using FrictionCouplingKernel =
90 typename detail::KernelTrait<FloatType,
91 Architecture>::FrictionCouplingKernel;
92 using DiffusiveFluxKernelElectrostaticUnthermalized =
93 typename detail::KernelTrait<
94 FloatType, Architecture>::DiffusiveFluxKernelElectrostatic;
95 using DiffusiveFluxKernelElectrostaticThermalized =
96 typename detail::KernelTrait<
97 FloatType, Architecture>::DiffusiveFluxKernelElectrostaticThermalized;
98
99 using DiffusiveFluxKernel = std::variant<DiffusiveFluxKernelUnthermalized,
100 DiffusiveFluxKernelThermalized>;
101 using DiffusiveFluxKernelElectrostatic =
102 std::variant<DiffusiveFluxKernelElectrostaticUnthermalized,
103 DiffusiveFluxKernelElectrostaticThermalized>;
104
105 using Dirichlet =
107 using FixedFlux =
109
112 using BoundaryModelFlux =
114
115public:
116 /** @brief Stencil for collision and streaming operations. */
117 using Stencil = stencil::D3Q27;
118 /** @brief Lattice model (e.g. blockforest). */
120
121protected:
122 template <typename FT, lbmpy::Arch AT = lbmpy::Arch::CPU> struct FieldTrait {
123 // Type definitions
126 template <class Field>
127 using PackInfo = field::communication::PackInfo<Field>;
128 template <class Stencil>
130 blockforest::communication::UniformBufferedScheme<Stencil>;
131 template <class Stencil>
133 blockforest::communication::UniformBufferedScheme<Stencil>;
134 };
135 using FlagField = walberla::FlagField<walberla::uint8_t>;
136#if defined(__CUDACC__) and defined(WALBERLA_BUILD_WITH_CUDA)
137 template <typename FT> struct FieldTrait<FT, lbmpy::Arch::GPU> {
138 private:
139 static auto constexpr AT = lbmpy::Arch::GPU;
140 template <class Field>
141 using MemcpyPackInfo = gpu::communication::MemcpyPackInfo<Field>;
142
143 public:
144 template <typename Stencil>
145 class UniformGPUScheme
146 : public gpu::communication::UniformGPUScheme<Stencil> {
147 public:
148 explicit UniformGPUScheme(auto const &bf)
149 : gpu::communication::UniformGPUScheme<Stencil>(
150 bf, /* sendDirectlyFromGPU */ false,
151 /* useLocalCommunication */ false) {}
152 };
153 using FluxField = gpu::GPUField<FT>;
154 using DensityField = gpu::GPUField<FT>;
155 template <class Field> using PackInfo = MemcpyPackInfo<Field>;
156 template <class Stencil>
158 template <class Stencil>
159 using BoundaryCommScheme =
160 blockforest::communication::UniformBufferedScheme<Stencil>;
161 };
162 using GPUField = gpu::GPUField<FloatType>;
163#endif
164
165 struct GhostComm {
166 /** @brief Ghost communication operations. */
167 enum GhostCommFlags : unsigned {
168 FLB, ///< flux boundary communication
169 DENS, ///< density communication
170 SIZE
171 };
172 };
173
174 // "underlying" field types (`GPUField` has no f-size info at compile time)
177
178public:
182
183 template <typename T> FloatType FloatType_c(T t) {
184 return numeric_cast<FloatType>(t);
185 }
186
187 [[nodiscard]] std::size_t stencil_size() const noexcept override {
188 return FluxCount;
189 }
190
192 return std::is_same_v<FloatType, double>;
193 }
194
195private:
196 FloatType m_diffusion;
197 FloatType m_kT;
198 FloatType m_valency;
199 Utils::Vector3d m_ext_efield;
200 bool m_advection;
201 bool m_friction_coupling;
202 unsigned int m_seed;
203
204protected:
205 // Block data access handles
207
209
212
213 /** Flag for domain cells, i.e. all cells. */
214 FlagUID const Domain_flag{"domain"};
215 /** Flag for boundary cells. */
216 FlagUID const Boundary_flag{"boundary"};
217
218 /** Block forest */
219 std::shared_ptr<LatticeWalberla> m_lattice;
220
221 std::unique_ptr<BoundaryModelDensity> m_boundary_density;
222 std::shared_ptr<BoundaryModelFlux> m_boundary_flux;
223
224 std::unique_ptr<DiffusiveFluxKernel> m_diffusive_flux;
225 std::unique_ptr<DiffusiveFluxKernelElectrostatic>
227 std::unique_ptr<ContinuityKernel> m_continuity;
228
229 // ResetFlux + external force
230 // TODO: kernel for that
231 // std::shared_ptr<ResetForce<PdfField, VectorField>> m_reset_force;
232
233 /**
234 * @brief Convenience function to add a field with a custom allocator.
235 *
236 * When vectorization is off, let waLBerla decide which memory allocator
237 * to use. When vectorization is on, the aligned memory allocator is
238 * required, otherwise <tt>cpu_vectorize_info["assume_aligned"]</tt> will
239 * trigger assertions. That is because for single-precision kernels the
240 * waLBerla heuristic in <tt>src/field/allocation/FieldAllocator.h</tt>
241 * will fall back to @c StdFieldAlloc, yet @c AllocateAligned is needed
242 * for intrinsics to work.
243 */
244 template <typename Field>
245 auto add_to_storage(std::string const tag, FloatType value) {
246 auto const &blocks = m_lattice->get_blocks();
247 auto const n_ghost_layers = m_lattice->get_ghost_layers();
248#if defined(__CUDACC__) and defined(WALBERLA_BUILD_WITH_CUDA)
249 if constexpr (Architecture == lbmpy::Arch::GPU) {
250 auto field_id = gpu::addGPUFieldToStorage<GPUField>(
251 blocks, tag, Field::F_SIZE, field::fzyx, n_ghost_layers);
252 if constexpr (std::is_same_v<Field, _DensityField>) {
253 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
254 auto field = block->template getData<GPUField>(field_id);
255 ek::accessor::Scalar::initialize(field, FloatType{value});
256 }
257 } else if constexpr (std::is_same_v<Field, _FluxField>) {
258 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
259 auto field = block->template getData<GPUField>(field_id);
261 std::array<FloatType, FluxCount>{});
262 }
263 }
264 return field_id;
265 }
266#endif
267 return field::addToStorage<Field>(blocks, tag, FloatType{value},
268 field::fzyx, n_ghost_layers);
269 }
270
271 void
272 reset_density_boundary_handling(std::shared_ptr<BlockStorage> const &blocks) {
273 auto const [lc, uc] = m_lattice->get_local_grid_range(true);
274 m_boundary_density = std::make_unique<BoundaryModelDensity>(
276 CellInterval{to_cell(lc), to_cell(uc)});
277 }
278
279 void
280 reset_flux_boundary_handling(std::shared_ptr<BlockStorage> const &blocks) {
281 auto const [lc, uc] = m_lattice->get_local_grid_range(true);
282 m_boundary_flux = std::make_shared<BoundaryModelFlux>(
284 CellInterval{to_cell(lc), to_cell(uc)});
285 }
286
288 typename FieldTrait<FloatType, Architecture>::template RegularCommScheme<
289 typename stencil::D3Q27>;
291 typename FieldTrait<FloatType, Architecture>::template BoundaryCommScheme<
292 typename stencil::D3Q27>;
293 std::shared_ptr<FullCommunicator> m_full_communication;
294 std::shared_ptr<BoundaryFullCommunicator> m_boundary_communicator;
295 std::bitset<GhostComm::SIZE> m_pending_ghost_comm;
297 template <class Field>
298 using PackInfo =
300
301public:
302 EKinWalberlaImpl(std::shared_ptr<LatticeWalberla> lattice, double diffusion,
303 double kT, double valency, Utils::Vector3d const &ext_efield,
304 double density, bool advection, bool friction_coupling,
305 bool thermalized, unsigned int seed)
306 : m_diffusion(FloatType_c(diffusion)), m_kT(FloatType_c(kT)),
307 m_valency(FloatType_c(valency)), m_ext_efield(ext_efield),
308 m_advection(advection), m_friction_coupling(friction_coupling),
309 m_seed(seed), m_lattice(std::move(lattice)),
311
312 auto const &blocks = m_lattice->get_blocks();
313 auto const n_ghost_layers = m_lattice->get_ghost_layers();
314
318 add_to_storage<_FluxField>("flux field", FloatType_c(0.0));
319
321 std::make_unique<ContinuityKernel>(m_flux_field_id, m_density_field_id);
322
323 if (thermalized) {
324 set_diffusion_kernels(*m_lattice, seed);
325 } else {
326 set_diffusion_kernels();
327 }
328
329 // Init boundary related stuff
330 m_flag_field_density_id = field::addFlagFieldToStorage<FlagField>(
331 blocks, "flag field density", n_ghost_layers);
333
334 m_flag_field_flux_id = field::addFlagFieldToStorage<FlagField>(
335 blocks, "flag field flux", n_ghost_layers);
337
338 m_full_communication = std::make_shared<FullCommunicator>(blocks);
339 m_full_communication->addPackInfo(
340 std::make_shared<PackInfo<DensityField>>(m_density_field_id));
342 std::make_shared<BoundaryFullCommunicator>(blocks);
343 m_boundary_communicator->addPackInfo(
346 auto flux_boundary_packinfo = std::make_shared<
351
353 }
354
355 // Global parameters
356 [[nodiscard]] double get_diffusion() const noexcept override {
357 return m_diffusion;
358 }
359 [[nodiscard]] double get_kT() const noexcept override { return m_kT; }
360 [[nodiscard]] double get_valency() const noexcept override {
361 return m_valency;
362 }
363 [[nodiscard]] bool get_advection() const noexcept override {
364 return m_advection;
365 }
367 return m_friction_coupling;
368 }
370 return m_ext_efield;
371 }
373 return static_cast<bool>(
374 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux));
375 }
376 [[nodiscard]] unsigned int get_seed() const noexcept override {
377 return m_seed;
378 }
379 [[nodiscard]] std::optional<uint64_t> get_rng_state() const override {
380 auto const kernel =
381 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
382 if (!kernel) {
383 return std::nullopt;
384 }
385 return {static_cast<uint64_t>(kernel->getTime_step())};
386 }
387
388 void set_diffusion(double diffusion) override {
389 m_diffusion = FloatType_c(diffusion);
390 auto visitor = [m_diffusion = m_diffusion](auto &kernel) {
391 kernel.setD(m_diffusion);
392 };
393 std::visit(visitor, *m_diffusive_flux);
395 }
396
397 void set_kT(double kT) override {
398 m_kT = FloatType_c(kT);
399 std::visit([m_kT = m_kT](auto &kernel) { kernel.setKt(m_kT); },
401 }
402
403 void set_valency(double valency) override {
404 m_valency = FloatType_c(valency);
405 std::visit(
406 [m_valency = m_valency](auto &kernel) { kernel.setZ(m_valency); },
408 }
409
410 void set_advection(bool advection) override { m_advection = advection; }
411
413 m_friction_coupling = friction_coupling;
414 }
415
416 void set_rng_state(uint64_t counter) override {
417 auto const kernel =
418 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
419 auto const kernel_electrostatic =
420 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
422
423 if (!kernel or !kernel_electrostatic) {
424 throw std::runtime_error("This EK instance is unthermalized");
425 }
426 assert(counter <=
427 static_cast<uint32_t>(std::numeric_limits<uint_t>::max()));
428 kernel->setTime_step(static_cast<uint32_t>(counter));
429 kernel_electrostatic->setTime_step(static_cast<uint32_t>(counter));
430 }
431
432 void set_ext_efield(Utils::Vector3d const &field) override {
433 m_ext_efield = field;
434
435 std::visit(
436 [this](auto &kernel) {
437 kernel.setF_ext_0(FloatType_c(m_ext_efield[0]));
438 kernel.setF_ext_1(FloatType_c(m_ext_efield[1]));
439 kernel.setF_ext_2(FloatType_c(m_ext_efield[2]));
440 },
442 }
443
444 void ghost_communication() override {
447 (*m_full_communication)();
449 }
451 }
452
460
461private:
462 void set_diffusion_kernels() {
463 auto kernel = DiffusiveFluxKernelUnthermalized(
465 m_diffusive_flux = std::make_unique<DiffusiveFluxKernel>(std::move(kernel));
466
467 auto kernel_electrostatic = DiffusiveFluxKernelElectrostaticUnthermalized(
469 FloatType_c(m_diffusion), FloatType_c(m_ext_efield[0]),
470 FloatType_c(m_ext_efield[1]), FloatType_c(m_ext_efield[2]),
471 FloatType_c(m_kT), FloatType_c(m_valency));
472
474 std::make_unique<DiffusiveFluxKernelElectrostatic>(
475 std::move(kernel_electrostatic));
476 }
477
478 void set_diffusion_kernels(LatticeWalberla const &lattice,
479 unsigned int seed) {
480 auto const grid_dim = lattice.get_grid_dimensions();
481
482 auto kernel = DiffusiveFluxKernelThermalized(
484 grid_dim[0], grid_dim[1], grid_dim[2], seed, 0);
485
486 auto kernel_electrostatic = DiffusiveFluxKernelElectrostaticThermalized(
488 FloatType_c(m_diffusion), FloatType_c(m_ext_efield[0]),
489 FloatType_c(m_ext_efield[1]), FloatType_c(m_ext_efield[2]), grid_dim[0],
490 grid_dim[1], grid_dim[2], FloatType_c(m_kT), seed, 0,
491 FloatType_c(m_valency));
492
493 auto const blocks = lattice.get_blocks();
494
495 for (auto &block : *blocks) {
496 kernel.configure(blocks, &block);
497 kernel_electrostatic.configure(blocks, &block);
498 }
499
500 m_diffusive_flux = std::make_unique<DiffusiveFluxKernel>(std::move(kernel));
502 std::make_unique<DiffusiveFluxKernelElectrostatic>(
503 std::move(kernel_electrostatic));
504 }
505
506 void kernel_boundary_density() {
507 for (auto &block : *m_lattice->get_blocks()) {
508 (*m_boundary_density)(&block);
509 }
510 }
511
512 void kernel_boundary_flux() {
513 for (auto &block : *m_lattice->get_blocks()) {
514 (*m_boundary_flux)(&block);
515 }
516 }
517
518 void kernel_continuity() {
519 for (auto &block : *m_lattice->get_blocks()) {
520 (*m_continuity).run(&block);
521 }
522 }
523
524 void kernel_diffusion() {
525 for (auto &block : *m_lattice->get_blocks()) {
526 std::visit([&block](auto &kernel) { kernel.run(&block); },
528 }
529
530 if (auto *kernel =
531 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux)) {
532 kernel->setTime_step(kernel->getTime_step() + 1u);
533
535 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
537 kernel_electrostatic->setTime_step(kernel_electrostatic->getTime_step() +
538 1u);
539 }
540 }
541
542 void kernel_advection(std::size_t const velocity_id) {
543 auto kernel = AdvectiveFluxKernel(m_flux_field_id, m_density_field_id,
545 for (auto &block : *m_lattice->get_blocks()) {
546 kernel.run(&block);
547 }
548 }
549
550 void kernel_friction_coupling(std::size_t const force_id,
551 double const lb_density) {
552 auto kernel = FrictionCouplingKernel(
554 FloatType_c(get_kT()), FloatType(lb_density));
555 for (auto &block : *m_lattice->get_blocks()) {
556 kernel.run(&block);
557 }
558 }
559
560 void kernel_diffusion_electrostatic(std::size_t const potential_id) {
561 auto const phiID = BlockDataID(potential_id);
562 std::visit([phiID](auto &kernel) { kernel.setPhiID(phiID); },
564
565 for (auto &block : *m_lattice->get_blocks()) {
566 std::visit([&block](auto &kernel) { kernel.run(&block); },
568 }
569
570 if (auto *kernel_electrostatic =
571 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
573 kernel_electrostatic->setTime_step(kernel_electrostatic->getTime_step() +
574 1u);
575
576 auto *kernel =
577 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
578 kernel->setTime_step(kernel->getTime_step() + 1u);
579 }
580 }
581
582 void kernel_migration() {}
583
584 void update_boundary_fields() {
585 m_boundary_flux->boundary_update();
586 m_boundary_density->boundary_update();
587 }
588
589protected:
590 void integrate_vtk_writers() override {
591 for (auto const &vtk_handle : m_vtk_auto | std::views::values) {
592 if (vtk_handle->enabled) {
593 vtk::writeFiles(vtk_handle->ptr)();
594 vtk_handle->execution_count++;
595 }
596 }
597 }
598
599public:
600 void integrate(std::size_t potential_id, std::size_t velocity_id,
601 std::size_t force_id, double lb_density) override {
602
604 update_boundary_fields();
605
606 if (get_diffusion() == 0.)
607 return;
608
609 if (get_valency() != 0.) {
610 if (potential_id == walberla::BlockDataID{}) {
611 throw std::runtime_error("Walberla EK: electrostatic potential enabled "
612 "but no field accessible. potential id is " +
613 std::to_string(potential_id));
614 }
615 kernel_diffusion_electrostatic(potential_id);
616 } else {
617 kernel_diffusion();
618 }
619
620 kernel_migration();
621 kernel_boundary_flux();
622 // friction coupling
623 if (get_friction_coupling()) {
624 if (force_id == walberla::BlockDataID{}) {
625 throw std::runtime_error("Walberla EK: friction coupling enabled but "
626 "no force field accessible. force_id is " +
627 std::to_string(force_id) +
628 ". Hint: LB may be inactive.");
629 }
630 kernel_friction_coupling(force_id, lb_density);
631 }
632
633 if (get_advection()) {
634 if (velocity_id == walberla::BlockDataID{}) {
635 throw std::runtime_error("Walberla EK: advection enabled but no "
636 "velocity field accessible. velocity_id is " +
637 std::to_string(velocity_id) +
638 ". Hint: LB may be inactive.");
639 }
640 kernel_advection(velocity_id);
641 kernel_boundary_flux();
642 }
643 kernel_continuity();
644
645 // is this the expected behavior when reactions are included?
646 kernel_boundary_density();
648
649 // Handle VTK writers
651 }
652
653 [[nodiscard]] std::size_t get_density_id() const noexcept override {
654 static_assert(std::is_same_v<std::size_t, walberla::uint_t>);
655 return static_cast<std::size_t>(m_density_field_id);
656 }
657
658 bool set_node_density(Utils::Vector3i const &node, double density) override {
660 auto bc = get_block_and_cell(get_lattice(), node, false);
661 if (!bc)
662 return false;
663
664 auto density_field =
667 return true;
668 }
669
670 [[nodiscard]] std::optional<double>
672 bool consider_ghosts = false) const override {
673 if (m_boundary_density->node_is_boundary(node)) {
674 return m_boundary_density->get_node_value_at_boundary(node);
675 }
676
678
679 if (!bc)
680 return std::nullopt;
681
682 auto const density_field =
685 }
686
687 [[nodiscard]] std::vector<double>
689 Utils::Vector3i const &upper_corner) const override {
690 std::vector<double> out;
691#ifndef NDEBUG
693#endif
694 auto const &lattice = get_lattice();
695 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
696 out = std::vector<double>(ci->numCells());
697 for (auto &block : *lattice.get_blocks()) {
698 auto const block_offset = lattice.get_block_corner(block, true);
699 if (auto const bci = get_block_interval(
701 auto const density_field =
704 assert(values.size() == bci->numCells());
705#ifndef NDEBUG
706 values_size += bci->numCells();
707#endif
708 auto kernel = [this, &values, &out](unsigned const block_index,
709 unsigned const local_index,
710 Utils::Vector3i const &node) {
711 if (m_boundary_density->node_is_boundary(node)) {
713 m_boundary_density->get_node_value_at_boundary(node);
714 } else {
716 }
717 };
718
720 }
721 }
722 assert(values_size == ci->numCells());
723 }
724 return out;
725 }
726
729 std::vector<double> const &density) override {
731 auto const &lattice = get_lattice();
732 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
733 assert(density.size() == ci->numCells());
734 for (auto &block : *lattice.get_blocks()) {
735 auto const block_offset = lattice.get_block_corner(block, true);
736 if (auto const bci = get_block_interval(
738 auto const density_field =
740 std::vector<FloatType> values(bci->numCells());
741
742 auto kernel = [&values, &density](unsigned const block_index,
743 unsigned const local_index,
744 Utils::Vector3i const &) {
746 };
747
750 }
751 }
752 }
753 }
754
755 [[nodiscard]] std::optional<Utils::Vector3d>
757 bool consider_ghosts = false) const override {
758 if (m_boundary_flux->node_is_boundary(node)) {
759 return to_vector3d(m_boundary_flux->get_node_value_at_boundary(node));
760 }
761
763
764 if (!bc)
765 return std::nullopt;
766
767 auto const flux_field =
768 bc->block->template getData<FluxField>(m_flux_field_id);
770 }
771
772 std::vector<double>
774 Utils::Vector3i const &upper_corner) const override {
775 std::vector<double> out;
776#ifndef NDEBUG
778#endif
779 auto const &lattice = get_lattice();
780 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
781 out = std::vector<double>(3u * ci->numCells());
782 for (auto &block : *lattice.get_blocks()) {
783 auto const block_offset = lattice.get_block_corner(block, true);
784 if (auto const bci = get_block_interval(
786 auto const flux_field =
789 assert(values.size() == 3u * bci->numCells());
790#ifndef NDEBUG
791 values_size += 3u * bci->numCells();
792#endif
793
794 auto kernel = [&values, &out, this](unsigned const block_index,
795 unsigned const local_index,
796 Utils::Vector3i const &node) {
797 if (m_boundary_flux->node_is_boundary(node)) {
798 auto const &vec =
799 m_boundary_flux->get_node_value_at_boundary(node);
800 for (uint_t f = 0u; f < 3u; ++f) {
801 out[3u * local_index + f] = double_c(vec[f]);
802 }
803 } else {
804 for (uint_t f = 0u; f < 3u; ++f) {
805 out[3u * local_index + f] =
806 double_c(values[3u * block_index + f]);
807 }
808 }
809 };
810
812 }
813 }
814 assert(values_size == 3u * ci->numCells());
815 }
816 return out;
817 }
818
823
824 void clear_density_boundaries() override {
826 }
827
829 Utils::Vector3d const &flux) override {
831 auto bc = get_block_and_cell(get_lattice(), node, true);
832 if (!bc)
833 return false;
834
835 m_boundary_flux->set_node_value_at_boundary(
836 node, to_vector3<FloatType>(flux), *bc);
837 return true;
838 }
839
840 [[nodiscard]] std::optional<Utils::Vector3d>
842 bool consider_ghosts = false) const override {
844 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
845 if (!bc or !m_boundary_flux->node_is_boundary(node))
846 return std::nullopt;
847
848 return {to_vector3d(m_boundary_flux->get_node_value_at_boundary(node))};
849 }
850
853 auto bc = get_block_and_cell(get_lattice(), node, true);
854 if (!bc)
855 return false;
856
857 m_boundary_flux->remove_node_from_boundary(node, *bc);
858 return true;
859 }
860
862 double density) override {
863 auto bc = get_block_and_cell(get_lattice(), node, true);
864 if (!bc)
865 return false;
866
867 m_boundary_density->set_node_value_at_boundary(node, FloatType_c(density),
868 *bc);
869
870 return true;
871 }
872
873 [[nodiscard]] std::optional<double>
875 bool consider_ghosts = false) const override {
876 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
877 if (!bc or !m_boundary_density->node_is_boundary(node))
878 return std::nullopt;
879
880 return {double_c(m_boundary_density->get_node_value_at_boundary(node))};
881 }
882
885 std::vector<std::optional<double>> const &density) override {
886 auto const &lattice = get_lattice();
887 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
888 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
889 auto const lower_cell = ci->min();
890 auto const upper_cell = ci->max();
891 auto it = density.begin();
892 assert(density.size() == ci->numCells());
893 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
894 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
895 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
896 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
897 auto const bc = get_block_and_cell(lattice, node, false);
898 auto const &opt = *it;
899 if (opt) {
900 m_boundary_density->set_node_value_at_boundary(
901 node, FloatType_c(*opt), *bc);
902 } else {
903 m_boundary_density->remove_node_from_boundary(node, *bc);
904 }
905 ++it;
906 }
907 }
908 }
909 }
910 }
911
912 [[nodiscard]] std::vector<std::optional<double>>
915 Utils::Vector3i const &upper_corner) const override {
916 std::vector<std::optional<double>> out;
917 auto const &lattice = get_lattice();
918 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
919 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
920 auto const lower_cell = ci->min();
921 auto const upper_cell = ci->max();
922 auto const n_values = ci->numCells();
923 out.reserve(n_values);
924 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
925 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
926 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
927 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
928 if (m_boundary_density->node_is_boundary(node)) {
929 out.emplace_back(double_c(
930 m_boundary_density->get_node_value_at_boundary(node)));
931 } else {
932 out.emplace_back(std::nullopt);
933 }
934 }
935 }
936 }
937 assert(out.size() == n_values);
938 }
939 return out;
940 }
941
944 std::vector<std::optional<Utils::Vector3d>> const &flux) override {
946 auto const &lattice = get_lattice();
947 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
948 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
949 auto const lower_cell = ci->min();
950 auto const upper_cell = ci->max();
951 auto it = flux.begin();
952 assert(flux.size() == ci->numCells());
953 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
954 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
955 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
956 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
957 auto const bc = get_block_and_cell(lattice, node, false);
958 auto const &opt = *it;
959 if (opt) {
960 m_boundary_flux->set_node_value_at_boundary(
961 node, to_vector3<FloatType>(*opt), *bc);
962 } else {
963 m_boundary_flux->remove_node_from_boundary(node, *bc);
964 }
965 ++it;
966 }
967 }
968 }
969 }
970 }
971
972 [[nodiscard]] std::vector<std::optional<Utils::Vector3d>>
975 Utils::Vector3i const &upper_corner) const override {
976 std::vector<std::optional<Utils::Vector3d>> out;
977 auto const &lattice = get_lattice();
978 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
979 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
980 auto const lower_cell = ci->min();
981 auto const upper_cell = ci->max();
982 auto const n_values = ci->numCells();
983 out.reserve(n_values);
984 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
985 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
986 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
987 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
988 if (m_boundary_flux->node_is_boundary(node)) {
989 out.emplace_back(to_vector3d(
990 m_boundary_flux->get_node_value_at_boundary(node)));
991 } else {
992 out.emplace_back(std::nullopt);
993 }
994 }
995 }
996 }
997 assert(out.size() == n_values);
998 }
999 return out;
1000 }
1001
1002 [[nodiscard]] std::vector<bool>
1004 Utils::Vector3i const &upper_corner) const override {
1005 std::vector<bool> out;
1006 auto const &lattice = get_lattice();
1007 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
1008 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
1009 auto const lower_cell = ci->min();
1010 auto const upper_cell = ci->max();
1011 auto const n_values = ci->numCells();
1012 out.reserve(n_values);
1013 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
1014 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
1015 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
1016 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
1017 out.emplace_back(m_boundary_density->node_is_boundary(node) or
1018 m_boundary_flux->node_is_boundary(node));
1019 }
1020 }
1021 }
1022 assert(out.size() == n_values);
1023 }
1024 return out;
1025 }
1026
1028 auto bc = get_block_and_cell(get_lattice(), node, true);
1029 if (!bc)
1030 return false;
1031
1032 m_boundary_density->remove_node_from_boundary(node, *bc);
1033
1034 return true;
1035 }
1036
1037 [[nodiscard]] std::optional<bool>
1039 bool consider_ghosts) const override {
1042 if (!bc)
1043 return std::nullopt;
1044
1045 return {m_boundary_flux->node_is_boundary(node)};
1046 }
1047
1048 [[nodiscard]] std::optional<bool>
1050 bool consider_ghosts) const override {
1052 if (!bc)
1053 return std::nullopt;
1054
1055 return {m_boundary_density->node_is_boundary(node)};
1056 }
1057
1058 [[nodiscard]] std::optional<bool>
1060 bool consider_ghosts = false) const override {
1062 if (!bc)
1063 return std::nullopt;
1064
1065 return {m_boundary_density->node_is_boundary(node) or
1066 m_boundary_flux->node_is_boundary(node)};
1067 }
1068
1070 const std::vector<int> &raster_flat,
1071 const std::vector<double> &data_flat) override {
1073 auto const grid_size = get_lattice().get_grid_dimensions();
1074 auto const data = fill_3D_vector_array(data_flat, grid_size);
1077 }
1078
1080 const std::vector<int> &raster_flat,
1081 const std::vector<double> &data_flat) override {
1082 auto const grid_size = get_lattice().get_grid_dimensions();
1083 auto const data = fill_3D_scalar_array(data_flat, grid_size);
1085 data);
1087 }
1088
1090
1092 m_boundary_density->boundary_update();
1093 }
1094
1096 return *m_lattice;
1097 }
1098
1099 [[nodiscard]] bool is_gpu() const noexcept override {
1101 }
1102
1103 void register_vtk_field_filters(walberla::vtk::VTKOutput &vtk_obj) override {
1104 field::FlagFieldCellFilter<FlagField> dens_filter(m_flag_field_density_id);
1105 field::FlagFieldCellFilter<FlagField> flux_filter(m_flag_field_flux_id);
1106 dens_filter.addFlag(Boundary_flag);
1107 flux_filter.addFlag(Boundary_flag);
1108 vtk_obj.addCellExclusionFilter(dens_filter);
1109 vtk_obj.addCellExclusionFilter(flux_filter);
1110 }
1111
1112protected:
1113 template <typename VecType, uint_t F_SIZE_ARG, typename OutputType>
1114 class VTKWriter : public vtk::BlockCellDataWriter<OutputType, F_SIZE_ARG> {
1115 public:
1116 VTKWriter(ConstBlockDataID const &block_id, std::string const &id,
1117 FloatType unit_conversion)
1118 : vtk::BlockCellDataWriter<OutputType, F_SIZE_ARG>(id),
1120
1121 protected:
1123
1124 std::size_t get_first_index(cell_idx_t const x, cell_idx_t const y,
1125 cell_idx_t const z) {
1126 return (static_cast<std::size_t>(x) * m_dims[2] * m_dims[1] +
1127 static_cast<std::size_t>(y) * m_dims[2] +
1128 static_cast<std::size_t>(z)) *
1129 F_SIZE_ARG;
1130 }
1131
1132 FloatType m_conversion;
1135
1136 public:
1138
1139 void set_dims(Vector3<uint_t> dims) { m_dims = dims; }
1140 };
1141
1142 template <typename OutputType = float>
1144 : public VTKWriter<std::vector<FloatType>, 1u, OutputType> {
1145 public:
1146 using Base = VTKWriter<std::vector<FloatType>, 1u, OutputType>;
1147 using Base::Base;
1148 using Base::evaluate;
1149
1150 protected:
1151 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1152 cell_idx_t const z, cell_idx_t const) override {
1153 WALBERLA_ASSERT(!this->m_content.empty());
1154 auto const density = this->m_content[this->get_first_index(x, y, z)];
1156 }
1157 };
1158
1159 template <typename OutputType = float>
1161 : public VTKWriter<std::vector<FloatType>, 3u, OutputType> {
1162 public:
1163 using Base = VTKWriter<std::vector<FloatType>, 3u, OutputType>;
1164 using Base::Base;
1165 using Base::evaluate;
1166
1167 protected:
1168 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1169 cell_idx_t const z, cell_idx_t const f) override {
1170 WALBERLA_ASSERT(!this->m_content.empty());
1171 auto flux = this->m_content[this->get_first_index(x, y, z) + f];
1173 }
1174 };
1175
1176 template <typename OutputType = float>
1177 class BoundaryVTKWriter : public vtk::BlockCellDataWriter<OutputType, 1u> {
1178 public:
1179 using Base = vtk::BlockCellDataWriter<OutputType, 1u>;
1180 using Base::evaluate;
1182 std::string const &id, FlagUID const &boundary_flag)
1183 : vtk::BlockCellDataWriter<OutputType, 1u>(id),
1186
1187 protected:
1193
1194 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1195 cell_idx_t const z, cell_idx_t const) override {
1197 return m_flag_field->isFlagSet(x, y, z, m_boundary_flag_value)
1198 ? OutputType{1}
1199 : OutputType{0};
1200 }
1201
1205 typename FlagField::flag_t m_boundary_flag_value;
1206 };
1207
1208public:
1209 void register_vtk_field_writers(walberla::vtk::VTKOutput &vtk_obj,
1211 int flag_observables) override {
1212 if (flag_observables & static_cast<int>(EKOutputVTK::density)) {
1213 auto const unit_conversion = FloatType_c(units.at("density"));
1214 auto const blocks = m_lattice->get_blocks();
1218 auto before_function = [this, blocks, density_writer]() {
1219 for (auto &block : *blocks) {
1220 auto *density_field =
1222
1223 auto const offset = m_lattice->get_block_corner(block, true);
1224 auto const *flag_field =
1226 auto const boundary_flag = flag_field->getFlag(Boundary_flag);
1228 if (flag_field->isFlagSet(x, y, z, boundary_flag)) {
1229 Cell const global(offset[0] + x, offset[1] + y, offset[2] + z);
1230 auto const density =
1231 m_boundary_density->get_node_value_at_boundary(global);
1232 Cell const local(x, y, z);
1233 ek::accessor::Scalar::set(density_field, density, local);
1234 }
1235 }) // WALBERLA_FOR_ALL_CELLS_XYZ
1236
1237 auto const bci = density_field->xyzSize();
1238 density_writer->set_content(
1240 density_writer->set_dims(
1241 Vector3<uint_t>(bci.xSize(), bci.ySize(), bci.zSize()));
1242 }
1243 };
1244
1245 vtk_obj.addBeforeFunction(std::move(before_function));
1246 vtk_obj.addCellDataWriter(density_writer);
1247 }
1248 if (flag_observables & static_cast<int>(EKOutputVTK::flux)) {
1249 auto const unit_conversion = FloatType_c(units.at("flux"));
1250 auto const blocks = m_lattice->get_blocks();
1254 auto before_function = [this, blocks, flux_writer]() {
1255 for (auto &block : *blocks) {
1257 auto const bci = flux_field->xyzSize();
1259 auto const block_offset = m_lattice->get_block_corner(block, true);
1260 std::size_t index = 0u;
1261 for (auto x = bci.xMin(); x <= bci.xMax(); ++x) {
1262 for (auto y = bci.yMin(); y <= bci.yMax(); ++y) {
1263 for (auto z = bci.zMin(); z <= bci.zMax(); ++z) {
1264 auto const node = block_offset + Utils::Vector3i{{x, y, z}};
1265 if (m_boundary_flux->node_is_boundary(node)) {
1266 auto const &vec =
1267 m_boundary_flux->get_node_value_at_boundary(node);
1268 values[3u * index + 0u] = vec[0];
1269 values[3u * index + 1u] = vec[1];
1270 values[3u * index + 2u] = vec[2];
1271 }
1272 ++index;
1273 }
1274 }
1275 }
1276 flux_writer->set_content(std::move(values));
1277 flux_writer->set_dims(
1278 Vector3<uint_t>(bci.xSize(), bci.ySize(), bci.zSize()));
1279 }
1280 };
1281 vtk_obj.addBeforeFunction(std::move(before_function));
1282 vtk_obj.addCellDataWriter(flux_writer);
1283 }
1284 if (flag_observables & static_cast<int>(EKOutputVTK::boundary)) {
1285 vtk_obj.addCellDataWriter(make_shared<BoundaryVTKWriter<float>>(
1287 }
1288 }
1289
1290 ~EKinWalberlaImpl() override = default;
1291};
1292
1293} // namespace walberla
Vector implementation and trait types for boost qvm interoperability.
Interface of a lattice-based electrokinetic model.
std::map< std::string, std::shared_ptr< VTKHandle > > m_vtk_auto
VTK writers that are executed automatically.
std::unordered_map< std::string, double > units_map
Class that runs and controls the BlockForest in waLBerla.
walberla::blockforest::StructuredBlockForest Lattice_T
std::pair< Utils::Vector3i, Utils::Vector3i > get_local_grid_range(bool with_halo=false) const
Utils::Vector3i get_block_corner(IBlock const &block, bool lower) const
Boundary class optimized for sparse data.
vtk::BlockCellDataWriter< OutputType, 1u > Base
OutputType evaluate(cell_idx_t const x, cell_idx_t const y, cell_idx_t const z, cell_idx_t const) override
BoundaryVTKWriter(ConstBlockDataID const &flag_field_id, std::string const &id, FlagUID const &boundary_flag)
OutputType evaluate(cell_idx_t const x, cell_idx_t const y, cell_idx_t const z, cell_idx_t const) override
OutputType evaluate(cell_idx_t const x, cell_idx_t const y, cell_idx_t const z, cell_idx_t const f) override
void set_dims(Vector3< uint_t > dims)
std::size_t get_first_index(cell_idx_t const x, cell_idx_t const y, cell_idx_t const z)
VTKWriter(ConstBlockDataID const &block_id, std::string const &id, FloatType unit_conversion)
Class that runs and controls the EK on waLBerla.
~EKinWalberlaImpl() override=default
void set_slice_flux_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< std::optional< Utils::Vector3d > > const &flux) override
void set_kT(double kT) override
std::optional< double > get_node_density_at_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
double get_kT() const noexcept override
std::unique_ptr< DiffusiveFluxKernelElectrostatic > m_diffusive_flux_electrostatic
walberla::FlagField< walberla::uint8_t > FlagField
void set_friction_coupling(bool friction_coupling) override
void set_rng_state(uint64_t counter) override
void integrate(std::size_t potential_id, std::size_t velocity_id, std::size_t force_id, double lb_density) override
bool set_node_density_boundary(Utils::Vector3i const &node, double density) override
void set_slice_density(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< double > const &density) override
std::shared_ptr< FullCommunicator > m_full_communication
std::bitset< GhostComm::SIZE > m_pending_ghost_comm
std::vector< double > get_slice_density(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void update_density_boundary_from_shape(const std::vector< int > &raster_flat, const std::vector< double > &data_flat) override
void update_flux_boundary_from_shape(const std::vector< int > &raster_flat, const std::vector< double > &data_flat) override
std::vector< bool > get_slice_is_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void set_ext_efield(Utils::Vector3d const &field) override
bool set_node_density(Utils::Vector3i const &node, double density) override
double get_diffusion() const noexcept override
void set_valency(double valency) override
bool is_thermalized() const noexcept override
auto add_to_storage(std::string const tag, FloatType value)
Convenience function to add a field with a custom allocator.
std::optional< double > get_node_density(Utils::Vector3i const &node, bool consider_ghosts=false) const override
std::size_t get_density_id() const noexcept override
unsigned int get_seed() const noexcept override
std::unique_ptr< ContinuityKernel > m_continuity
double get_valency() const noexcept override
typename FieldTrait< FloatType, Architecture >::FluxField FluxField
std::shared_ptr< BoundaryModelFlux > m_boundary_flux
void set_slice_density_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< std::optional< double > > const &density) override
void reset_flux_boundary_handling(std::shared_ptr< BlockStorage > const &blocks)
bool get_advection() const noexcept override
std::optional< Utils::Vector3d > get_node_flux_vector(Utils::Vector3i const &node, bool consider_ghosts=false) const override
typename FieldTrait< FloatType, Architecture >::template BoundaryCommScheme< typename stencil::D3Q27 > BoundaryFullCommunicator
typename FieldTrait< FloatType, Architecture >::template RegularCommScheme< typename stencil::D3Q27 > FullCommunicator
std::optional< uint64_t > get_rng_state() const override
void set_advection(bool advection) override
bool remove_node_from_density_boundary(Utils::Vector3i const &node) override
typename FieldTrait< FloatType, Architecture >::template PackInfo< Field > PackInfo
bool get_friction_coupling() const noexcept override
Utils::Vector3d get_ext_efield() const noexcept override
stencil::D3Q27 Stencil
Stencil for collision and streaming operations.
LatticeWalberla const & get_lattice() const noexcept override
bool remove_node_from_flux_boundary(Utils::Vector3i const &node) override
bool is_double_precision() const noexcept override
typename FieldTrait< FloatType, Architecture >::DensityField DensityField
bool is_gpu() const noexcept override
void clear_density_boundaries() override
std::optional< bool > get_node_is_flux_boundary(Utils::Vector3i const &node, bool consider_ghosts) const override
LatticeWalberla::Lattice_T BlockStorage
Lattice model (e.g.
void reset_density_boundary_handling(std::shared_ptr< BlockStorage > const &blocks)
std::vector< std::optional< Utils::Vector3d > > get_slice_flux_at_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
ResourceObserver m_mpi_cart_comm_observer
std::vector< std::optional< double > > get_slice_density_at_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void register_vtk_field_writers(walberla::vtk::VTKOutput &vtk_obj, LatticeModel::units_map const &units, int flag_observables) override
std::optional< Utils::Vector3d > get_node_flux_at_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
std::vector< double > get_slice_flux_vector(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
typename FieldTrait< FloatType >::DensityField _DensityField
std::shared_ptr< BoundaryFullCommunicator > m_boundary_communicator
std::optional< bool > get_node_is_density_boundary(Utils::Vector3i const &node, bool consider_ghosts) const override
std::unique_ptr< DiffusiveFluxKernel > m_diffusive_flux
void set_diffusion(double diffusion) override
std::size_t stencil_size() const noexcept override
FlagUID const Boundary_flag
Flag for boundary cells.
bool set_node_flux_boundary(Utils::Vector3i const &node, Utils::Vector3d const &flux) override
typename FieldTrait< FloatType >::FluxField _FluxField
std::optional< bool > get_node_is_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
std::unique_ptr< BoundaryModelDensity > m_boundary_density
EKinWalberlaImpl(std::shared_ptr< LatticeWalberla > lattice, double diffusion, double kT, double valency, Utils::Vector3d const &ext_efield, double density, bool advection, bool friction_coupling, bool thermalized, unsigned int seed)
std::shared_ptr< LatticeWalberla > m_lattice
Block forest.
FlagUID const Domain_flag
Flag for domain cells, i.e.
void register_vtk_field_filters(walberla::vtk::VTKOutput &vtk_obj) override
void setup_boundary_handle(std::shared_ptr< LatticeWalberla > lattice, std::shared_ptr< Boundary_T > boundary)
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
static double * block(double *p, std::size_t index, std::size_t size)
Definition elc.cpp:169
STL namespace.
auto get_vector(GhostLayerField< double, uint_t{13u}> const *flux_field, Cell const &cell)
void initialize(GhostLayerField< double, uint_t{13u}> *flux_field, std::array< double, 13 > const &values)
void initialize(GhostLayerField< double, 1u > *scalar_field, double const &value)
void set(GhostLayerField< double, 1u > *scalar_field, double const &value, Cell const &cell)
auto get(GhostLayerField< double, 1u > const *scalar_field, Cell const &cell)
static FUNC_PREFIX double *RESTRICT const double *RESTRICT const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const uint32_t uint32_t uint32_t uint32_t uint32_t uint32_t uint32_t seed
\file PackInfoPdfDoublePrecision.cpp \author pystencils
auto to_vector3d(Vector3< T > const &v) noexcept
std::vector< double > fill_3D_scalar_array(std::vector< double > const &vec_flat, Utils::Vector3i const &grid_size)
Definition boundary.hpp:60
void set_boundary_from_grid(BoundaryModel &boundary, LatticeWalberla const &lattice, std::vector< int > const &raster_flat, std::vector< DataType > const &data_flat)
Definition boundary.hpp:81
void copy_block_buffer(CellInterval const &bci, CellInterval const &ci, Utils::Vector3i const &block_offset, Utils::Vector3i const &lower_corner, auto &&kernel)
Synchronize data between a sliced block and a container.
std::optional< BlockAndCell > get_block_and_cell(::LatticeWalberla const &lattice, signed_integral_vector auto const &node, bool consider_ghost_layers)
Cell to_cell(signed_integral_vector auto const &xyz)
ResourceObserver get_mpi_cart_comm_observer()
Get an observer on waLBerla's MPI Cartesian communicator status.
std::optional< walberla::cell::CellInterval > get_block_interval(::LatticeWalberla const &lattice, Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, Utils::Vector3i const &block_offset, IBlock const &block)
std::optional< walberla::cell::CellInterval > get_interval(::LatticeWalberla const &lattice, Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner)
std::vector< Utils::Vector3d > fill_3D_vector_array(std::vector< double > const &vec_flat, Utils::Vector3i const &grid_size)
Definition boundary.hpp:36
Observer to monitor the lifetime of a shared resource.
blockforest::communication::UniformBufferedScheme< Stencil > RegularCommScheme
GhostLayerField< FT, FluxCount > FluxField
field::communication::PackInfo< Field > PackInfo
blockforest::communication::UniformBufferedScheme< Stencil > BoundaryCommScheme
GhostCommFlags
Ghost communication operations.