OpenLB 1.7
Loading...
Searching...
No Matches
particleContactDetectionFunctions.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2021 Jan E. Marquardt, Mathias J. Krause
4 * E-mail contact: info@openlb.net
5 * The most recent release of OpenLB can be downloaded at
6 * <http://www.openlb.net/>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
24/*
25 * This file contains functions used for the particle-wall and particle-particle contact detection.
26*/
27
28#ifndef PARTICLE_CONTACT_DETECTION_FUNCTIONS_H
29#define PARTICLE_CONTACT_DETECTION_FUNCTIONS_H
30
31namespace olb {
32
33namespace particles {
34
35namespace contact {
36
37template <typename CONTACTTYPE>
38auto getContactIterator(std::vector<CONTACTTYPE>& contacts,
39 const std::function<bool(const CONTACTTYPE&)> condition)
40{
41 auto contactIt = std::find_if(contacts.begin(), contacts.end(),
42 [&condition](const auto& contact) -> bool {
43 return condition(contact);
44 });
45 return contactIt;
46}
47
48std::array<std::size_t, 2>
49sortParticleIDs(const std::array<std::size_t, 2>& ids)
50{
51 return std::array<std::size_t, 2>(
52 {util::min(ids[0], ids[1]), util::max(ids[0], ids[1])});
53}
54
55template <typename T, typename PARTICLETYPE, typename F>
58 const PhysR<T, PARTICLETYPE::d>& cellMin,
59 const PhysR<T, PARTICLETYPE::d>& cellMax,
60 F getSetupPeriodicity,
61 std::array<PhysR<T, PARTICLETYPE::d>, 2>& positions,
62 T deltaX)
63{
64 using namespace descriptors;
65
66 const PhysR<T, PARTICLETYPE::d> pos1 =
68 const PhysR<T, PARTICLETYPE::d> pos2 =
70 positions[0] = pos1;
71 positions[1] = pos2;
72
73 if constexpr (isPeriodic(getSetupPeriodicity())) {
74 constexpr Vector<bool, PARTICLETYPE::d> isPeriodic(getSetupPeriodicity());
75
76 auto sIndicator1 = particle1.template getField<SURFACE, SINDICATOR>();
77 const T circumRadius1 = sIndicator1->getCircumRadius() -
78 sIndicator1->getEpsilon() +
79 util::max(sIndicator1->getEpsilon(), 0.5 * deltaX);
80 auto sIndicator2 = particle2.template getField<SURFACE, SINDICATOR>();
81 const T circumRadius2 = sIndicator2->getCircumRadius() -
82 sIndicator2->getEpsilon() +
83 util::max(sIndicator2->getEpsilon(), 0.5 * deltaX);
84
85 const PhysR<T, PARTICLETYPE::d> middle = 0.5 * (cellMin + cellMax);
86
87 for (unsigned i = 0; i < PARTICLETYPE::d; ++i) {
88 T const particleMin1 = pos1[i] - circumRadius1;
89 T const particleMax1 = pos1[i] + circumRadius1;
90 T const particleMin2 = pos2[i] - circumRadius2;
91 T const particleMax2 = pos2[i] + circumRadius2;
92
93 // Always solely "move" the second particle
94 if (particleMin1 < cellMin[i] && isPeriodic[i]) {
95 if (pos2[i] > middle[i]) {
96 positions[1][i] = communication::movePositionToStart(
97 pos2[i], cellMax[i], cellMin[i]);
98 }
99 }
100 else if (particleMax1 > cellMax[i] && isPeriodic[i]) {
101 if (pos2[i] < middle[i]) {
102 positions[1][i] = communication::movePositionToEnd(
103 pos2[i], cellMax[i], cellMin[i]);
104 }
105 }
106 else if (particleMin2 < cellMin[i] && isPeriodic[i]) {
107 if (pos1[i] > middle[i]) {
108 positions[1][i] = communication::movePositionToEnd(
109 pos2[i], cellMax[i], cellMin[i]);
110 }
111 }
112 else if (particleMax2 > cellMax[i] && isPeriodic[i]) {
113 if (pos1[i] < middle[i]) {
114 positions[1][i] = communication::movePositionToStart(
115 pos2[i], cellMax[i], cellMin[i]);
116 }
117 }
118 }
119 }
120}
121
122template <typename T, typename PARTICLETYPE, typename F>
125 const PhysR<T, PARTICLETYPE::d>& cellMin,
126 const PhysR<T, PARTICLETYPE::d>& cellMax, F getSetupPeriodicity,
127 T deltaX)
128{
129 using namespace descriptors;
130 const PhysR<T, PARTICLETYPE::d> pos =
132 PhysR<T, PARTICLETYPE::d> unifiedPosition(pos);
133
134 if constexpr (isPeriodic(getSetupPeriodicity())) {
135 constexpr Vector<bool, PARTICLETYPE::d> isPeriodic(getSetupPeriodicity());
136
137 auto sIndicator = particle.template getField<SURFACE, SINDICATOR>();
138 const T circumRadius = sIndicator->getCircumRadius() -
139 sIndicator->getEpsilon() +
140 util::max(sIndicator->getEpsilon(), 0.5 * deltaX);
141
142 for (unsigned i = 0; i < PARTICLETYPE::d; ++i) {
143 T const particleMax = pos[i] + circumRadius;
144 //T const particleMin = pos[i] - circumRadius;
145
146 if (particleMax > cellMax[i] && isPeriodic[i]) {
147 unifiedPosition[i] = communication::movePositionToStart(
148 pos[i], cellMax[i], cellMin[i]);
149 }
150 /*
151 else if (particleMin < cellMin[i] && isPeriodic[i]) {
152 unifiedPosition[i] = cellMax[i] - (cellMin[i] - pos[i]);
153 }
154 */
155 }
156 }
157 return unifiedPosition;
158}
159
160template <typename T, typename PARTICLETYPE, typename F>
163 const PhysR<T, PARTICLETYPE::d>& particlePos,
164 const PhysR<T, PARTICLETYPE::d>& contactPos,
165 const PhysR<T, PARTICLETYPE::d>& cellMin,
166 const PhysR<T, PARTICLETYPE::d>& cellMax,
167 F getSetupPeriodicity, T deltaX)
168{
169 using namespace descriptors;
170
171 if constexpr (!(isPeriodic(getSetupPeriodicity()))) {
172 return contactPos;
173 }
174 else {
175 auto sIndicator = particle.template getField<SURFACE, SINDICATOR>();
176 const T circumRadius = sIndicator->getCircumRadius() -
177 sIndicator->getEpsilon() +
178 util::max(sIndicator->getEpsilon(), 0.5 * deltaX);
179
180 PhysR<T, PARTICLETYPE::d> ghostPos = contactPos;
181 for (unsigned i = 0; i < PARTICLETYPE::d; ++i) {
182 T const particleMin = particlePos[i] - circumRadius;
183 T const particleMax = particlePos[i] + circumRadius;
184 if (particleMin > contactPos[i] && getSetupPeriodicity()[i]) {
186 contactPos[i], cellMax[i], cellMin[i]);
187 }
188 else if (particleMax < contactPos[i] && getSetupPeriodicity()[i]) {
190 contactPos[i], cellMax[i], cellMin[i]);
191 }
192 }
193 return ghostPos;
194 }
195}
196
197template <typename PARTICLECONTACTTYPE, bool IS_INPUT_SORTED = false>
198bool particleContactConsistsOfIDs(PARTICLECONTACTTYPE& particleContact,
199 const std::array<size_t, 2>& ids)
200{
201 if constexpr (!IS_INPUT_SORTED) {
202 return (particleContact.getIDs()[0] == ids[0] &&
203 particleContact.getIDs()[1] == ids[1]) ||
204 (particleContact.getIDs()[0] == ids[1] &&
205 particleContact.getIDs()[1] == ids[0]);
206 }
207 else {
208 return particleContact.getIDs()[0] == ids[0] &&
209 particleContact.getIDs()[1] == ids[1];
210 }
211 __builtin_unreachable();
212}
213
214template <typename T, typename PARTICLETYPE, bool CONVEX, typename F>
216 CONVEX>& contact,
217 Particle<T, PARTICLETYPE>& particle1,
218 Particle<T, PARTICLETYPE>& particle2,
219 const PhysR<T, PARTICLETYPE::d>& contactPos,
220 const PhysR<T, PARTICLETYPE::d>& cellMin,
221 const PhysR<T, PARTICLETYPE::d>& cellMax,
222 F getSetupPeriodicity, T deltaX)
223{
224 if (!contact.isParticlePositionUpdated()) {
225 std::array<PhysR<T, PARTICLETYPE::d>, 2> positions;
226 unifyPositions(particle1, particle2, cellMin, cellMax, getSetupPeriodicity,
227 positions, deltaX);
228 contact.setParticlePositions(positions);
229 }
230 // It doesn't matter which particle is used, since the contact must be in both
231 contact.updateMinMax(evalContactPosition(
232 particle1, contact.getParticlePosition(contact.getIDs()[0]),
233 contactPos, cellMin, cellMax, getSetupPeriodicity, deltaX));
234}
235
236template <typename T, typename PARTICLETYPE, bool CONVEX, typename F>
238 CONVEX>& contact,
240 const PhysR<T, PARTICLETYPE::d>& contactPos,
241 const PhysR<T, PARTICLETYPE::d>& cellMin,
242 const PhysR<T, PARTICLETYPE::d>& cellMax,
243 F getSetupPeriodicity, T deltaX)
244{
245 if (!contact.isParticlePositionUpdated()) {
246 contact.setParticlePosition(
247 unifyPosition(particle, cellMin, cellMax, getSetupPeriodicity, deltaX));
248 }
249 contact.updateMinMax(
250 evalContactPosition(particle, contact.getParticlePosition(), contactPos,
251 cellMin, cellMax, getSetupPeriodicity, deltaX));
252}
253
254template <typename T, typename PARTICLETYPE, typename PARTICLECONTACTTYPE,
255 typename WALLCONTACTTYPE, typename F>
258 //const std::array<size_t, 2>& ids,
259 std::array<std::size_t, 2>&& ids, const PhysR<T, PARTICLETYPE::d>& pos,
261 const PhysR<T, PARTICLETYPE::d>& cellMin,
262 const PhysR<T, PARTICLETYPE::d>& cellMax, F getSetupPeriodicity, T deltaX)
263{
264 // find the contact by checking particle ids
265 const std::function<bool(const PARTICLECONTACTTYPE&)> condition =
266 [&ids](const PARTICLECONTACTTYPE& contact) {
267 // we assume that ids aren't sorted
268 return particleContactConsistsOfIDs(contact, ids);
269 };
270 auto contactIt =
271 getContactIterator(contactContainer.particleContacts, condition);
272
273 if (contactIt != std::end(contactContainer.particleContacts)) {
274 if (contactIt->isNew()) {
275 if (particleContactConsistsOfIDs<PARTICLECONTACTTYPE, true>(
276 *contactIt, ids)) {
277 updateContact(*contactIt, particle1, particle2, pos, cellMin, cellMax,
278 getSetupPeriodicity, deltaX);
279 }
280 else {
281 updateContact(*contactIt, particle2, particle1, pos, cellMin, cellMax,
282 getSetupPeriodicity, deltaX);
283 }
284 }
285 }
286 else {
287 contactContainer.particleContacts.push_back(PARTICLECONTACTTYPE(ids));
288 if (particleContactConsistsOfIDs<PARTICLECONTACTTYPE, true>(
289 *(contactContainer.particleContacts.end() - 1), ids)) {
290 updateContact(*(contactContainer.particleContacts.end() - 1), particle1,
291 particle2, pos, cellMin, cellMax, getSetupPeriodicity,
292 deltaX);
293 }
294 else {
295 updateContact(*(contactContainer.particleContacts.end() - 1), particle2,
296 particle1, pos, cellMin, cellMax, getSetupPeriodicity,
297 deltaX);
298 }
299 }
300}
301
302template <typename T, typename PARTICLETYPE, typename PARTICLECONTACTTYPE,
303 typename WALLCONTACTTYPE, typename F>
306 size_t particleID, unsigned wallID, const PhysR<T, PARTICLETYPE::d>& pos,
308 const PhysR<T, PARTICLETYPE::d>& cellMin,
309 const PhysR<T, PARTICLETYPE::d>& cellMax, F getSetupPeriodicity, T deltaX)
310{
311 // find the contact by checking ids
312 const std::function<bool(const WALLCONTACTTYPE&)> condition =
313 [&particleID, &wallID](const WALLCONTACTTYPE& contact) {
314 return particleID == contact.getParticleID() &&
315 wallID == contact.getWallID();
316 };
317 auto contactIt =
318 getContactIterator(contactContainer.wallContacts, condition);
319
320 if (contactIt != std::end(contactContainer.wallContacts)) {
321 if (contactIt->isNew()) {
322 updateContact(*contactIt, particle, pos, cellMin, cellMax,
323 getSetupPeriodicity, deltaX);
324 }
325 }
326 else {
327 contactContainer.wallContacts.push_back(
328 WALLCONTACTTYPE(particleID, wallID));
329 updateContact(*(contactContainer.wallContacts.end() - 1), particle, pos,
330 cellMin, cellMax, getSetupPeriodicity, deltaX);
331 }
332}
333
334} //namespace contact
335
336} //namespace particles
337
338} //namespace olb
339
340#endif
Plain old scalar vector.
Definition vector.h:47
Vector< T, PARTICLETYPE::d > getPosition(Particle< T, PARTICLETYPE > particle)
T movePositionToEnd(const T position, const T max, const T min)
Definition utilities.h:260
T movePositionToStart(const T position, const T max, const T min)
Definition utilities.h:254
void unifyPositions(Particle< T, PARTICLETYPE > &particle1, Particle< T, PARTICLETYPE > &particle2, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, std::array< PhysR< T, PARTICLETYPE::d >, 2 > &positions, T deltaX)
void updateContact(ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, Particle< T, PARTICLETYPE > &particle1, Particle< T, PARTICLETYPE > &particle2, const PhysR< T, PARTICLETYPE::d > &contactPos, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
std::array< std::size_t, 2 > sortParticleIDs(const std::array< std::size_t, 2 > &ids)
bool particleContactConsistsOfIDs(PARTICLECONTACTTYPE &particleContact, const std::array< size_t, 2 > &ids)
PhysR< T, PARTICLETYPE::d > evalContactPosition(Particle< T, PARTICLETYPE > &particle, const PhysR< T, PARTICLETYPE::d > &particlePos, const PhysR< T, PARTICLETYPE::d > &contactPos, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
auto getContactIterator(std::vector< CONTACTTYPE > &contacts, const std::function< bool(const CONTACTTYPE &)> condition)
void updateContacts(ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, std::array< std::size_t, 2 > &&ids, const PhysR< T, PARTICLETYPE::d > &pos, Particle< T, PARTICLETYPE > &particle1, Particle< T, PARTICLETYPE > &particle2, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
PhysR< T, PARTICLETYPE::d > unifyPosition(Particle< T, PARTICLETYPE > &particle, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
constexpr bool isPeriodic(const Vector< bool, D > &periodic)
cpu::simd::Pack< T > min(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
Definition pack.h:124
cpu::simd::Pack< T > max(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
Definition pack.h:130
Top level namespace for all of OpenLB.
std::vector< PARTICLECONTACTTYPE > particleContacts
resizeable vector containing all particle-particle contacts
std::vector< WALLCONTACTTYPE > wallContacts
resizeable vector containg all particle-wall contacts
An object holding data for a contact which is described analog to Nassauer and Kuna (2013)