104 dictionary fvSourceSubDict =
allOptions.subDict(
"fvSource");
106 word diskName0 = fvSourceSubDict.toc()[0];
107 word source0 = fvSourceSubDict.subDict(diskName0).getWord(
"source");
109 if (source0 ==
"cylinderAnnulusToCell")
120 dictionary diskSubDict = fvSourceSubDict.subDict(diskName);
125 diskSubDict.readEntry<scalarList>(
"p1", point1);
126 diskSubDict.readEntry<scalarList>(
"p2", point2);
127 vector p1 = {point1[0], point1[1], point1[2]};
128 vector p2 = {point2[0], point2[1], point2[2]};
129 vector diskCenter = (p1 + p2) / 2.0;
130 vector diskDir = p2 - p1;
131 vector diskDirNorm = diskDir / mag(diskDir);
132 scalar outerRadius = diskSubDict.getScalar(
"outerRadius");
133 scalar innerRadius = diskSubDict.getScalar(
"innerRadius");
134 word rotDir = diskSubDict.getWord(
"rotDir");
135 scalar scale = diskSubDict.getScalar(
"scale");
136 scalar POD = diskSubDict.getScalar(
"POD");
139 scalar thrustSourceSum = 0.0;
140 scalar torqueSourceSum = 0.0;
147 vector cellC =
mesh_.C()[cellI];
149 vector cellC2AVec = cellC - diskCenter;
151 tensor cellC2AVecE(tensor::zero);
152 cellC2AVecE.xx() = cellC2AVec.x();
153 cellC2AVecE.yy() = cellC2AVec.y();
154 cellC2AVecE.zz() = cellC2AVec.z();
158 vector cellC2AVecA = cellC2AVecE & diskDirNorm;
160 vector cellC2AVecR = cellC2AVec - cellC2AVecA;
164 vector cellC2AVecC(vector::zero);
165 if (rotDir ==
"left")
168 cellC2AVecC = cellC2AVecR ^ diskDirNorm;
170 else if (rotDir ==
"right")
173 cellC2AVecC = diskDirNorm ^ cellC2AVecR;
177 FatalErrorIn(
" ") <<
"rotDir not valid" << abort(FatalError);
181 scalar cellC2AVecRLen = mag(cellC2AVecR);
183 scalar cellC2AVecCLen = mag(cellC2AVecC);
185 vector cellC2AVecCNorm = cellC2AVecC / cellC2AVecCLen;
188 scalar rPrime = cellC2AVecRLen / outerRadius;
189 scalar rPrimeHub = innerRadius / outerRadius;
191 scalar rStar = (rPrime - rPrimeHub) / (1.0 - rPrimeHub);
194 scalar fAxial = rStar * sqrt(1.0 - rStar) * scale;
196 scalar fCirc = fAxial * POD / constant::mathematical::pi / rPrime;
197 vector sourceVec = (fAxial * diskDirNorm + fCirc * cellC2AVecCNorm);
200 thrustSourceSum += fAxial *
mesh_.V()[cellI];
201 torqueSourceSum += fCirc *
mesh_.V()[cellI];
204 reduce(thrustSourceSum, sumOp<scalar>());
205 reduce(torqueSourceSum, sumOp<scalar>());
211 Info <<
"ThrustCoeff Source Term for " << diskName <<
": " << thrustSourceSum << endl;
212 Info <<
"TorqueCoeff Source Term for " << diskName <<
": " << torqueSourceSum << endl;
217 else if (source0 ==
"cylinderAnnulusSmooth")
220 forAll(fvSourceSubDict.toc(), idxI)
222 word diskName = fvSourceSubDict.toc()[idxI];
223 dictionary diskSubDict = fvSourceSubDict.subDict(diskName);
225 scalarList direction;
226 diskSubDict.readEntry<scalarList>(
"direction", direction);
227 vector dirNorm = {direction[0], direction[1], direction[2]};
228 dirNorm = dirNorm / mag(dirNorm);
233 word rotDir = diskSubDict.getWord(
"rotDir");
237 scalar eps = diskSubDict.getScalar(
"eps");
244 scalar epsRStar = eps / (outerRadius - innerRadius);
245 scalar rStarMin = epsRStar;
246 scalar rStarMax = 1.0 - epsRStar;
247 scalar fRMin = pow(rStarMin, expM) * pow(1.0 - rStarMin, expN);
248 scalar fRMax = pow(rStarMax, expM) * pow(1.0 - rStarMax, expN);
250 label adjustThrust = diskSubDict.getLabel(
"adjustThrust");
258 scalar tmpThrustSumAll = 0.0;
262 vector cellC =
mesh_.C()[cellI];
264 vector cellC2AVec = cellC - center;
266 tensor cellC2AVecE(tensor::zero);
267 cellC2AVecE.xx() = cellC2AVec.x();
268 cellC2AVecE.yy() = cellC2AVec.y();
269 cellC2AVecE.zz() = cellC2AVec.z();
273 vector cellC2AVecA = cellC2AVecE & dirNorm;
275 vector cellC2AVecR = cellC2AVec - cellC2AVecA;
278 scalar cellC2AVecRLen = mag(cellC2AVecR);
280 scalar cellC2AVecALen = mag(cellC2AVecA);
283 scalar rPrime = cellC2AVecRLen / outerRadius;
284 scalar rPrimeHub = innerRadius / outerRadius;
286 scalar rStar = (rPrime - rPrimeHub) / (1.0 - rPrimeHub);
290 scalar dA2 = cellC2AVecALen * cellC2AVecALen;
292 if (rStar < rStarMin)
294 scalar dR2 = (rStar - rStarMin) * (rStar - rStarMin);
295 scalar fR = fRMin * exp(-dR2 / epsRStar / epsRStar) * scale;
296 fAxial = fR * exp(-dA2 / eps / eps);
298 else if (rStar >= rStarMin && rStar <= rStarMax)
300 scalar fR = pow(rStar, expM) * pow(1.0 - rStar, expN) * scale;
301 fAxial = fR * exp(-dA2 / eps / eps);
305 scalar dR2 = (rStar - rStarMax) * (rStar - rStarMax);
306 scalar fR = fRMax * exp(-dR2 / epsRStar / epsRStar) * scale;
307 fAxial = fR * exp(-dA2 / eps / eps);
310 tmpThrustSumAll += fAxial *
mesh_.V()[cellI];
312 reduce(tmpThrustSumAll, sumOp<scalar>());
314 scale = targetThrust / tmpThrustSumAll;
322 scalar thrustSourceSum = 0.0;
323 scalar torqueSourceSum = 0.0;
327 vector cellC =
mesh_.C()[cellI];
329 vector cellC2AVec = cellC - center;
331 tensor cellC2AVecE(tensor::zero);
332 cellC2AVecE.xx() = cellC2AVec.x();
333 cellC2AVecE.yy() = cellC2AVec.y();
334 cellC2AVecE.zz() = cellC2AVec.z();
338 vector cellC2AVecA = cellC2AVecE & dirNorm;
340 vector cellC2AVecR = cellC2AVec - cellC2AVecA;
344 vector cellC2AVecC(vector::zero);
345 if (rotDir ==
"left")
348 cellC2AVecC = cellC2AVecR ^ dirNorm;
350 else if (rotDir ==
"right")
353 cellC2AVecC = dirNorm ^ cellC2AVecR;
357 FatalErrorIn(
" ") <<
"rotDir not valid" << abort(FatalError);
361 scalar cellC2AVecRLen = mag(cellC2AVecR);
363 scalar cellC2AVecCLen = mag(cellC2AVecC);
365 scalar cellC2AVecALen = mag(cellC2AVecA);
367 vector cellC2AVecCNorm = cellC2AVecC / cellC2AVecCLen;
370 scalar rPrime = cellC2AVecRLen / outerRadius;
371 scalar rPrimeHub = innerRadius / outerRadius;
373 scalar rStar = (rPrime - rPrimeHub) / (1.0 - rPrimeHub);
376 scalar dA2 = cellC2AVecALen * cellC2AVecALen;
378 if (rStar < rStarMin)
380 scalar dR2 = (rStar - rStarMin) * (rStar - rStarMin);
381 scalar fR = fRMin * exp(-dR2 / epsRStar / epsRStar) * scale;
382 fAxial = fR * exp(-dA2 / eps / eps);
384 else if (rStar >= rStarMin && rStar <= rStarMax)
386 scalar fR = pow(rStar, expM) * pow(1.0 - rStar, expN) * scale;
387 fAxial = fR * exp(-dA2 / eps / eps);
391 scalar dR2 = (rStar - rStarMax) * (rStar - rStarMax);
392 scalar fR = fRMax * exp(-dR2 / epsRStar / epsRStar) * scale;
393 fAxial = fR * exp(-dA2 / eps / eps);
398 scalar fCirc = fAxial * POD / constant::mathematical::pi / (rPrime + 0.01 * eps / outerRadius);
400 vector sourceVec = (fAxial * dirNorm + fCirc * cellC2AVecCNorm);
403 thrustSourceSum += fAxial *
mesh_.V()[cellI];
404 torqueSourceSum += fCirc *
mesh_.V()[cellI];
407 reduce(thrustSourceSum, sumOp<scalar>());
408 reduce(torqueSourceSum, sumOp<scalar>());
414 Info <<
"ThrustCoeff Source Term for " << diskName <<
": " << thrustSourceSum << endl;
415 Info <<
"TorqueCoeff Source Term for " << diskName <<
": " << torqueSourceSum << endl;
418 Info <<
"Dynamically adjusted scale for " << diskName <<
": " << scale << endl;
422 Info <<
"adjustThrust for " << diskName <<
": " << adjustThrust << endl;
423 Info <<
"center for " << diskName <<
": " << center << endl;
424 Info <<
"innerRadius for " << diskName <<
": " << innerRadius << endl;
425 Info <<
"outerRadius for " << diskName <<
": " << outerRadius << endl;
426 Info <<
"scale for " << diskName <<
": " << scale << endl;
427 Info <<
"POD for " << diskName <<
": " << POD << endl;
428 Info <<
"eps for " << diskName <<
": " << eps << endl;
429 Info <<
"expM for " << diskName <<
": " << expM << endl;
430 Info <<
"expN for " << diskName <<
": " << expN << endl;
431 Info <<
"epsRStar for " << diskName <<
": " << epsRStar << endl;
432 Info <<
"rStarMin for " << diskName <<
": " << rStarMin << endl;
433 Info <<
"rStarMax for " << diskName <<
": " << rStarMax << endl;
441 FatalErrorIn(
"calcFvSourceCells") <<
"source: " << source0 <<
" not supported!"
442 <<
"Options are: cylinderAnnulusToCell and cylinderAnnulusSmooth!"
443 << abort(FatalError);
446 fvSource.correctBoundaryConditions();
503 dictionary fvSourceSubDict =
allOptions.subDict(
"fvSource");
505 if (fvSourceSubDict.toc().size() == 0)
507 FatalErrorIn(
"calcSourceCells") <<
"actuatorDisk is selected as fvSource "
508 <<
" but the options are empty!"
509 << abort(FatalError);
512 forAll(fvSourceSubDict.toc(), idxI)
514 word diskName = fvSourceSubDict.toc()[idxI];
516 fvSourceCellIndices.set(diskName, {});
518 dictionary diskSubDict = fvSourceSubDict.subDict(diskName);
519 word sourceType = diskSubDict.getWord(
"source");
522 if (sourceType ==
"cylinderAnnulusToCell")
525 autoPtr<topoSet> currentSet(
537 diskSubDict.readEntry<scalarList>(
"p1", point1);
538 diskSubDict.readEntry<scalarList>(
"p2", point2);
549 scalar outerRadius = diskSubDict.getScalar(
"outerRadius");
550 scalar innerRadius = diskSubDict.getScalar(
"innerRadius");
553 tmpDict.set(
"p1", p1);
554 tmpDict.set(
"p2", p2);
555 tmpDict.set(
"innerRadius", innerRadius);
556 tmpDict.set(
"outerRadius", outerRadius);
559 autoPtr<topoSetSource> sourceSet(
560 topoSetSource::New(sourceType,
mesh_, tmpDict));
563 sourceSet().applyToSet(topoSetSource::NEW, currentSet());
566 for (
const label i : currentSet())
568 fvSourceCellIndices[diskName].append(i);
571 else if (sourceType ==
"cylinderAnnulusSmooth")
579 FatalErrorIn(
"calcFvSourceCells") <<
"source: " << sourceType <<
" not supported!"
580 <<
"Options are: cylinderAnnulusToCell and cylinderAnnulusSmooth!"
581 << abort(FatalError);
587 Info <<
"fvSourceCellIndices " << fvSourceCellIndices << endl;