1081 {
1082 TRACE();
1083
1086
1088
1089
1091
1092
1095 }
1096
1097
1098
1099
1100
1101
1102 const MFloat breakupLength =
1104
1105
1106
1107
1108
1109
1110
1112 ASSERT(breakupLength > -MFloatEps, "ERROR: Invalid breakup length.");
1113
1114
1115 for(
MInt i = 0; i < noPart; i++) {
1116 auto& droplet =
s_backPtr->m_partList.at(i);
1117
1118 if(droplet.firstStep()) continue;
1119 if(droplet.isInvalid()) continue;
1120 if(droplet.fullyEvaporated()) continue;
1121 ASSERT(!isnan(droplet.m_diameter), "Invalid diameter! ");
1122 if(droplet.m_diameter <
s_backPtr->m_sizeLimit)
continue;
1123 if(droplet.hadWallColl()) continue;
1124
1125 ASSERT(droplet.m_cellId > 0, "ERROR: Invalid cellId");
1126
1127
1128 droplet.m_breakUpTime += dt;
1129
1130 ASSERT(!isnan(droplet.m_shedDiam) && droplet.m_shedDiam > -MFloatEps, "");
1131
1132
1133
1134
1135
1136
1137 MFloat liquidLength = MFloatMax;
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151 }
1152
1153 const MFloat dropRadius = 0.5 * droplet.m_diameter;
1154 const MFloat relV = droplet.magRelVel(&droplet.m_fluidVel[0], &droplet.m_velocity[0]);
1155
1156
1157 if(isnan(relV)) {
1158 cerr << droplet.m_fluidVel[0] << " " << droplet.m_fluidVel[1] << " " << droplet.m_fluidVel[nDim - 1] << endl;
1160 }
1161
1162
1163
1165 droplet.WeberNumber(
s_backPtr->m_material->density(droplet.m_temperature), pow(relV, 2), droplet.m_temperature)
1166 * droplet.s_We;
1167
1168
1170
1171
1172
1174 * droplet.particleRe(
material().density(droplet.m_temperature), relV,
1175 material().dynamicViscosity(droplet.m_temperature))
1176 * droplet.s_Re;
1177
1178
1179 const MFloat We_g = droplet.WeberNumber(droplet.m_fluidDensity, pow(relV, 2), droplet.m_temperature) * droplet.s_We;
1180
1181 const MFloat Z = sqrt(We_l) / Re_l;
1182
1183 const MFloat T = Z * sqrt(We_g);
1184
1185
1186 const MFloat KH_waveL = 9.02 * dropRadius * (1.0 + 0.45 * sqrt(Z)) * (1.0 + 0.4 * pow(T, 0.7))
1187 / pow(1.0 + 0.865 * pow(We_g, 1.67), 0.6);
1188
1189
1190
1191 const MFloat KH_diameter = 2.0 *
m_B0 * KH_waveL;
1192
1193
1194
1195 if(KH_diameter < 2 * MFloatEps) {
1196 cerr << KH_diameter << " d_KH " << dropRadius << " " << Z << " " << T << " " << We_g << " " << We_l << endl;
1197 }
1198
1199
1200 const MFloat KH_growthR = ((0.34 + 0.38 * pow(We_g, 1.5)) / ((1.0 + Z) * (1.0 + 1.4 * pow(T, 0.6))))
1201 * sqrt(
material().spraySurfaceTension(droplet.m_temperature)
1202 / (
material().density(droplet.m_temperature) * pow(dropRadius, 3)))
1203 * sqrt(1 / droplet.s_We);
1204
1205
1206
1207 const MFloat KH_time = 3.726 *
m_B1 * dropRadius / (KH_waveL * KH_growthR);
1208
1209
1210
1211
1212
1213 const MFloat magVel = droplet.magVel();
1214 array<MFloat, nDim> parentTrajectory{};
1215
1216 for(
MInt v = 0; v < nDim; v++) {
1217 parentTrajectory.at(v) = droplet.m_velocity.at(v) / magVel;
1218 }
1219
1220
1221 if(magVel < MFloatEps) {
1222
1223 continue;
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236 }
1237
1238
1240 for(
MInt dir = 0; dir < nDim; dir++) {
1241 drop_accel +=
POW2(droplet.m_accel.at(dir));
1242 }
1243 drop_accel = sqrt(drop_accel);
1244
1245
1246 const MFloat oldMass = droplet.sphericalMass() * droplet.m_noParticles;
1247 vector<MFloat> oldMom(nDim);
1248 for(
MInt n = 0; n < nDim; n++) {
1249 oldMom[n] = oldMass * droplet.m_velocity[n];
1250 }
1251 const MFloat oldDiameter = droplet.m_diameter;
1252
1253
1254
1255
1256
1257
1258
1260 2.0 * PI
1261 * sqrt(3.0 *
material().spraySurfaceTension(droplet.m_temperature)
1262 / (drop_accel * (
material().density(droplet.m_temperature) - droplet.m_fluidDensity)))
1263 / sqrt(droplet.s_We);
1264
1265
1266 const MFloat RT_frequency =
1267 sqrt(2.0 / (3.0 * sqrt(3.0 *
material().spraySurfaceTension(droplet.m_temperature)))
1268 * pow(drop_accel * (
material().density(droplet.m_temperature) - droplet.m_fluidDensity), 3.0 / 2.0)
1269 / (
material().density(droplet.m_temperature) + droplet.m_fluidDensity))
1270 * pow(droplet.s_We, 1 / 4);
1271
1273
1274
1276
1277 ASSERT(RT_diameter > 0, "");
1278
1279
1280
1281
1282
1283 if(
m_RTsecBreakUp && liquidLength >= breakupLength && droplet.m_breakUpTime >= RT_time
1285
1286 MFloat childDiameter = RT_diameter;
1293 if(droplet.m_diameter < childDiameter) {
1294
1295 continue;
1296 }
1298 childDiameter = pow(oldDiameter, 2 / 3) * pow(RT_diameter, 1 / 3);
1299 }
1300
1302
1303 auto noDroplets =
static_cast<MInt>(droplet.m_noParticles *
POW3(oldDiameter / childDiameter));
1304
1305
1306
1307
1308 if(noDroplets > 0) {
1309 childDiameter = pow(6.0 / PI, 1.0 / 3.0)
1310 * pow(oldMass / (noDroplets *
material().density(droplet.m_temperature)), 1.0 / 3.0);
1311 droplet.m_diameter = childDiameter;
1312 droplet.m_shedDiam = childDiameter;
1313 droplet.m_noParticles = noDroplets;
1314 droplet.m_breakUpTime = 0.0;
1316
1317 const MFloat newMass =
sphericalMass(droplet.m_diameter, droplet.m_temperature) * droplet.m_noParticles;
1318 if(fabs(newMass - oldMass) > MFloatEps) {
1319 cerr << "Missing mass is RT-breakup " << oldMass << " " << newMass << endl;
1320 }
1321 }
1322
1323 } else {
1326 }
1327
1328
1329 const MFloat dropletVolume = pow(droplet.m_diameter, 3.0);
1330 const MFloat dropletRTVolume = pow(childDiameter, 3.0);
1331
1332 MInt noBrokenUpDroplets = dropletVolume / dropletRTVolume;
1333
1334
1335 if(noBrokenUpDroplets == 1) {
1336 continue;
1337 }
1338 noBrokenUpDroplets *= droplet.m_noParticles;
1339
1340
1341 auto dropsPerParcel =
static_cast<MInt>(
1343
1344
1345 MInt noNewParcels = noBrokenUpDroplets;
1346 if(dropsPerParcel > 1) {
1348 } else {
1349 --noNewParcels;
1350 }
1351
1353 const MFloat parentMass = oldMass - dropsPerParcel * RT_dropletMass * noNewParcels;
1354 const MFloat parentDiam =
1355 pow(6.0 / PI, 1.0 / 3.0)
1356 * pow(parentMass / (dropsPerParcel *
material().density(droplet.m_temperature)), 1.0 / 3.0);
1357
1358 ASSERT(parentMass > 0, "Invalid mass!");
1359 ASSERT(parentDiam > 0 && !isnan(parentDiam), "");
1360 ASSERT(dropsPerParcel > 0, "");
1361
1362
1363 droplet.m_diameter = parentDiam;
1364 droplet.m_shedDiam = parentDiam;
1365 droplet.m_noParticles = dropsPerParcel;
1366 droplet.m_breakUpTime = 0.0;
1368
1369#ifdef _OPENMP
1370#pragma omp critical
1371#endif
1373 cerr << "#################################################" << endl;
1374 cerr << "Break-Up type: RT" << endl;
1375 cerr << "parent diameter: " << droplet.m_diameter << endl;
1377 cerr << "old number of particles: " << droplet.m_noParticles << endl;
1378 cerr << "new particles/parcels: " << noNewParcels << endl;
1379 cerr << "parcel size: " << dropsPerParcel << endl;
1380 cerr << "Weber number: " << We_l << endl;
1381 cerr << "#################################################" << endl;
1382 }
1383
1386
1387
1388 static constexpr MFloat angularGapAngle = 45.0;
1390 }
1391
1392#ifdef LPT_DEBUG
1393 vector<MFloat> mom(nDim);
1394#endif
1395
1396
1397 array<MFloat, nDim> childVelocity{};
1398 for(
MInt s = 0; s < noNewParcels; s++) {
1401
1402 const MInt childId =
s_backPtr->addParticle(droplet.m_cellId, childDiameter, droplet.m_densityRatio, 0, 3,
1403 &childVelocity[0], &droplet.m_position[0], dropsPerParcel);
1404
1405
1406 s_backPtr->m_partList[childId].m_temperature = droplet.m_temperature;
1407 s_backPtr->m_partList[childId].m_heatFlux = 0.0;
1408 s_backPtr->m_partList[childId].m_dM = 0.0;
1409
1410
1411#ifdef LPT_DEBUG
1412
1414 for(
MInt n = 0; n < nDim; n++) {
1415 magVelChild +=
POW2(childVelocity[n]);
1416 }
1417 magVelChild = sqrt(magVelChild);
1418 if(fabs(magVel - magVelChild) > MFloatEps) {
1419 cerr << "RT kin. energy loss: " << magVel << " " << magVelChild << endl;
1420 }
1421 for(
MInt n = 0; n < nDim; n++) {
1422 mom[n] +=
sphericalMass(childDiameter, droplet.m_temperature) * dropsPerParcel * childVelocity[n];
1423 }
1424#endif
1425 }
1426
1427#ifdef LPT_DEBUG
1428
1429 for(
MInt n = 0; n < nDim; n++) {
1430 mom[n] +=
1431 droplet.m_velocity[n] *
sphericalMass(droplet.m_diameter, droplet.m_temperature) * droplet.m_noParticles;
1432
1433 if(fabs(oldMom[n] - mom[n]) > MFloatEps) {
1434 cerr << "RT momentum change: " << oldMom[n] << " " << mom[n] << endl;
1435 }
1436 }
1437
1438
1439 const MFloat newMass =
sphericalMass(droplet.m_diameter, droplet.m_temperature) * droplet.m_noParticles;
1441 for(
MInt n = 0; n < noNewParcels; n++) {
1445 }
1446 const MFloat massLoss_RT = oldMass - newMass - childMass;
1447 if(fabs(massLoss_RT) > MFloatEps) {
1448 cerr << "RT Mass loss! Old " << oldMass << " parent " << newMass << " childs " << childMass << " diff "
1449 << massLoss_RT << endl;
1450 }
1451#endif
1452 }
1453 continue;
1454 }
1455
1456
1457
1458
1461 if(KH_mass < MFloatEps) continue;
1462
1463
1464
1465
1466
1467 droplet.m_shedDiam -= (droplet.m_shedDiam - KH_diameter) / KH_time * dt;
1468
1469
1470
1471
1472 if(droplet.m_shedDiam < KH_diameter) {
1473 MInt noDroplets = floor(oldMass / KH_mass);
1474 if(noDroplets > 0) {
1475 const MFloat diameter = pow(6.0 / PI, 1.0 / 3.0)
1476 * pow(oldMass / (noDroplets *
material().density(droplet.m_temperature)), 1.0 / 3.0);
1477
1478
1479
1480 droplet.m_diameter = diameter;
1481 droplet.m_shedDiam = diameter;
1482 droplet.m_noParticles = noDroplets;
1484
1485 const MFloat newMass =
sphericalMass(droplet.m_diameter, droplet.m_temperature) * droplet.m_noParticles;
1486 if(fabs(newMass - oldMass) > MFloatEps) {
1487 cerr << "Missing mass at KH-breakup 1 is " << oldMass << " " << newMass << endl;
1488 }
1489 continue;
1490 }
1491 }
1492
1493
1494 const MFloat sheddedMass =
1495 oldMass -
sphericalMass(droplet.m_shedDiam, droplet.m_temperature) * droplet.m_noParticles;
1496
1498 continue;
1499 }
1500
1501 MInt noSheddedOffDrops = floor(sheddedMass / KH_mass);
1502 if(noSheddedOffDrops <= 0) continue;
1503 const MFloat parentMass = oldMass - KH_mass * noSheddedOffDrops;
1504 ASSERT(parentMass > 0, "");
1505
1506 const MFloat parentDiam =
1507 pow(6.0 / PI * parentMass / (droplet.m_noParticles *
material().density(droplet.m_temperature)), 1.0 / 3.0);
1508
1509
1510
1511
1512
1514
1515
1516 droplet.m_diameter = parentDiam;
1517 droplet.m_shedDiam = parentDiam;
1518
1519
1523 if(liquidLength < breakupLength) {
1525 }
1530 if(liquidLength < breakupLength) {
1532 } else {
1534 }
1535 }
1536
1537 if(angle < 0 || angle > 90) {
1538 cerr << "Large KH-spray angle : " << angle << endl;
1539 }
1540
1541 array<MFloat, nDim> childVelocity{};
1544
1545
1546 const MInt childId =
s_backPtr->addParticle(droplet.m_cellId, KH_diameter, droplet.m_densityRatio, 0, 3,
1547 &childVelocity[0], &droplet.m_position[0], noSheddedOffDrops);
1548
1549
1550 s_backPtr->m_partList[childId].m_temperature = droplet.m_temperature;
1551 s_backPtr->m_partList[childId].m_heatFlux = 0.0;
1552 s_backPtr->m_partList[childId].m_dM = 0.0;
1553
1554
1556
1557#ifdef _OPENMP
1558#pragma omp critical
1559#endif
1561 cerr << "#################################################" << endl;
1562 cerr << "Break-Up type: KH" << endl;
1563 cerr << "parent diameter: " << droplet.m_diameter << " " << parentDiam << endl;
1564 cerr << "KH size: " << KH_diameter << endl;
1565 cerr << "KH time: " << KH_time << endl;
1567 cerr << "old #droplets: " << droplet.m_noParticles << endl;
1568 cerr << "# new droplets: " << noSheddedOffDrops << endl;
1569 cerr << "Weber number: " << We_l << endl;
1570 cerr << "#################################################" << endl;
1571 }
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589#ifdef LPT_DEBUG
1590
1591 vector<MFloat> mom(nDim);
1592 for(
MInt n = 0; n < nDim; n++) {
1593 mom[n] =
1594 droplet.m_velocity[n] *
sphericalMass(droplet.m_diameter, droplet.m_temperature) * droplet.m_noParticles
1595 +
sphericalMass(KH_diameter, droplet.m_temperature) * noSheddedOffDrops * childVelocity[n];
1596 if(fabs(oldMom[n] - mom[n]) > MFloatEps) {
1597 cerr << "KH momentum change: " << oldMom[n] << " " << mom[n] << " "
1598 << droplet.m_velocity[n] *
sphericalMass(droplet.m_diameter, droplet.m_temperature)
1599 * droplet.m_noParticles
1600 << endl;
1601 }
1602 }
1603
1604
1606 for(
MInt n = 0; n < nDim; n++) {
1607 magVelChild +=
POW2(childVelocity[n]);
1608 }
1609 magVelChild = sqrt(magVelChild);
1610 if(fabs(magVel - magVelChild) > MFloatEps) {
1611 cerr << "KH kin. energy loss: " << magVel << " " << magVelChild << endl;
1612 }
1613 MFloat magVelNew = droplet.magVel();
1614 if(fabs(magVel - magVelNew) > MFloatEps) {
1615 cerr << "KH kin. energy loss: " << magVel << " " << magVelNew << endl;
1616 }
1617
1618 const MFloat newMass =
sphericalMass(droplet.m_diameter, droplet.m_temperature) * droplet.m_noParticles;
1622 *
s_backPtr->m_partList[childId].m_noParticles;
1623 const MFloat massLoss_KH = oldMass - newMass - childMass;
1624 if(fabs(massLoss_KH) > MFloatEps) {
1625 cerr << "KH Mass loss! Old " << oldMass << " parent " << newMass << " childs " << childMass << " diff "
1626 << massLoss_KH << endl;
1627 }
1628#endif
1629 }
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650 }
1651}
std::mt19937_64 & randomSecBreakUp()
MBool m_secBUDisplayMessage
MBool m_RTsecBreakUpLength
void initPRNG(const MInt seed, const MInt discard)
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
constexpr Real POW3(const Real x)
MFloat distance(const MFloat *a, const MFloat *b)