28#ifndef PARTICLE_CONTACT_FORCE_FUNCTIONS_H
29#define PARTICLE_CONTACT_FORCE_FUNCTIONS_H
40template <
typename T,
unsigned D>
44 const std::array<std::size_t, 2>& ids, T overlapVolume, T indentation,
45 bool isParticleWallContact) {};
50template <
typename T,
unsigned D,
typename CONTACTTYPE>
55 if (contact.getDampingFactor() < 0) {
56 contact.setDampingFactorFromInitialVelocity(
57 coefficientOfRestitution,
norm(initialRelativeNormalVelocity));
59 return contact.getDampingFactor();
63template <
typename T,
typename PARTICLETYPE>
73template <
typename T,
typename PARTICLETYPE>
81template <
typename T,
unsigned D>
86 return Vector<T, D>((relVel * contactNormal) * contactNormal);
89template <
typename T,
typename F>
93 for (pos[0] = startPos[0]; pos[0] <= endPos[0]; ++pos[0]) {
94 for (pos[1] = startPos[1]; pos[1] <= endPos[1]; ++pos[1]) {
95 for (pos[2] = startPos[2]; pos[2] <= endPos[2]; ++pos[2]) {
102template <
typename T,
typename F>
106 for (pos[0] = startPos[0]; pos[0] <= endPos[0]; ++pos[0]) {
107 for (pos[1] = startPos[1]; pos[1] <= endPos[1]; ++pos[1]) {
113template <
typename T,
typename F>
117 bool breakLoops =
false;
119 for (pos[0] = startPos[0]; pos[0] <= endPos[0]; ++pos[0]) {
120 for (pos[1] = startPos[1]; pos[1] <= endPos[1]; ++pos[1]) {
121 for (pos[2] = startPos[2]; pos[2] <= endPos[2]; ++pos[2]) {
131template <
typename T,
typename F>
135 bool breakLoops =
false;
137 for (pos[0] = startPos[0]; pos[0] <= endPos[0]; ++pos[0]) {
138 for (pos[1] = startPos[1]; pos[1] <= endPos[1]; ++pos[1]) {
146template <
typename T,
unsigned D>
150 const unsigned contactBoxResolutionPerDirection)
155 std::array<bool, D> fallbackUsed {[]() {
156 static_assert(D == 2 || D == 3,
"Only D=2 and D=3 are supported");
157 if constexpr (D == 3) {
158 return std::array<bool, D> {
false,
false,
false};
161 return std::array<bool, D> {
false,
false};
165 for (
unsigned iD = 0; iD < D; ++iD) {
166 contactPhysDeltaX[iD] /= contactBoxResolutionPerDirection;
168 contactPhysDeltaX[iD] = physDeltaX / contactBoxResolutionPerDirection;
169 fallbackUsed[iD] =
true;
176 for (
unsigned iD = 0; iD < D; ++iD) {
177 if (fallbackUsed[iD]) {
178 for (
unsigned iD2 = 0; iD2 < D; ++iD2) {
180 contactPhysDeltaX[iD] =
181 util::min(contactPhysDeltaX[iD], contactPhysDeltaX[iD2]);
187 return contactPhysDeltaX;
190template <
typename T,
typename PARTICLETYPE,
typename PARTICLECONTACTTYPE,
191 typename WALLCONTACTTYPE,
bool CONVEX>
198 if constexpr (!CONVEX) {
202 clout <<
"WARNING: Concave particles aren't supported." << std::endl;
207template <
typename T,
unsigned D>
209 T indentation, T dampingFactor,
214 T sum = relVelNormal[0] * contactNormal[0];
215 for (
unsigned iD = 1; iD < D; ++iD) {
216 sum += relVelNormal[iD] * contactNormal[iD];
219 const T forceMagnitude =
220 effectiveE * k *
util::sqrt(overlapVolume * indentation) *
222 return util::max(forceMagnitude, T {0}) * contactNormal;
226template <
typename T,
unsigned D>
231 if constexpr (D == 3) {
233 contactPhysDeltaX[1] * contactPhysDeltaX[2] *
235 normalizedNormal[0] * normalizedNormal[0];
237 contactPhysDeltaX[0] * contactPhysDeltaX[2] *
239 normalizedNormal[1] * normalizedNormal[1];
241 contactPhysDeltaX[0] * contactPhysDeltaX[1] *
243 normalizedNormal[2] * normalizedNormal[2];
247 contactPhysDeltaX[0] *
249 normalizedNormal[1] * normalizedNormal[1];
251 contactPhysDeltaX[1] *
253 normalizedNormal[0] * normalizedNormal[0];
255 return approxSurface;
259template <
typename T,
unsigned D>
261 const Vector<T, D>& contactNormal,
const T coefficientStaticFriction,
262 const T coefficientKineticFriction,
const T staticKineticTransitionVelocity,
266 if (coefficientStaticFriction > T {0.}) {
269 const Vector<T, D> relVelTangential(relVel - relVelNormal);
270 T
const magnitudeTangentialVelocity =
norm(relVelTangential);
271 if (magnitudeTangentialVelocity != T {0}) {
272 T
const velocityQuotient =
273 magnitudeTangentialVelocity / staticKineticTransitionVelocity;
275 T magnitudeTangentialForce =
276 2 * coefficientStaticFriction *
277 (1 - T {0.09} *
util::pow(coefficientKineticFriction /
278 coefficientStaticFriction,
280 magnitudeTangentialForce -= coefficientKineticFriction;
281 magnitudeTangentialForce *= velocityQuotient * velocityQuotient /
283 magnitudeTangentialForce += coefficientKineticFriction;
284 magnitudeTangentialForce -= coefficientKineticFriction /
285 (velocityQuotient * velocityQuotient + 1);
286 magnitudeTangentialForce *=
norm(normalForce);
288 return -magnitudeTangentialForce * relVelTangential /
289 magnitudeTangentialVelocity;
296template <
typename T,
unsigned D>
299 const T indentation,
const T overlapVolume,
300 const T effectiveE,
const T dampingFactor,
306 dampingFactor, relVelNormal, contactNormal);
309template <
typename T,
typename PARTICLETYPE>
311 std::multimap<
int, std::unique_ptr<std::uint8_t[]>>& dataMap,
318 using namespace descriptors;
319 constexpr unsigned D = PARTICLETYPE::d;
321 Vector<T, D> contactForce = normalForce + tangentialForce;
322 const PhysR<T, D> position = particle.template getField<GENERAL, POSITION>();
323 const PhysR<T, D> contactPointDistance = contactPoint - position;
326 contactForce, contactPointDistance));
329 bool applyNow =
true;
331 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
332 auto& loadBalancer = particleSystem.getSuperStructure().getLoadBalancer();
333 const std::size_t globalParticleIC =
334 particle.template getField<PARALLELIZATION, IC>();
335 int responsibleRank = loadBalancer.rank(globalParticleIC);
338 const std::size_t globalParticleID =
339 particle.template getField<PARALLELIZATION, ID>();
341 torqueFromContact, responsibleRank,
347 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
349 const std::size_t globalParticleID =
350 particle.template getField<PARALLELIZATION, ID>();
356 const int globalParticleIC =
357 particle.template getField<PARALLELIZATION, IC>();
358 const std::size_t currGlobalParticleID =
359 particle.template getField<PARALLELIZATION, ID>();
360 if (currGlobalParticleID == globalParticleID &&
361 globiC == globalParticleIC) {
364 particle.template getField<FORCING, FORCE>();
365 particle.template setField<FORCING, FORCE>(force +
370 particle.template getField<FORCING, TORQUE>());
371 particle.template setField<FORCING, TORQUE>(
373 torque + torqueFromContact));
374#ifdef VERBOSE_CONTACT_COMMUNICATION
376 <<
" procsses data of particle " << globalParticleID
377 <<
" (contactForce = " << contactForce + force
378 <<
"; torque = " << torqueFromContact + torque <<
")"
386 const Vector<T, D> force = particle.template getField<FORCING, FORCE>();
387 particle.template setField<FORCING, FORCE>(force + contactForce);
391 particle.template getField<FORCING, TORQUE>());
392 particle.template setField<FORCING, TORQUE>(
394 torque + torqueFromContact));
401 typename T,
typename PARTICLETYPE,
typename CONTACTPROPERTIES,
402 typename F =
decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
404 std::multimap<
int, std::unique_ptr<std::uint8_t[]>>& dataMap,
410 const T dampingFactor,
const CONTACTPROPERTIES& contactProperties, T k,
411 const std::size_t& particleAID,
const std::size_t& particleBID,
412 F processContactForce = defaults::processContactForce<T, PARTICLETYPE::d>)
414 using namespace descriptors;
415 constexpr unsigned D = PARTICLETYPE::d;
417 const unsigned materialA =
418 particleA.template getField<MECHPROPERTIES, MATERIAL>();
419 const unsigned materialB =
420 particleB.template getField<MECHPROPERTIES, MATERIAL>();
424 contactNormal, indentation, overlapVolume,
425 contactProperties.getEffectiveYoungsModulus(materialA, materialB),
426 dampingFactor, k, relVel);
429 contactProperties.getStaticFrictionCoefficient(materialA, materialB),
430 contactProperties.getKineticFrictionCoefficient(materialA, materialB),
431 contactProperties.getStaticFrictionCoefficient(materialA, materialB), k,
432 relVel, normalForce);
434 processContactForce(contactPoint, contactNormal, normalForce, tangentialForce,
435 std::array<std::size_t, 2>({particleAID, particleBID}),
436 overlapVolume, indentation,
false);
440 normalForce, tangentialForce);
442 -1 * normalForce, -1 * tangentialForce);
446 typename T,
typename PARTICLETYPE,
typename CONTACTPROPERTIES,
447 typename F =
decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
449 std::multimap<
int, std::unique_ptr<std::uint8_t[]>>& dataMap,
456 const T dampingFactor,
const CONTACTPROPERTIES& contactProperties, T k,
457 const std::size_t& particleID,
const std::size_t& wallID,
458 F processContactForce = defaults::processContactForce<T, PARTICLETYPE::d>)
460 using namespace descriptors;
461 constexpr unsigned D = PARTICLETYPE::d;
463 const unsigned particleMaterial =
464 particle.template getField<MECHPROPERTIES, MATERIAL>();
469 contactNormal, indentation, overlapVolume,
470 contactProperties.getEffectiveYoungsModulus(particleMaterial,
472 dampingFactor, k, relVel);
475 contactProperties.getStaticFrictionCoefficient(particleMaterial,
477 contactProperties.getKineticFrictionCoefficient(particleMaterial,
479 contactProperties.getStaticKineticTransitionVelocity(particleMaterial,
481 k, relVel, normalForce);
483 processContactForce(contactPoint, contactNormal, normalForce, tangentialForce,
484 std::array<std::size_t, 2>({particleID, wallID}),
485 overlapVolume, indentation,
true);
489 normalForce, tangentialForce);
492template <
typename T,
unsigned D>
497 for (
unsigned iD = 0; iD < D; ++iD) {
498 startPos[iD] =
util::floor(min[iD] / contactPhysDeltaX[iD]);
499 endPos[iD] =
util::ceil(max[iD] / contactPhysDeltaX[iD]);
503template <
typename T,
unsigned D>
511 T boundingBoxVolume = 1;
512 for (
unsigned iD = 0; iD < D; ++iD) {
513 boundingBoxVolume *= length[iD];
523 const T contactSurface,
524 const T indentationDepth)
526 constexpr T a = 0.6118229;
527 constexpr T b = 1.900093;
528 constexpr T c = 0.651237;
530 const T x = indentationDepth * contactSurface / contactVolume;
535template <
typename T,
unsigned D,
typename F1,
typename F2,
typename F3,
536 typename F4,
typename F5>
539 unsigned& volumeCellCount, T& surfaceCellCount, F1 isInside,
540 F2 isOnSurface, F3 calcNormalA, F4 calcNormalB,
544 if (!isInside(pos)) {
545 bool onSurfaceA =
false, onSurfaceB =
false;
550 normalA = calcNormalA(pos, meshSize);
551 normalB = calcNormalB(pos, meshSize);
559 if (isOnSurface(pos, contactPhysDeltaX, onSurfaceA, onSurfaceB, normalA,
564 surfaceCellCount += approxSurface;
565 contactNormal += normalA * approxSurface;
569 surfaceCellCount += approxSurface;
570 contactNormal -= normalB * approxSurface;
578 for (
unsigned iD = 0; iD < D; ++iD) {
579 center[iD] += pos[iD];
586template <
typename T,
unsigned D,
typename F1,
typename F2,
typename F3,
590 unsigned contactBoxResolutionPerDirection,
591 F1 resetContactBox, F2 processCellWrapped,
592 F3 calculateIndentation, F4 applyForce)
602 unsigned volumeCellCount = 0;
604 T surfaceCellCount = 0.;
606 T infinitesimalVolume = contactPhysDeltaX[0] * contactPhysDeltaX[1];
607 if constexpr (D == 3) {
608 infinitesimalVolume *= contactPhysDeltaX[2];
622 for (
unsigned iD = 0; iD < D; ++iD) {
623 physPos[iD] = pos[iD] * contactPhysDeltaX[iD];
625 processCellWrapped(contactNormal, center, volumeCellCount, surfaceCellCount,
626 physPos, contactPhysDeltaX);
630 if (volumeCellCount > 0 && surfaceCellCount > 0) {
632 center /= volumeCellCount;
634 contactNormal =
normalize(contactNormal);
637 for (
unsigned iD = 0; iD < D; ++iD) {
638 precision +=
util::pow(contactNormal[iD] * contactPhysDeltaX[iD], 2);
640 precision = T {1e-2} *
util::sqrt(precision / D);
641 const T indentation =
642 calculateIndentation(center, contactNormal, precision);
646 if (indentation > 0) {
647 applyForce(center, contactNormal,
util::max(indentation, T {0}),
648 volumeCellCount * infinitesimalVolume);
655 clout <<
"WARNING: The contact normal's norm is zero. Therefore, the "
656 "detected contact is ignored."
662template <
typename T,
unsigned D,
typename F1>
668 bool pointFound =
false;
673 for (
unsigned iD = 0; iD < D; ++iD) {
674 physPos[iD] = contactPhysDeltaX[iD] * pos[iD];
676 if (isInsideContact(physPos)) {
686template <
typename T,
unsigned D,
typename F1,
typename F2>
695 for (
unsigned iD = 0; iD < D; ++iD) {
696 currPhysPos[iD] = contactPhysDeltaX[iD] * currPos[iD];
698 bool isInside = isInsideContact(currPhysPos);
699 bool isInsideBB =
true;
700 for (
unsigned iD = 0; iD < D; ++iD) {
701 if (currPos[iD] < startPos[iD] || currPos[iD] > endPos[iD]) {
708 if (isInside || isInsideBB) {
716 if (
norm(dirOut) >= 1) {
718 for (
unsigned iD = 0; iD < D; ++iD) {
719 signedDirOut[iD] = dirOut[iD] * dirIn[iD];
723 startPos, endPos, contactPhysDeltaX, nextPos,
730template <
typename T,
unsigned D,
typename F1,
typename F2,
typename F3>
733 const unsigned contactBoxResolutionPerDirection,
734 F1 isInsideContact, F2 resetContactBox, F3
updateMinMax)
745 startPos, endPos, contactPhysDeltaX, origin, isInsideContact);
749 for (
unsigned iD = 0; iD < D; ++iD) {
750 physOrigin[iD] = contactPhysDeltaX[iD] * origin[iD];
754 for (
unsigned i = 0; i < utilities::dimensions::convert<D>::neighborsCount;
759 origin + direction, direction, isInsideContact,
765template <
typename T,
unsigned D,
typename F1,
typename F2,
typename F3>
768 unsigned contactBoxResolutionPerDirection,
769 F1 signedDistanceToIntersection,
775 for (
unsigned iD = 0; iD < D; ++iD) {
777 min[iD] -= contactPhysDeltaX[iD];
779 max[iD] += contactPhysDeltaX[iD];
790 bool isOnContactSurface =
false;
791 for (
unsigned iD = 0; iD < D; ++iD) {
792 if (pos[iD] == startPos[iD] || pos[iD] == endPos[iD]) {
793 isOnContactSurface =
true;
798 if (isOnContactSurface) {
801 for (
unsigned iD = 0; iD < D; ++iD) {
802 physPos[iD] = pos[iD] * contactPhysDeltaX[iD];
806 i < utilities::dimensions::convert<D>::neighborsCount; ++i) {
808 bool regardDirection =
true;
813 for (
unsigned iD = 0; iD < D; ++iD) {
814 if (neighborPos[iD] <= startPos[iD] ||
815 neighborPos[iD] >= endPos[iD]) {
816 regardDirection =
false;
821 if (regardDirection) {
824 D>::template normalizedNeighborDirections<T>[i]);
837 if (util::distance<T, D, false>(
838 distance, physPos, normalizedDirection, physDeltaX * T {1e-2},
840 return signedDistanceToIntersection(pos);
845 physPos + distance * normalizedDirection;
856template <
typename T,
typename PARTICLETYPE,
typename PARTICLECONTACTTYPE,
857 typename WALLCONTACTTYPE,
unsigned BBCORRECTIONMETHOD = 0,
858 bool CONVEX =
true,
bool useSDF =
true>
861template <
typename T,
typename PARTICLETYPE,
typename WALLCONTACTTYPE,
862 unsigned BBCORRECTIONMETHOD,
bool CONVEX,
bool useSDF>
866 WALLCONTACTTYPE, BBCORRECTIONMETHOD, CONVEX, useSDF> {
871 WALLCONTACTTYPE>& contactContainer)
873 for (
auto& contact : contactContainer.particleContacts) {
874 contact.resetMinMax();
888 constexpr unsigned D = PARTICLETYPE::d;
891 const std::function<bool(
const PhysR<T, D>&)> isInside =
893 bool const isInsideParticleA =
896 bool const isInsideParticleB =
899 return isInsideParticleA && isInsideParticleB;
907 bool& onSurfaceA,
bool& onSurfaceB,
911 for (
unsigned iD = 0; iD < D; ++iD) {
912 neighbor[iD] = -normalA[iD] * contactPhysDeltaX[iD];
915 particleA, pos + neighbor) <=
917 for (
unsigned iD = 0; iD < D; ++iD) {
918 neighbor[iD] = -normalB[iD] * contactPhysDeltaX[iD];
921 particleB, pos + neighbor) <=
923 return onSurfaceA || onSurfaceB;
927 const std::function<Vector<T, D>(
const PhysR<T, D>&,
const T)> calcNormalA =
934 const std::function<Vector<T, D>(
const PhysR<T, D>&,
const T)> calcNormalB =
943 contact.updateMinMax(pos);
947 contactNormal, volumeCellCount,
948 surfaceCellCount, isInside, isOnSurface,
953 typename CONTACTPROPERTIES,
954 typename F =
decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
956 std::multimap<
int, std::unique_ptr<std::uint8_t[]>>& dataMap,
960 const CONTACTPROPERTIES& contactProperties,
const T physDeltaX,
961 const unsigned contactBoxResolutionPerDirection,
const T k,
962 F processContactForce = defaults::processContactForce<T, PARTICLETYPE::d>)
964 using namespace descriptors;
965 constexpr unsigned D = PARTICLETYPE::d;
968 T indentationDepth = T(0.);
973 auto particleA = particleSystem.get(contact.
getIDs()[0]);
974 auto particleB = particleSystem.get(contact.
getIDs()[1]);
977 const std::function<void()> resetMinMax = [&contact]() {
985 unsigned& volumeCellCount, T& surfaceCellCount,
988 processCell(contact, particleA, particleB, contactNormal,
989 center, volumeCellCount, surfaceCellCount, physPos,
996 const T distancePrecision) {
1007 particleA, originA, contactNormal, distancePrecision) +
1009 particleB, originB, -1 * contactNormal, distancePrecision);
1017 const unsigned materialA =
1018 particleA.template getField<MECHPROPERTIES, MATERIAL>();
1019 const unsigned materialB =
1020 particleB.template getField<MECHPROPERTIES, MATERIAL>();
1022 indentationDepth = indentation;
1027 contactProperties.getCoefficientOfRestitution(materialA,
1032 dataMap, particleA, particleB, particleSystem, center,
1033 contactNormal, indentation, overlapVolume, relVel,
1034 dampingFactor, contactProperties, k, contact.
getIDs()[0],
1035 contact.
getIDs()[1], processContactForce);
1039 contactBoxResolutionPerDirection, resetMinMax,
1040 processCellWrapped, calculateIndentation,
1049 const T physDeltaX,
const unsigned contactBoxResolutionPerDirection)
1051 using namespace descriptors;
1052 constexpr unsigned D = PARTICLETYPE::d;
1054 auto particleA = particleSystem.get(contact.
getIDs()[0]);
1055 auto particleB = particleSystem.get(contact.
getIDs()[1]);
1059 contactBoxResolutionPerDirection,
1061 return sdf::intersection(
1063 particles::resolved::signedDistanceToParticle(particleA, pos),
1064 particles::access::getEnlargementForContact(particleA)),
1066 particles::resolved::signedDistanceToParticle(particleB, pos),
1067 particles::access::getEnlargementForContact(particleB)));
1070 contact.resetMinMax();
1073 contact.updateMinMax(pos);
1082 const T physDeltaX,
const unsigned contactBoxResolutionPerDirection)
1084 using namespace descriptors;
1085 constexpr unsigned D = PARTICLETYPE::d;
1089 contactBoxResolutionPerDirection);
1092 contactBoxResolutionPerDirection);
1099 T physDeltaX,
unsigned contactBoxResolutionPerDirection)
1101 using namespace descriptors;
1102 constexpr unsigned D = PARTICLETYPE::d;
1104 auto particleA = particleSystem.get(contact.
getIDs()[0]);
1105 auto particleB = particleSystem.get(contact.
getIDs()[1]);
1107 const std::function<bool(
const PhysR<T, D>&)> isInsideContact =
1112 const std::function<void()> resetMinMax = [&contact]() {
1122 contactBoxResolutionPerDirection, isInsideContact, resetMinMax,
1127 typename CONTACTPROPERTIES,
1128 typename F1 =
decltype(defaults::periodicity<PARTICLETYPE::d>),
1129 typename F2 =
decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
1135 WALLCONTACTTYPE>& contactContainer,
1136 const CONTACTPROPERTIES& contactProperties,
1138 std::multimap<
int, std::unique_ptr<std::uint8_t[]>>& dataMap,
1139 const unsigned contactBoxResolutionPerDirection = 8,
1141 F1 getSetupPeriodicity = defaults::periodicity<PARTICLETYPE::d>,
1142 F2 processContactForce =
1143 defaults::processContactForce<T, PARTICLETYPE::d>)
1145 using namespace descriptors;
1146 const T physDeltaX =
1149 for (
auto& particleContact : contactContainer.particleContacts) {
1150 if (!particleContact.isEmpty()) {
1151 bool isResponsible =
true;
1153 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
1155 particleContact.getResponsibleRank();
1158 if (isResponsible) {
1160 bool computeContact =
true;
1161 if constexpr (access::providesComputeContact<PARTICLETYPE>()) {
1162 auto particleA = particleSystem.get(particleContact.getIDs()[0]);
1163 auto particleB = particleSystem.get(particleContact.getIDs()[1]);
1168 if (computeContact) {
1169 std::array<PhysR<T, PARTICLETYPE::d>, 2> originalPos;
1170 if constexpr (
isPeriodic(getSetupPeriodicity())) {
1171 for (
unsigned i = 0; i < 2; ++i) {
1172 auto particle = particleSystem.get(particleContact.getIDs()[i]);
1174 particle.template getField<GENERAL, POSITION>();
1175 particle.template setField<GENERAL, POSITION>(
1176 particleContact.getParticlePositions()[i]);
1180 if (particleContact.isNew()) {
1183 contactBoxResolutionPerDirection);
1184 particleContact.isNew(particleContact.isEmpty());
1187 if constexpr (BBCORRECTIONMETHOD == 1) {
1188 correctBoundingBoxExistingContact(
1189 particleSystem, particleContact, physDeltaX,
1190 contactBoxResolutionPerDirection);
1195 contactBoxResolutionPerDirection);
1198 apply(dataMap, particleSystem, particleContact, contactProperties,
1199 physDeltaX, contactBoxResolutionPerDirection, k,
1200 processContactForce);
1202 if constexpr (
isPeriodic(getSetupPeriodicity())) {
1203 for (
unsigned i = 0; i < 2; ++i) {
1204 auto particle = particleSystem.get(particleContact.getIDs()[i]);
1205 particle.template setField<GENERAL, POSITION>(originalPos[i]);
1208 particleContact.setParticlePositionUpdated(
false);
1213 particleContact.resetMinMax();
1221template <
typename T,
typename PARTICLETYPE,
typename PARTICLECONTACTTYPE,
1222 typename WALLCONTACTTYPE,
unsigned BBCORRECTIONMETHOD = 0,
1223 bool CONVEX =
true,
bool useSDF =
true>
1226template <
typename T,
typename PARTICLETYPE,
typename PARTICLECONTACTTYPE,
1227 unsigned BBCORRECTIONMETHOD,
bool CONVEX,
bool useSDF>
1229 T, PARTICLETYPE, PARTICLECONTACTTYPE,
1231 BBCORRECTIONMETHOD, CONVEX, useSDF> {
1234 T, PARTICLECONTACTTYPE,
1238 for (
auto& contact : contactContainer.wallContacts) {
1254 constexpr unsigned D = PARTICLETYPE::d;
1257 const std::function<bool(
const PhysR<T, D>&)> isInside =
1259 bool const isInsideIndicator =
1262 bool const isInsideParticle =
1265 return isInsideParticle && isInsideIndicator;
1273 bool& onSurfaceA,
bool& onSurfaceB,
1277 for (
unsigned iD = 0; iD < D; ++iD) {
1278 neighbor[iD] = -normalA[iD] * contactPhysDeltaX[iD];
1281 particle, pos + neighbor) <=
1283 for (
unsigned iD = 0; iD < D; ++iD) {
1284 neighbor[iD] = -normalB[iD] * contactPhysDeltaX[iD];
1286 onSurfaceB = solidBoundary.
getIndicator()->signedDistance(
1287 (pos + neighbor).data()) <=
1289 return onSurfaceA || onSurfaceB;
1293 const std::function<Vector<T, D>(
const PhysR<T, D>&,
const T)> calcNormalA =
1300 const std::function<Vector<T, D>(
const PhysR<T, D>&,
const T)> calcNormalB =
1302 return solidBoundary.
getIndicator()->surfaceNormal(pos, meshSize);
1311 contactNormal, volumeCellCount,
1312 surfaceCellCount, isInside, isOnSurface,
1317 typename CONTACTPROPERTIES,
1318 typename F =
decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
1320 std::multimap<
int, std::unique_ptr<std::uint8_t[]>>& dataMap,
1325 const CONTACTPROPERTIES& contactProperties,
const T physDeltaX,
1326 const unsigned contactBoxResolutionPerDirection,
const T k,
1327 F processContactForce = defaults::processContactForce<T, PARTICLETYPE::d>)
1329 using namespace descriptors;
1330 constexpr unsigned D = PARTICLETYPE::d;
1333 T indentationDepth = T(0.);
1337 auto particle = particleSystem.get(contact.
getParticleID());
1341 const std::function<void()> resetMinMax = [&contact]() {
1347 processCellWrapped =
1349 unsigned& volumeCellCount, T& surfaceCellCount,
1352 processCell(contact, particle, solidBoundary, contactNormal,
1353 center, volumeCellCount, surfaceCellCount, physPos,
1360 const T distancePrecision) {
1371 particle, origin, contactNormal, distancePrecision);
1374 if (solidBoundary.
getIndicator()->distance(distToWall, center,
1376 -1 * contactNormal)) {
1385 clout <<
"WARNING: No distance to wall determined." << std::endl;
1395 const unsigned particleMaterial =
1396 particle.template getField<MECHPROPERTIES, MATERIAL>();
1399 indentationDepth = indentation;
1403 contactProperties.getCoefficientOfRestitution(particleMaterial,
1408 dataMap, particle, particleSystem, solidBoundary, center,
1409 contactNormal, indentation, overlapVolume, relVel,
1410 dampingFactor, contactProperties, k, contact.
getParticleID(),
1411 contact.
getWallID(), processContactForce);
1415 contactBoxResolutionPerDirection, resetMinMax,
1416 processCellWrapped, calculateIndentation,
1426 const T physDeltaX,
const unsigned contactBoxResolutionPerDirection)
1428 using namespace descriptors;
1429 constexpr unsigned D = PARTICLETYPE::d;
1438 contactBoxResolutionPerDirection,
1440 return sdf::intersection(
1442 particles::resolved::signedDistanceToParticle(particle, pos),
1443 particles::access::getEnlargementForContact(particle)),
1444 sdf::rounding(solidBoundary.getIndicator()->signedDistance(pos),
1445 solidBoundary.getEnlargementForContact()));
1448 contact.resetMinMax();
1451 contact.updateMinMax(pos);
1460 const T physDeltaX,
const unsigned contactBoxResolutionPerDirection)
1462 using namespace descriptors;
1463 constexpr unsigned D = PARTICLETYPE::d;
1467 contactBoxResolutionPerDirection);
1470 physDeltaX, contactBoxResolutionPerDirection);
1478 const T physDeltaX,
const unsigned contactBoxResolutionPerDirection)
1480 using namespace descriptors;
1481 constexpr unsigned D = PARTICLETYPE::d;
1483 auto particle = particleSystem.get(contact.
getParticleID());
1486 const std::function<bool(
const PhysR<T, D>&)> isInsideContact =
1489 solidBoundary.
getIndicator()->operator()(&isInsideWall, pos.data());
1493 const std::function<void()> resetMinMax = [&contact]() {
1503 contactBoxResolutionPerDirection, isInsideContact, resetMinMax,
1508 typename CONTACTPROPERTIES,
1509 typename F1 =
decltype(defaults::periodicity<PARTICLETYPE::d>),
1510 typename F2 =
decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
1515 T, PARTICLECONTACTTYPE,
1518 const CONTACTPROPERTIES& contactProperties,
1520 std::multimap<
int, std::unique_ptr<std::uint8_t[]>>& dataMap,
1521 const unsigned contactBoxResolutionPerDirection = 8,
1523 F1 getSetupPeriodicity = defaults::periodicity<PARTICLETYPE::d>,
1524 F2 processContactForce =
1525 defaults::processContactForce<T, PARTICLETYPE::d>)
1527 using namespace descriptors;
1528 const T physDeltaX =
1531 for (
auto& wallContact : contactContainer.wallContacts) {
1532 if (!wallContact.isEmpty()) {
1533 bool isResponsible =
true;
1535 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
1540 if (isResponsible) {
1542 bool computeContact =
true;
1543 if constexpr (access::providesComputeContact<PARTICLETYPE>()) {
1544 auto particle = particleSystem.get(wallContact.getParticleID());
1548 if (computeContact) {
1550 if constexpr (
isPeriodic(getSetupPeriodicity())) {
1551 auto particle = particleSystem.get(wallContact.getParticleID());
1552 originalPos = particle.template getField<GENERAL, POSITION>();
1553 particle.template setField<GENERAL, POSITION>(
1554 wallContact.getParticlePosition());
1557 if (wallContact.isNew()) {
1559 wallContact, physDeltaX,
1560 contactBoxResolutionPerDirection);
1561 wallContact.isNew(wallContact.isEmpty());
1564 if constexpr (BBCORRECTIONMETHOD == 1) {
1565 correctBoundingBoxExistingContact(
1566 particleSystem, solidBoundaries, wallContact, physDeltaX,
1567 contactBoxResolutionPerDirection);
1572 contactBoxResolutionPerDirection);
1575 apply(dataMap, particleSystem, solidBoundaries, wallContact,
1576 contactProperties, physDeltaX,
1577 contactBoxResolutionPerDirection, k, processContactForce);
1579 if constexpr (
isPeriodic(getSetupPeriodicity())) {
1580 particleSystem.get(wallContact.getParticleID())
1581 .
template setField<GENERAL, POSITION>(originalPos);
1584 wallContact.setParticlePositionUpdated(
false);
1589 wallContact.resetMinMax();
1604 typename T,
typename PARTICLETYPE,
typename PARTICLECONTACTTYPE,
1605 typename WALLCONTACTTYPE,
typename CONTACTPROPERTIES,
1606 unsigned BBCORRECTIONMETHOD = 0,
1607 typename F1 =
decltype(defaults::periodicity<PARTICLETYPE::d>),
1608 typename F2 =
decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
1613 const CONTACTPROPERTIES& contactProperties,
1615#ifdef PARALLEL_MODE_MPI
1616 MPI_Comm contactTreatmentComm,
1618 const unsigned contactBoxResolutionPerDirection = 8,
1620 F1 getSetupPeriodicity = defaults::periodicity<PARTICLETYPE::d>,
1621 F2 processContactForce = defaults::processContactForce<T, PARTICLETYPE::d>)
1624 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
1627 BBCORRECTIONMETHOD>::apply(particleSystem, contactContainer,
1628 contactProperties, sGeometry,
1630 contactBoxResolutionPerDirection,
1631 k, getSetupPeriodicity,
1632 processContactForce);
1634 particle_wall<T, PARTICLETYPE, PARTICLECONTACTTYPE, WALLCONTACTTYPE,
1635 BBCORRECTIONMETHOD>::apply(particleSystem, solidBoundaries,
1636 contactContainer, contactProperties,
1638 contactBoxResolutionPerDirection, k,
1639 getSetupPeriodicity,
1640 processContactForce);
1641 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
1642 communicateContactTreatmentResults<T, PARTICLETYPE>(particleSystem, dataMap
1643#ifdef PARALLEL_MODE_MPI
1645 contactTreatmentComm
1652 typename T,
typename PARTICLETYPE,
typename PARTICLECONTACTTYPE,
1653 typename WALLCONTACTTYPE,
typename CONTACTPROPERTIES,
1654 unsigned BBCORRECTIONMETHOD = 0,
1655 typename F1 =
decltype(defaults::periodicity<PARTICLETYPE::d>),
1656 typename F2 =
decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
1661 const CONTACTPROPERTIES& contactProperties,
1663 const unsigned contactBoxResolutionPerDirection = 8,
1665 F1 getSetupPeriodicity = defaults::periodicity<PARTICLETYPE::d>,
1666 F2 processContactForce = defaults::processContactForce<T, PARTICLETYPE::d>)
1669 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
1672 BBCORRECTIONMETHOD>::apply(particleSystem, contactContainer,
1673 contactProperties, sGeometry,
1675 contactBoxResolutionPerDirection,
1676 k, getSetupPeriodicity,
1677 processContactForce);
1679 particle_wall<T, PARTICLETYPE, PARTICLECONTACTTYPE, WALLCONTACTTYPE,
1680 BBCORRECTIONMETHOD>::apply(particleSystem, solidBoundaries,
1681 contactContainer, contactProperties,
1683 contactBoxResolutionPerDirection, k,
1684 getSetupPeriodicity,
1685 processContactForce);
class for marking output with some text
Representation of a statistic for a parallel 2D geometry.
CuboidGeometry< T, D > & getCuboidGeometry()
Read and write access to cuboid geometry.
constexpr const T * data() const any_platform
int getRank() const
Returns the process ID.
bool isContactComputationEnabled(Particle< T, PARTICLETYPE > &particle)
Check if contact should be regarded (specification for a single particle)
T getEnlargementForContact(Particle< T, PARTICLETYPE > particle)
void forParticlesInSuperParticleSystem(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, F f)
void processContacts(SuperParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, const CONTACTPROPERTIES &contactProperties, const SuperGeometry< T, PARTICLETYPE::d > &sGeometry, MPI_Comm contactTreatmentComm, const unsigned contactBoxResolutionPerDirection=8, const T k=static_cast< T >(4./(3 *util::sqrt(M_PI))), F1 getSetupPeriodicity=defaults::periodicity< PARTICLETYPE::d >, F2 processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
void evalStartAndEndPos(Vector< long, D > &startPos, Vector< long, D > &endPos, const PhysR< T, D > &max, const PhysR< T, D > &min, const PhysR< T, D > &contactPhysDeltaX)
T evalForceViaVolumeCoefficient(const Vector< T, D > &min, const Vector< T, D > &max, T overlapVolume)
constexpr T evalCurrentDampingFactor(CONTACTTYPE &contact, const T coefficientOfRestitution, const Vector< T, D > &initialRelativeNormalVelocity)
constexpr Vector< T, D > evalContactDeltaX(const Vector< T, D > &min, const Vector< T, D > &max, const T physDeltaX, const unsigned contactBoxResolutionPerDirection)
void processCell(const PhysR< T, D > &pos, const PhysR< T, D > &contactPhysDeltaX, PhysR< T, D > ¢er, Vector< T, D > &contactNormal, unsigned &volumeCellCount, T &surfaceCellCount, F1 isInside, F2 isOnSurface, F3 calcNormalA, F4 calcNormalB, F5 updateMinMax)
void prepareForceCalculation(ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer)
constexpr Vector< T, PARTICLETYPE::d > evalRelativeVelocity(Particle< T, PARTICLETYPE > &particleA, Particle< T, PARTICLETYPE > &particleB, const Vector< T, PARTICLETYPE::d > &position)
Returns the relative velocity of two particles at a defined position.
void correctBoundingBoxNewContact(PhysR< T, D > min, PhysR< T, D > max, T physDeltaX, unsigned contactBoxResolutionPerDirection, F1 signedDistanceToIntersection, F2 resetContactBox, F3 updateMinMax)
void correctBoundingBox(const PhysR< T, D > &min, const PhysR< T, D > &max, const T physDeltaX, const unsigned contactBoxResolutionPerDirection, F1 isInsideContact, F2 resetContactBox, F3 updateMinMax)
Vector< T, D > calcElasticAndViscousForce(T effectiveE, T k, T overlapVolume, T indentation, T dampingFactor, const Vector< T, D > &relVelNormal, const Vector< T, D > &contactNormal)
Elastic and viscous force from overlap volume according to Nassauer & Kuna (2013)
T evalApproxSurface(const Vector< T, D > &normalizedNormal, const PhysR< T, D > &contactPhysDeltaX)
Takes a normalized normal and the voxel sizes and approximates the corresponding surface.
constexpr void forEachPosition(Vector< T, 3 > startPos, Vector< T, 3 > endPos, F f)
void updateMinMax(PhysR< T, D > &min, PhysR< T, D > &max, const PhysR< T, D > &pos)
Vector< T, D > getNormalForceFromOverlapVolume(const Vector< T, D > &contactNormal, const T indentation, const T overlapVolume, const T effectiveE, const T dampingFactor, const T k, const Vector< T, D > &relVel)
void applyForceFromOverlapVolume(std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, Particle< T, PARTICLETYPE > &particleA, Particle< T, PARTICLETYPE > &particleB, XParticleSystem< T, PARTICLETYPE > &particleSystem, const PhysR< T, PARTICLETYPE::d > &contactPoint, const Vector< T, PARTICLETYPE::d > &contactNormal, const T indentation, const T overlapVolume, const Vector< T, PARTICLETYPE::d > &relVel, const T dampingFactor, const CONTACTPROPERTIES &contactProperties, T k, const std::size_t &particleAID, const std::size_t &particleBID, F processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
bool evalStartingPoint(const Vector< long, D > &startPos, const Vector< long, D > &endPos, const Vector< T, D > &contactPhysDeltaX, Vector< long, D > &currPos, F1 isInsideContact)
void extendContactTreatmentResultsDataMap(const std::size_t &globalParticleID, Vector< T, D > &force, Vector< T, utilities::dimensions::convert< D >::rotation > &torque, const int destRank, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap)
constexpr Vector< T, D > evalRelativeNormalVelocity(const Vector< T, D > &contactNormal, const Vector< T, D > &relVel)
void applyForceOnParticle(std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, Particle< T, PARTICLETYPE > &particle, XParticleSystem< T, PARTICLETYPE > &particleSystem, const Vector< T, PARTICLETYPE::d > &contactPoint, const Vector< T, PARTICLETYPE::d > &normalForce, const Vector< T, PARTICLETYPE::d > &tangentialForce)
constexpr void forEachPositionWithBreak(Vector< T, 3 > startPos, Vector< T, 3 > endPos, F f)
void processContactViaVolume(const Vector< T, D > &min, const Vector< T, D > &max, T physDeltaX, unsigned contactBoxResolutionPerDirection, F1 resetContactBox, F2 processCellWrapped, F3 calculateIndentation, F4 applyForce)
Vector< T, D > getTangentialForceFromOverlapVolume(const Vector< T, D > &contactNormal, const T coefficientStaticFriction, const T coefficientKineticFriction, const T staticKineticTransitionVelocity, const T k, const Vector< T, D > &relVel, const Vector< T, D > &normalForce)
void evalBoundingBoxRecursive(const Vector< long, D > &startPos, const Vector< long, D > &endPos, const Vector< T, D > &contactPhysDeltaX, const Vector< long, D > &currPos, const Vector< short, D > &dirIn, F1 isInsideContact, F2 updateMinMax)
void communicateContacts(ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer)
const auto processContactForce
constexpr Vector< T, PARTICLETYPE::d > calculateLocalVelocity(Particle< T, PARTICLETYPE > &particle, const PhysR< T, PARTICLETYPE::d > &input)
const S distanceToParticle(Particle< T, PARTICLETYPE > &particle, const Vector< S, PARTICLETYPE::d > &origin, const Vector< S, PARTICLETYPE::d > &direction, S precision, S pitch)
Vector< S, PARTICLETYPE::d > normalOnParticleSurface(Particle< T, PARTICLETYPE > &particle, const Vector< S, PARTICLETYPE::d > &pos, const T meshSize)
bool isInsideParticle(Particle< T, PARTICLETYPE > &particle, const PhysR< S, PARTICLETYPE::d > &input)
const S signedDistanceToParticle(Particle< T, PARTICLETYPE > &particle, const PhysR< S, PARTICLETYPE::d > &input)
std::conditional_t< PARTICLETYPE::template providesNested< descriptors::PARALLELIZATION >(), SuperParticleSystem< T, PARTICLETYPE >, ParticleSystem< T, PARTICLETYPE > > XParticleSystem
constexpr bool isPeriodic(const Vector< bool, D > &periodic)
cpu::simd::Pack< T > sqrt(cpu::simd::Pack< T > value)
ADf< T, DIM > ceil(const ADf< T, DIM > &a)
ADf< T, DIM > floor(const ADf< T, DIM > &a)
cpu::simd::Pack< T > min(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
ADf< T, DIM > log(const ADf< T, DIM > &a)
T average(const Vector< T, Size > &a)
computes the average of all elements
cpu::simd::Pack< T > max(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
cpu::simd::Pack< T > pow(cpu::simd::Pack< T > base, cpu::simd::Pack< T > exp)
bool nearZero(const ADf< T, DIM > &a)
ADf< T, DIM > exp(const ADf< T, DIM > &a)
Top level namespace for all of OpenLB.
std::enable_if_t< std::is_arithmetic< T >::type::value, T > abs(T x)
constexpr T norm(const ScalarVector< T, D, IMPL > &a)
Euclidean vector norm.
constexpr Vector< T, D > normalize(const ScalarVector< T, D, IMPL > &a, T scale=T{1})
constexpr unsigned getContactMaterial() const
constexpr T getEnlargementForContact() const
IndicatorF< T, D > * getIndicator()
An object holding data for a contact which is described analog to Nassauer and Kuna (2013)
constexpr const std::array< std::size_t, 2 > & getIDs() const
Read access to particle IDs.
constexpr void updateMinMax(const PhysR< T, D > &positionInsideTheContact)
Update min and max with given position inside the contact.
constexpr const PhysR< T, D > & getMax() const
Read access to max.
constexpr bool isEmpty() const
Returns if contact holds data.
constexpr const PhysR< T, D > & getMin() const
Read access to min.
constexpr void resetMinMax()
Reset min and max to default values.
constexpr const std::size_t & getParticleID() const
Read access to particle ID.
constexpr const PhysR< T, D > & getMin() const
Read access to min.
constexpr void resetMinMax()
Reset min and max to default values.
constexpr unsigned getWallID() const
Read access to wall matreial.
constexpr bool isEmpty() const
Returns if contact holds data.
constexpr const PhysR< T, D > & getMax() const
Read access to max.
constexpr void increaseMinMax(const Vector< T, D > &increaseBy)
Increase bounding box size.
constexpr void updateMinMax(const PhysR< T, D > &positionInsideTheContact)
Update min and max with given position inside the contact.
static void apply(XParticleSystem< T, PARTICLETYPE > &particleSystem, ContactContainer< T, ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX >, WALLCONTACTTYPE > &contactContainer, const CONTACTPROPERTIES &contactProperties, const SuperGeometry< T, PARTICLETYPE::d > &sGeometry, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, const unsigned contactBoxResolutionPerDirection=8, const T k=T {4./(3 *util::sqrt(M_PI))}, F1 getSetupPeriodicity=defaults::periodicity< PARTICLETYPE::d >, F2 processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
static void correctBoundingBoxExistingContact(XParticleSystem< T, PARTICLETYPE > &particleSystem, ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, T physDeltaX, unsigned contactBoxResolutionPerDirection)
static void correctBoundingBoxNewContact(XParticleSystem< T, PARTICLETYPE > &particleSystem, ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, const T physDeltaX, const unsigned contactBoxResolutionPerDirection)
static void correctBoundingBox(XParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, const T physDeltaX, const unsigned contactBoxResolutionPerDirection)
static void apply(std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, XParticleSystem< T, PARTICLETYPE > &particleSystem, ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, const CONTACTPROPERTIES &contactProperties, const T physDeltaX, const unsigned contactBoxResolutionPerDirection, const T k, F processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
static void resetContainer(ContactContainer< T, ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX >, WALLCONTACTTYPE > &contactContainer)
static void processCell(ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, Particle< T, PARTICLETYPE > &particleA, Particle< T, PARTICLETYPE > &particleB, Vector< T, PARTICLETYPE::d > &contactNormal, Vector< T, PARTICLETYPE::d > ¢er, unsigned &volumeCellCount, T &surfaceCellCount, const Vector< T, PARTICLETYPE::d > &pos, const Vector< T, PARTICLETYPE::d > &contactPhysDeltaX)
static void correctBoundingBoxExistingContact(XParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, const T physDeltaX, const unsigned contactBoxResolutionPerDirection)
static void resetContainer(ContactContainer< T, PARTICLECONTACTTYPE, WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > > &contactContainer)
static void processCell(WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, Particle< T, PARTICLETYPE > &particle, SolidBoundary< T, PARTICLETYPE::d > &solidBoundary, Vector< T, PARTICLETYPE::d > &contactNormal, Vector< T, PARTICLETYPE::d > ¢er, unsigned &volumeCellCount, T &surfaceCellCount, const Vector< T, PARTICLETYPE::d > &pos, const Vector< T, PARTICLETYPE::d > &contactPhysDeltaX)
static void correctBoundingBox(XParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, const T physDeltaX, const unsigned contactBoxResolutionPerDirection)
static void apply(std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, XParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, const CONTACTPROPERTIES &contactProperties, const T physDeltaX, const unsigned contactBoxResolutionPerDirection, const T k, F processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
static void apply(XParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, ContactContainer< T, PARTICLECONTACTTYPE, WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > > &contactContainer, const CONTACTPROPERTIES &contactProperties, const SuperGeometry< T, PARTICLETYPE::d > &sGeometry, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, const unsigned contactBoxResolutionPerDirection=8, const T k=T {4./(3 *util::sqrt(M_PI))}, F1 getSetupPeriodicity=defaults::periodicity< PARTICLETYPE::d >, F2 processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
static void correctBoundingBoxNewContact(XParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, const T physDeltaX, const unsigned contactBoxResolutionPerDirection)
Converts dimensions by deriving from given cartesian dimension D.
efficient implementation of a vector class