212 if (particles.empty()) {
215 enum coupling_modes { none, particle_force, swimmer_force_on_fluid };
216 auto const halo = 0.5 * m_lb.
get_agrid();
218 auto const fully_inside_lower = m_local_box.
my_left() + 2. * halo_vec;
219 auto const fully_inside_upper = m_local_box.
my_right() - 2. * halo_vec;
220 auto const halo_lower_corner = m_local_box.
my_left() - halo_vec;
221 auto const halo_upper_corner = m_local_box.
my_right() + halo_vec;
222 std::vector<Utils::Vector3d> positions_velocity_coupling;
223 std::vector<Utils::Vector3d> positions_force_coupling;
224 std::vector<Utils::Vector3d> force_coupling_forces;
225 std::vector<uint8_t> positions_force_coupling_counter;
226 std::vector<Particle *> coupled_particles;
227 for (
auto ptr : particles) {
229 auto span_size = uint8_t{1u};
231 if (
in_box(folded_pos, fully_inside_lower, fully_inside_upper)) {
232 positions_force_coupling.emplace_back(folded_pos);
234 auto const old_size = positions_force_coupling.size();
236 m_box_geo, positions_force_coupling);
237 auto const new_size = positions_force_coupling.size();
238 span_size =
static_cast<uint8_t
>(new_size - old_size);
240 auto coupling_mode = none;
241#ifdef ESPRESSO_ENGINE
242 if (p.swimming().is_engine_force_on_fluid) {
243 coupling_mode = swimmer_force_on_fluid;
246 if (coupling_mode == none) {
247 for (
auto end = positions_force_coupling.end();
248 auto const &pos : std::views::counted(end - span_size, span_size)) {
249 if (pos >= halo_lower_corner and pos < halo_upper_corner) {
250 positions_velocity_coupling.emplace_back(pos);
251 coupling_mode = particle_force;
256 if (coupling_mode == none) {
257 positions_force_coupling.erase(positions_force_coupling.end() - span_size,
258 positions_force_coupling.end());
260 coupled_particles.emplace_back(ptr);
261 positions_force_coupling_counter.emplace_back(span_size);
265 if (coupled_particles.empty()) {
268 auto interpolated_velocities =
271 auto const &domain_lower_corner = m_local_box.
my_left();
272 auto const &domain_upper_corner = m_local_box.
my_right();
273 auto it_interpolated_velocities = interpolated_velocities.begin();
274 auto it_positions_force_coupling = positions_force_coupling.begin();
275 auto it_positions_velocity_coupling = positions_velocity_coupling.begin();
276 auto it_positions_force_coupling_counter =
277 positions_force_coupling_counter.begin();
278 for (
auto ptr : coupled_particles) {
280 auto coupling_mode = particle_force;
281#ifdef ESPRESSO_ENGINE
282 if (p.swimming().is_engine_force_on_fluid) {
283 coupling_mode = swimmer_force_on_fluid;
287 if (coupling_mode == particle_force) {
288#ifndef ESPRESSO_THERMOSTAT_PER_PARTICLE
289 if (m_thermostat.
gamma > 0.)
292 auto &v_fluid = *it_interpolated_velocities;
298 *it_positions_velocity_coupling, p.pos(), m_box_geo);
299 v_fluid += vel_correction;
303 force_on_particle = drag_force + random_force;
305 ++it_interpolated_velocities;
306 ++it_positions_velocity_coupling;
309 auto force_on_fluid = -force_on_particle;
310#ifdef ESPRESSO_ENGINE
311 if (coupling_mode == swimmer_force_on_fluid) {
312 force_on_fluid = p.calc_director() * p.swimming().f_swim;
316 auto const span_size = *it_positions_force_coupling_counter;
317 ++it_positions_force_coupling_counter;
318 for (uint8_t i{0u}; i < span_size; ++i) {
319 auto &pos = *it_positions_force_coupling;
320 if (pos >= domain_lower_corner and pos < domain_upper_corner) {
323 p.force() += force_on_particle;
325 force_coupling_forces.emplace_back(force_on_fluid);
326 ++it_positions_force_coupling;
350#ifdef ESPRESSO_CALIPER
351 CALI_CXX_MARK_FUNCTION;
353 assert(thermostat->lb !=
nullptr);
354 if (thermostat->lb->couple_to_md) {
355 if (not lb.is_solver_set()) {
359 auto const real_particles = cell_structure->local_particles();
360 auto const ghost_particles = cell_structure->ghost_particles();
363 lb.ghost_communication_vel();
364 std::vector<Particle *> particles{};
365 for (
auto const *particle_range : {&real_particles, &ghost_particles}) {
366 for (
auto &p : *particle_range) {
367 if (not
LB::is_tracer(p) and bookkeeping.should_be_coupled(p)) {
368#if defined(ESPRESSO_THERMOSTAT_PER_PARTICLE) and \
369 defined(ESPRESSO_PARTICLE_ANISOTROPY)
372 particles.emplace_back(&p);
376 coupling.kernel(particles);
void kernel(std::vector< Particle * > const &particles)
Utils::Vector3d get_noise_term(Particle const &p) const
bool in_local_halo(LocalBox const &local_box, Utils::Vector3d const &pos, double agrid)
Check if a position is within the local LB domain plus halo.
static auto lees_edwards_vel_shift(Utils::Vector3d const &pos_shifted_by_box_l, Utils::Vector3d const &orig_pos, BoxGeometry const &box_geo)
static bool in_box(Utils::Vector3d const &pos, Utils::Vector3d const &lower_corner, Utils::Vector3d const &upper_corner)
static bool in_local_domain(LocalBox const &local_box, Utils::Vector3d const &pos, double halo=0.)
Check if a position is within the local box + halo.
static void positions_in_halo_impl(Utils::Vector3d const &pos_folded, Utils::Vector3d const &halo_lower_corner, Utils::Vector3d const &halo_upper_corner, BoxGeometry const &box_geo, std::vector< Utils::Vector3d > &res)
std::vector< Utils::Vector3d > positions_in_halo(Utils::Vector3d const &pos, BoxGeometry const &box_geo, LocalBox const &local_box, double agrid)
Return a vector of positions shifted by +,- box length in each coordinate.
static Utils::Vector3d lb_drag_force(Particle const &p, double lb_gamma, Utils::Vector3d const &v_fluid)
static Thermostat::GammaType lb_handle_particle_anisotropy(Particle const &p, double lb_gamma)
Struct holding all information for one particle.
auto const & gamma() const
auto const & mu_E() const