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 <iterator>
59#include <memory>
60#include <optional>
61#include <stdexcept>
62#include <string>
63#include <type_traits>
64#include <variant>
65#include <vector>
66
67namespace walberla {
68
69/** @brief Class that runs and controls the EK on waLBerla. */
70template <std::size_t FluxCount = 13, typename FloatType = double,
71 lbmpy::Arch Architecture = lbmpy::Arch::CPU>
73#if not defined(WALBERLA_BUILD_WITH_CUDA)
74 static_assert(Architecture != lbmpy::Arch::GPU,
75 "waLBerla was compiled without CUDA support");
76#endif
77 using ContinuityKernel =
79 using DiffusiveFluxKernelUnthermalized =
80 typename detail::KernelTrait<FloatType,
81 Architecture>::DiffusiveFluxKernel;
82 using DiffusiveFluxKernelThermalized = typename detail::KernelTrait<
83 FloatType, Architecture>::DiffusiveFluxKernelThermalized;
84 using AdvectiveFluxKernel =
85 typename detail::KernelTrait<FloatType,
86 Architecture>::AdvectiveFluxKernel;
87 using FrictionCouplingKernel =
88 typename detail::KernelTrait<FloatType,
89 Architecture>::FrictionCouplingKernel;
90 using DiffusiveFluxKernelElectrostaticUnthermalized =
91 typename detail::KernelTrait<
92 FloatType, Architecture>::DiffusiveFluxKernelElectrostatic;
93 using DiffusiveFluxKernelElectrostaticThermalized =
94 typename detail::KernelTrait<
95 FloatType, Architecture>::DiffusiveFluxKernelElectrostaticThermalized;
96
97 using DiffusiveFluxKernel = std::variant<DiffusiveFluxKernelUnthermalized,
98 DiffusiveFluxKernelThermalized>;
99 using DiffusiveFluxKernelElectrostatic =
100 std::variant<DiffusiveFluxKernelElectrostaticUnthermalized,
101 DiffusiveFluxKernelElectrostaticThermalized>;
102
103 using Dirichlet =
105 using FixedFlux =
107
110 using BoundaryModelFlux =
112
113public:
114 /** @brief Stencil for collision and streaming operations. */
115 using Stencil = stencil::D3Q27;
116 /** @brief Lattice model (e.g. blockforest). */
118
119protected:
120 template <typename FT, lbmpy::Arch AT = lbmpy::Arch::CPU> struct FieldTrait {
121 // Type definitions
122 using FluxField = GhostLayerField<FT, FluxCount>;
123 using DensityField = GhostLayerField<FT, 1>;
124 template <class Field>
125 using PackInfo = field::communication::PackInfo<Field>;
126 template <class Stencil>
128 blockforest::communication::UniformBufferedScheme<Stencil>;
129 template <class Stencil>
131 blockforest::communication::UniformBufferedScheme<Stencil>;
132 };
133 using FlagField = walberla::FlagField<walberla::uint8_t>;
134#if defined(__CUDACC__) and defined(WALBERLA_BUILD_WITH_CUDA)
135 template <typename FT> struct FieldTrait<FT, lbmpy::Arch::GPU> {
136 private:
137 static auto constexpr AT = lbmpy::Arch::GPU;
138 template <class Field>
139 using MemcpyPackInfo = gpu::communication::MemcpyPackInfo<Field>;
140
141 public:
142 template <typename Stencil>
143 class UniformGPUScheme
144 : public gpu::communication::UniformGPUScheme<Stencil> {
145 public:
146 explicit UniformGPUScheme(auto const &bf)
147 : gpu::communication::UniformGPUScheme<Stencil>(
148 bf, /* sendDirectlyFromGPU */ false,
149 /* useLocalCommunication */ false) {}
150 };
151 using FluxField = gpu::GPUField<FT>;
152 using DensityField = gpu::GPUField<FT>;
153 template <class Field> using PackInfo = MemcpyPackInfo<Field>;
154 template <class Stencil>
155 using RegularCommScheme = UniformGPUScheme<Stencil>;
156 template <class Stencil>
157 using BoundaryCommScheme =
158 blockforest::communication::UniformBufferedScheme<Stencil>;
159 };
160 using GPUField = gpu::GPUField<FloatType>;
161#endif
162
163 struct GhostComm {
164 /** @brief Ghost communication operations. */
165 enum GhostCommFlags : unsigned {
166 FLB, ///< flux boundary communication
167 DENS, ///< density communication
168 SIZE
169 };
170 };
171
172 // "underlying" field types (`GPUField` has no f-size info at compile time)
175
176public:
180
181 template <typename T> FloatType FloatType_c(T t) {
182 return numeric_cast<FloatType>(t);
183 }
184
185 [[nodiscard]] std::size_t stencil_size() const noexcept override {
186 return FluxCount;
187 }
188
189 [[nodiscard]] bool is_double_precision() const noexcept override {
190 return std::is_same_v<FloatType, double>;
191 }
192
193private:
194 FloatType m_diffusion;
195 FloatType m_kT;
196 FloatType m_valency;
197 Utils::Vector3d m_ext_efield;
198 bool m_advection;
199 bool m_friction_coupling;
200 unsigned int m_seed;
201
202protected:
203 // Block data access handles
205
206 BlockDataID m_flux_field_id;
207
210
211 /** Flag for domain cells, i.e. all cells. */
212 FlagUID const Domain_flag{"domain"};
213 /** Flag for boundary cells. */
214 FlagUID const Boundary_flag{"boundary"};
215
216 /** Block forest */
217 std::shared_ptr<LatticeWalberla> m_lattice;
218
219 std::unique_ptr<BoundaryModelDensity> m_boundary_density;
220 std::shared_ptr<BoundaryModelFlux> m_boundary_flux;
221
222 std::unique_ptr<DiffusiveFluxKernel> m_diffusive_flux;
223 std::unique_ptr<DiffusiveFluxKernelElectrostatic>
225 std::unique_ptr<ContinuityKernel> m_continuity;
226
227 // ResetFlux + external force
228 // TODO: kernel for that
229 // std::shared_ptr<ResetForce<PdfField, VectorField>> m_reset_force;
230
231 /**
232 * @brief Convenience function to add a field with a custom allocator.
233 *
234 * When vectorization is off, let waLBerla decide which memory allocator
235 * to use. When vectorization is on, the aligned memory allocator is
236 * required, otherwise <tt>cpu_vectorize_info["assume_aligned"]</tt> will
237 * trigger assertions. That is because for single-precision kernels the
238 * waLBerla heuristic in <tt>src/field/allocation/FieldAllocator.h</tt>
239 * will fall back to @c StdFieldAlloc, yet @c AllocateAligned is needed
240 * for intrinsics to work.
241 */
242 template <typename Field>
243 auto add_to_storage(std::string const tag, FloatType value) {
244 auto const &blocks = m_lattice->get_blocks();
245 auto const n_ghost_layers = m_lattice->get_ghost_layers();
246#if defined(__CUDACC__) and defined(WALBERLA_BUILD_WITH_CUDA)
247 if constexpr (Architecture == lbmpy::Arch::GPU) {
248 auto field_id = gpu::addGPUFieldToStorage<GPUField>(
249 blocks, tag, Field::F_SIZE, field::fzyx, n_ghost_layers);
250 if constexpr (std::is_same_v<Field, _DensityField>) {
251 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
252 auto field = block->template getData<GPUField>(field_id);
253 ek::accessor::Scalar::initialize(field, FloatType{value});
254 }
255 } else if constexpr (std::is_same_v<Field, _FluxField>) {
256 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
257 auto field = block->template getData<GPUField>(field_id);
259 std::array<FloatType, FluxCount>{});
260 }
261 }
262 return field_id;
263 }
264#endif
265 return field::addToStorage<Field>(blocks, tag, FloatType{value},
266 field::fzyx, n_ghost_layers);
267 }
268
269 void
270 reset_density_boundary_handling(std::shared_ptr<BlockStorage> const &blocks) {
271 auto const [lc, uc] = m_lattice->get_local_grid_range(true);
272 m_boundary_density = std::make_unique<BoundaryModelDensity>(
274 CellInterval{to_cell(lc), to_cell(uc)});
275 }
276
277 void
278 reset_flux_boundary_handling(std::shared_ptr<BlockStorage> const &blocks) {
279 auto const [lc, uc] = m_lattice->get_local_grid_range(true);
280 m_boundary_flux = std::make_shared<BoundaryModelFlux>(
282 CellInterval{to_cell(lc), to_cell(uc)});
283 }
284
286 typename FieldTrait<FloatType, Architecture>::template RegularCommScheme<
287 typename stencil::D3Q27>;
289 typename FieldTrait<FloatType, Architecture>::template BoundaryCommScheme<
290 typename stencil::D3Q27>;
291 std::shared_ptr<FullCommunicator> m_full_communication;
292 std::shared_ptr<BoundaryFullCommunicator> m_boundary_communicator;
293 std::bitset<GhostComm::SIZE> m_pending_ghost_comm;
295 template <class Field>
296 using PackInfo =
298
299public:
300 EKinWalberlaImpl(std::shared_ptr<LatticeWalberla> lattice, double diffusion,
301 double kT, double valency, Utils::Vector3d const &ext_efield,
302 double density, bool advection, bool friction_coupling,
303 bool thermalized, unsigned int seed)
304 : m_diffusion(FloatType_c(diffusion)), m_kT(FloatType_c(kT)),
305 m_valency(FloatType_c(valency)), m_ext_efield(ext_efield),
306 m_advection(advection), m_friction_coupling(friction_coupling),
307 m_seed(seed), m_lattice(std::move(lattice)),
309
310 auto const &blocks = m_lattice->get_blocks();
311 auto const n_ghost_layers = m_lattice->get_ghost_layers();
312
314 add_to_storage<_DensityField>("density field", FloatType_c(density));
316 add_to_storage<_FluxField>("flux field", FloatType_c(0.0));
317
319 std::make_unique<ContinuityKernel>(m_flux_field_id, m_density_field_id);
320
321 if (thermalized) {
322 set_diffusion_kernels(*m_lattice, seed);
323 } else {
324 set_diffusion_kernels();
325 }
326
327 // Init boundary related stuff
328 m_flag_field_density_id = field::addFlagFieldToStorage<FlagField>(
329 blocks, "flag field density", n_ghost_layers);
331
332 m_flag_field_flux_id = field::addFlagFieldToStorage<FlagField>(
333 blocks, "flag field flux", n_ghost_layers);
335
336 m_full_communication = std::make_shared<FullCommunicator>(blocks);
337 m_full_communication->addPackInfo(
338 std::make_shared<PackInfo<DensityField>>(m_density_field_id));
340 std::make_shared<BoundaryFullCommunicator>(blocks);
341 m_boundary_communicator->addPackInfo(
344 auto flux_boundary_packinfo = std::make_shared<
347 flux_boundary_packinfo->setup_boundary_handle(m_lattice, m_boundary_flux);
348 m_boundary_communicator->addPackInfo(flux_boundary_packinfo);
349
351 }
352
353 // Global parameters
354 [[nodiscard]] double get_diffusion() const noexcept override {
355 return m_diffusion;
356 }
357 [[nodiscard]] double get_kT() const noexcept override { return m_kT; }
358 [[nodiscard]] double get_valency() const noexcept override {
359 return m_valency;
360 }
361 [[nodiscard]] bool get_advection() const noexcept override {
362 return m_advection;
363 }
364 [[nodiscard]] bool get_friction_coupling() const noexcept override {
365 return m_friction_coupling;
366 }
367 [[nodiscard]] Utils::Vector3d get_ext_efield() const noexcept override {
368 return m_ext_efield;
369 }
370 [[nodiscard]] bool is_thermalized() const noexcept override {
371 return static_cast<bool>(
372 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux));
373 }
374 [[nodiscard]] unsigned int get_seed() const noexcept override {
375 return m_seed;
376 }
377 [[nodiscard]] std::optional<uint64_t> get_rng_state() const override {
378 auto const kernel =
379 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
380 if (!kernel) {
381 return std::nullopt;
382 }
383 return {static_cast<uint64_t>(kernel->getTime_step())};
384 }
385
386 void set_diffusion(double diffusion) override {
387 m_diffusion = FloatType_c(diffusion);
388 auto visitor = [m_diffusion = m_diffusion](auto &kernel) {
389 kernel.setD(m_diffusion);
390 };
391 std::visit(visitor, *m_diffusive_flux);
392 std::visit(visitor, *m_diffusive_flux_electrostatic);
393 }
394
395 void set_kT(double kT) override {
396 m_kT = FloatType_c(kT);
397 std::visit([m_kT = m_kT](auto &kernel) { kernel.setKt(m_kT); },
399 }
400
401 void set_valency(double valency) override {
402 m_valency = FloatType_c(valency);
403 std::visit(
404 [m_valency = m_valency](auto &kernel) { kernel.setZ(m_valency); },
406 }
407
408 void set_advection(bool advection) override { m_advection = advection; }
409
410 void set_friction_coupling(bool friction_coupling) override {
411 m_friction_coupling = friction_coupling;
412 }
413
414 void set_rng_state(uint64_t counter) override {
415 auto const kernel =
416 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
417 auto const kernel_electrostatic =
418 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
420
421 if (!kernel or !kernel_electrostatic) {
422 throw std::runtime_error("This EK instance is unthermalized");
423 }
424 assert(counter <=
425 static_cast<uint32_t>(std::numeric_limits<uint_t>::max()));
426 kernel->setTime_step(static_cast<uint32_t>(counter));
427 kernel_electrostatic->setTime_step(static_cast<uint32_t>(counter));
428 }
429
430 void set_ext_efield(Utils::Vector3d const &field) override {
431 m_ext_efield = field;
432
433 std::visit(
434 [this](auto &kernel) {
435 kernel.setF_ext_0(FloatType_c(m_ext_efield[0]));
436 kernel.setF_ext_1(FloatType_c(m_ext_efield[1]));
437 kernel.setF_ext_2(FloatType_c(m_ext_efield[2]));
438 },
440 }
441
442 void ghost_communication() override {
445 (*m_full_communication)();
447 }
449 }
450
458
459private:
460 void set_diffusion_kernels() {
461 auto kernel = DiffusiveFluxKernelUnthermalized(
463 m_diffusive_flux = std::make_unique<DiffusiveFluxKernel>(std::move(kernel));
464
465 auto kernel_electrostatic = DiffusiveFluxKernelElectrostaticUnthermalized(
466 m_flux_field_id, BlockDataID{}, m_density_field_id,
467 FloatType_c(m_diffusion), FloatType_c(m_ext_efield[0]),
468 FloatType_c(m_ext_efield[1]), FloatType_c(m_ext_efield[2]),
469 FloatType_c(m_kT), FloatType_c(m_valency));
470
472 std::make_unique<DiffusiveFluxKernelElectrostatic>(
473 std::move(kernel_electrostatic));
474 }
475
476 void set_diffusion_kernels(LatticeWalberla const &lattice,
477 unsigned int seed) {
478 auto const grid_dim = lattice.get_grid_dimensions();
479
480 auto kernel = DiffusiveFluxKernelThermalized(
482 grid_dim[0], grid_dim[1], grid_dim[2], seed, 0);
483
484 auto kernel_electrostatic = DiffusiveFluxKernelElectrostaticThermalized(
485 m_flux_field_id, BlockDataID{}, m_density_field_id,
486 FloatType_c(m_diffusion), FloatType_c(m_ext_efield[0]),
487 FloatType_c(m_ext_efield[1]), FloatType_c(m_ext_efield[2]), grid_dim[0],
488 grid_dim[1], grid_dim[2], FloatType_c(m_kT), seed, 0,
489 FloatType_c(m_valency));
490
491 auto const blocks = lattice.get_blocks();
492
493 for (auto &block : *blocks) {
494 kernel.configure(blocks, &block);
495 kernel_electrostatic.configure(blocks, &block);
496 }
497
498 m_diffusive_flux = std::make_unique<DiffusiveFluxKernel>(std::move(kernel));
500 std::make_unique<DiffusiveFluxKernelElectrostatic>(
501 std::move(kernel_electrostatic));
502 }
503
504 void kernel_boundary_density() {
505 for (auto &block : *m_lattice->get_blocks()) {
506 (*m_boundary_density)(&block);
507 }
508 }
509
510 void kernel_boundary_flux() {
511 for (auto &block : *m_lattice->get_blocks()) {
512 (*m_boundary_flux)(&block);
513 }
514 }
515
516 void kernel_continuity() {
517 for (auto &block : *m_lattice->get_blocks()) {
518 (*m_continuity).run(&block);
519 }
520 }
521
522 void kernel_diffusion() {
523 for (auto &block : *m_lattice->get_blocks()) {
524 std::visit([&block](auto &kernel) { kernel.run(&block); },
526 }
527
528 if (auto *kernel =
529 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux)) {
530 kernel->setTime_step(kernel->getTime_step() + 1u);
531
532 auto *kernel_electrostatic =
533 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
535 kernel_electrostatic->setTime_step(kernel_electrostatic->getTime_step() +
536 1u);
537 }
538 }
539
540 void kernel_advection(std::size_t const velocity_id) {
541 auto kernel = AdvectiveFluxKernel(m_flux_field_id, m_density_field_id,
542 BlockDataID(velocity_id));
543 for (auto &block : *m_lattice->get_blocks()) {
544 kernel.run(&block);
545 }
546 }
547
548 void kernel_friction_coupling(std::size_t const force_id,
549 double const lb_density) {
550 auto kernel = FrictionCouplingKernel(
551 BlockDataID(force_id), m_flux_field_id, FloatType_c(get_diffusion()),
552 FloatType_c(get_kT()), FloatType(lb_density));
553 for (auto &block : *m_lattice->get_blocks()) {
554 kernel.run(&block);
555 }
556 }
557
558 void kernel_diffusion_electrostatic(std::size_t const potential_id) {
559 auto const phiID = BlockDataID(potential_id);
560 std::visit([phiID](auto &kernel) { kernel.setPhiID(phiID); },
562
563 for (auto &block : *m_lattice->get_blocks()) {
564 std::visit([&block](auto &kernel) { kernel.run(&block); },
566 }
567
568 if (auto *kernel_electrostatic =
569 std::get_if<DiffusiveFluxKernelElectrostaticThermalized>(
571 kernel_electrostatic->setTime_step(kernel_electrostatic->getTime_step() +
572 1u);
573
574 auto *kernel =
575 std::get_if<DiffusiveFluxKernelThermalized>(&*m_diffusive_flux);
576 kernel->setTime_step(kernel->getTime_step() + 1u);
577 }
578 }
579
580 void kernel_migration() {}
581
582 void update_boundary_fields() {
583 m_boundary_flux->boundary_update();
584 m_boundary_density->boundary_update();
585 }
586
587protected:
588 void integrate_vtk_writers() override {
589 for (auto const &it : m_vtk_auto) {
590 auto &vtk_handle = it.second;
591 if (vtk_handle->enabled) {
592 vtk::writeFiles(vtk_handle->ptr)();
593 vtk_handle->execution_count++;
594 }
595 }
596 }
597
598public:
599 void integrate(std::size_t potential_id, std::size_t velocity_id,
600 std::size_t force_id, double lb_density) override {
601
603 update_boundary_fields();
604
605 if (get_diffusion() == 0.)
606 return;
607
608 if (get_valency() != 0.) {
609 if (potential_id == walberla::BlockDataID{}) {
610 throw std::runtime_error("Walberla EK: electrostatic potential enabled "
611 "but no field accessible. potential id is " +
612 std::to_string(potential_id));
613 }
614 kernel_diffusion_electrostatic(potential_id);
615 } else {
616 kernel_diffusion();
617 }
618
619 kernel_migration();
620 kernel_boundary_flux();
621 // friction coupling
622 if (get_friction_coupling()) {
623 if (force_id == walberla::BlockDataID{}) {
624 throw std::runtime_error("Walberla EK: friction coupling enabled but "
625 "no force field accessible. force_id is " +
626 std::to_string(force_id) +
627 ". Hint: LB may be inactive.");
628 }
629 kernel_friction_coupling(force_id, lb_density);
630 }
631
632 if (get_advection()) {
633 if (velocity_id == walberla::BlockDataID{}) {
634 throw std::runtime_error("Walberla EK: advection enabled but no "
635 "velocity field accessible. velocity_id is " +
636 std::to_string(velocity_id) +
637 ". Hint: LB may be inactive.");
638 }
639 kernel_advection(velocity_id);
640 kernel_boundary_flux();
641 }
642 kernel_continuity();
643
644 // is this the expected behavior when reactions are included?
645 kernel_boundary_density();
647
648 // Handle VTK writers
650 }
651
652 [[nodiscard]] std::size_t get_density_id() const noexcept override {
653 static_assert(std::is_same_v<std::size_t, walberla::uint_t>);
654 return static_cast<std::size_t>(m_density_field_id);
655 }
656
657 bool set_node_density(Utils::Vector3i const &node, double density) override {
659 auto bc = get_block_and_cell(get_lattice(), node, false);
660 if (!bc)
661 return false;
662
663 auto density_field =
664 bc->block->template getData<DensityField>(m_density_field_id);
665 ek::accessor::Scalar::set(density_field, FloatType_c(density), bc->cell);
666 return true;
667 }
668
669 [[nodiscard]] std::optional<double>
671 bool consider_ghosts = false) const override {
672 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
673
674 if (!bc)
675 return std::nullopt;
676
677 auto const density_field =
678 bc->block->template getData<DensityField>(m_density_field_id);
679 return {double_c(ek::accessor::Scalar::get(density_field, bc->cell))};
680 }
681
682 [[nodiscard]] std::vector<double>
684 Utils::Vector3i const &upper_corner) const override {
685 std::vector<double> out;
686#ifndef NDEBUG
687 uint_t values_size = 0u;
688#endif
689 auto const &lattice = get_lattice();
690 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
691 out = std::vector<double>(ci->numCells());
692 for (auto &block : *lattice.get_blocks()) {
693 auto const block_offset = lattice.get_block_corner(block, true);
694 if (auto const bci = get_block_interval(
695 lattice, lower_corner, upper_corner, block_offset, block)) {
696 auto const density_field =
697 block.template getData<DensityField>(m_density_field_id);
698 auto const values = ek::accessor::Scalar::get(density_field, *bci);
699 assert(values.size() == bci->numCells());
700#ifndef NDEBUG
701 values_size += bci->numCells();
702#endif
703 auto kernel = [&values, &out](unsigned const block_index,
704 unsigned const local_index,
705 Utils::Vector3i const &) {
706 out[local_index] = double_c(values[block_index]);
707 };
708
709 copy_block_buffer(*bci, *ci, block_offset, lower_corner, kernel);
710 }
711 }
712 assert(values_size == ci->numCells());
713 }
714 return out;
715 }
716
717 void set_slice_density(Utils::Vector3i const &lower_corner,
718 Utils::Vector3i const &upper_corner,
719 std::vector<double> const &density) override {
721 auto const &lattice = get_lattice();
722 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
723 assert(density.size() == ci->numCells());
724 for (auto &block : *lattice.get_blocks()) {
725 auto const block_offset = lattice.get_block_corner(block, true);
726 if (auto const bci = get_block_interval(
727 lattice, lower_corner, upper_corner, block_offset, block)) {
728 auto const density_field =
729 block.template getData<DensityField>(m_density_field_id);
730 std::vector<FloatType> values(bci->numCells());
731
732 auto kernel = [&values, &density](unsigned const block_index,
733 unsigned const local_index,
734 Utils::Vector3i const &) {
735 values[block_index] = numeric_cast<FloatType>(density[local_index]);
736 };
737
738 copy_block_buffer(*bci, *ci, block_offset, lower_corner, kernel);
739 ek::accessor::Scalar::set(density_field, values, *bci);
740 }
741 }
742 }
743 }
744
745 [[nodiscard]] std::optional<Utils::Vector3d>
747 bool consider_ghosts = false) const override {
748 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
749
750 if (!bc)
751 return std::nullopt;
752
753 auto const flux_field =
754 bc->block->template getData<FluxField>(m_flux_field_id);
755 return to_vector3d(ek::accessor::Flux::get_vector(flux_field, bc->cell));
756 }
757
758 std::vector<double>
760 Utils::Vector3i const &upper_corner) const override {
761 std::vector<double> out;
762#ifndef NDEBUG
763 uint_t values_size = 0;
764#endif
765 auto const &lattice = get_lattice();
766 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
767 out = std::vector<double>(3u * ci->numCells());
768 for (auto &block : *lattice.get_blocks()) {
769 auto const block_offset = lattice.get_block_corner(block, true);
770 if (auto const bci = get_block_interval(
771 lattice, lower_corner, upper_corner, block_offset, block)) {
772 auto const flux_field =
773 block.template getData<FluxField>(m_flux_field_id);
774 auto const values = ek::accessor::Flux::get_vector(flux_field, *bci);
775 assert(values.size() == 3u * bci->numCells());
776#ifndef NDEBUG
777 values_size += 3u * bci->numCells();
778#endif
779
780 auto kernel = [&values, &out, this](unsigned const block_index,
781 unsigned const local_index,
782 Utils::Vector3i const &node) {
783 if (m_boundary_flux->node_is_boundary(node)) {
784 auto const &vec =
785 m_boundary_flux->get_node_value_at_boundary(node);
786 for (uint_t f = 0u; f < 3u; ++f) {
787 out[3u * local_index + f] = double_c(vec[f]);
788 }
789 } else {
790 for (uint_t f = 0u; f < 3u; ++f) {
791 out[3u * local_index + f] =
792 double_c(values[3u * block_index + f]);
793 }
794 }
795 };
796
797 copy_block_buffer(*bci, *ci, block_offset, lower_corner, kernel);
798 }
799 }
800 assert(values_size == 3u * ci->numCells());
801 }
802 return out;
803 }
804
809
810 void clear_density_boundaries() override {
812 }
813
815 Utils::Vector3d const &flux) override {
817 auto bc = get_block_and_cell(get_lattice(), node, true);
818 if (!bc)
819 return false;
820
821 m_boundary_flux->set_node_value_at_boundary(
822 node, to_vector3<FloatType>(flux), *bc);
823 return true;
824 }
825
826 [[nodiscard]] std::optional<Utils::Vector3d>
828 bool consider_ghosts = false) const override {
829 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::FLB)));
830 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
831 if (!bc or !m_boundary_flux->node_is_boundary(node))
832 return std::nullopt;
833
834 return {to_vector3d(m_boundary_flux->get_node_value_at_boundary(node))};
835 }
836
839 auto bc = get_block_and_cell(get_lattice(), node, true);
840 if (!bc)
841 return false;
842
843 m_boundary_flux->remove_node_from_boundary(node, *bc);
844 return true;
845 }
846
848 double density) override {
849 auto bc = get_block_and_cell(get_lattice(), node, true);
850 if (!bc)
851 return false;
852
853 m_boundary_density->set_node_value_at_boundary(node, FloatType_c(density),
854 *bc);
855
856 return true;
857 }
858
859 [[nodiscard]] std::optional<double>
861 bool consider_ghosts = false) const override {
862 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
863 if (!bc or !m_boundary_density->node_is_boundary(node))
864 return std::nullopt;
865
866 return {double_c(m_boundary_density->get_node_value_at_boundary(node))};
867 }
868
870 Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner,
871 std::vector<std::optional<double>> const &density) override {
872 auto const &lattice = get_lattice();
873 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
874 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
875 auto const lower_cell = ci->min();
876 auto const upper_cell = ci->max();
877 auto it = density.begin();
878 assert(density.size() == ci->numCells());
879 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
880 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
881 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
882 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
883 auto const bc = get_block_and_cell(lattice, node, false);
884 auto const &opt = *it;
885 if (opt) {
886 m_boundary_density->set_node_value_at_boundary(
887 node, FloatType_c(*opt), *bc);
888 } else {
889 m_boundary_density->remove_node_from_boundary(node, *bc);
890 }
891 ++it;
892 }
893 }
894 }
895 }
896 }
897
898 [[nodiscard]] std::vector<std::optional<double>>
900 Utils::Vector3i const &lower_corner,
901 Utils::Vector3i const &upper_corner) const override {
902 std::vector<std::optional<double>> out;
903 auto const &lattice = get_lattice();
904 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
905 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
906 auto const lower_cell = ci->min();
907 auto const upper_cell = ci->max();
908 auto const n_values = ci->numCells();
909 out.reserve(n_values);
910 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
911 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
912 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
913 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
914 if (m_boundary_density->node_is_boundary(node)) {
915 out.emplace_back(double_c(
916 m_boundary_density->get_node_value_at_boundary(node)));
917 } else {
918 out.emplace_back(std::nullopt);
919 }
920 }
921 }
922 }
923 assert(out.size() == n_values);
924 }
925 return out;
926 }
927
929 Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner,
930 std::vector<std::optional<Utils::Vector3d>> const &flux) override {
932 auto const &lattice = get_lattice();
933 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
934 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
935 auto const lower_cell = ci->min();
936 auto const upper_cell = ci->max();
937 auto it = flux.begin();
938 assert(flux.size() == ci->numCells());
939 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
940 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
941 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
942 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
943 auto const bc = get_block_and_cell(lattice, node, false);
944 auto const &opt = *it;
945 if (opt) {
946 m_boundary_flux->set_node_value_at_boundary(
947 node, to_vector3<FloatType>(*opt), *bc);
948 } else {
949 m_boundary_flux->remove_node_from_boundary(node, *bc);
950 }
951 ++it;
952 }
953 }
954 }
955 }
956 }
957
958 [[nodiscard]] std::vector<std::optional<Utils::Vector3d>>
960 Utils::Vector3i const &lower_corner,
961 Utils::Vector3i const &upper_corner) const override {
962 std::vector<std::optional<Utils::Vector3d>> out;
963 auto const &lattice = get_lattice();
964 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
965 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
966 auto const lower_cell = ci->min();
967 auto const upper_cell = ci->max();
968 auto const n_values = ci->numCells();
969 out.reserve(n_values);
970 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
971 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
972 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
973 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
974 if (m_boundary_flux->node_is_boundary(node)) {
975 out.emplace_back(to_vector3d(
976 m_boundary_flux->get_node_value_at_boundary(node)));
977 } else {
978 out.emplace_back(std::nullopt);
979 }
980 }
981 }
982 }
983 assert(out.size() == n_values);
984 }
985 return out;
986 }
987
988 [[nodiscard]] std::vector<bool>
990 Utils::Vector3i const &upper_corner) const override {
991 std::vector<bool> out;
992 auto const &lattice = get_lattice();
993 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
994 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
995 auto const lower_cell = ci->min();
996 auto const upper_cell = ci->max();
997 auto const n_values = ci->numCells();
998 out.reserve(n_values);
999 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
1000 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
1001 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
1002 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
1003 out.emplace_back(m_boundary_density->node_is_boundary(node) or
1004 m_boundary_flux->node_is_boundary(node));
1005 }
1006 }
1007 }
1008 assert(out.size() == n_values);
1009 }
1010 return out;
1011 }
1012
1014 auto bc = get_block_and_cell(get_lattice(), node, true);
1015 if (!bc)
1016 return false;
1017
1018 m_boundary_density->remove_node_from_boundary(node, *bc);
1019
1020 return true;
1021 }
1022
1023 [[nodiscard]] std::optional<bool>
1025 bool consider_ghosts) const override {
1026 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::FLB)));
1027 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1028 if (!bc)
1029 return std::nullopt;
1030
1031 return {m_boundary_flux->node_is_boundary(node)};
1032 }
1033
1034 [[nodiscard]] std::optional<bool>
1036 bool consider_ghosts) const override {
1037 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1038 if (!bc)
1039 return std::nullopt;
1040
1041 return {m_boundary_density->node_is_boundary(node)};
1042 }
1043
1044 [[nodiscard]] std::optional<bool>
1046 bool consider_ghosts = false) const override {
1047 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1048 if (!bc)
1049 return std::nullopt;
1050
1051 return {m_boundary_density->node_is_boundary(node) or
1052 m_boundary_flux->node_is_boundary(node)};
1053 }
1054
1056 const std::vector<int> &raster_flat,
1057 const std::vector<double> &data_flat) override {
1059 auto const grid_size = get_lattice().get_grid_dimensions();
1060 auto const data = fill_3D_vector_array(data_flat, grid_size);
1061 set_boundary_from_grid(*m_boundary_flux, get_lattice(), raster_flat, data);
1063 }
1064
1066 const std::vector<int> &raster_flat,
1067 const std::vector<double> &data_flat) override {
1068 auto const grid_size = get_lattice().get_grid_dimensions();
1069 auto const data = fill_3D_scalar_array(data_flat, grid_size);
1071 data);
1073 }
1074
1076
1078 m_boundary_density->boundary_update();
1079 }
1080
1081 [[nodiscard]] LatticeWalberla const &get_lattice() const noexcept override {
1082 return *m_lattice;
1083 }
1084
1085 [[nodiscard]] bool is_gpu() const noexcept override {
1086 return Architecture == lbmpy::Arch::GPU;
1087 }
1088
1089 void register_vtk_field_filters(walberla::vtk::VTKOutput &vtk_obj) override {
1090 field::FlagFieldCellFilter<FlagField> fluid_filter(m_flag_field_density_id);
1091 fluid_filter.addFlag(Boundary_flag);
1092 vtk_obj.addCellExclusionFilter(fluid_filter);
1093 }
1094
1095protected:
1096 template <typename VecType, uint_t F_SIZE_ARG, typename OutputType>
1097 class VTKWriter : public vtk::BlockCellDataWriter<OutputType, F_SIZE_ARG> {
1098 public:
1099 VTKWriter(ConstBlockDataID const &block_id, std::string const &id,
1100 FloatType unit_conversion)
1101 : vtk::BlockCellDataWriter<OutputType, F_SIZE_ARG>(id),
1102 m_conversion(unit_conversion), m_content{} {}
1103
1104 protected:
1105 void configure() override { WALBERLA_ASSERT_NOT_NULLPTR(this->block_); }
1106
1107 std::size_t get_first_index(cell_idx_t const x, cell_idx_t const y,
1108 cell_idx_t const z) {
1109 return (static_cast<std::size_t>(x) * m_dims[2] * m_dims[1] +
1110 static_cast<std::size_t>(y) * m_dims[2] +
1111 static_cast<std::size_t>(z)) *
1112 F_SIZE_ARG;
1113 }
1114
1115 FloatType m_conversion;
1116 VecType m_content;
1117 Vector3<uint_t> m_dims;
1118
1119 public:
1120 void set_content(VecType content) { m_content = std::move(content); }
1121
1122 void set_dims(Vector3<uint_t> dims) { m_dims = dims; }
1123 };
1124
1125 template <typename OutputType = float>
1127 : public VTKWriter<std::vector<FloatType>, 1u, OutputType> {
1128 public:
1129 using Base = VTKWriter<std::vector<FloatType>, 1u, OutputType>;
1130 using Base::Base;
1131 using Base::evaluate;
1132
1133 protected:
1134 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1135 cell_idx_t const z, cell_idx_t const) override {
1136 WALBERLA_ASSERT(!this->m_content.empty());
1137 auto const density = this->m_content[this->get_first_index(x, y, z)];
1138 return numeric_cast<OutputType>(this->m_conversion * density);
1139 }
1140 };
1141
1142 template <typename OutputType = float>
1144 : public VTKWriter<std::vector<FloatType>, 3u, OutputType> {
1145 public:
1146 using Base = VTKWriter<std::vector<FloatType>, 3u, 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 f) override {
1153 WALBERLA_ASSERT(!this->m_content.empty());
1154 auto flux = this->m_content[this->get_first_index(x, y, z) + f];
1155 return numeric_cast<OutputType>(this->m_conversion * flux);
1156 }
1157 };
1158
1159 template <typename OutputType = float>
1160 class BoundaryVTKWriter : public vtk::BlockCellDataWriter<OutputType, 1u> {
1161 public:
1162 using Base = vtk::BlockCellDataWriter<OutputType, 1u>;
1163 using Base::evaluate;
1164 BoundaryVTKWriter(ConstBlockDataID const &flag_field_id,
1165 std::string const &id, FlagUID const &boundary_flag)
1166 : vtk::BlockCellDataWriter<OutputType, 1u>(id),
1167 m_flag_field_id(flag_field_id), m_flag_field(nullptr),
1168 m_boundary_flag(boundary_flag) {}
1169
1170 protected:
1171 void configure() override {
1172 WALBERLA_ASSERT_NOT_NULLPTR(this->block_);
1173 m_flag_field = this->block_->template getData<FlagField>(m_flag_field_id);
1175 }
1176
1177 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1178 cell_idx_t const z, cell_idx_t const) override {
1179 WALBERLA_ASSERT_NOT_NULLPTR(m_flag_field);
1180 return m_flag_field->isFlagSet(x, y, z, m_boundary_flag_value)
1181 ? OutputType{1}
1182 : OutputType{0};
1183 }
1184
1185 ConstBlockDataID const m_flag_field_id;
1187 FlagUID const m_boundary_flag;
1188 typename FlagField::flag_t m_boundary_flag_value;
1189 };
1190
1191public:
1192 void register_vtk_field_writers(walberla::vtk::VTKOutput &vtk_obj,
1193 LatticeModel::units_map const &units,
1194 int flag_observables) override {
1195 if (flag_observables & static_cast<int>(EKOutputVTK::density)) {
1196 auto const unit_conversion = FloatType_c(units.at("density"));
1197 auto const blocks = m_lattice->get_blocks();
1198 WALBERLA_ASSERT_NOT_NULLPTR(blocks);
1199 auto density_writer = make_shared<DensityVTKWriter<float>>(
1200 m_density_field_id, "density", unit_conversion);
1201 auto before_function = [this, blocks, density_writer]() {
1202 for (auto &block : *blocks) {
1203 auto *density_field =
1204 block.template getData<DensityField>(m_density_field_id);
1205
1206 auto const offset = m_lattice->get_block_corner(block, true);
1207 auto const *flag_field =
1208 block.template getData<FlagField>(m_flag_field_density_id);
1209 auto const boundary_flag = flag_field->getFlag(Boundary_flag);
1210 WALBERLA_FOR_ALL_CELLS_XYZ(flag_field, {
1211 if (flag_field->isFlagSet(x, y, z, boundary_flag)) {
1212 Cell const global(offset[0] + x, offset[1] + y, offset[2] + z);
1213 auto const density =
1214 m_boundary_density->get_node_value_at_boundary(global);
1215 Cell const local(x, y, z);
1216 ek::accessor::Scalar::set(density_field, density, local);
1217 }
1218 }) // WALBERLA_FOR_ALL_CELLS_XYZ
1219
1220 auto const bci = density_field->xyzSize();
1221 density_writer->set_content(
1222 ek::accessor::Scalar::get(density_field, bci));
1223 density_writer->set_dims(
1224 Vector3<uint_t>(bci.xSize(), bci.ySize(), bci.zSize()));
1225 }
1226 };
1227
1228 vtk_obj.addBeforeFunction(std::move(before_function));
1229 vtk_obj.addCellDataWriter(density_writer);
1230 }
1231 if (flag_observables & static_cast<int>(EKOutputVTK::flux)) {
1232 auto const unit_conversion = FloatType_c(units.at("flux"));
1233 auto const blocks = m_lattice->get_blocks();
1234 WALBERLA_ASSERT_NOT_NULLPTR(blocks);
1235 auto flux_writer = make_shared<FluxVTKWriter<float>>(
1236 m_flux_field_id, "flux", unit_conversion);
1237 auto before_function = [this, blocks, flux_writer]() {
1238 for (auto &block : *blocks) {
1239 auto *flux_field = block.template getData<FluxField>(m_flux_field_id);
1240 auto const bci = flux_field->xyzSize();
1241 auto values = ek::accessor::Flux::get_vector(flux_field, bci);
1242 auto const block_offset = m_lattice->get_block_corner(block, true);
1243 std::size_t index = 0u;
1244 for (auto x = bci.xMin(); x <= bci.xMax(); ++x) {
1245 for (auto y = bci.yMin(); y <= bci.yMax(); ++y) {
1246 for (auto z = bci.zMin(); z <= bci.zMax(); ++z) {
1247 auto const node = block_offset + Utils::Vector3i{{x, y, z}};
1248 if (m_boundary_flux->node_is_boundary(node)) {
1249 auto const &vec =
1250 m_boundary_flux->get_node_value_at_boundary(node);
1251 values[3u * index + 0u] = vec[0];
1252 values[3u * index + 1u] = vec[1];
1253 values[3u * index + 2u] = vec[2];
1254 }
1255 ++index;
1256 }
1257 }
1258 }
1259 flux_writer->set_content(std::move(values));
1260 flux_writer->set_dims(
1261 Vector3<uint_t>(bci.xSize(), bci.ySize(), bci.zSize()));
1262 }
1263 };
1264 vtk_obj.addBeforeFunction(std::move(before_function));
1265 vtk_obj.addCellDataWriter(flux_writer);
1266 }
1267 if (flag_observables & static_cast<int>(EKOutputVTK::boundary)) {
1268 vtk_obj.addCellDataWriter(make_shared<BoundaryVTKWriter<float>>(
1270 }
1271 }
1272
1273 ~EKinWalberlaImpl() override = default;
1274};
1275
1276} // 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)
static double * block(double *p, std::size_t index, std::size_t size)
Definition elc.cpp:175
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.