ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
LBWalberlaImpl.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019-2024 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/**
23 * @file
24 * @ref walberla::LBWalberlaImpl implements the interface of the LB
25 * waLBerla bridge using sweeps generated by lbmpy
26 * (see <tt>maintainer/walberla_kernels</tt>).
27 */
28
29#include <blockforest/Initialization.h>
30#include <blockforest/StructuredBlockForest.h>
31#include <blockforest/communication/UniformBufferedScheme.h>
32#include <domain_decomposition/BlockDataID.h>
33#include <domain_decomposition/IBlock.h>
34#include <field/AddToStorage.h>
35#include <field/GhostLayerField.h>
36#include <field/communication/PackInfo.h>
37#include <field/vtk/FlagFieldCellFilter.h>
38#include <field/vtk/VTKWriter.h>
39#include <stencil/D3Q19.h>
40#include <stencil/D3Q27.h>
41#if defined(__CUDACC__)
42#include <gpu/AddGPUFieldToStorage.h>
43#include <gpu/communication/MemcpyPackInfo.h>
44#include <gpu/communication/UniformGPUScheme.h>
45#endif
46
47#include "../BoundaryHandling.hpp"
48#include "../BoundaryPackInfo.hpp"
49#include "../utils/boundary.hpp"
50#include "../utils/types_conversion.hpp"
52#include "ResetForce.hpp"
53#include "lb_kernels.hpp"
54#if defined(__CUDACC__)
55#include "lb_kernels.cuh"
56#endif
57
63
64#include <utils/Vector.hpp>
67
68#include <array>
69#include <bitset>
70#include <cmath>
71#include <cstddef>
72#include <functional>
73#include <initializer_list>
74#include <limits>
75#include <memory>
76#include <optional>
77#include <stdexcept>
78#include <string>
79#include <tuple>
80#include <type_traits>
81#include <utility>
82#include <variant>
83#include <vector>
84
85namespace walberla {
86
87/** @brief Class that runs and controls the LB on waLBerla. */
88template <typename FloatType, lbmpy::Arch Architecture>
90protected:
92 typename detail::KernelTrait<FloatType,
93 Architecture>::CollisionModelLeesEdwards;
95 typename detail::KernelTrait<FloatType,
96 Architecture>::CollisionModelThermalized;
103 typename detail::BoundaryHandlingTrait<
104 FloatType, Architecture>::Dynamic_UBB>;
106 std::variant<CollisionModelThermalized, CollisionModelLeesEdwards>;
107
108public:
109 /** @brief Stencil for collision and streaming operations. */
110 using Stencil = stencil::D3Q19;
111 /** @brief Stencil for ghost communication (includes domain corners). */
112 using StencilFull = stencil::D3Q27;
113 /** @brief Lattice model (e.g. blockforest). */
115
116protected:
117 template <typename FT, lbmpy::Arch AT = lbmpy::Arch::CPU> struct FieldTrait {
118 using PdfField = field::GhostLayerField<FT, Stencil::Size>;
119 using VectorField = field::GhostLayerField<FT, uint_t{3u}>;
120 template <class Field>
121 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
134#if defined(__CUDACC__)
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 PdfField = gpu::GPUField<FT>;
152 using VectorField = gpu::GPUField<FT>;
153 template <class Field> using PackInfo = MemcpyPackInfo<Field>;
158 template <class Stencil>
159 using RegularCommScheme = UniformGPUScheme<Stencil>;
160 template <class Stencil>
161 using BoundaryCommScheme =
162 blockforest::communication::UniformBufferedScheme<Stencil>;
163 };
164#endif
165
166 // "underlying" field types (`GPUField` has no f-size info at compile time)
169
170public:
174#if defined(__CUDACC__)
175 using GPUField = gpu::GPUField<FloatType>;
176#endif
177
178 struct GhostComm {
179 /** @brief Ghost communication operations. */
180 enum GhostCommFlags : unsigned {
181 PDF, ///< PDFs communication
182 VEL, ///< velocities communication
183 LAF, ///< last applied forces communication
184 UBB, ///< boundaries communication
185 SIZE
186 };
187 };
188
189public:
190 template <typename T> FloatType FloatType_c(T t) const {
191 return numeric_cast<FloatType>(t);
192 }
193
194 [[nodiscard]] std::size_t stencil_size() const noexcept override {
195 return static_cast<std::size_t>(Stencil::Size);
196 }
197
198 [[nodiscard]] virtual bool is_double_precision() const noexcept override {
199 return std::is_same_v<FloatType, double>;
200 }
201
202private:
203 class CollideSweepVisitor {
204 public:
205 using StructuredBlockStorage = LatticeWalberla::Lattice_T;
206
207 void operator()(CollisionModelThermalized &cm, IBlock *b) {
208 cm.configure(m_storage, b);
209 cm(b);
210 }
211
212 void operator()(CollisionModelLeesEdwards &cm, IBlock *b) {
213 cm.v_s_ = static_cast<decltype(cm.v_s_)>(
214 m_lees_edwards_callbacks->get_shear_velocity());
215 cm(b);
216 }
217
218 CollideSweepVisitor() = default;
219 CollideSweepVisitor(std::shared_ptr<StructuredBlockStorage> storage) {
220 m_storage = std::move(storage);
221 }
222 CollideSweepVisitor(std::shared_ptr<StructuredBlockStorage> storage,
223 std::shared_ptr<LeesEdwardsPack> callbacks) {
224 m_storage = std::move(storage);
225 m_lees_edwards_callbacks = std::move(callbacks);
226 }
227
228 private:
229 std::shared_ptr<StructuredBlockStorage> m_storage{};
230 std::shared_ptr<LeesEdwardsPack> m_lees_edwards_callbacks{};
231 };
232 CollideSweepVisitor m_run_collide_sweep{};
233
234 FloatType shear_mode_relaxation_rate() const {
235 return FloatType{2} / (FloatType{6} * m_viscosity + FloatType{1});
236 }
237
238 FloatType odd_mode_relaxation_rate(
239 FloatType shear_relaxation,
240 FloatType magic_number = FloatType{3} / FloatType{16}) const {
241 return (FloatType{4} - FloatType{2} * shear_relaxation) /
242 (FloatType{4} * magic_number * shear_relaxation + FloatType{2} -
243 shear_relaxation);
244 }
245
246 void reset_boundary_handling() {
247 auto const &blocks = get_lattice().get_blocks();
248 m_boundary = std::make_shared<BoundaryModel>(blocks, m_pdf_field_id,
250 }
251
252 FloatType pressure_tensor_correction_factor() const {
253 return m_viscosity / (m_viscosity + FloatType{1} / FloatType{6});
254 }
255
256 void pressure_tensor_correction(Matrix3<FloatType> &tensor) const {
257 auto const revert_factor = pressure_tensor_correction_factor();
258 for (auto const i : {1u, 2u, 3u, 5u, 6u, 7u}) {
259 tensor[i] *= revert_factor;
260 }
261 }
262
263 void pressure_tensor_correction(std::span<FloatType, 9ul> tensor) const {
264 auto const revert_factor = pressure_tensor_correction_factor();
265 for (auto const i : {1u, 2u, 3u, 5u, 6u, 7u}) {
266 tensor[i] *= revert_factor;
267 }
268 }
269
270 class interpolation_illegal_access : public std::runtime_error {
271 public:
272 explicit interpolation_illegal_access(std::string const &field,
273 Utils::Vector3d const &pos,
274 std::array<int, 3> const &node,
275 double weight)
276 : std::runtime_error("Access to LB " + field + " field failed") {
277 std::cerr << "pos [" << pos << "], node [" << Utils::Vector3i(node)
278 << "], weight " << weight << "\n";
279 }
280 };
281
282 class vtk_runtime_error : public std::runtime_error {
283 public:
284 explicit vtk_runtime_error(std::string const &vtk_uid,
285 std::string const &reason)
286 : std::runtime_error("VTKOutput object '" + vtk_uid + "' " + reason) {}
287 };
288
289protected:
290 // Member variables
291 FloatType m_viscosity; /// kinematic viscosity
292 FloatType m_density;
293 FloatType m_kT;
294 unsigned int m_seed;
295
296 // Block data access handles
297 BlockDataID m_pdf_field_id;
299 BlockDataID m_flag_field_id;
300
303
306
307 /** Flag for boundary cells. */
308 FlagUID const Boundary_flag{"boundary"};
309 bool m_has_boundaries{false};
310
311 /**
312 * @brief Full communicator.
313 * We use the D3Q27 directions to update cells along the diagonals during
314 * a full ghost communication. This is needed to properly update the corners
315 * of the ghost layer when setting cell velocities or populations.
316 */
318 typename FieldTrait<FloatType, Architecture>::template RegularCommScheme<
319 typename stencil::D3Q27>;
321 typename FieldTrait<FloatType, Architecture>::template BoundaryCommScheme<
322 typename stencil::D3Q27>;
323 /**
324 * @brief Regular communicator.
325 * We use the same directions as the stencil during integration.
326 */
328 typename FieldTrait<FloatType,
329 Architecture>::template RegularCommScheme<Stencil>;
330 template <class Field>
331 using PackInfo =
333
334 // communicators
335 std::shared_ptr<BoundaryFullCommunicator> m_boundary_communicator;
336 std::shared_ptr<RegularFullCommunicator> m_full_communicator;
337 std::shared_ptr<RegularFullCommunicator> m_pdf_communicator;
338 std::shared_ptr<RegularFullCommunicator> m_vel_communicator;
339 std::shared_ptr<RegularFullCommunicator> m_laf_communicator;
340 std::shared_ptr<PDFStreamingCommunicator> m_pdf_streaming_communicator;
341 std::bitset<GhostComm::SIZE> m_pending_ghost_comm;
342
343 // ResetForce sweep + external force handling
344 std::shared_ptr<ResetForce<PdfField, VectorField>> m_reset_force;
345
346 // Stream sweep
347 std::shared_ptr<StreamSweep> m_stream;
348
349 // Lees Edwards boundary interpolation
350 std::shared_ptr<LeesEdwardsPack> m_lees_edwards_callbacks;
351 std::shared_ptr<InterpolateAndShiftAtBoundary<_PdfField, FloatType>>
353 std::shared_ptr<InterpolateAndShiftAtBoundary<_VectorField, FloatType>>
355 std::shared_ptr<InterpolateAndShiftAtBoundary<_VectorField, FloatType>>
357
358 // Collision sweep
359 std::shared_ptr<CollisionModel> m_collision_model;
360
361 // boundaries
362 std::shared_ptr<BoundaryModel> m_boundary;
363
364 // lattice
365 std::shared_ptr<LatticeWalberla> m_lattice;
366
367 [[nodiscard]] std::optional<CellInterval>
368 get_interval(Utils::Vector3i const &lower_corner,
369 Utils::Vector3i const &upper_corner) const {
370 auto const &lattice = get_lattice();
371 auto const &cell_min = lower_corner;
372 auto const cell_max = upper_corner - Utils::Vector3i::broadcast(1);
373 auto const lower_bc = get_block_and_cell(lattice, cell_min, true);
374 auto const upper_bc = get_block_and_cell(lattice, cell_max, true);
375 if (not lower_bc or not upper_bc) {
376 return std::nullopt;
377 }
378 assert(&(*(lower_bc->block)) == &(*(upper_bc->block)));
379 return {CellInterval(lower_bc->cell, upper_bc->cell)};
380 }
381
382 /**
383 * @brief Convenience function to add a field with a custom allocator.
384 *
385 * When vectorization is off, let waLBerla decide which memory allocator
386 * to use. When vectorization is on, the aligned memory allocator is
387 * required, otherwise <tt>cpu_vectorize_info["assume_aligned"]</tt> will
388 * trigger assertions. That is because for single-precision kernels the
389 * waLBerla heuristic in <tt>src/field/allocation/FieldAllocator.h</tt>
390 * will fall back to @c StdFieldAlloc, yet @c AllocateAligned is needed
391 * for intrinsics to work.
392 */
393 template <typename Field> auto add_to_storage(std::string const tag) {
394 auto const &blocks = m_lattice->get_blocks();
395 auto const n_ghost_layers = m_lattice->get_ghost_layers();
396 if constexpr (Architecture == lbmpy::Arch::CPU) {
397#ifdef ESPRESSO_BUILD_WITH_AVX_KERNELS
398#if defined(__AVX512F__)
399 constexpr uint_t alignment = 64u;
400#elif defined(__AVX__)
401 constexpr uint_t alignment = 32u;
402#elif defined(__SSE__)
403 constexpr uint_t alignment = 16u;
404#else
405#error "Unsupported arch, check walberla src/field/allocation/FieldAllocator.h"
406#endif
407 using value_type = typename Field::value_type;
408 using Allocator = field::AllocateAligned<value_type, alignment>;
409 auto const allocator = std::make_shared<Allocator>();
410 auto const empty_set = Set<SUID>::emptySet();
411 return field::addToStorage<Field>(
412 blocks, tag, field::internal::defaultSize, FloatType{0}, field::fzyx,
413 n_ghost_layers, false, {}, empty_set, empty_set, allocator);
414#else // ESPRESSO_BUILD_WITH_AVX_KERNELS
415 return field::addToStorage<Field>(blocks, tag, FloatType{0}, field::fzyx,
416 n_ghost_layers);
417#endif // ESPRESSO_BUILD_WITH_AVX_KERNELS
418 }
419#if defined(__CUDACC__)
420 else {
421 auto field_id = gpu::addGPUFieldToStorage<GPUField>(
422 blocks, tag, Field::F_SIZE, field::fzyx, n_ghost_layers);
423 if constexpr (std::is_same_v<Field, _VectorField>) {
424 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
425 auto field = block->template getData<GPUField>(field_id);
426 lbm::accessor::Vector::initialize(field, Vector3<FloatType>{0});
427 }
428 } else if constexpr (std::is_same_v<Field, _PdfField>) {
429 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
430 auto field = block->template getData<GPUField>(field_id);
432 field, std::array<FloatType, Stencil::Size>{});
433 }
434 }
435 return field_id;
436 }
437#endif
438 }
439
441 auto const setup = [this]<typename PackInfoPdf, typename PackInfoVec>() {
442 auto const &blocks = m_lattice->get_blocks();
444 std::make_shared<PDFStreamingCommunicator>(blocks);
445 m_pdf_streaming_communicator->addPackInfo(
446 std::make_shared<PackInfoPdf>(m_pdf_field_id));
447 m_pdf_streaming_communicator->addPackInfo(
448 std::make_shared<PackInfoVec>(m_last_applied_force_field_id));
449 };
451 using PackInfoPdf = typename FieldTrait::PackInfoStreamingPdf;
452 using PackInfoVec = typename FieldTrait::PackInfoStreamingVec;
453 if (m_has_boundaries or (m_collision_model and has_lees_edwards_bc())) {
454 setup.template operator()<PackInfo<PdfField>, PackInfoVec>();
455 } else {
456 setup.template operator()<PackInfoPdf, PackInfoVec>();
457 }
458 }
459
460public:
461 LBWalberlaImpl(std::shared_ptr<LatticeWalberla> lattice, double viscosity,
462 double density)
464 m_kT(FloatType{0}), m_seed(0u), m_lattice(std::move(lattice)) {
465
466 auto const &blocks = m_lattice->get_blocks();
467 auto const n_ghost_layers = m_lattice->get_ghost_layers();
468 if (n_ghost_layers == 0u)
469 throw std::runtime_error("At least one ghost layer must be used");
470
471 // Initialize and register fields (must use the "underlying" types)
472 m_pdf_field_id = add_to_storage<_PdfField>("pdfs");
473 m_pdf_tmp_field_id = add_to_storage<_PdfField>("pdfs_tmp");
474 m_last_applied_force_field_id = add_to_storage<_VectorField>("force last");
475 m_force_to_be_applied_id = add_to_storage<_VectorField>("force next");
476 m_velocity_field_id = add_to_storage<_VectorField>("velocity");
477 m_vec_tmp_field_id = add_to_storage<_VectorField>("velocity_tmp");
478
479 // Initialize and register pdf field
480 auto pdf_setter =
483 for (auto b = blocks->begin(); b != blocks->end(); ++b) {
484 pdf_setter(&*b);
485 }
486
487 // Initialize and register flag field (fluid/boundary)
488 m_flag_field_id = field::addFlagFieldToStorage<FlagField>(
489 blocks, "flag field", n_ghost_layers);
490 // Initialize boundary sweep
491 reset_boundary_handling();
492
493 // Set up the communication and register fields
495
496 m_full_communicator = std::make_shared<RegularFullCommunicator>(blocks);
497 m_full_communicator->addPackInfo(
498 std::make_shared<PackInfo<PdfField>>(m_pdf_field_id));
499 m_full_communicator->addPackInfo(
501 m_full_communicator->addPackInfo(
502 std::make_shared<PackInfo<VectorField>>(m_velocity_field_id));
503
504 m_pdf_communicator = std::make_shared<RegularFullCommunicator>(blocks);
505 m_vel_communicator = std::make_shared<RegularFullCommunicator>(blocks);
506 m_laf_communicator = std::make_shared<RegularFullCommunicator>(blocks);
507 m_pdf_communicator->addPackInfo(
508 std::make_shared<PackInfo<PdfField>>(m_pdf_field_id));
509 m_vel_communicator->addPackInfo(
510 std::make_shared<PackInfo<VectorField>>(m_velocity_field_id));
511 m_laf_communicator->addPackInfo(
513
515 std::make_shared<BoundaryFullCommunicator>(blocks);
516 m_boundary_communicator->addPackInfo(
517 std::make_shared<field::communication::PackInfo<FlagField>>(
519 auto boundary_packinfo = std::make_shared<
522 boundary_packinfo->setup_boundary_handle(m_lattice, m_boundary);
523 m_boundary_communicator->addPackInfo(boundary_packinfo);
524
526
527 // Instantiate the sweep responsible for force double buffering and
528 // external forces
529 m_reset_force = std::make_shared<ResetForce<PdfField, VectorField>>(
531
532 // Prepare LB sweeps
533 // Note: For now, combined collide-stream sweeps cannot be used,
534 // because the collide-push variant is not supported by lbmpy.
535 // The following functors are individual in-place collide and stream steps
536 m_stream = std::make_shared<StreamSweep>(
538 }
539
540private:
541 void integrate_stream(std::shared_ptr<Lattice_T> const &blocks) {
542 for (auto b = blocks->begin(); b != blocks->end(); ++b)
543 (*m_stream)(&*b);
544 }
545
546 void integrate_collide(std::shared_ptr<Lattice_T> const &blocks) {
547 auto &cm_variant = *m_collision_model;
548 for (auto b = blocks->begin(); b != blocks->end(); ++b)
549 std::visit(m_run_collide_sweep, cm_variant, std::variant<IBlock *>(&*b));
550 if (auto *cm = std::get_if<CollisionModelThermalized>(&cm_variant)) {
551 cm->time_step_++;
552 }
553 }
554
555 auto has_lees_edwards_bc() const {
556 return std::holds_alternative<CollisionModelLeesEdwards>(
558 }
559
560 void apply_lees_edwards_pdf_interpolation(
561 std::shared_ptr<Lattice_T> const &blocks) {
562 for (auto b = blocks->begin(); b != blocks->end(); ++b)
564 }
565
566 void apply_lees_edwards_vel_interpolation_and_shift(
567 std::shared_ptr<Lattice_T> const &blocks) {
568 for (auto b = blocks->begin(); b != blocks->end(); ++b)
570 }
571
572 void apply_lees_edwards_last_applied_force_interpolation(
573 std::shared_ptr<Lattice_T> const &blocks) {
574 for (auto b = blocks->begin(); b != blocks->end(); ++b)
576 }
577
578 void integrate_reset_force(std::shared_ptr<Lattice_T> const &blocks) {
579 for (auto b = blocks->begin(); b != blocks->end(); ++b)
580 (*m_reset_force)(&*b);
581 }
582
583 void integrate_boundaries(std::shared_ptr<Lattice_T> const &blocks) {
584 for (auto b = blocks->begin(); b != blocks->end(); ++b)
585 (*m_boundary)(&*b);
586 }
587
588 void integrate_push_scheme() {
589 auto const &blocks = get_lattice().get_blocks();
590 // Reset force fields
591 integrate_reset_force(blocks);
592 // LB collide
593 integrate_collide(blocks);
594 m_pdf_streaming_communicator->communicate();
595 // Handle boundaries
596 if (m_has_boundaries) {
597 integrate_boundaries(blocks);
598 }
599 // LB stream
600 integrate_stream(blocks);
601 // Mark pending ghost layer updates
605 // Refresh ghost layers
607 }
608
609 void integrate_pull_scheme() {
610 auto const &blocks = get_lattice().get_blocks();
611 // Handle boundaries
612 if (m_has_boundaries) {
613 integrate_boundaries(blocks);
614 }
615 // LB stream
616 integrate_stream(blocks);
617 // LB collide
618 integrate_collide(blocks);
619 // Reset force fields
620 integrate_reset_force(blocks);
621 // Mark pending ghost layer updates
625 // Refresh ghost layers
627 }
628
629protected:
630 void integrate_vtk_writers() override {
631 for (auto const &it : m_vtk_auto) {
632 auto &vtk_handle = it.second;
633 if (vtk_handle->enabled) {
634 vtk::writeFiles(vtk_handle->ptr)();
635 vtk_handle->execution_count++;
636 }
637 }
638 }
639
640public:
641 void integrate() override {
642 if (has_lees_edwards_bc()) {
643 integrate_pull_scheme();
644 } else {
645 integrate_push_scheme();
646 }
647 // Handle VTK writers
649 }
650
651 void ghost_communication() override {
652 if (m_pending_ghost_comm.any()) {
655 }
656 }
657
658 void ghost_communication_pdf() override {
660 m_pdf_communicator->communicate();
661 if (has_lees_edwards_bc()) {
662 auto const &blocks = get_lattice().get_blocks();
663 apply_lees_edwards_pdf_interpolation(blocks);
664 }
666 }
667 }
668
669 void ghost_communication_vel() override {
671 m_vel_communicator->communicate();
672 if (has_lees_edwards_bc()) {
673 auto const &blocks = get_lattice().get_blocks();
674 apply_lees_edwards_vel_interpolation_and_shift(blocks);
675 }
677 }
678 }
679
682 m_laf_communicator->communicate();
683 if (has_lees_edwards_bc()) {
684 auto const &blocks = get_lattice().get_blocks();
685 apply_lees_edwards_last_applied_force_interpolation(blocks);
686 }
688 }
689 }
690
697
699 m_full_communicator->communicate();
700 if (has_lees_edwards_bc()) {
701 auto const &blocks = get_lattice().get_blocks();
702 apply_lees_edwards_pdf_interpolation(blocks);
703 apply_lees_edwards_vel_interpolation_and_shift(blocks);
704 apply_lees_edwards_last_applied_force_interpolation(blocks);
705 }
709 }
710
712 if (has_lees_edwards_bc()) {
713 m_full_communicator->communicate();
714 auto const &blocks = get_lattice().get_blocks();
715 apply_lees_edwards_pdf_interpolation(blocks);
716 apply_lees_edwards_vel_interpolation_and_shift(blocks);
717 apply_lees_edwards_last_applied_force_interpolation(blocks);
721 }
722 }
723
724 void set_collision_model(double kT, unsigned int seed) override {
725 auto const omega = shear_mode_relaxation_rate();
726 auto const omega_odd = odd_mode_relaxation_rate(omega);
727 auto const blocks = get_lattice().get_blocks();
728 m_kT = FloatType_c(kT);
729 m_seed = seed;
731 m_pdf_field_id, m_kT, omega, omega,
732 omega_odd, omega, seed, uint32_t{0u});
733 m_collision_model = std::make_shared<CollisionModel>(std::move(obj));
734 m_run_collide_sweep = CollideSweepVisitor(blocks);
736 }
737
739 std::unique_ptr<LeesEdwardsPack> &&lees_edwards_pack) override {
740 assert(m_kT == 0.);
741#if defined(__CUDACC__)
742 if constexpr (Architecture == lbmpy::Arch::GPU) {
743 throw std::runtime_error("Lees-Edwards LB doesn't support GPU yet");
744 }
745#endif
746 auto const shear_direction = lees_edwards_pack->shear_direction;
747 auto const shear_plane_normal = lees_edwards_pack->shear_plane_normal;
748 auto const shear_vel = FloatType_c(lees_edwards_pack->get_shear_velocity());
749 auto const omega = shear_mode_relaxation_rate();
750 if (shear_plane_normal != 1u) {
751 throw std::domain_error(
752 "Lees-Edwards LB only supports shear_plane_normal=\"y\"");
753 }
754 auto const &lattice = get_lattice();
755 auto const n_ghost_layers = lattice.get_ghost_layers();
756 auto const blocks = lattice.get_blocks();
757 auto const agrid =
758 FloatType_c(lattice.get_grid_dimensions()[shear_plane_normal]);
759 auto obj = CollisionModelLeesEdwards(
760 m_last_applied_force_field_id, m_pdf_field_id, agrid, omega, shear_vel);
761 m_collision_model = std::make_shared<CollisionModel>(std::move(obj));
762 m_lees_edwards_callbacks = std::move(lees_edwards_pack);
763 m_run_collide_sweep = CollideSweepVisitor(blocks, m_lees_edwards_callbacks);
765 std::make_shared<InterpolateAndShiftAtBoundary<_PdfField, FloatType>>(
766 blocks, m_pdf_field_id, m_pdf_tmp_field_id, n_ghost_layers,
767 shear_direction, shear_plane_normal,
768 m_lees_edwards_callbacks->get_pos_offset);
769 m_lees_edwards_vel_interpol_sweep = std::make_shared<
771 blocks, m_velocity_field_id, m_vec_tmp_field_id, n_ghost_layers,
772 shear_direction, shear_plane_normal,
773 m_lees_edwards_callbacks->get_pos_offset,
774 m_lees_edwards_callbacks->get_shear_velocity);
778 n_ghost_layers, shear_direction, shear_plane_normal,
779 m_lees_edwards_callbacks->get_pos_offset);
781 }
782
783 void check_lebc(unsigned int shear_direction,
784 unsigned int shear_plane_normal) const override {
786 if (m_lees_edwards_callbacks->shear_direction != shear_direction or
787 m_lees_edwards_callbacks->shear_plane_normal != shear_plane_normal) {
788 throw std::runtime_error(
789 "MD and LB Lees-Edwards boundary conditions disagree");
790 }
791 }
792 }
793
794 void set_viscosity(double viscosity) override {
795 m_viscosity = FloatType_c(viscosity);
796 }
797
798 [[nodiscard]] double get_viscosity() const noexcept override {
799 return numeric_cast<double>(m_viscosity);
800 }
801
802 [[nodiscard]] double get_density() const noexcept override {
803 return numeric_cast<double>(m_density);
804 }
805
806 // Velocity
807 std::optional<Utils::Vector3d>
809 bool consider_ghosts = false) const override {
810 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::VEL)));
811 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::UBB)));
812 if (m_has_boundaries) {
813 auto const is_boundary = get_node_is_boundary(node, consider_ghosts);
814 if (is_boundary and *is_boundary) {
815 return get_node_velocity_at_boundary(node, consider_ghosts);
816 }
817 }
818 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
819 if (!bc)
820 return std::nullopt;
821
822 auto field = bc->block->template uncheckedFastGetData<VectorField>(
824 auto const vec = lbm::accessor::Vector::get(field, bc->cell);
825 return to_vector3d(vec);
826 }
827
829 Utils::Vector3d const &v) override {
832 auto bc = get_block_and_cell(get_lattice(), node, false);
833 if (!bc)
834 return false;
835
836 // We have to set both, the pdf and the stored velocity field
837 auto pdf_field = bc->block->template getData<PdfField>(m_pdf_field_id);
838 auto vel_field =
839 bc->block->template getData<VectorField>(m_velocity_field_id);
840 auto force_field =
841 bc->block->template getData<VectorField>(m_last_applied_force_field_id);
842 auto const vel = to_vector3<FloatType>(v);
843 lbm::accessor::Velocity::set(pdf_field, vel_field, force_field, vel,
844 bc->cell);
845
846 return true;
847 }
848
849 std::vector<double>
851 Utils::Vector3i const &upper_corner) const override {
852 std::vector<double> out;
853 if (auto const ci = get_interval(lower_corner, upper_corner)) {
854 auto const &lattice = get_lattice();
855 auto const &block = *(lattice.get_blocks()->begin());
856 auto const field =
857 block.template getData<VectorField>(m_velocity_field_id);
858 auto const values = lbm::accessor::Vector::get(field, *ci);
859 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
860 assert(values.size() == 3u * ci->numCells());
861 if constexpr (std::is_same_v<typename decltype(values)::value_type,
862 double>) {
863 out = std::move(values);
864 } else {
865 out = std::vector<double>(values.begin(), values.end());
866 }
867 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
868 auto const lower_cell = ci->min();
869 auto const upper_cell = ci->max();
870 auto it = out.begin();
871 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
872 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
873 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
874 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
875 if (m_boundary->node_is_boundary(node)) {
876 auto const &vec = m_boundary->get_node_value_at_boundary(node);
877 for (uint_t f = 0u; f < 3u; ++f) {
878 (*it) = double_c(vec[f]);
879 std::advance(it, 1l);
880 }
881 } else {
882 std::advance(it, 3l);
883 }
884 }
885 }
886 }
887 }
888 return out;
889 }
890
891 void set_slice_velocity(Utils::Vector3i const &lower_corner,
892 Utils::Vector3i const &upper_corner,
893 std::vector<double> const &velocity) override {
896 if (auto const ci = get_interval(lower_corner, upper_corner)) {
897 auto const &lattice = get_lattice();
898 auto &block = *(lattice.get_blocks()->begin());
899 auto pdf_field = block.template getData<PdfField>(m_pdf_field_id);
900 auto force_field =
901 block.template getData<VectorField>(m_last_applied_force_field_id);
902 auto vel_field = block.template getData<VectorField>(m_velocity_field_id);
903 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
904 assert(velocity.size() == 3u * ci->numCells());
905 std::vector<FloatType> const values(velocity.begin(), velocity.end());
906 lbm::accessor::Velocity::set(pdf_field, vel_field, force_field, values,
907 *ci);
908 }
909 }
910
911 [[nodiscard]] bool is_gpu() const noexcept override {
912 return Architecture == lbmpy::Arch::GPU;
913 }
914
915 void add_forces_at_pos(std::vector<Utils::Vector3d> const &pos,
916 std::vector<Utils::Vector3d> const &forces) override {
917 assert(pos.size() == forces.size());
918 if (pos.empty()) {
919 return;
920 }
921 if constexpr (Architecture == lbmpy::Arch::CPU) {
922 for (std::size_t i = 0ul; i < pos.size(); ++i) {
923 add_force_at_pos(pos[i], forces[i]);
924 }
925 }
926#if defined(__CUDACC__)
927 if constexpr (Architecture == lbmpy::Arch::GPU) {
928 auto const &lattice = get_lattice();
929 auto const &block = *(lattice.get_blocks()->begin());
930 auto const origin = block.getAABB().min();
931 std::vector<FloatType> host_pos;
932 std::vector<FloatType> host_force;
933 host_pos.reserve(3ul * pos.size());
934 host_force.reserve(3ul * forces.size());
935 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
936 for (auto const &vec : pos) {
937#pragma unroll
938 for (std::size_t i : {0ul, 1ul, 2ul}) {
939 host_pos.emplace_back(static_cast<FloatType>(vec[i] - origin[i]));
940 }
941 }
942 for (auto const &vec : forces) {
943#pragma unroll
944 for (std::size_t i : {0ul, 1ul, 2ul}) {
945 host_force.emplace_back(static_cast<FloatType>(vec[i]));
946 }
947 }
948 auto const gl = lattice.get_ghost_layers();
949 auto field = block.template uncheckedFastGetData<VectorField>(
951 lbm::accessor::Interpolation::set(field, host_pos, host_force, gl);
952 }
953#endif
954 }
955
956 std::vector<Utils::Vector3d>
957 get_velocities_at_pos(std::vector<Utils::Vector3d> const &pos) override {
958 if (pos.empty()) {
959 return {};
960 }
961 if constexpr (Architecture == lbmpy::Arch::CPU) {
962 std::vector<Utils::Vector3d> vel{};
963 vel.reserve(pos.size());
964 for (auto const &vec : pos) {
965 auto res = get_velocity_at_pos(vec, true);
966 assert(res.has_value());
967 vel.emplace_back(*res);
968 }
969 return vel;
970 }
971#if defined(__CUDACC__)
972 if constexpr (Architecture == lbmpy::Arch::GPU) {
973 auto const &lattice = get_lattice();
974 auto const &block = *(lattice.get_blocks()->begin());
975 auto const origin = block.getAABB().min();
976 std::vector<FloatType> host_pos;
977 host_pos.reserve(3ul * pos.size());
978 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
979 for (auto const &vec : pos) {
980#pragma unroll
981 for (std::size_t i : {0ul, 1ul, 2ul}) {
982 host_pos.emplace_back(static_cast<FloatType>(vec[i] - origin[i]));
983 }
984 }
985 auto const gl = lattice.get_ghost_layers();
986 auto field =
987 block.template uncheckedFastGetData<VectorField>(m_velocity_field_id);
988 auto const res = lbm::accessor::Interpolation::get(field, host_pos, gl);
989 std::vector<Utils::Vector3d> vel{};
990 vel.reserve(res.size() / 3ul);
991 for (auto it = res.begin(); it != res.end(); it += 3) {
992 vel.emplace_back(Utils::Vector3d{static_cast<double>(*(it + 0)),
993 static_cast<double>(*(it + 1)),
994 static_cast<double>(*(it + 2))});
995 }
996 return vel;
997 }
998#endif
999 return {};
1000 }
1001
1002 std::optional<Utils::Vector3d>
1004 bool consider_points_in_halo = false) const override {
1005 assert(not m_pending_ghost_comm.test(GhostComm::VEL));
1006 assert(not m_pending_ghost_comm.test(GhostComm::UBB));
1007 if (!consider_points_in_halo and !m_lattice->pos_in_local_domain(pos))
1008 return std::nullopt;
1009 if (consider_points_in_halo and !m_lattice->pos_in_local_halo(pos))
1010 return std::nullopt;
1011 Utils::Vector3d v{0., 0., 0.};
1013 pos, [this, &v, &pos](std::array<int, 3> const node, double weight) {
1014 // Nodes with zero weight might not be accessible, because they can be
1015 // outside ghost layers
1016 if (weight != 0.) {
1017 auto const res = get_node_velocity(Utils::Vector3i(node), true);
1018 if (!res) {
1019 throw interpolation_illegal_access("velocity", pos, node, weight);
1020 }
1021 v += *res * weight;
1022 }
1023 });
1024 return {std::move(v)};
1025 }
1026
1027 std::optional<double>
1029 bool consider_points_in_halo = false) const override {
1030 assert(not m_pending_ghost_comm.test(GhostComm::PDF));
1031 if (!consider_points_in_halo and !m_lattice->pos_in_local_domain(pos))
1032 return std::nullopt;
1033 if (consider_points_in_halo and !m_lattice->pos_in_local_halo(pos))
1034 return std::nullopt;
1035 double dens = 0.;
1037 pos, [this, &dens, &pos](std::array<int, 3> const node, double weight) {
1038 // Nodes with zero weight might not be accessible, because they can be
1039 // outside ghost layers
1040 if (weight != 0.) {
1041 auto const res = get_node_density(Utils::Vector3i(node), true);
1042 if (!res) {
1043 throw interpolation_illegal_access("density", pos, node, weight);
1044 }
1045 dens += *res * weight;
1046 }
1047 });
1048 return {std::move(dens)};
1049 }
1050
1051 // Local force
1053 Utils::Vector3d const &force) override {
1054 if (!m_lattice->pos_in_local_halo(pos))
1055 return false;
1056 auto const force_at_node = [this, &force](std::array<int, 3> const node,
1057 double weight) {
1058 auto const bc =
1060 if (bc) {
1061 auto const weighted_force = to_vector3<FloatType>(weight * force);
1062 auto force_field =
1063 bc->block->template uncheckedFastGetData<VectorField>(
1065 lbm::accessor::Vector::add(force_field, weighted_force, bc->cell);
1066 }
1067 };
1068 interpolate_bspline_at_pos(pos, force_at_node);
1069 return true;
1070 }
1071
1072 std::optional<Utils::Vector3d>
1073 get_node_force_to_be_applied(Utils::Vector3i const &node) const override {
1074 auto const bc = get_block_and_cell(get_lattice(), node, true);
1075 if (!bc)
1076 return std::nullopt;
1077
1078 auto field =
1079 bc->block->template getData<VectorField>(m_force_to_be_applied_id);
1080 auto const vec = lbm::accessor::Vector::get(field, bc->cell);
1081 return to_vector3d(vec);
1082 }
1083
1084 std::optional<Utils::Vector3d>
1086 bool consider_ghosts = false) const override {
1087 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::LAF)));
1088 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1089 if (!bc)
1090 return std::nullopt;
1091
1092 auto const field =
1093 bc->block->template getData<VectorField>(m_last_applied_force_field_id);
1094 auto const vec = lbm::accessor::Vector::get(field, bc->cell);
1095 return to_vector3d(vec);
1096 }
1097
1099 Utils::Vector3d const &force) override {
1102 auto bc = get_block_and_cell(get_lattice(), node, false);
1103 if (!bc)
1104 return false;
1105
1106 auto pdf_field = bc->block->template getData<PdfField>(m_pdf_field_id);
1107 auto force_field =
1108 bc->block->template getData<VectorField>(m_last_applied_force_field_id);
1109 auto vel_field =
1110 bc->block->template getData<VectorField>(m_velocity_field_id);
1111 auto const vec = to_vector3<FloatType>(force);
1112 lbm::accessor::Force::set(pdf_field, vel_field, force_field, vec, bc->cell);
1113
1114 return true;
1115 }
1116
1117 std::vector<double> get_slice_last_applied_force(
1118 Utils::Vector3i const &lower_corner,
1119 Utils::Vector3i const &upper_corner) const override {
1120 std::vector<double> out;
1121 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1122 auto const &lattice = get_lattice();
1123 auto const &block = *(lattice.get_blocks()->begin());
1124 auto const field =
1125 block.template getData<VectorField>(m_last_applied_force_field_id);
1126 auto const values = lbm::accessor::Vector::get(field, *ci);
1127 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
1128 assert(values.size() == 3u * ci->numCells());
1129 if constexpr (std::is_same_v<typename decltype(values)::value_type,
1130 double>) {
1131 out = std::move(values);
1132 } else {
1133 out = std::vector<double>(values.begin(), values.end());
1134 }
1135 }
1136 return out;
1137 }
1138
1140 Utils::Vector3i const &upper_corner,
1141 std::vector<double> const &force) override {
1144 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1145 auto const &lattice = get_lattice();
1146 auto &block = *(lattice.get_blocks()->begin());
1147 auto pdf_field = block.template getData<PdfField>(m_pdf_field_id);
1148 auto force_field =
1149 block.template getData<VectorField>(m_last_applied_force_field_id);
1150 auto vel_field = block.template getData<VectorField>(m_velocity_field_id);
1151 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
1152 assert(force.size() == 3u * ci->numCells());
1153 std::vector<FloatType> const values(force.begin(), force.end());
1154 lbm::accessor::Force::set(pdf_field, vel_field, force_field, values, *ci);
1155 }
1156 }
1157
1158 // Population
1159 std::optional<std::vector<double>>
1161 bool consider_ghosts = false) const override {
1162 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::PDF)));
1163 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1164 if (!bc)
1165 return std::nullopt;
1166
1167 auto pdf_field = bc->block->template getData<PdfField>(m_pdf_field_id);
1168 auto const pop = lbm::accessor::Population::get(pdf_field, bc->cell);
1169 std::vector<double> population(Stencil::Size);
1170 for (uint_t f = 0u; f < Stencil::Size; ++f) {
1171 population[f] = double_c(pop[f]);
1172 }
1173
1174 return {std::move(population)};
1175 }
1176
1178 std::vector<double> const &population) override {
1181 auto bc = get_block_and_cell(get_lattice(), node, false);
1182 if (!bc)
1183 return false;
1184
1185 auto pdf_field = bc->block->template getData<PdfField>(m_pdf_field_id);
1186 auto force_field =
1187 bc->block->template getData<VectorField>(m_last_applied_force_field_id);
1188 auto vel_field =
1189 bc->block->template getData<VectorField>(m_velocity_field_id);
1190 std::array<FloatType, Stencil::Size> pop;
1191 for (uint_t f = 0u; f < Stencil::Size; ++f) {
1192 pop[f] = FloatType_c(population[f]);
1193 }
1194 lbm::accessor::Population::set(pdf_field, vel_field, force_field, pop,
1195 bc->cell);
1196
1197 return true;
1198 }
1199
1200 std::vector<double>
1202 Utils::Vector3i const &upper_corner) const override {
1203 std::vector<double> out;
1204 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1205 auto const &lattice = get_lattice();
1206 auto const &block = *(lattice.get_blocks()->begin());
1207 auto const pdf_field = block.template getData<PdfField>(m_pdf_field_id);
1208 auto const values = lbm::accessor::Population::get(pdf_field, *ci);
1209 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
1210 assert(values.size() == stencil_size() * ci->numCells());
1211 if constexpr (std::is_same_v<typename decltype(values)::value_type,
1212 double>) {
1213 out = std::move(values);
1214 } else {
1215 out = std::vector<double>(values.begin(), values.end());
1216 }
1217 }
1218 return out;
1219 }
1220
1221 void set_slice_population(Utils::Vector3i const &lower_corner,
1222 Utils::Vector3i const &upper_corner,
1223 std::vector<double> const &population) override {
1224 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1225 auto const &lattice = get_lattice();
1226 auto &block = *(lattice.get_blocks()->begin());
1227 auto pdf_field = block.template getData<PdfField>(m_pdf_field_id);
1228 auto force_field =
1229 block.template getData<VectorField>(m_last_applied_force_field_id);
1230 auto vel_field = block.template getData<VectorField>(m_velocity_field_id);
1231 assert(population.size() == stencil_size() * ci->numCells());
1232 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
1233 std::vector<FloatType> const values(population.begin(), population.end());
1234 lbm::accessor::Population::set(pdf_field, vel_field, force_field, values,
1235 *ci);
1236 }
1237 }
1238
1239 // Density
1240 std::optional<double>
1242 bool consider_ghosts = false) const override {
1243 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::PDF)));
1244 auto bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1245 if (!bc)
1246 return std::nullopt;
1247
1248 auto pdf_field =
1249 bc->block->template uncheckedFastGetData<PdfField>(m_pdf_field_id);
1250 auto const density = lbm::accessor::Density::get(pdf_field, bc->cell);
1251 return {double_c(density)};
1252 }
1253
1254 bool set_node_density(Utils::Vector3i const &node, double density) override {
1256 auto bc = get_block_and_cell(get_lattice(), node, false);
1257 if (!bc)
1258 return false;
1259
1260 auto pdf_field = bc->block->template getData<PdfField>(m_pdf_field_id);
1261 lbm::accessor::Density::set(pdf_field, FloatType_c(density), bc->cell);
1262
1263 return true;
1264 }
1265
1266 std::vector<double>
1268 Utils::Vector3i const &upper_corner) const override {
1269 std::vector<double> out;
1270 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1271 auto const &lattice = get_lattice();
1272 auto const &block = *(lattice.get_blocks()->begin());
1273 auto const pdf_field = block.template getData<PdfField>(m_pdf_field_id);
1274 auto const values = lbm::accessor::Density::get(pdf_field, *ci);
1275 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
1276 assert(values.size() == ci->numCells());
1277 if constexpr (std::is_same_v<typename decltype(values)::value_type,
1278 double>) {
1279 out = std::move(values);
1280 } else {
1281 out = std::vector<double>(values.begin(), values.end());
1282 }
1283 }
1284 return out;
1285 }
1286
1287 void set_slice_density(Utils::Vector3i const &lower_corner,
1288 Utils::Vector3i const &upper_corner,
1289 std::vector<double> const &density) override {
1291 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1292 auto const &lattice = get_lattice();
1293 auto &block = *(lattice.get_blocks()->begin());
1294 auto pdf_field = block.template getData<PdfField>(m_pdf_field_id);
1295 assert(density.size() == ci->numCells());
1296 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
1297 std::vector<FloatType> const values(density.begin(), density.end());
1298 lbm::accessor::Density::set(pdf_field, values, *ci);
1299 }
1300 }
1301
1302 std::optional<Utils::Vector3d>
1304 bool consider_ghosts = false) const override {
1305 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::UBB)));
1306 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1307 if (!bc or !m_boundary->node_is_boundary(node))
1308 return std::nullopt;
1309
1310 return {to_vector3d(m_boundary->get_node_value_at_boundary(node))};
1311 }
1312
1314 Utils::Vector3d const &velocity) override {
1317 auto bc = get_block_and_cell(get_lattice(), node, true);
1318 if (bc) {
1319 m_boundary->set_node_value_at_boundary(
1320 node, to_vector3<FloatType>(velocity), *bc);
1321 }
1322 return bc.has_value();
1323 }
1324
1325 std::vector<std::optional<Utils::Vector3d>> get_slice_velocity_at_boundary(
1326 Utils::Vector3i const &lower_corner,
1327 Utils::Vector3i const &upper_corner) const override {
1328 std::vector<std::optional<Utils::Vector3d>> out;
1329 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1330 auto const &lattice = get_lattice();
1331 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
1332 auto const lower_cell = ci->min();
1333 auto const upper_cell = ci->max();
1334 auto const n_values = ci->numCells();
1335 out.reserve(n_values);
1336 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
1337 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
1338 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
1339 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
1340 if (m_boundary->node_is_boundary(node)) {
1341 out.emplace_back(
1342 to_vector3d(m_boundary->get_node_value_at_boundary(node)));
1343 } else {
1344 out.emplace_back(std::nullopt);
1345 }
1346 }
1347 }
1348 }
1349 assert(out.size() == n_values);
1350 }
1351 return out;
1352 }
1353
1355 Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner,
1356 std::vector<std::optional<Utils::Vector3d>> const &velocity) override {
1359 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1360 auto const &lattice = get_lattice();
1361 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
1362 auto const lower_cell = ci->min();
1363 auto const upper_cell = ci->max();
1364 auto it = velocity.begin();
1365 assert(velocity.size() == ci->numCells());
1366 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
1367 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
1368 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
1369 auto const node = local_offset + Utils::Vector3i{{x, y, z}};
1370 auto const bc = get_block_and_cell(lattice, node, false);
1371 auto const &opt = *it;
1372 if (opt) {
1373 m_boundary->set_node_value_at_boundary(
1374 node, to_vector3<FloatType>(*opt), *bc);
1375 } else {
1376 m_boundary->remove_node_from_boundary(node, *bc);
1377 }
1378 ++it;
1379 }
1380 }
1381 }
1382 }
1383 }
1384
1385 std::optional<Utils::Vector3d>
1386 get_node_boundary_force(Utils::Vector3i const &node) const override {
1387 auto const bc = get_block_and_cell(get_lattice(), node, true);
1388 if (!bc or !m_boundary->node_is_boundary(node))
1389 return std::nullopt;
1390
1391 return get_node_last_applied_force(node, true);
1392 }
1393
1394 bool remove_node_from_boundary(Utils::Vector3i const &node) override {
1395 auto bc = get_block_and_cell(get_lattice(), node, true);
1396 if (bc) {
1397 m_boundary->remove_node_from_boundary(node, *bc);
1398 }
1399 return bc.has_value();
1400 }
1401
1402 std::optional<bool>
1404 bool consider_ghosts = false) const override {
1405 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::UBB)));
1406 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
1407 if (!bc)
1408 return std::nullopt;
1409
1410 return {m_boundary->node_is_boundary(node)};
1411 }
1412
1413 std::vector<bool>
1415 Utils::Vector3i const &upper_corner) const override {
1416 std::vector<bool> out;
1417 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1418 auto const &lattice = get_lattice();
1419 auto const local_offset = std::get<0>(lattice.get_local_grid_range());
1420 auto const lower_cell = ci->min();
1421 auto const upper_cell = ci->max();
1422 auto const n_values = ci->numCells();
1423 out.reserve(n_values);
1424 for (auto x = lower_cell.x(); x <= upper_cell.x(); ++x) {
1425 for (auto y = lower_cell.y(); y <= upper_cell.y(); ++y) {
1426 for (auto z = lower_cell.z(); z <= upper_cell.z(); ++z) {
1427 auto const node = local_offset + Utils::Vector3i{x, y, z};
1428 out.emplace_back(m_boundary->node_is_boundary(node));
1429 }
1430 }
1431 }
1432 assert(out.size() == n_values);
1433 }
1434 return out;
1435 }
1436
1437 void reallocate_ubb_field() override { m_boundary->boundary_update(); }
1438
1440 if (not m_has_boundaries) {
1441 m_has_boundaries = true;
1443 }
1444 m_has_boundaries = true;
1445 }
1446
1447 void clear_boundaries() override {
1448 reset_boundary_handling();
1451 m_has_boundaries = false;
1453 }
1454
1455 void
1456 update_boundary_from_shape(std::vector<int> const &raster_flat,
1457 std::vector<double> const &data_flat) override {
1460 auto const grid_size = get_lattice().get_grid_dimensions();
1461 auto const data = fill_3D_vector_array(data_flat, grid_size);
1462 set_boundary_from_grid(*m_boundary, get_lattice(), raster_flat, data);
1465 }
1466
1467 // Pressure tensor
1468 std::optional<Utils::VectorXd<9>>
1469 get_node_pressure_tensor(Utils::Vector3i const &node) const override {
1470 auto bc = get_block_and_cell(get_lattice(), node, false);
1471 if (!bc)
1472 return std::nullopt;
1473
1474 auto pdf_field = bc->block->template getData<PdfField>(m_pdf_field_id);
1475 auto tensor = lbm::accessor::PressureTensor::get(pdf_field, bc->cell);
1476 pressure_tensor_correction(tensor);
1477
1478 return to_vector9d(tensor);
1479 }
1480
1481 std::vector<double> get_slice_pressure_tensor(
1482 Utils::Vector3i const &lower_corner,
1483 Utils::Vector3i const &upper_corner) const override {
1484 std::vector<double> out;
1485 if (auto const ci = get_interval(lower_corner, upper_corner)) {
1486 auto const &lattice = get_lattice();
1487 auto const &block = *(lattice.get_blocks()->begin());
1488 auto const pdf_field = block.template getData<PdfField>(m_pdf_field_id);
1489 auto values = lbm::accessor::PressureTensor::get(pdf_field, *ci);
1490 assert(++(lattice.get_blocks()->begin()) == lattice.get_blocks()->end());
1491 assert(values.size() == 9u * ci->numCells());
1492 for (auto it = values.begin(); it != values.end(); std::advance(it, 9l)) {
1493 pressure_tensor_correction(std::span<FloatType, 9ul>(it, 9ul));
1494 }
1495 if constexpr (std::is_same_v<typename decltype(values)::value_type,
1496 double>) {
1497 out = std::move(values);
1498 } else {
1499 out = std::vector<double>(values.begin(), values.end());
1500 }
1501 }
1502 return out;
1503 }
1504
1505 // Global pressure tensor
1506 [[nodiscard]] Utils::VectorXd<9> get_pressure_tensor() const override {
1507 auto const &blocks = get_lattice().get_blocks();
1508 Matrix3<FloatType> tensor(FloatType{0});
1509 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
1510 auto pdf_field = block->template getData<PdfField>(m_pdf_field_id);
1511 WALBERLA_FOR_ALL_CELLS_XYZ(pdf_field, {
1512 tensor += lbm::accessor::PressureTensor::get(pdf_field, Cell{x, y, z});
1513 });
1514 }
1515 auto const grid_size = get_lattice().get_grid_dimensions();
1516 auto const number_of_nodes = Utils::product(grid_size);
1517 pressure_tensor_correction(tensor);
1518 return to_vector9d(tensor) * (1. / static_cast<double>(number_of_nodes));
1519 }
1520
1521 // Global momentum
1522 [[nodiscard]] Utils::Vector3d get_momentum() const override {
1523 auto const &blocks = get_lattice().get_blocks();
1524 Vector3<FloatType> mom(FloatType{0});
1525 for (auto block = blocks->begin(); block != blocks->end(); ++block) {
1526 auto pdf_field = block->template getData<PdfField>(m_pdf_field_id);
1527 auto force_field =
1528 block->template getData<VectorField>(m_last_applied_force_field_id);
1529 mom += lbm::accessor::MomentumDensity::reduce(pdf_field, force_field);
1530 }
1531 return to_vector3d(mom);
1532 }
1533
1534 // Global external force
1535 void set_external_force(Utils::Vector3d const &ext_force) override {
1536 m_reset_force->set_ext_force(ext_force);
1537 }
1538
1539 [[nodiscard]] Utils::Vector3d get_external_force() const noexcept override {
1540 return m_reset_force->get_ext_force();
1541 }
1542
1543 [[nodiscard]] double get_kT() const noexcept override {
1544 return numeric_cast<double>(m_kT);
1545 }
1546
1547 [[nodiscard]] unsigned int get_seed() const noexcept override {
1548 return m_seed;
1549 }
1550
1551 [[nodiscard]] std::optional<uint64_t> get_rng_state() const override {
1552 auto const cm = std::get_if<CollisionModelThermalized>(&*m_collision_model);
1553 if (!cm or m_kT == 0.) {
1554 return std::nullopt;
1555 }
1556 return {static_cast<uint64_t>(cm->time_step_)};
1557 }
1558
1559 void set_rng_state(uint64_t counter) override {
1560 auto const cm = std::get_if<CollisionModelThermalized>(&*m_collision_model);
1561 if (!cm or m_kT == 0.) {
1562 throw std::runtime_error("This LB instance is unthermalized");
1563 }
1564 assert(counter <=
1565 static_cast<uint32_t>(std::numeric_limits<uint_t>::max()));
1566 cm->time_step_ = static_cast<uint32_t>(counter);
1567 }
1568
1569 [[nodiscard]] LatticeWalberla const &get_lattice() const noexcept override {
1570 return *m_lattice;
1571 }
1572
1573 [[nodiscard]] std::size_t get_velocity_field_id() const noexcept override {
1574 return m_velocity_field_id;
1575 }
1576
1577 [[nodiscard]] std::size_t get_force_field_id() const noexcept override {
1579 }
1580
1581 void register_vtk_field_filters(walberla::vtk::VTKOutput &vtk_obj) override {
1582 if constexpr (Architecture == lbmpy::Arch::GPU) {
1583 throw std::runtime_error("VTK output not supported for GPU");
1584 } else {
1585 field::FlagFieldCellFilter<FlagField> fluid_filter(m_flag_field_id);
1586 fluid_filter.addFlag(Boundary_flag);
1587 vtk_obj.addCellExclusionFilter(fluid_filter);
1588 }
1589 }
1590
1591protected:
1592 template <typename Field_T, uint_t F_SIZE_ARG, typename OutputType>
1593 class VTKWriter : public vtk::BlockCellDataWriter<OutputType, F_SIZE_ARG> {
1594 public:
1595 VTKWriter(ConstBlockDataID const &block_id, std::string const &id,
1596 FloatType unit_conversion)
1597 : vtk::BlockCellDataWriter<OutputType, F_SIZE_ARG>(id),
1598 m_block_id(block_id), m_field(nullptr),
1599 m_conversion(unit_conversion) {}
1600
1601 protected:
1602 void configure() override {
1603 WALBERLA_ASSERT_NOT_NULLPTR(this->block_);
1604 m_field = this->block_->template getData<Field_T>(m_block_id);
1605 }
1606
1607 ConstBlockDataID const m_block_id;
1608 Field_T const *m_field;
1609 FloatType const m_conversion;
1610 };
1611
1612 template <typename OutputType = float>
1613 class DensityVTKWriter : public VTKWriter<PdfField, 1u, OutputType> {
1614 public:
1616 using Base::Base;
1617 using Base::evaluate;
1618
1619 protected:
1620 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1621 cell_idx_t const z, cell_idx_t const) override {
1622 WALBERLA_ASSERT_NOT_NULLPTR(this->m_field);
1623 auto const density =
1624 lbm::accessor::Density::get(this->m_field, {x, y, z});
1625 return numeric_cast<OutputType>(this->m_conversion * density);
1626 }
1627 };
1628
1629 template <typename OutputType = float>
1630 class VelocityVTKWriter : public VTKWriter<VectorField, 3u, OutputType> {
1631 public:
1633 using Base::Base;
1634 using Base::evaluate;
1635
1636 protected:
1637 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1638 cell_idx_t const z, cell_idx_t const f) override {
1639 WALBERLA_ASSERT_NOT_NULLPTR(this->m_field);
1640 auto const velocity =
1641 lbm::accessor::Vector::get(this->m_field, {x, y, z});
1642 return numeric_cast<OutputType>(this->m_conversion * velocity[uint_c(f)]);
1643 }
1644 };
1645
1646 template <typename OutputType = float>
1647 class PressureTensorVTKWriter : public VTKWriter<PdfField, 9u, OutputType> {
1648 public:
1650 using Base::Base;
1651 using Base::evaluate;
1652
1653 PressureTensorVTKWriter(ConstBlockDataID const &block_id,
1654 std::string const &id, FloatType unit_conversion,
1655 FloatType off_diag_factor)
1656 : Base(block_id, id, unit_conversion),
1657 m_off_diag_factor(off_diag_factor) {}
1658
1659 protected:
1660 OutputType evaluate(cell_idx_t const x, cell_idx_t const y,
1661 cell_idx_t const z, cell_idx_t const f) override {
1662 WALBERLA_ASSERT_NOT_NULLPTR(this->m_field);
1663 auto const pressure =
1665 auto const revert_factor =
1666 (f == 0 or f == 4 or f == 8) ? FloatType{1} : m_off_diag_factor;
1667 return numeric_cast<OutputType>(this->m_conversion * revert_factor *
1668 pressure[uint_c(f)]);
1669 }
1670 FloatType const m_off_diag_factor;
1671 };
1672
1673public:
1674 void register_vtk_field_writers(walberla::vtk::VTKOutput &vtk_obj,
1675 LatticeModel::units_map const &units,
1676 int flag_observables) override {
1677 if constexpr (Architecture == lbmpy::Arch::GPU) {
1678 throw std::runtime_error("VTK output not supported for GPU");
1679 } else {
1680 if (flag_observables & static_cast<int>(OutputVTK::density)) {
1681 auto const unit_conversion = FloatType_c(units.at("density"));
1682 vtk_obj.addCellDataWriter(std::make_shared<DensityVTKWriter<float>>(
1683 m_pdf_field_id, "density", unit_conversion));
1684 }
1685 if (flag_observables & static_cast<int>(OutputVTK::velocity_vector)) {
1686 auto const unit_conversion = FloatType_c(units.at("velocity"));
1687 vtk_obj.addCellDataWriter(std::make_shared<VelocityVTKWriter<float>>(
1688 m_velocity_field_id, "velocity_vector", unit_conversion));
1689 }
1690 if (flag_observables & static_cast<int>(OutputVTK::pressure_tensor)) {
1691 auto const unit_conversion = FloatType_c(units.at("pressure"));
1692 vtk_obj.addCellDataWriter(
1693 std::make_shared<PressureTensorVTKWriter<float>>(
1694 m_pdf_field_id, "pressure_tensor", unit_conversion,
1695 pressure_tensor_correction_factor()));
1696 }
1697 }
1698 }
1699
1700 ~LBWalberlaImpl() override = default;
1701};
1702
1703} // namespace walberla
LBWalberlaBase provides the public interface of the LB waLBerla bridge.
Vector implementation and trait types for boost qvm interoperability.
Definition Cell.hpp:97
Interface of a lattice-based fluid 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
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value)
Create a vector that has all entries set to the same value.
Definition Vector.hpp:110
Boundary class optimized for sparse data.
field::FlagField< uint8_t > FlagField
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
PressureTensorVTKWriter(ConstBlockDataID const &block_id, std::string const &id, FloatType unit_conversion, FloatType off_diag_factor)
VTKWriter(ConstBlockDataID const &block_id, std::string const &id, FloatType unit_conversion)
OutputType evaluate(cell_idx_t const x, cell_idx_t const y, cell_idx_t const z, cell_idx_t const f) override
Class that runs and controls the LB on waLBerla.
void add_forces_at_pos(std::vector< Utils::Vector3d > const &pos, std::vector< Utils::Vector3d > const &forces) override
typename FieldTrait< FloatType, Architecture >::template RegularCommScheme< typename stencil::D3Q27 > RegularFullCommunicator
Full communicator.
std::vector< double > get_slice_last_applied_force(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
LatticeWalberla::Lattice_T Lattice_T
Lattice model (e.g.
std::shared_ptr< RegularFullCommunicator > m_pdf_communicator
std::vector< std::optional< Utils::Vector3d > > get_slice_velocity_at_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
std::optional< Utils::Vector3d > get_node_last_applied_force(Utils::Vector3i const &node, bool consider_ghosts=false) const override
stencil::D3Q19 Stencil
Stencil for collision and streaming operations.
std::optional< Utils::Vector3d > get_node_velocity_at_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
void ghost_communication() override
std::optional< Utils::Vector3d > get_node_velocity(Utils::Vector3i const &node, bool consider_ghosts=false) const override
void reallocate_ubb_field() override
std::shared_ptr< RegularFullCommunicator > m_full_communicator
typename detail::KernelTrait< FloatType, Architecture >::CollisionModelLeesEdwards CollisionModelLeesEdwards
std::size_t get_force_field_id() const noexcept override
std::shared_ptr< CollisionModel > m_collision_model
typename FieldTrait< FloatType, Architecture >::VectorField VectorField
void set_slice_velocity(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< double > const &velocity) override
unsigned int get_seed() const noexcept override
void integrate_vtk_writers() override
bool remove_node_from_boundary(Utils::Vector3i const &node) override
std::optional< Utils::Vector3d > get_node_boundary_force(Utils::Vector3i const &node) const override
std::optional< double > get_density_at_pos(Utils::Vector3d const &pos, bool consider_points_in_halo=false) const override
void set_slice_velocity_at_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< std::optional< Utils::Vector3d > > const &velocity) override
std::vector< double > get_slice_population(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void set_rng_state(uint64_t counter) override
std::vector< double > get_slice_velocity(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
std::shared_ptr< LatticeWalberla > m_lattice
std::shared_ptr< LeesEdwardsPack > m_lees_edwards_callbacks
LBWalberlaImpl(std::shared_ptr< LatticeWalberla > lattice, double viscosity, double density)
bool set_node_last_applied_force(Utils::Vector3i const &node, Utils::Vector3d const &force) override
std::shared_ptr< InterpolateAndShiftAtBoundary< _VectorField, FloatType > > m_lees_edwards_vel_interpol_sweep
std::vector< bool > get_slice_is_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
std::vector< double > get_slice_density(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void update_boundary_from_shape(std::vector< int > const &raster_flat, std::vector< double > const &data_flat) override
std::shared_ptr< BoundaryModel > m_boundary
std::vector< double > get_slice_pressure_tensor(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
bool set_node_density(Utils::Vector3i const &node, double density) override
void set_collision_model(double kT, unsigned int seed) override
std::variant< CollisionModelThermalized, CollisionModelLeesEdwards > CollisionModel
std::vector< Utils::Vector3d > get_velocities_at_pos(std::vector< Utils::Vector3d > const &pos) override
std::optional< bool > get_node_is_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
std::shared_ptr< ResetForce< PdfField, VectorField > > m_reset_force
virtual bool is_double_precision() const noexcept override
std::shared_ptr< StreamSweep > m_stream
FlagUID const Boundary_flag
Flag for boundary cells.
~LBWalberlaImpl() override=default
std::optional< uint64_t > get_rng_state() const override
std::optional< std::vector< double > > get_node_population(Utils::Vector3i const &node, bool consider_ghosts=false) const override
FloatType m_density
kinematic viscosity
double get_viscosity() const noexcept override
double get_kT() const noexcept override
Utils::Vector3d get_momentum() const override
void set_viscosity(double viscosity) override
std::shared_ptr< BoundaryFullCommunicator > m_boundary_communicator
std::size_t stencil_size() const noexcept override
auto add_to_storage(std::string const tag)
Convenience function to add a field with a custom allocator.
typename detail::KernelTrait< FloatType, Architecture >::InitialPDFsSetter InitialPDFsSetter
bool set_node_velocity_at_boundary(Utils::Vector3i const &node, Utils::Vector3d const &velocity) override
stencil::D3Q27 StencilFull
Stencil for ghost communication (includes domain corners).
void register_vtk_field_writers(walberla::vtk::VTKOutput &vtk_obj, LatticeModel::units_map const &units, int flag_observables) override
typename BoundaryModel::FlagField FlagField
std::optional< double > get_node_density(Utils::Vector3i const &node, bool consider_ghosts=false) const override
void check_lebc(unsigned int shear_direction, unsigned int shear_plane_normal) const override
void set_slice_density(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< double > const &density) override
void ghost_communication_vel() override
typename FieldTrait< FloatType >::PdfField _PdfField
Utils::Vector3d get_external_force() const noexcept override
FloatType FloatType_c(T t) const
std::shared_ptr< RegularFullCommunicator > m_laf_communicator
std::size_t get_velocity_field_id() const noexcept override
Utils::VectorXd< 9 > get_pressure_tensor() const override
std::shared_ptr< InterpolateAndShiftAtBoundary< _PdfField, FloatType > > m_lees_edwards_pdf_interpol_sweep
void set_external_force(Utils::Vector3d const &ext_force) override
std::optional< Utils::Vector3d > get_velocity_at_pos(Utils::Vector3d const &pos, bool consider_points_in_halo=false) const override
void set_slice_last_applied_force(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< double > const &force) override
void set_collision_model(std::unique_ptr< LeesEdwardsPack > &&lees_edwards_pack) override
std::shared_ptr< RegularFullCommunicator > m_vel_communicator
typename FieldTrait< FloatType, Architecture >::template BoundaryCommScheme< typename stencil::D3Q27 > BoundaryFullCommunicator
std::bitset< GhostComm::SIZE > m_pending_ghost_comm
typename FieldTrait< FloatType, Architecture >::template RegularCommScheme< Stencil > PDFStreamingCommunicator
Regular communicator.
LatticeWalberla const & get_lattice() const noexcept override
void set_slice_population(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< double > const &population) override
typename FieldTrait< FloatType, Architecture >::template PackInfo< Field > PackInfo
double get_density() const noexcept override
typename detail::KernelTrait< FloatType, Architecture >::CollisionModelThermalized CollisionModelThermalized
typename FieldTrait< FloatType, Architecture >::PdfField PdfField
void ghost_communication_pdf() override
void register_vtk_field_filters(walberla::vtk::VTKOutput &vtk_obj) override
std::optional< Utils::Vector3d > get_node_force_to_be_applied(Utils::Vector3i const &node) const override
typename FieldTrait< FloatType >::VectorField _VectorField
bool set_node_velocity(Utils::Vector3i const &node, Utils::Vector3d const &v) override
std::optional< CellInterval > get_interval(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const
bool set_node_population(Utils::Vector3i const &node, std::vector< double > const &population) override
bool is_gpu() const noexcept override
std::shared_ptr< PDFStreamingCommunicator > m_pdf_streaming_communicator
BlockDataID m_last_applied_force_field_id
std::optional< Utils::VectorXd< 9 > > get_node_pressure_tensor(Utils::Vector3i const &node) const override
std::shared_ptr< InterpolateAndShiftAtBoundary< _VectorField, FloatType > > m_lees_edwards_last_applied_force_interpol_sweep
typename detail::KernelTrait< FloatType, Architecture >::StreamSweep StreamSweep
bool add_force_at_pos(Utils::Vector3d const &pos, Utils::Vector3d const &force) override
void setup_boundary_handle(std::shared_ptr< LatticeWalberla > lattice, std::shared_ptr< Boundary_T > boundary)
static double weight(int type, double r_cut, double k, double r)
Definition dpd.cpp:78
static double * block(double *p, std::size_t index, std::size_t size)
Definition elc.cpp:172
T product(Vector< T, N > const &v)
Definition Vector.hpp:374
VectorXi< 3 > Vector3i
Definition Vector.hpp:173
void set(GhostLayerField< double, uint_t{19u}> *pdf_field, double const rho_in, Cell const &cell)
double get(GhostLayerField< double, uint_t{19u}> const *pdf_field, Cell const &cell)
void set(GhostLayerField< double, uint_t{19u}> const *pdf_field, GhostLayerField< double, uint_t{3u}> *velocity_field, GhostLayerField< double, uint_t{3u}> *force_field, Vector3< double > const &force, Cell const &cell)
std::vector< double > get(gpu::GPUField< double > const *vec_field, std::vector< double > const &pos, uint gl)
void set(gpu::GPUField< double > const *vec_field, std::vector< double > const &pos, std::vector< double > const &forces, uint gl)
auto reduce(GhostLayerField< double, uint_t{19u}> const *pdf_field, GhostLayerField< double, uint_t{3u}> const *force_field)
void set(GhostLayerField< double, uint_t{19u}> *pdf_field, std::array< double, 19u > const &pop, Cell const &cell)
auto get(GhostLayerField< double, uint_t{19u}> const *pdf_field, Cell const &cell)
void initialize(GhostLayerField< double, uint_t{19u}> *pdf_field, std::array< double, 19u > const &pop)
auto get(GhostLayerField< double, uint_t{19u}> const *pdf_field, Cell const &cell)
void initialize(GhostLayerField< double, uint_t{3u}> *vec_field, Vector3< double > const &vec)
void add(GhostLayerField< double, uint_t{3u}> *vec_field, Vector3< double > const &vec, Cell const &cell)
auto get(GhostLayerField< double, uint_t{3u}> const *vec_field, Cell const &cell)
void set(GhostLayerField< double, uint_t{19u}> *pdf_field, GhostLayerField< double, uint_t{3u}> *velocity_field, GhostLayerField< double, uint_t{3u}> const *force_field, Vector3< double > const &u, Cell const &cell)
\file PackInfoPdfDoublePrecision.cpp \author pystencils
std::optional< BlockAndCell > get_block_and_cell(::LatticeWalberla const &lattice, Utils::Vector3i const &node, bool consider_ghost_layers)
void interpolate_bspline_at_pos(Utils::Vector3d const &pos, Function const &f)
Utils::VectorXd< 9 > to_vector9d(Matrix3< double > const &m)
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
std::vector< Utils::Vector3d > fill_3D_vector_array(std::vector< double > const &vec_flat, Utils::Vector3i const &grid_size)
Definition boundary.hpp:36
Utils::Vector3d to_vector3d(Vector3< float > const &v)
static Utils::Vector3d velocity(Particle const &p_ref, Particle const &p_vs)
Velocity of the virtual site.
Definition relative.cpp:64
DEVICE_QUALIFIER constexpr iterator begin() noexcept
Definition Array.hpp:128
DEVICE_QUALIFIER constexpr size_type size() const noexcept
Definition Array.hpp:154
DEVICE_QUALIFIER constexpr iterator end() noexcept
Definition Array.hpp:140
typename detail::KernelTrait< FT, AT >::PackInfoVec PackInfoStreamingVec
typename detail::KernelTrait< FT, AT >::PackInfoPdf PackInfoStreamingPdf
field::GhostLayerField< FT, uint_t{3u}> VectorField
field::communication::PackInfo< Field > PackInfo
field::GhostLayerField< FT, Stencil::Size > PdfField
blockforest::communication::UniformBufferedScheme< Stencil > RegularCommScheme
blockforest::communication::UniformBufferedScheme< Stencil > BoundaryCommScheme
GhostCommFlags
Ghost communication operations.
@ LAF
last applied forces communication