213 if (particles.empty()) {
216 enum coupling_modes { none, particle_force, swimmer_force_on_fluid };
217 auto const halo = 0.5 * m_lb.
get_agrid();
219 auto const fully_inside_lower = m_local_box.
my_left() + 2. * halo_vec;
220 auto const fully_inside_upper = m_local_box.
my_right() - 2. * halo_vec;
221 auto const halo_lower_corner = m_local_box.
my_left() - halo_vec;
222 auto const halo_upper_corner = m_local_box.
my_right() + halo_vec;
223 std::vector<Utils::Vector3d> positions_velocity_coupling;
224 std::vector<Utils::Vector3d> positions_force_coupling;
225 std::vector<Utils::Vector3d> force_coupling_forces;
226 std::vector<uint8_t> positions_force_coupling_counter;
227 std::vector<Particle *> coupled_particles;
228 for (
auto ptr : particles) {
230 auto span_size = uint8_t{1u};
232 if (
in_box(folded_pos, fully_inside_lower, fully_inside_upper)) {
233 positions_force_coupling.emplace_back(folded_pos);
235 auto const old_size = positions_force_coupling.size();
237 m_box_geo, positions_force_coupling);
238 auto const new_size = positions_force_coupling.size();
239 span_size =
static_cast<uint8_t
>(new_size - old_size);
241 auto coupling_mode = none;
242#ifdef ESPRESSO_ENGINE
243 if (p.swimming().is_engine_force_on_fluid) {
244 coupling_mode = swimmer_force_on_fluid;
247 if (coupling_mode == none) {
248 for (
auto end = positions_force_coupling.end();
249 auto const &pos : std::views::counted(end - span_size, span_size)) {
250 if (pos >= halo_lower_corner and pos < halo_upper_corner) {
251 positions_velocity_coupling.emplace_back(pos);
252 coupling_mode = particle_force;
257 if (coupling_mode == none) {
258 positions_force_coupling.erase(positions_force_coupling.end() - span_size,
259 positions_force_coupling.end());
261 coupled_particles.emplace_back(ptr);
262 positions_force_coupling_counter.emplace_back(span_size);
266 if (coupled_particles.empty()) {
269 auto interpolated_velocities =
272 auto const &domain_lower_corner = m_local_box.
my_left();
273 auto const &domain_upper_corner = m_local_box.
my_right();
274 auto it_interpolated_velocities = interpolated_velocities.begin();
275 auto it_positions_force_coupling = positions_force_coupling.begin();
276 auto it_positions_velocity_coupling = positions_velocity_coupling.begin();
277 auto it_positions_force_coupling_counter =
278 positions_force_coupling_counter.begin();
279 for (
auto ptr : coupled_particles) {
281 auto coupling_mode = particle_force;
282#ifdef ESPRESSO_ENGINE
283 if (p.swimming().is_engine_force_on_fluid) {
284 coupling_mode = swimmer_force_on_fluid;
288 if (coupling_mode == particle_force) {
289#ifndef ESPRESSO_THERMOSTAT_PER_PARTICLE
290 if (m_thermostat.
gamma > 0.)
293 auto &v_fluid = *it_interpolated_velocities;
299 *it_positions_velocity_coupling, p.pos(), m_box_geo);
300 v_fluid += vel_correction;
304 force_on_particle = drag_force + random_force;
306 ++it_interpolated_velocities;
307 ++it_positions_velocity_coupling;
310 auto force_on_fluid = -force_on_particle;
311#ifdef ESPRESSO_ENGINE
312 if (coupling_mode == swimmer_force_on_fluid) {
313 force_on_fluid = p.calc_director() * p.swimming().f_swim;
317 auto const span_size = *it_positions_force_coupling_counter;
318 ++it_positions_force_coupling_counter;
319 for (uint8_t i{0u}; i < span_size; ++i) {
320 auto &pos = *it_positions_force_coupling;
321 if (pos >= domain_lower_corner and pos < domain_upper_corner) {
324 p.force() += force_on_particle;
326 force_coupling_forces.emplace_back(force_on_fluid);
327 ++it_positions_force_coupling;
351#ifdef ESPRESSO_CALIPER
352 CALI_CXX_MARK_FUNCTION;
354 assert(thermostat->lb !=
nullptr);
355 if (thermostat->lb->couple_to_md) {
356 if (not lb.is_solver_set()) {
360 auto const real_particles = cell_structure->local_particles();
361 auto const ghost_particles = cell_structure->ghost_particles();
364 lb.ghost_communication_vel();
365 std::vector<Particle *> particles{};
366 for (
auto const *particle_range : {&real_particles, &ghost_particles}) {
367 for (
auto &p : *particle_range) {
368 if (not
LB::is_tracer(p) and bookkeeping.should_be_coupled(p)) {
369#if defined(ESPRESSO_THERMOSTAT_PER_PARTICLE) and \
370 defined(ESPRESSO_PARTICLE_ANISOTROPY)
373 particles.emplace_back(&p);
377 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