211 if (particles.empty()) {
214 enum coupling_modes { none, particle_force, swimmer_force_on_fluid };
215 auto const halo = 0.5 * m_lb.
get_agrid();
217 auto const fully_inside_lower = m_local_box.
my_left() + 2. * halo_vec;
218 auto const fully_inside_upper = m_local_box.
my_right() - 2. * halo_vec;
219 auto const halo_lower_corner = m_local_box.
my_left() - halo_vec;
220 auto const halo_upper_corner = m_local_box.
my_right() + halo_vec;
221 std::vector<Utils::Vector3d> positions_velocity_coupling;
222 std::vector<Utils::Vector3d> positions_force_coupling;
223 std::vector<Utils::Vector3d> force_coupling_forces;
224 std::vector<uint8_t> positions_force_coupling_counter;
225 std::vector<Particle *> coupled_particles;
226 for (
auto ptr : particles) {
228 auto span_size = uint8_t{1u};
230 if (
in_box(folded_pos, fully_inside_lower, fully_inside_upper)) {
231 positions_force_coupling.emplace_back(folded_pos);
233 auto const old_size = positions_force_coupling.size();
235 m_box_geo, positions_force_coupling);
236 auto const new_size = positions_force_coupling.size();
237 span_size =
static_cast<uint8_t
>(new_size - old_size);
239 auto coupling_mode = none;
240#ifdef ESPRESSO_ENGINE
241 if (p.swimming().is_engine_force_on_fluid) {
242 coupling_mode = swimmer_force_on_fluid;
245 if (coupling_mode == none) {
246 for (
auto end = positions_force_coupling.end();
247 auto const &pos : std::views::counted(end - span_size, span_size)) {
248 if (pos >= halo_lower_corner and pos < halo_upper_corner) {
249 positions_velocity_coupling.emplace_back(pos);
250 coupling_mode = particle_force;
255 if (coupling_mode == none) {
256 positions_force_coupling.erase(positions_force_coupling.end() - span_size,
257 positions_force_coupling.end());
259 coupled_particles.emplace_back(ptr);
260 positions_force_coupling_counter.emplace_back(span_size);
264 if (coupled_particles.empty()) {
267 auto interpolated_velocities =
270 auto const &domain_lower_corner = m_local_box.
my_left();
271 auto const &domain_upper_corner = m_local_box.
my_right();
272 auto it_interpolated_velocities = interpolated_velocities.begin();
273 auto it_positions_force_coupling = positions_force_coupling.begin();
274 auto it_positions_velocity_coupling = positions_velocity_coupling.begin();
275 auto it_positions_force_coupling_counter =
276 positions_force_coupling_counter.begin();
277 for (
auto ptr : coupled_particles) {
279 auto coupling_mode = particle_force;
280#ifdef ESPRESSO_ENGINE
281 if (p.swimming().is_engine_force_on_fluid) {
282 coupling_mode = swimmer_force_on_fluid;
286 if (coupling_mode == particle_force) {
287#ifndef ESPRESSO_THERMOSTAT_PER_PARTICLE
288 if (m_thermostat.
gamma > 0.)
291 auto &v_fluid = *it_interpolated_velocities;
297 *it_positions_velocity_coupling, p.pos(), m_box_geo);
298 v_fluid += vel_correction;
302 force_on_particle = drag_force + random_force;
304 ++it_interpolated_velocities;
305 ++it_positions_velocity_coupling;
308 auto force_on_fluid = -force_on_particle;
309#ifdef ESPRESSO_ENGINE
310 if (coupling_mode == swimmer_force_on_fluid) {
311 force_on_fluid = p.calc_director() * p.swimming().f_swim;
315 auto const span_size = *it_positions_force_coupling_counter;
316 ++it_positions_force_coupling_counter;
317 for (uint8_t i{0u}; i < span_size; ++i) {
318 auto &pos = *it_positions_force_coupling;
319 if (pos >= domain_lower_corner and pos < domain_upper_corner) {
322 p.force() += force_on_particle;
324 force_coupling_forces.emplace_back(force_on_fluid);
325 ++it_positions_force_coupling;
349#ifdef ESPRESSO_CALIPER
350 CALI_CXX_MARK_FUNCTION;
352 assert(thermostat->lb !=
nullptr);
353 if (thermostat->lb->couple_to_md) {
354 if (not lb.is_solver_set()) {
358 auto const real_particles = cell_structure->local_particles();
359 auto const ghost_particles = cell_structure->ghost_particles();
362 lb.ghost_communication_vel();
363 std::vector<Particle *> particles{};
364 for (
auto const *particle_range : {&real_particles, &ghost_particles}) {
365 for (
auto &p : *particle_range) {
366 if (not
LB::is_tracer(p) and bookkeeping.should_be_coupled(p)) {
367#if defined(ESPRESSO_THERMOSTAT_PER_PARTICLE) and \
368 defined(ESPRESSO_PARTICLE_ANISOTROPY)
371 particles.emplace_back(&p);
375 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