100 dictionary fvSourceSubDict =
allOptions.subDict(
"fvSource");
102 forAll(fvSourceSubDict.toc(), idxI)
104 word diskName = fvSourceSubDict.toc()[idxI];
105 dictionary diskSubDict = fvSourceSubDict.subDict(diskName);
106 word
source = diskSubDict.getWord(
"source");
108 if (
source ==
"cylinderAnnulusToCell")
115 diskSubDict.readEntry<scalarList>(
"p1", point1);
116 diskSubDict.readEntry<scalarList>(
"p2", point2);
117 vector
p1 = {point1[0], point1[1], point1[2]};
118 vector
p2 = {point2[0], point2[1], point2[2]};
119 vector diskCenter = (
p1 +
p2) / 2.0;
120 vector diskDir =
p2 -
p1;
121 vector diskDirNorm = diskDir / mag(diskDir);
122 scalar outerRadius = diskSubDict.getScalar(
"outerRadius");
123 scalar innerRadius = diskSubDict.getScalar(
"innerRadius");
124 word rotDir = diskSubDict.getWord(
"rotDir");
125 scalar scale = diskSubDict.getScalar(
"scale");
126 scalar POD = diskSubDict.getScalar(
"POD");
129 scalar thrustSourceSum = 0.0;
130 scalar torqueSourceSum = 0.0;
137 vector cellC =
mesh_.C()[cellI];
139 vector cellC2AVec = cellC - diskCenter;
141 tensor cellC2AVecE(tensor::zero);
142 cellC2AVecE.xx() = cellC2AVec.x();
143 cellC2AVecE.yy() = cellC2AVec.y();
144 cellC2AVecE.zz() = cellC2AVec.z();
148 vector cellC2AVecA = cellC2AVecE & diskDirNorm;
150 vector cellC2AVecR = cellC2AVec - cellC2AVecA;
154 vector cellC2AVecC(vector::zero);
155 if (rotDir ==
"left")
158 cellC2AVecC = cellC2AVecR ^ diskDirNorm;
160 else if (rotDir ==
"right")
163 cellC2AVecC = diskDirNorm ^ cellC2AVecR;
167 FatalErrorIn(
" ") <<
"rotDir not valid" << abort(FatalError);
171 scalar cellC2AVecRLen = mag(cellC2AVecR);
173 scalar cellC2AVecCLen = mag(cellC2AVecC);
175 vector cellC2AVecCNorm = cellC2AVecC / cellC2AVecCLen;
178 scalar rPrime = cellC2AVecRLen / outerRadius;
179 scalar rPrimeHub = innerRadius / outerRadius;
181 scalar rStar = (rPrime - rPrimeHub) / (1.0 - rPrimeHub);
184 scalar fAxial = rStar * sqrt(1.0 - rStar) * scale;
186 scalar fCirc = fAxial * POD / constant::mathematical::pi / rPrime;
187 vector sourceVec = (fAxial * diskDirNorm + fCirc * cellC2AVecCNorm);
190 thrustSourceSum += fAxial *
mesh_.V()[cellI];
191 torqueSourceSum += fCirc *
mesh_.V()[cellI];
194 reduce(thrustSourceSum, sumOp<scalar>());
195 reduce(torqueSourceSum, sumOp<scalar>());
200 Info <<
"ThrustCoeff Source Term for " << diskName <<
": " << thrustSourceSum << endl;
201 Info <<
"TorqueCoeff Source Term for " << diskName <<
": " << torqueSourceSum << endl;
205 else if (
source ==
"cylinderAnnulusSmooth")
211 vector center = {actuatorDiskPars[diskName][0], actuatorDiskPars[diskName][1], actuatorDiskPars[diskName][2]};
212 vector dirNorm = {actuatorDiskPars[diskName][3], actuatorDiskPars[diskName][4], actuatorDiskPars[diskName][5]};
213 dirNorm = dirNorm / mag(dirNorm);
214 scalar innerRadius = actuatorDiskPars[diskName][6];
215 scalar outerRadius = actuatorDiskPars[diskName][7];
216 word rotDir = diskSubDict.getWord(
"rotDir");
219 scalar POD = actuatorDiskPars[diskName][9];
220 scalar eps = diskSubDict.getScalar(
"eps");
221 scalar expM = actuatorDiskPars[diskName][10];
222 scalar expN = actuatorDiskPars[diskName][11];
227 scalar epsRStar = eps / (outerRadius - innerRadius);
228 scalar rStarMin = epsRStar;
229 scalar rStarMax = 1.0 - epsRStar;
230 scalar fRMin = pow(rStarMin, expM) * pow(1.0 - rStarMin, expN);
231 scalar fRMax = pow(rStarMax, expM) * pow(1.0 - rStarMax, expN);
233 label adjustThrust = diskSubDict.getLabel(
"adjustThrust");
241 scalar tmpThrustSumAll = 0.0;
245 vector cellC =
mesh_.C()[cellI];
247 vector cellC2AVec = cellC - center;
249 tensor cellC2AVecE(tensor::zero);
250 cellC2AVecE.xx() = cellC2AVec.x();
251 cellC2AVecE.yy() = cellC2AVec.y();
252 cellC2AVecE.zz() = cellC2AVec.z();
256 vector cellC2AVecA = cellC2AVecE & dirNorm;
258 vector cellC2AVecR = cellC2AVec - cellC2AVecA;
261 scalar cellC2AVecRLen = mag(cellC2AVecR);
263 scalar cellC2AVecALen = mag(cellC2AVecA);
266 scalar rPrime = cellC2AVecRLen / outerRadius;
267 scalar rPrimeHub = innerRadius / outerRadius;
269 scalar rStar = (rPrime - rPrimeHub) / (1.0 - rPrimeHub);
273 scalar dA2 = cellC2AVecALen * cellC2AVecALen;
275 if (rStar < rStarMin)
277 scalar dR2 = (rStar - rStarMin) * (rStar - rStarMin);
278 scalar fR = fRMin * exp(-dR2 / epsRStar / epsRStar) * scale;
279 fAxial = fR * exp(-dA2 / eps / eps);
281 else if (rStar >= rStarMin && rStar <= rStarMax)
283 scalar fR = pow(rStar, expM) * pow(1.0 - rStar, expN) * scale;
284 fAxial = fR * exp(-dA2 / eps / eps);
288 scalar dR2 = (rStar - rStarMax) * (rStar - rStarMax);
289 scalar fR = fRMax * exp(-dR2 / epsRStar / epsRStar) * scale;
290 fAxial = fR * exp(-dA2 / eps / eps);
293 tmpThrustSumAll += fAxial *
mesh_.V()[cellI];
295 reduce(tmpThrustSumAll, sumOp<scalar>());
296 scalar targetThrust = actuatorDiskPars[diskName][12];
297 scale = targetThrust / tmpThrustSumAll;
301 scale = actuatorDiskPars[diskName][8];
305 scalar thrustSourceSum = 0.0;
306 scalar torqueSourceSum = 0.0;
310 vector cellC =
mesh_.C()[cellI];
312 vector cellC2AVec = cellC - center;
314 tensor cellC2AVecE(tensor::zero);
315 cellC2AVecE.xx() = cellC2AVec.x();
316 cellC2AVecE.yy() = cellC2AVec.y();
317 cellC2AVecE.zz() = cellC2AVec.z();
321 vector cellC2AVecA = cellC2AVecE & dirNorm;
323 vector cellC2AVecR = cellC2AVec - cellC2AVecA;
327 vector cellC2AVecC(vector::zero);
328 if (rotDir ==
"left")
331 cellC2AVecC = cellC2AVecR ^ dirNorm;
333 else if (rotDir ==
"right")
336 cellC2AVecC = dirNorm ^ cellC2AVecR;
340 FatalErrorIn(
" ") <<
"rotDir not valid" << abort(FatalError);
344 scalar cellC2AVecRLen = mag(cellC2AVecR);
346 scalar cellC2AVecCLen = mag(cellC2AVecC);
348 scalar cellC2AVecALen = mag(cellC2AVecA);
350 vector cellC2AVecCNorm = cellC2AVecC / cellC2AVecCLen;
353 scalar rPrime = cellC2AVecRLen / outerRadius;
354 scalar rPrimeHub = innerRadius / outerRadius;
356 scalar rStar = (rPrime - rPrimeHub) / (1.0 - rPrimeHub);
359 scalar dA2 = cellC2AVecALen * cellC2AVecALen;
361 if (rStar < rStarMin)
363 scalar dR2 = (rStar - rStarMin) * (rStar - rStarMin);
364 scalar fR = fRMin * exp(-dR2 / epsRStar / epsRStar) * scale;
365 fAxial = fR * exp(-dA2 / eps / eps);
367 else if (rStar >= rStarMin && rStar <= rStarMax)
369 scalar fR = pow(rStar, expM) * pow(1.0 - rStar, expN) * scale;
370 fAxial = fR * exp(-dA2 / eps / eps);
374 scalar dR2 = (rStar - rStarMax) * (rStar - rStarMax);
375 scalar fR = fRMax * exp(-dR2 / epsRStar / epsRStar) * scale;
376 fAxial = fR * exp(-dA2 / eps / eps);
381 scalar fCirc = fAxial * POD / constant::mathematical::pi / (rPrime + 0.01 * eps / outerRadius);
383 vector sourceVec = (fAxial * dirNorm + fCirc * cellC2AVecCNorm);
386 thrustSourceSum += fAxial *
mesh_.V()[cellI];
387 torqueSourceSum += fCirc *
mesh_.V()[cellI];
390 reduce(thrustSourceSum, sumOp<scalar>());
391 reduce(torqueSourceSum, sumOp<scalar>());
396 Info <<
"ThrustCoeff Source Term for " << diskName <<
": " << thrustSourceSum << endl;
397 Info <<
"TorqueCoeff Source Term for " << diskName <<
": " << torqueSourceSum << endl;
400 Info <<
"Dynamically adjusted scale for " << diskName <<
": " << scale << endl;
404 Info <<
"adjustThrust for " << diskName <<
": " << adjustThrust << endl;
405 Info <<
"center for " << diskName <<
": " << center << endl;
406 Info <<
"innerRadius for " << diskName <<
": " << innerRadius << endl;
407 Info <<
"outerRadius for " << diskName <<
": " << outerRadius << endl;
408 Info <<
"scale for " << diskName <<
": " << scale << endl;
409 Info <<
"POD for " << diskName <<
": " << POD << endl;
410 Info <<
"eps for " << diskName <<
": " << eps << endl;
411 Info <<
"expM for " << diskName <<
": " << expM << endl;
412 Info <<
"expN for " << diskName <<
": " << expN << endl;
413 Info <<
"epsRStar for " << diskName <<
": " << epsRStar << endl;
414 Info <<
"rStarMin for " << diskName <<
": " << rStarMin << endl;
415 Info <<
"rStarMax for " << diskName <<
": " << rStarMax << endl;
422 FatalErrorIn(
"calcFvSourceCells") <<
"source: " <<
source <<
" not supported!"
423 <<
"Options are: cylinderAnnulusToCell and cylinderAnnulusSmooth!"
424 << abort(FatalError);
428 fvSource.correctBoundaryConditions();
442 forAll(fvSourceSubDict.toc(), idxI)
444 word diskName = fvSourceSubDict.toc()[idxI];
446 dictionary diskSubDict = fvSourceSubDict.subDict(diskName);
447 word type = diskSubDict.getWord(
"type");
448 word
source = diskSubDict.getWord(
"source");
450 if (type ==
"actuatorDisk" &&
source ==
"cylinderAnnulusSmooth")
454 scalarList centerList;
455 diskSubDict.readEntry<scalarList>(
"center", centerList);
458 diskSubDict.readEntry<scalarList>(
"direction", dirList);
461 scalarList dvList(13);
462 dvList[0] = centerList[0];
463 dvList[1] = centerList[1];
464 dvList[2] = centerList[2];
465 dvList[3] = dirList[0];
466 dvList[4] = dirList[1];
467 dvList[5] = dirList[2];
468 dvList[6] = diskSubDict.getScalar(
"innerRadius");
469 dvList[7] = diskSubDict.getScalar(
"outerRadius");
470 dvList[8] = diskSubDict.getScalar(
"scale");
471 dvList[9] = diskSubDict.getScalar(
"POD");
472 dvList[10] = diskSubDict.getScalar(
"expM");
473 dvList[11] = diskSubDict.getScalar(
"expN");
474 dvList[12] = diskSubDict.getScalar(
"targetThrust");
538 dictionary fvSourceSubDict =
allOptions.subDict(
"fvSource");
540 if (fvSourceSubDict.toc().size() == 0)
542 FatalErrorIn(
"calcSourceCells") <<
"actuatorDisk is selected as fvSource "
543 <<
" but the options are empty!"
544 << abort(FatalError);
547 forAll(fvSourceSubDict.toc(), idxI)
549 word diskName = fvSourceSubDict.toc()[idxI];
551 fvSourceCellIndices.set(diskName, {});
553 dictionary diskSubDict = fvSourceSubDict.subDict(diskName);
554 word sourceType = diskSubDict.getWord(
"source");
557 if (sourceType ==
"cylinderAnnulusToCell")
560 autoPtr<topoSet> currentSet(
572 diskSubDict.readEntry<scalarList>(
"p1", point1);
573 diskSubDict.readEntry<scalarList>(
"p2", point2);
584 scalar outerRadius = diskSubDict.getScalar(
"outerRadius");
585 scalar innerRadius = diskSubDict.getScalar(
"innerRadius");
588 tmpDict.set(
"p1",
p1);
589 tmpDict.set(
"p2",
p2);
590 tmpDict.set(
"innerRadius", innerRadius);
591 tmpDict.set(
"outerRadius", outerRadius);
594 autoPtr<topoSetSource> sourceSet(
595 topoSetSource::New(sourceType,
mesh_, tmpDict));
598 sourceSet().applyToSet(topoSetSource::NEW, currentSet());
601 for (
const label i : currentSet())
603 fvSourceCellIndices[diskName].append(i);
606 else if (sourceType ==
"cylinderAnnulusSmooth")
614 FatalErrorIn(
"calcFvSourceCells") <<
"source: " << sourceType <<
" not supported!"
615 <<
"Options are: cylinderAnnulusToCell and cylinderAnnulusSmooth!"
616 << abort(FatalError);
622 Info <<
"fvSourceCellIndices " << fvSourceCellIndices << endl;