VirtualFluids 0.2.0
Parallel CFD LBM Solver
Loading...
Searching...
No Matches
ActuatorLineDisk.cpp
Go to the documentation of this file.
1//=======================================================================================
2// ____ ____ __ ______ __________ __ __ __ __
3// \ \ | | | | | _ \ |___ ___| | | | | / \ | |
4// \ \ | | | | | |_) | | | | | | | / \ | |
5// \ \ | | | | | _ / | | | | | | / /\ \ | |
6// \ \ | | | | | | \ \ | | | \__/ | / ____ \ | |____
7// \ \ | | |__| |__| \__\ |__| \________/ /__/ \__\ |_______|
8// \ \ | | ________________________________________________________________
9// \ \ | | | ______________________________________________________________|
10// \ \| | | | __ __ __ __ ______ _______
11// \ | | |_____ | | | | | | | | | _ \ / _____)
12// \ | | _____| | | | | | | | | | | \ \ \_______
13// \ | | | | |_____ | \_/ | | | | |_/ / _____ |
14// \ _____| |__| |________| \_______/ |__| |______/ (_______/
15//
16// This file is part of VirtualFluids. VirtualFluids is free software: you can
17// redistribute it and/or modify it under the terms of the GNU General Public
18// License as published by the Free Software Foundation, either version 3 of
19// the License, or (at your option) any later version.
20//
21// VirtualFluids is distributed in the hope that it will be useful, but WITHOUT
22// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24// for more details.
25//
26// SPDX-License-Identifier: GPL-3.0-or-later
27// SPDX-FileCopyrightText: Copyright © VirtualFluids Project contributors, see AUTHORS.md in root folder
28//
33//=======================================================================================
34
35#include <algorithm>
36#include <cmath>
37#include <optional>
38#include <sstream>
39#include <string>
40#include <vector>
41
42#include <basics/DataTypes.h>
45
46#include <logger/Logger.h>
47
50
61
62namespace
63{
64const std::string defaultConfigFile = "actuatorlinedisk.cfg";
65using namespace vf::basics::constant;
66using namespace vf::gpu;
67
68std::vector<real> parseNumberList(std::string text)
69{
70 for (char& ch : text) {
71 if (ch == ',')
72 ch = ' ';
73 }
74
75 std::stringstream stream(text);
76 std::vector<real> values;
77 real value = c0o1;
78 while (stream >> value)
79 values.push_back(value);
80
81 return values;
82}
83
84std::vector<std::vector<real>> parseNestedNumberLists(const std::string& text)
85{
86 std::vector<std::vector<real>> lists;
87
88 size_t start = text.find('[');
89 while (start != std::string::npos) {
90 const size_t end = text.find(']', start);
91 lists.push_back(parseNumberList(text.substr(start + 1, end - start - 1)));
92 start = text.find('[', end);
93 }
94
95 return lists;
96}
97
98void scaleNestedNumberLists(std::vector<std::vector<real>>& lists, const real factor)
99{
100 for (auto& list : lists) {
101 for (real& value : list)
102 value *= factor;
103 }
104}
105
106std::vector<real> computeBladeRadii(const real diameter, const uint numberOfPointsPerBlade)
107{
108 std::vector<real> bladeRadii(numberOfPointsPerBlade);
109 const real spacing = c1o2 * diameter / static_cast<real>(numberOfPointsPerBlade);
110
111 for (uint i = 0; i < numberOfPointsPerBlade; ++i)
112 bladeRadii[i] = spacing * (static_cast<real>(i) + c1o2);
113
114 return bladeRadii;
115}
116
118{
119 const real induction = c1o2 * (c1o1 - std::sqrt(c1o1 - thrustCoefficient));
120 return c4o1 * induction / (c1o1 - induction);
121}
122
124 const vf::basics::ConfigurationFile& config,
125 const std::string& key,
126 const std::string& fallbackKey)
127{
128 if (config.contains(key))
129 return config.getValue<real>(key);
130 return config.getValue<real>(fallbackKey);
131}
132
134 const vf::basics::ConfigurationFile& config)
135{
136 if (!config.contains("VELOCITY_BOUNDARY_CONDITION"))
137 return BoundaryConditionFactory::VelocityBC::VelocityInterpolatedCompressible;
138
139 const auto velocityBoundaryCondition = config.getValue<std::string>("VELOCITY_BOUNDARY_CONDITION");
140 if (velocityBoundaryCondition == "VelocityBounceBack")
141 return BoundaryConditionFactory::VelocityBC::VelocityBounceBack;
142 if (velocityBoundaryCondition == "VelocityInterpolatedIncompressible")
143 return BoundaryConditionFactory::VelocityBC::VelocityInterpolatedIncompressible;
144 if (velocityBoundaryCondition == "VelocityInterpolatedCompressible")
145 return BoundaryConditionFactory::VelocityBC::VelocityInterpolatedCompressible;
146 if (velocityBoundaryCondition == "VelocityWithPressureInterpolatedCompressible")
147 return BoundaryConditionFactory::VelocityBC::VelocityWithPressureInterpolatedCompressible;
148
149 throw std::runtime_error(
150 "VELOCITY_BOUNDARY_CONDITION must be one of: VelocityBounceBack, "
151 "VelocityInterpolatedIncompressible, VelocityInterpolatedCompressible, "
152 "VelocityWithPressureInterpolatedCompressible.");
153}
154
155real computeDiskHubRadius(const real diameter, const uint numberOfPointsPerBlade)
156{
157 return c1o4 * diameter / static_cast<real>(numberOfPointsPerBlade);
158}
159
160std::vector<real> computeDiskBladeAnnulusAreas(
161 const real diameter,
162 const uint numberOfBlades,
163 const uint numberOfPointsPerBlade)
164{
165 const auto bladeRadii = computeBladeRadii(diameter, numberOfPointsPerBlade);
166 std::vector<real> annulusAreas(numberOfPointsPerBlade);
167
168 const real pi = std::acos(-c1o1);
169 for (uint i = 0; i < numberOfPointsPerBlade; ++i) {
170 const real innerRadius = (i == 0)
171 ? computeDiskHubRadius(diameter, numberOfPointsPerBlade)
172 : c1o2 * (bladeRadii[i] + bladeRadii[i - 1]);
173 const real outerRadius = (i + 1 == numberOfPointsPerBlade)
174 ? c1o2 * diameter
175 : c1o2 * (bladeRadii[i] + bladeRadii[i + 1]);
177 static_cast<real>(numberOfBlades);
178 }
179
180 return annulusAreas;
181}
182
183std::vector<real> computeDiskBladeNormalCoefficients(
184 const real diameter,
185 const uint numberOfBlades,
186 const uint numberOfPointsPerBlade,
188{
189 const auto bladeRadii = computeBladeRadii(diameter, numberOfPointsPerBlade);
190 const auto annulusAreas = computeDiskBladeAnnulusAreas(diameter, numberOfBlades, numberOfPointsPerBlade);
192
193 std::vector<real> bladeNormalCoefficients(numberOfPointsPerBlade);
194 for (uint i = 0; i < numberOfPointsPerBlade; ++i) {
195 const real previousRadius = (i == 0) ? c0o1 : bladeRadii[i - 1];
196 const real nextRadius = (i + 1 == numberOfPointsPerBlade) ? c1o2 * diameter : bladeRadii[i + 1];
198 const real chordArgument = c1o1 - std::pow(c4o1 * bladeRadii[i] / diameter - c1o1, c2o1);
199 const real bladeChord = c2o1 * std::sqrt(std::max(chordArgument, c0o1));
200 bladeNormalCoefficients[i] = diskNormalCoefficient * annulusAreas[i] / (bladeChord * bladePointWidth);
201 }
202
203 return bladeNormalCoefficients;
204}
205
206struct DiskActuatorConfig
207{
208 ActuatorFarm::HubConfig hubConfig;
209 real hubDragCoefficient;
210 real hubSkinFrictionCoefficient;
211 std::vector<real> bladeNormalCoefficients;
212};
213
214DiskActuatorConfig buildDiskActuatorConfig(
215 const real diameter,
216 const uint numberOfBlades,
217 const uint numberOfPointsPerBlade,
219{
221 return {
222 ActuatorFarm::HubConfig { c0o1, computeDiskHubRadius(diameter, numberOfPointsPerBlade), c0o1, 1 },
224 c0o1,
225 computeDiskBladeNormalCoefficients(diameter, numberOfBlades, numberOfPointsPerBlade, thrustCoefficient)
226 };
227}
228
230{
231 return std::max(static_cast<uint>(1), static_cast<uint>(timeFlowThroughDomain * flowThroughCount / deltaT));
232}
233
234void run(const vf::basics::ConfigurationFile& config)
235{
236 const real viscosity = config.getValue<real>("VISCOSITY_KINEMATIC");
237 const uint numberOfBlades = config.getValue<uint>("NUMBER_BLADES");
238 const real diskDiameter = config.getValue<real>("DISK_DIAMETER");
239 const real velocityInlet = config.getValue<real>("VELOCITY_INLET");
240 const real thrustCoefficient = config.getValue<real>("THRUST_COEFFICIENT");
241 const uint numberOfCellsPerDiameter = config.getValue<uint>("NUMBER_CELLS_PER_DIAMETER");
242 const uint numberOfPointsPerBlade = config.getValue<uint>("NUMBER_ALM_NODES_PER_SPAN");
243 const real smearingWidthPerDx = config.getValue<real>("SMEARING_WIDTH_PER_DX");
244 auto positionDomain = parseNestedNumberLists(config.getValue<std::string>("POSITION_DOMAIN"));
245 auto positionDiskCenter = parseNestedNumberLists(config.getValue<std::string>("POSITION_DISK_CENTER"));
246 auto positionProbePlaneZ = parseNestedNumberLists(config.getValue<std::string>("POSITION_PROBE_PLANE_Z"));
247 const real quadricDelimiter = config.getValue<real>("QUADRIC_DELIMITER");
248 const real machNumber = config.getValue<real>("LBM_MACH_NUMBER");
249 const bool printFiles = config.getValue<bool>("FLAG_PRINT_FILES");
250 const real nStartWriteLoads = config.getValue<real>("N_START_WRITE_LOADS");
251 const real nStartWriteProbe = config.getValue<real>("N_START_WRITE_PROBE");
252 const real nStartWriteField = config.getValue<real>("N_START_WRITE_FIELD");
253 const real nStartProbeAveraging = config.getValue<real>("N_START_PROBE_AVERAGING");
254 const real nIntervallAveraging = config.getValue<real>("N_INTERVALL_AVERAGING");
255 const real nIntervallWriteLoad = config.getValue<real>("N_INTERVALL_WRITE_LOAD");
256 const real nIntervallWriteProbe = config.getValue<real>("N_INTERVALL_WRITE_PROBE");
258 getRealConfigValueWithFallback(config, "N_INTERVALL_WRITE_FIELD", "N_INTERVALL_WRTIE_FIELD");
259 const real nEnd = config.getValue<real>("N_END");
260
264
265 if (positionDomain.size() != 3 || positionDomain[0].size() != 2 || positionDomain[1].size() != 2 ||
266 positionDomain[2].size() != 2) {
267 throw std::runtime_error("POSITION_DOMAIN must be [x_min,x_max],[y_min,y_max],[z_min,z_max].");
268 }
269 if (positionDiskCenter.size() != 3 || positionDiskCenter[0].size() != 1 || positionDiskCenter[1].size() != 1 ||
270 positionDiskCenter[2].size() != 1) {
271 throw std::runtime_error("POSITION_DISK_CENTER must be [x],[y],[z].");
272 }
273
274 const real xcm = positionDomain[0][0];
275 const real xcp = positionDomain[0][1];
276 const real ycm = positionDomain[1][0];
277 const real ycp = positionDomain[1][1];
278 const real zcm = positionDomain[2][0];
279 const real zcp = positionDomain[2][1];
280
281 const real diskCenterX = positionDiskCenter[0][0];
282 const real diskCenterY = positionDiskCenter[1][0];
283 const real diskCenterZ = positionDiskCenter[2][0];
284
285 const real timeFlowThroughDomain = (xcp - xcm) / velocityInlet;
286 const real deltaX = diskDiameter / static_cast<real>(numberOfCellsPerDiameter);
287 const real deltaT = machNumber * deltaX / (std::sqrt(c3o1) * velocityInlet);
288 const real velocityRatio = deltaX / deltaT;
289 const real velocityLB = velocityInlet / velocityRatio;
290 const real viscosityLB = viscosity / (velocityRatio * deltaX);
291 const real smearingWidth = smearingWidthPerDx * deltaX;
292 const auto velocityBoundaryCondition = getVelocityBoundaryCondition(config);
293
302 const uint timeStepEnd = static_cast<uint>(timeFlowThroughDomain * nEnd / deltaT);
303
304 auto gridBuilder = std::make_shared<MultipleGridBuilder>();
305 gridBuilder->addCoarseGrid(xcm, ycm, zcm, xcp, ycp, zcp, deltaX);
306 gridBuilder->setPeriodicBoundaryCondition(false, false, false);
307 gridBuilder->buildGrids(false);
308
309 auto para = std::make_shared<Parameter>(&config);
310 para->worldLength = xcp - xcm;
311 para->setOutputPath(config.getValue<std::string>("Path"));
312 para->setOutputPrefix("fields/disk");
313 para->setPrintFiles(printFiles);
314 para->setVelocityLB(velocityLB);
315 para->setViscosityLB(viscosityLB);
316 para->setVelocityRatio(velocityRatio);
317 para->setViscosityRatio(deltaX * deltaX / deltaT);
318 para->setDensityRatio(c1o1);
319 para->setOutflowPressureCorrectionFactor(c0o1);
320 para->configureMainKernel(vf::collision_kernel::compressible::K17CompressibleNavierStokes);
321 para->setInitialCondition([velocityLB](real, real, real, real& rho, real& vx, real& vy, real& vz) {
322 rho = c0o1;
323 vx = velocityLB;
324 vy = c0o1;
325 vz = c0o1;
326 });
327 para->setTimestepStartOut(timeStepStartWriteField);
328 para->setTimestepOut(timeStepIntervalWriteField);
329 para->setTimestepEnd(timeStepEnd);
330 para->setIsBodyForce(true);
331 para->setQuadricLimiters(quadricDelimiter, quadricDelimiter, quadricDelimiter);
332
333 gridBuilder->setVelocityBoundaryCondition(SideType::MX, velocityLB, c0o1, c0o1);
334 gridBuilder->setPressureBoundaryCondition(SideType::PX, c1o1);
335 gridBuilder->setVelocityBoundaryCondition(SideType::MY, velocityLB, c0o1, c0o1);
336 gridBuilder->setVelocityBoundaryCondition(SideType::PY, velocityLB, c0o1, c0o1);
337 gridBuilder->setVelocityBoundaryCondition(SideType::MZ, velocityLB, c0o1, c0o1);
338 gridBuilder->setVelocityBoundaryCondition(SideType::PZ, velocityLB, c0o1, c0o1);
339
340 BoundaryConditionFactory bcFactory;
341 bcFactory.setVelocityBoundaryCondition(velocityBoundaryCondition);
342 bcFactory.setSlipBoundaryCondition(BoundaryConditionFactory::SlipBC::SlipTurbulentViscosityCompressible);
343 bcFactory.setPressureBoundaryCondition(BoundaryConditionFactory::PressureBC::OutflowNonReflective);
344
345 auto tmFactory = std::make_shared<TurbulenceModelFactory>(para);
346 tmFactory->readConfigFile(config);
347
349 gridScalingFactory.setScalingFactory(GridScalingFactory::GridScaling::ScaleCompressible);
350
351 auto cudaMemoryManager = std::make_shared<CudaMemoryManager>(para);
352
353 const int gridLevelForAlm = 0;
354 const auto diskActuatorConfig =
355 buildDiskActuatorConfig(diskDiameter, numberOfBlades, numberOfPointsPerBlade, thrustCoefficient);
356 const std::vector<real> turbinePosX { diskCenterX };
357 const std::vector<real> turbinePosY { diskCenterY };
358 const std::vector<real> turbinePosZ { diskCenterZ };
359 const std::vector<real> rotorSpeeds { c0o1 };
360 auto actuatorFarm = std::make_shared<ActuatorFarmStandalone>(
361 para,
362 cudaMemoryManager,
364 numberOfPointsPerBlade,
368 rotorSpeeds,
369 smearingWidth,
371 diskActuatorConfig.hubConfig,
372 std::nullopt,
373 std::nullopt,
374 diskActuatorConfig.hubDragCoefficient,
375 diskActuatorConfig.hubSkinFrictionCoefficient,
376 std::nullopt,
377 numberOfBlades,
378 diskActuatorConfig.bladeNormalCoefficients);
380 para->addInteractor(actuatorFarm);
381
382 if (positionProbePlaneZ.size() != 3 || positionProbePlaneZ[0].size() != 2 || positionProbePlaneZ[1].size() != 2 ||
383 positionProbePlaneZ[2].empty()) {
384 throw std::runtime_error("POSITION_PROBE_PLANE_Z must be [x_range],[y_range],[z_positions].");
385 }
386
387 const auto& xRange = positionProbePlaneZ[0];
388 const auto& yRange = positionProbePlaneZ[1];
389 const auto& zPositions = positionProbePlaneZ[2];
390
391 const real x0 = std::min(xRange[0], xRange[1]);
392 const real x1 = std::max(xRange[0], xRange[1]);
393 const real y0 = std::min(yRange[0], yRange[1]);
394 const real y1 = std::max(yRange[0], yRange[1]);
396 const real level0MinZ = zcm - c1o2 * deltaX;
397 const real lowerProbePlaneZ =
398 level0MinZ + std::floor((requestedProbePlaneZ - level0MinZ) / deltaX) * deltaX;
399 const real upperProbePlaneZ = lowerProbePlaneZ + deltaX;
403
404 auto probe = std::make_shared<Probe>(
405 para,
406 cudaMemoryManager,
407 para->getOutputPath(),
408 "zplane/zPlane",
413 false,
414 false);
415 probe->addProbePlane(x0, y0, probePlaneZ, x1 - x0, y1 - y0, deltaX);
416 probe->addAllAvailableStatistics();
417 para->addSampler(probe);
418
419 VF_LOG_INFO("Start running ActuatorLineDisk...");
420 VF_LOG_INFO("thrust coefficient = {}", thrustCoefficient);
421 VF_LOG_INFO("time for one flow-through = {}", timeFlowThroughDomain);
422 VF_LOG_INFO("dx = {}", deltaX);
423 VF_LOG_INFO("dt = {}", deltaT);
424 VF_LOG_INFO("lbm velocity = {}", velocityLB);
425 VF_LOG_INFO("smearing width = {}", smearingWidth);
426 VF_LOG_INFO("timestep end = {}", timeStepEnd);
427 if (!config.contains("VELOCITY_BOUNDARY_CONDITION"))
428 VF_LOG_INFO("Using default inlet velocity BC: VelocityInterpolatedCompressible");
429
430 Simulation simulation(para, cudaMemoryManager, gridBuilder, &bcFactory, tmFactory, &gridScalingFactory);
431 simulation.run();
432}
433} // namespace
434
435int main(int argc, char* argv[])
436{
437 try {
439 const auto config = vf::basics::loadConfig(argc, argv, defaultConfigFile);
440 run(config);
441 } catch (const std::exception& e) {
442 VF_LOG_WARNING("{}", e.what());
443 return 1;
444 }
445
446 return 0;
447}
448
#define VF_LOG_INFO(...)
Definition Logger.h:50
#define VF_LOG_WARNING(...)
Definition Logger.h:51
A base class for main simulation loop.
Definition Simulation.h:52
bool contains(const std::string &key) const
check if value associated with given key exists
T getValue(const std::string &key) const
get value with key
void setPressureBoundaryCondition(BoundaryConditionFactory::PressureBC boundaryConditionType)
VelocityBC
An enumeration for selecting a velocity boundary condition.
void setSlipBoundaryCondition(BoundaryConditionFactory::SlipBC boundaryConditionType)
void setVelocityBoundaryCondition(BoundaryConditionFactory::VelocityBC boundaryConditionType)
void setScalingFactory(const GridScalingFactory::GridScaling gridScalingType, const GridScalingFactory::GridScalingAdvectionDiffusion gridScalingTypeAdvectionDiffusion=GridScalingAdvectionDiffusion::NotSpecified)
static void initializeLogger()
Definition Logger.cpp:43
int main(int argc, char *argv[])
const std::string defaultConfigFile
void run(string configname)
std::shared_ptr< T > SPtr
float real
Definition DataTypes.h:42
unsigned int uint
Definition DataTypes.h:47
ConfigurationFile loadConfig(int argc, char *argv[], std::string configPath)