diff --git a/aerodynamic_analysis/CMakeLists.txt b/aerodynamic_analysis/CMakeLists.txt index 54b457e0237cc071ffd4e6747d200ccf28da6372..0c1ea812d0fc097b979adbd377364beadf19964c 100644 --- a/aerodynamic_analysis/CMakeLists.txt +++ b/aerodynamic_analysis/CMakeLists.txt @@ -17,6 +17,10 @@ set(MODULE_SOURCES src/taw/tawDefaultData.cpp src/taw/tawCalculatePolarConfig.cpp src/taw/tawDefaultStrategy.cpp + src/tandem/tandemCalculatePolar.cpp + src/tandem/tandemDefaultData.cpp + src/tandem/tandemCalculatePolarConfig.cpp + src/tandem/tandemDefaultStrategy.cpp src/laminarTAW/laminarTAWCalculatePolar.cpp src/laminarTAW/laminarTAWConfig.cpp src/laminarTAW/HLFCData.cpp diff --git a/aerodynamic_analysis/aerodynamic_analysis_conf.xml b/aerodynamic_analysis/aerodynamic_analysis_conf.xml index 2f26006400324b47765f02fa32ff76eef0a388ab..799d573a8255b9e2b6a983eada06a5c1c13188c1 100644 --- a/aerodynamic_analysis/aerodynamic_analysis_conf.xml +++ b/aerodynamic_analysis/aerodynamic_analysis_conf.xml @@ -2,10 +2,10 @@ <module_configuration_file name="wingDesign_conf.xml"> <control_settings description="General control settings for this tool"> <aircraft_exchange_file_name description="Specify the name of the exchange file"> - <value>csmr-2020.xml</value> + <value>csmr-2020-voll.xml</value> </aircraft_exchange_file_name> <aircraft_exchange_file_directory description="Specify the direction in which the aircraft exchange file can be found"> - <value>../projects/</value> + <value>../projects/CSMR_voll/</value> </aircraft_exchange_file_directory> <own_tool_level description="Specify the tool level of this tool"> <value>3</value> @@ -108,6 +108,10 @@ <default>tawDefaultStrategy</default> <value>tawDefaultStrategy</value> </tawStrategies> + <tandemStrategies> <!--TODO kayra--> + <default>tandemDefaultStrategy</default> + <value>tandemDefaultStrategy</value> + </tandemStrategies> <bwbStrategies> <default>bwbDefaultStrategy</default> <value>bwbDefaultStrategy</value> diff --git a/aerodynamic_analysis/src/calculatePolar.cpp b/aerodynamic_analysis/src/calculatePolar.cpp index 36b543ad616243da2653e359be447aabb6f937cf..b67b1afc10e584d36ffa8c51b4c611850fb1c552 100644 --- a/aerodynamic_analysis/src/calculatePolar.cpp +++ b/aerodynamic_analysis/src/calculatePolar.cpp @@ -31,6 +31,8 @@ #include "laminarTAW/laminarTAWCalculatePolar.h" #include "bwb/bwbCalculatePolar.h" +#include "tandem/tandemCalculatePolar.h" + using std::endl; calculatePolar::calculatePolar(const int argc, char *argv[], const std::string &toolName, const std::string &toolVersion) @@ -51,11 +53,18 @@ strategyaccess calculatePolar::routing(const std::vector<std::string> &route) { {"true", [](const std::shared_ptr<RuntimeIO>& arg) { return std::make_unique<laminarTAWCalculatePolar>(arg); }}, } }, + {"tandem", + std::map<std::string, strategyaccess>{ + {"false", [](const std::shared_ptr<RuntimeIO>& arg) { return std::make_unique<tandemCalculatePolar>(arg); }}, + //TODO kayra: {"true", [](const std::shared_ptr<RuntimeIO>& arg) { return std::make_unique<laminarTAWCalculatePolar>(arg); }}, + } + }, {"blended_wing_body", std::map<std::string, strategyaccess>{ {"false", [](const std::shared_ptr<RuntimeIO>& arg) { return std::make_unique<bwbCalculatePolar>(arg); }}, } } }; + myRuntimeInfo->out << "ROUTE: " << route.at(0) << " " << route.at(1) << std::endl; return table[route.at(0)][route.at(1)]; } \ No newline at end of file diff --git a/aerodynamic_analysis/src/polar.cpp b/aerodynamic_analysis/src/polar.cpp index 47ac7f52e8f9d362092e22203dac4adfd7628756..45dc9e6e3299da34d269595634d0500c151b211c 100644 --- a/aerodynamic_analysis/src/polar.cpp +++ b/aerodynamic_analysis/src/polar.cpp @@ -34,6 +34,10 @@ tawDefaultPolar::tawDefaultPolar() { } +tandemDefaultPolar::tandemDefaultPolar() { + +} + PolarPoint::PolarPoint() : AoA(0.), @@ -66,3 +70,11 @@ tawDBPolarPoint::tawDBPolarPoint() CD_wave(0.) { } +tandemDBPolarPoint::tandemDBPolarPoint() + : + CD_ind(0.), + CD_visc_turb(0.), + CD_visc_lam(0.), + CD_wave(0.) { +} + diff --git a/aerodynamic_analysis/src/polar.h b/aerodynamic_analysis/src/polar.h index 00f032eaada78f0c48197eae3cddf737506a437d..c3389134478760354c394ce72fb9b88c894abc2c 100644 --- a/aerodynamic_analysis/src/polar.h +++ b/aerodynamic_analysis/src/polar.h @@ -71,6 +71,17 @@ class tawDBPolarPoint : public PolarPoint { virtual ~tawDBPolarPoint() {} }; +class tandemDBPolarPoint : public PolarPoint { //TODO kayra: adapt it for tandem if needed + public: + double CD_ind; /**< Induced drag coefficient [-] */ + double CD_visc_turb; /**< Turbulent viscous drag coefficient [-] */ + double CD_visc_lam; /**< Laminar viscous drag coefficient [-] */ + double CD_wave; /**< Wave drag coefficient [-] */ + + tandemDBPolarPoint(); + virtual ~tandemDBPolarPoint() {} +}; + /** \brief Class for lifting surfaces, also contains lift distribution and coefficients of respective areas */ class defaultPolarPointLiftSurface: public defaultPolarPoint { @@ -119,4 +130,20 @@ class tawDefaultPolar : public Polar { virtual ~tawDefaultPolar() {} }; +class tandemDefaultPolar : public Polar { + public: + std::vector<defaultPolarPoint> Points; + std::vector<defaultPolarPoint> PointsFuselage; + std::vector<defaultPolarPoint> PointsNacelles; + std::vector<defaultPolarPoint> PointsFin; + std::vector<defaultPolarPoint> PointsMisc; + + //TODO kayra: Two main wings instead of one wing + horizontal stab + std::vector<defaultPolarPointLiftSurface> PointsWing; //PointsFrontWing + std::vector<defaultPolarPointLiftSurface> PointsBackWing; + + tandemDefaultPolar(); + virtual ~tandemDefaultPolar() {} +}; + #endif // CALCULATEPOLAR_SRC_POLAR_H_ diff --git a/aerodynamic_analysis/src/tandem/tandemCalculatePolar.cpp b/aerodynamic_analysis/src/tandem/tandemCalculatePolar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b383cfb4c2c9457f1fda9018cefd9c49d55ca4d --- /dev/null +++ b/aerodynamic_analysis/src/tandem/tandemCalculatePolar.cpp @@ -0,0 +1,90 @@ +/* Copyright (C) 2010-2024 Institute of Aerospace Systems, RWTH Aachen University - All rights reserved. + This file is part of UNICADO. + + UNICADO is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UNICADO is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UNICADO. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "tandemCalculatePolar.h" +#include "tandemDefaultStrategy.h" +#include "tandemCalculatePolarConfig.h" + +#include <moduleBasics/strategySelector.h> +#include <moduleBasics/report.h> +#include <moduleBasics/plot.h> +#include <aixml/node.h> + +#include <algorithm> +#include <memory> +#include <exception> +#include <iomanip> +#include <string> +#include <vector> +#include <utility> // make_pair + +#ifdef _WIN32 + #include <fileapi.h> + #include <windows.h> +#endif // _WIN32 + +using std::endl; +using std::exception; +using std::fixed; +using std::ofstream; +using std::setprecision; +using std::string; +using std::stringstream; +using std::vector; + +void tandemCalculatePolar::initialize() { + myRuntimeInfo->out << "Calculate Polar for tandem: Initialize..." << endl; + config_ = std::make_shared<tandemCalculatePolarConfig>(rtIO_->moduleConfig); + myDefaultStrategy = std::make_shared<tandemDefaultStrategy>(rtIO_, config_); + this->selectAeroStrategy(); //TODO kayra: suan herhangi bir strategy user ile belirlenmiyor +} + +void tandemCalculatePolar::run() { + myRuntimeInfo->out << "Calculate Polar for tandem: Run..." << endl; + std::string strategy = "defaultStrategy"; + if (strategy == "defaultStrategy") { + myDefaultStrategy->run(); + } +} + +void tandemCalculatePolar::update() { + myRuntimeInfo->out << "Calculate Polar for tandem: Update..." << endl; + if (config_->execution_mode.value() == "mode_0") { + myDefaultStrategy->writePolarXML(); + myDefaultStrategy->setOutputValues(); + myDefaultStrategy->setReferenceValues(); + } else if (config_->execution_mode.value() == "mode_1") { + myDefaultStrategy->setReferenceValues(); + } else { + myRuntimeInfo->err << "execution_mode: " << config_->execution_mode.value() << " in config file program_settings/execution_mode is not supported! " << endl; + } + myDefaultStrategy->update_xml_entries(config_->execution_mode.value()); +} + +void tandemCalculatePolar::report() { + myRuntimeInfo->out << "Calculate Polar for tandem: Report..." << endl; + myDefaultStrategy->writePolarData(); + myRuntimeInfo->out << "Calculate Polar for tandem: Report..." << endl; + myDefaultStrategy->writeViscDragData(); +} + +void tandemCalculatePolar::save() { + myRuntimeInfo->out << "Calculate Polar for tandem: Save..." << endl; +} + +void tandemCalculatePolar::selectAeroStrategy() { +} diff --git a/aerodynamic_analysis/src/tandem/tandemCalculatePolar.h b/aerodynamic_analysis/src/tandem/tandemCalculatePolar.h new file mode 100644 index 0000000000000000000000000000000000000000..9f80cc311ec432aeec9b74d4159e40c23fd2f863 --- /dev/null +++ b/aerodynamic_analysis/src/tandem/tandemCalculatePolar.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2010-2024 Institute of Aerospace Systems, RWTH Aachen University - All rights reserved. + This file is part of UNICADO. + + UNICADO is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UNICADO is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UNICADO. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CALCULATEPOLAR_SRC_TANDEM_TANDEMCALCULATEPOLAR_H_ +#define CALCULATEPOLAR_SRC_TANDEM_TANDEMCALCULATEPOLAR_H_ + +#include "tandemCalculatePolarConfig.h" +#include "tandemDefaultStrategy.h" + +#include <moduleBasics/module.h> +#include <moduleBasics/strategySelector.h> +#include <moduleBasics/report.h> +#include <moduleBasics/plot.h> + +#include <memory> +#include <vector> +#include <string> + +class tandemCalculatePolar : public Strategy { + public: + std::string polarXMLFilePath; /**< Path to the polar XML output file, derived from the I/O file path */ + + explicit tandemCalculatePolar(std::shared_ptr<RuntimeIO> rtIO): rtIO_(rtIO), report_(rtIO) {} + ~tandemCalculatePolar() = default; + void initialize(); + void run(); + void update(); + void report(); + void save(); + void selectAeroStrategy(); + + private: + std::shared_ptr<RuntimeIO> rtIO_; /*<-- RuntimeIO object*/ + std::shared_ptr<tandemCalculatePolarConfig> config_; + std::shared_ptr<tandemDefaultStrategy> myDefaultStrategy; + Report report_; /*Report object*/ +}; + +#endif // CALCULATEPOLAR_SRC_TANDEM_TANDEMCALCULATEPOLAR_H_ diff --git a/aerodynamic_analysis/src/tandem/tandemCalculatePolarConfig.cpp b/aerodynamic_analysis/src/tandem/tandemCalculatePolarConfig.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fcd1158bbf78e7042b3893324384f124e4310bd8 --- /dev/null +++ b/aerodynamic_analysis/src/tandem/tandemCalculatePolarConfig.cpp @@ -0,0 +1,192 @@ +/* Copyright (C) 2010-2024 Institute of Aerospace Systems, RWTH Aachen University - All rights reserved. + This file is part of UNICADO. + + UNICADO is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UNICADO is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UNICADO. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "tandemCalculatePolarConfig.h" + +#include <runtimeInfo/runtimeInfo.h> +#include <moduleBasics/module.h> + +#include <algorithm> +#include <exception> +#include <iomanip> +#include <string> +#include <vector> +#include <utility> // make_pair + +#ifdef _WIN32 + #include <fileapi.h> + #include <windows.h> +#endif // _WIN32 + +using std::endl; + +tandemCalculatePolarConfig::tandemCalculatePolarConfig(const node& config) + : + // execution mode + execution_mode(EndnodeReadOnly<std::string>("program_settings/execution_mode")), + // lifting line settings + stepWidthCL(EndnodeReadOnly<double>("LiftingLineForTAW/stepWidthCL")), //TODO kayra: LiftingLineForTandem gibi bir copy paste yapayim mi ayni yeri mi kullanayim + // other settings + CLModeAirfoilSelection(EndnodeReadOnly<std::string>("program_settings/CLModeAirfoilSelection")), + setFlightConditionsMode(EndnodeReadOnly<std::string>("program_settings/FlightConditions/AdaptMachNumbersToCruiseReq")), + extrapolationMargin(EndnodeReadOnly<double>("program_settings/FlightConditions/PolarAttributes/extrapolation_margin")), + allowGrideChange(EndnodeReadOnly<bool>("program_settings/FlightConditions/PolarAttributes/allow_grid_change")), + numberFlightConditions(EndnodeReadOnly<int>("program_settings/FlightConditions/numberFlightConditions")), + pathToLiftingLine(EndnodeReadOnly<std::string>("program_settings/LiftingLine/FolderPath")), + // lifting line for TAW pitching moment corrections + CM_corr_fuselage_mode(EndnodeReadOnly<std::string>("program_settings/LiftingLineForTAW/PitchingMoment/CM_corr_fuselage")), + CM_corr_nacelle_mode(EndnodeReadOnly<std::string>("program_settings/LiftingLineForTAW/PitchingMoment/CM_corr_nacelle")), + delta_CM0(EndnodeReadOnly<double>("LiftingLineForTAW/PitchingMoment/delta_CM0")), + delta_dCMdCL(EndnodeReadOnly<double>("LiftingLineForTAW/PitchingMoment/delta_dCMdCL")), + // lifiting line for TAW induced drag corrections + indDragCtCorrForCalibration(EndnodeReadOnly<double>("LiftingLineForTAW/InducedDragCorrection/indDragCtCorrForCalibration")), //TODO kayra: bu correctionlardan iki tane tanimlama gerek var mi mesela yoksa ortak kullanilir mi + factorIndDragCleanPolar(EndnodeReadOnly<double>("LiftingLineForTAW/InducedDragCorrection/factorIndDragCleanPolar")), + // visc drag raymer transition parameters + manualTransition(EndnodeReadOnly<bool>("program_settings/ViscDragRaymer/ManualTransition")), + manualTransitionWing(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/TransitionLocationWing")), + manualTransitionStabilizer(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/TransitionLocationStabilizer")), //TODO kayra:bunun degismesi lazim mesela ama araya back wing komple copy paste mi olsun + manualTransitionFin(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/TransitionLocationFin")), + // visc drag raymer calibration parameters + doViscDragCalibration(EndnodeReadOnly<bool>("program_settings/ViscDragRaymer/UseCalibration")), + CDvisc_CDsum(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/CalibrationHighMa/CDSum")), //TODO kayra: bunalri da front/back ayirmam gerekiyor mu yoksa ortak yeter mi + CDvisc_CLfact(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/CalibrationHighMa/CLFact")), + CDvisc_CLexp(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/CalibrationHighMa/CLExp")), + CDvisc_CDsum_lowMa(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/CalibrationLowMa/CDSum")), + CDvisc_CLfact_lowMa(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/CalibrationLowMa/CLFact")), + CDvisc_CLexp_lowMa(EndnodeReadOnly<double>("program_settings/ViscDragRaymer/CalibrationLowMa/CLExp")), + // wave drag mason + numberWingStrips(EndnodeReadOnly<int>("program_settings/WaveDragMason/NumberWingStrips")), + useCostomReferenceAngleForSweep(EndnodeReadOnly<bool>("program_settings/WaveDragMason/UseCostomReferenceAngleForSweep")), + doWaveDragMasonCalibration(EndnodeReadOnly<bool>("program_settings/WaveDragMason/UseCalibration")), + doWaveDragMasonDragCountCorrection(EndnodeReadOnly<bool>("program_settings/WaveDragMason/DoDragCountCorrection")), + Ka(EndnodeReadOnly<double>("program_settings/WaveDragMason/Ka")), + maximumSegmentSweep(EndnodeReadOnly<double>("program_settings/WaveDragMason/MaximumSegmentSweep")), + customSweepPosition(EndnodeReadOnly<double>("program_settings/WaveDragMason/CustomSweepAngle")), + CDwave_CLFact(EndnodeReadOnly<double>("program_settings/WaveDragMason/CLFact")), //TODO kayra:bu tarz factorler mesela liftin wave drage etki faktöri gibi + CDwave_CLExp(EndnodeReadOnly<double>("program_settings/WaveDragMason/CLExp")), + deltaWaveDragCountWing(EndnodeReadOnly<double>("program_settings/WaveDragMason/deltaWaveDragWing")), //TODO kayra: bu tarz parametreler de iki kanat icin farli olabilir mi + // trim settings + doTrim(EndnodeReadOnly<bool>("program_settings/Trim/DoTrim")), + trimAdditionalCGPositions(EndnodeReadOnly<bool>("program_settings/Trim/TrimWithAdditionalCoGPositions")), + trimHighLiftPolars(EndnodeReadOnly<bool>("program_settings/Trim/TrimHighLift")), + stabAngleGridMode(EndnodeReadOnly<std::string>("program_settings/Trim/StabAngleGrid")), + customStabAngleGrid(EndnodeReadOnly<std::string>("program_settings/Trim/customStabAngleGrid")), //TODO kayra: HLW/nur Höhenrudder?(aeleron ile böyle birsey yapilabilir) zaten set degil mi empenage design icin + deltaTotalDragHL(EndnodeReadOnly<double>("program_settings/SemiEmpiricalHighLiftAdaptions/deltaTotalDrag")), + factorDragHL(EndnodeReadOnly<double>("program_settings/SemiEmpiricalHighLiftAdaptions/factorDrag")), + // calibration settings + factorDragCleanPolar(EndnodeReadOnly<double>("program_settings/DragCorrection/factorDragCleanPolars")), + factorDragHighLiftPolar(EndnodeReadOnly<double>("program_settings/DragCorrection/factorDragHighliftPolar")), + deltaTotalDragCleanPolar(EndnodeReadOnly<double>("program_settings/DragCorrection/deltaTotalDragCleanPolars")), + deltaTotalDragHighLift(EndnodeReadOnly<double>("program_settings/DragCorrection/deltaTotalDragHighLift")) { + execution_mode.read(config); + CLModeAirfoilSelection.read(config); + stepWidthCL.read(config); + setFlightConditionsMode.read(config); + extrapolationMargin.read(config); + allowGrideChange.read(config); + numberFlightConditions.read(config); + pathToLiftingLine.read(config); + manualTransition.read(config); + manualTransitionWing.read(config); + manualTransitionStabilizer.read(config); + manualTransitionFin.read(config); + doViscDragCalibration.read(config); + CDvisc_CDsum.read(config); + CDvisc_CLfact.read(config); + CDvisc_CLexp.read(config); + CDvisc_CDsum_lowMa.read(config); + CDvisc_CLfact_lowMa.read(config); + CDvisc_CLexp_lowMa.read(config); + useCostomReferenceAngleForSweep.read(config); + doWaveDragMasonCalibration.read(config); + doWaveDragMasonDragCountCorrection.read(config); + Ka.read(config); + numberWingStrips.read(config); + maximumSegmentSweep.read(config); + customSweepPosition.read(config); + CDwave_CLFact.read(config); + CDwave_CLExp.read(config); + deltaWaveDragCountWing.read(config); + doTrim.read(config); + trimAdditionalCGPositions.read(config); + trimHighLiftPolars.read(config); + stabAngleGridMode.read(config); + customStabAngleGrid.read(config); + deltaTotalDragHL.read(config); + factorDragHL.read(config); + CM_corr_fuselage_mode.read(config); + CM_corr_nacelle_mode.read(config); + delta_CM0.read(config); + delta_dCMdCL.read(config); + indDragCtCorrForCalibration.read(config); + factorIndDragCleanPolar.read(config); + liftingLineFolderPath = pathToLiftingLine.value(); + factorDragCleanPolar.read(config); + factorDragHighLiftPolar.read(config); + deltaTotalDragCleanPolar.read(config); + deltaTotalDragHighLift.read(config); + myRuntimeInfo->out << "config: " << liftingLineFolderPath << endl; + if (setFlightConditionsMode.value() == "mode_0") { + myRuntimeInfo->info << "set flight conditions from config xml" << endl; + for (size_t i(0); i < numberFlightConditions.value(); i++) { + readflightConditions(config, i); + } + } else if (setFlightConditionsMode.value() == "mode_1") { + myRuntimeInfo->info << "Hab vergessen was hier rein sollte" << endl; + } + this->initializeTrimSettings(); +} + +void tandemCalculatePolarConfig::readflightConditions(const node& config, size_t ID) { + EndnodeReadOnly flightConditionExtrapolationMargin(EndnodeReadOnly<double>("program_settings/FlightConditions/FlightCondition@" + num2Str(ID) + "/extrapolation_margin")); + EndnodeReadOnly flightConditionAltitude(EndnodeReadOnly<double>("program_settings/FlightConditions/FlightCondition@" + num2Str(ID) + "/Altitude")); + EndnodeReadOnly flightConditionMach(EndnodeReadOnly<double>("program_settings/FlightConditions/FlightCondition@" + num2Str(ID) + "/Mach")); + EndnodeReadOnly flightConditionAllowGridChange(EndnodeReadOnly<bool>("program_settings/FlightConditions/FlightCondition@" + num2Str(ID) + "/allow_grid_change")); + flightConditionAllowGridChange.read(config); + flightConditionAltitude.read(config); + flightConditionMach.read(config); + flightConditionExtrapolationMargin.read(config); + flightConditions.push_back(flightCondition()); + flightConditions.back().Mach = flightConditionMach.value(); + flightConditions.back().Altitude = flightConditionAltitude.value(); + flightConditions.back().extrapolationMargin = flightConditionExtrapolationMargin.value(); + flightConditions.back().allowGridChange = flightConditionAllowGridChange.value(); + machNumbers.push_back(flightConditions.back().Mach); +} + +void tandemCalculatePolarConfig::initializeTrimSettings() { + if (doTrim.value()) { + if (stabAngleGridMode.value() == "mode_0") { + stabAngles = {-6.0, 0.0, 6.0}; + neutralStabAngleID = 1; + } else if (stabAngleGridMode.value() == "mode_1") { + stabAngles = {-6.0, -4.0, -2.0, 0.0, 0.2, 0.4, 0.6}; + neutralStabAngleID = 3; + } else if (stabAngleGridMode.value() == "mode_2") { + myRuntimeInfo->out << "read out custom angles not implemented yet, tschüss!" << endl; + exit(1); + } + } else { + stabAngles = {0.0}; + neutralStabAngleID = 0; + } + if (doTrim.value() && trimAdditionalCGPositions.value()) { + CGPositions = {"design", "forward", "aft"}; + } else { + CGPositions = {"design"}; + } +} diff --git a/aerodynamic_analysis/src/tandem/tandemCalculatePolarConfig.h b/aerodynamic_analysis/src/tandem/tandemCalculatePolarConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..e2624b5a579875a7525c18dea0ee3bfe5c8e286d --- /dev/null +++ b/aerodynamic_analysis/src/tandem/tandemCalculatePolarConfig.h @@ -0,0 +1,151 @@ +/* Copyright (C) 2010-2024 Institute of Aerospace Systems, RWTH Aachen University - All rights reserved. + This file is part of UNICADO. + + UNICADO is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UNICADO is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UNICADO. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CALCULATEPOLAR_SRC_TANDEM_TANDEMCALCULATEPOLARCONFIG_H_ +#define CALCULATEPOLAR_SRC_TANDEM_TANDEMCALCULATEPOLARCONFIG_H_ + +#include <aixml/endnode.h> +#include <standardFiles/settings.h> + +#include <map> +#include <set> +#include <string> +#include <vector> + +#include "../flightCondition.h" + +/** \brief Settings class for calculatePolar. Initializes tool with settings set in the respective config file. + * Inherits from the settings class (located in libraries and in unicadoRuntimeLibs) + */ + +class tandemCalculatePolarConfig{ + public: + /* !!! WARNING: All EndnodeReadOnly Values are converted automatically to SI-Units/RADIAN when read in */ + EndnodeReadOnly<std::string>execution_mode; + EndnodeReadOnly<std::string>pathToLiftingLine; + // general lifting line settings + EndnodeReadOnly<double> stepWidthCL; + EndnodeReadOnly<std::string> CLModeAirfoilSelection; + // fligt condition parameters + EndnodeReadOnly<std::string> setFlightConditionsMode; + EndnodeReadOnly<double> extrapolationMargin; + EndnodeReadOnly<bool> allowGrideChange; + EndnodeReadOnly<int> numberFlightConditions; + // lifting line pitching moment parameters + EndnodeReadOnly<std::string> CM_corr_fuselage_mode; + EndnodeReadOnly<std::string> CM_corr_nacelle_mode; + EndnodeReadOnly<double> delta_CM0; + EndnodeReadOnly<double> delta_dCMdCL; + // lifting line for TAW induced drag calibraitons + EndnodeReadOnly<double> indDragCtCorrForCalibration; + EndnodeReadOnly<double> factorIndDragCleanPolar; + // visc drag raymer + EndnodeReadOnly<bool> manualTransition; + EndnodeReadOnly<double> manualTransitionWing; + EndnodeReadOnly<double> manualTransitionStabilizer; + EndnodeReadOnly<double> manualTransitionFin; + EndnodeReadOnly<bool> doViscDragCalibration; + EndnodeReadOnly<double> CDvisc_CDsum; + EndnodeReadOnly<double> CDvisc_CLfact; + EndnodeReadOnly<double> CDvisc_CLexp; + EndnodeReadOnly<double> CDvisc_CDsum_lowMa; + EndnodeReadOnly<double> CDvisc_CLfact_lowMa; + EndnodeReadOnly<double> CDvisc_CLexp_lowMa; + // wave drag mason + EndnodeReadOnly<int> numberWingStrips; + EndnodeReadOnly<bool> useCostomReferenceAngleForSweep; + EndnodeReadOnly<bool> doWaveDragMasonCalibration; + EndnodeReadOnly<bool> doWaveDragMasonDragCountCorrection; + EndnodeReadOnly<double> Ka; + EndnodeReadOnly<double> maximumSegmentSweep; + EndnodeReadOnly<double> customSweepPosition; + EndnodeReadOnly<double> CDwave_CLFact; + EndnodeReadOnly<double> CDwave_CLExp; + EndnodeReadOnly<double> deltaWaveDragCountWing; + // trimInterpolationSettings + EndnodeReadOnly<bool> doTrim; + EndnodeReadOnly<bool> trimAdditionalCGPositions; + EndnodeReadOnly<bool> trimHighLiftPolars; + EndnodeReadOnly<std::string> stabAngleGridMode; + EndnodeReadOnly<std::string> customStabAngleGrid; + // semi empirical high lift adaptions + EndnodeReadOnly<double> deltaTotalDragHL; + EndnodeReadOnly<double> factorDragHL; + // calibration settings + EndnodeReadOnly<double> factorDragCleanPolar; + EndnodeReadOnly<double> factorDragHighLiftPolar; + EndnodeReadOnly<double> deltaTotalDragCleanPolar; + EndnodeReadOnly<double> deltaTotalDragHighLift; + void readflightConditions(const node& config, size_t ID); + void initializeTrimSettings(); + explicit tandemCalculatePolarConfig(const node& config); + virtual ~tandemCalculatePolarConfig() {} + // explicit calculatePolarSettings(const node& configXML); + /** \brief Virtual destructor of calculatePolarSettings + */ + // virtual ~calculatePolarSettings(); + /* Member Variables */ + std::string liftingLineFolderPath; /**< Path to LiftingLine folder */ + bool deleteLLfolder; /**< Switch which sets if liftingLine folder in project folder is deleted after execution */ + std::string aeroDatabaseFolderPath; /**< Path to AeroDatabase folder */ + bool getAlternativeDragComponentsFromDB; /**< Switch if also the friction and pressure drag should be read from DB and plotted */ + std::string stabtoolFolderPath; /**< Path to Stabtool folder */ + + // trim settings + std::vector<double> stabAngles; /**< vector of stabilizer angles in [deg] */ + std::vector<std::string> CGPositions; /**< vector of CG positions, order: design, fwd, aft*/ + size_t neutralStabAngleID; + + /* Polar Configuration */ + /** \brief Class which contains configurations for the polar calculations + */ + uint8_t plottingIncrement; /**< variable within database method */ + + /* Flight Conditions */ + bool adaptMachDistribution; /**< Switch to either use the list of flight conditions from the config file or to distribute them reasonably with respect to design mach number */ + double cruiseMach; /**< Cruise mach number [-] */ + double designAltitude; /**< Design altitude [ft] */ + bool useAverageCruiseAltitude; /**< Switch to either use the given design altitude or to calculate the average from the flown cruise steps set in aricraft xml */ + int numberOfCruiseSteps; /**< Number of cruise steps in design mission*/ + int numberOfFlightConditions; /**< Number of flight conditions [-] */ + std::vector <double> lowSpeed_Mach; /**< Vector of low speed mach numbers. Only used if adaptMachDistribution is set to true */ + std::vector <double> highSpeed_Mach_Deltas; /**< Vector of high speed mach number deviations. Used to distribute mach numbers around cruise mach number */ + std::vector <double> FreestreamMachNumbers; /**< Vector of Freestream Mach numbers */ + std::vector<flightCondition> flightConditions; /**< Vector of flightCondition objects representing the mission data */ + std::vector<double> machNumbers; /**< Vector with mach numbers corrsponding to their mach ID */ + + private: + /* Member functions */ + /** \brief Function reads polar settings from configuration XML and stores them in polarConfig object + * \param &polarNode aixml node that contains polar configuration information from corresponding XML file + */ + void readPolarSettings(const node& polarNode); + /** \brief Function reads flight condition settings from configuration XML and stores them in class variables + * \param &flightConditionNode aixml node that contains flight condition information from corresponding XML file + */ + void readFlightConditions(const node& flightConditionNode); + /** \brief Function reads viscous drag settings from configuration XML and stores them in class variables + * \param &viscousDragNode aixml node that contains flight condition information from corresponding XML file + */ + void readViscousDragSettings(const node& viscousDragNode); + /** \brief Function reads wave drag settings from configuration XML and stores them in class variables + * \param &viscousDragNode aixml node that contains flight condition information from corresponding XML file + */ + void readWaveDragSettings(const node& viscousWaveNode); +}; + +#endif // CALCULATEPOLAR_SRC_TANDEM_TANDEMCALCULATEPOLARCONFIG_H_ diff --git a/aerodynamic_analysis/src/tandem/tandemDefaultData.cpp b/aerodynamic_analysis/src/tandem/tandemDefaultData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b924f38e0af478ec830458b358c44c3f630d314f --- /dev/null +++ b/aerodynamic_analysis/src/tandem/tandemDefaultData.cpp @@ -0,0 +1,176 @@ +/* Copyright (C) 2010-2024 Institute of Aerospace Systems, RWTH Aachen University - All rights reserved. + This file is part of UNICADO. + + UNICADO is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UNICADO is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UNICADO. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "tandemDefaultData.h" + +#include <runtimeInfo/runtimeInfo.h> +#include <moduleBasics/module.h> + +#include <algorithm> +#include <exception> +#include <iomanip> +#include <string> +#include <vector> +#include <memory> +#include <utility> + +using std::endl; + +tandemDefaultData::tandemDefaultData(const std::shared_ptr<RuntimeIO>& rtIO) + : + rtIO_(rtIO), + engineType(EndnodeReadOnly<std::string>("type").read(rtIO->acxml.at("requirements_and_specifications/design_specification/propulsion/propulsor")).value()), + initialCruiseMachNumber(EndnodeReadOnly<double>("initial_cruise_mach_number").read( + rtIO->acxml.at("requirements_and_specifications/requirements/top_level_aircraft_requirements/design_mission")).value()), + bestCruiseCL(EndnodeReadOnly<double>("analysis/aerodynamics/lift_coefficients/C_LoptimumCruise").read(rtIO->acxml).value()), + designCoGX(EndnodeReadOnly<double>("analysis/masses_cg_inertia/design_mass/mass_properties/center_of_gravity/x").read(rtIO->acxml).value()), + designCoGY(EndnodeReadOnly<double>("analysis/masses_cg_inertia/design_mass/mass_properties/center_of_gravity/y").read(rtIO->acxml).value()), + designCoGZ(EndnodeReadOnly<double>("analysis/masses_cg_inertia/design_mass/mass_properties/center_of_gravity/z").read(rtIO->acxml).value()), + forwardCoGX(EndnodeReadOnly<double>("analysis/masses_cg_inertia/most_forward_mass/mass_properties/center_of_gravity/x").read(rtIO->acxml).value()), + forwardCoGY(EndnodeReadOnly<double>("analysis/masses_cg_inertia/most_forward_mass/mass_properties/center_of_gravity/y").read(rtIO->acxml).value()), + forwardCoGZ(EndnodeReadOnly<double>("analysis/masses_cg_inertia/most_forward_mass/mass_properties/center_of_gravity/z").read(rtIO->acxml).value()), + aftCoGX(EndnodeReadOnly<double>("analysis/masses_cg_inertia/most_afterward_mass/mass_properties/center_of_gravity/x").read(rtIO->acxml).value()), + aftCoGY(EndnodeReadOnly<double>("analysis/masses_cg_inertia/most_afterward_mass/mass_properties/center_of_gravity/y").read(rtIO->acxml).value()), + aftCoGZ(EndnodeReadOnly<double>("analysis/masses_cg_inertia/most_afterward_mass/mass_properties/center_of_gravity/z").read(rtIO->acxml).value()), + C_L_optimumCruise(Endnode<double>("analysis/aerodynamics/lift_coefficients/C_LoptimumCruise", "C_LoptimumCruise", 0, "1")), //TODO kayra: xml parsing basarisizsa default value ve uniti + CL_max_landing(Endnode<double>("analysis/aerodynamics/lift_coefficients/C_LmaxLanding", "C_LmaxLanding", 0, "1")), + C_LmaxTO(Endnode<double>("analysis/aerodynamics/lift_coefficients/C_LmaxT-O", "C_LmaxTO", 0, "1")), + C_LgroundRoll(Endnode<double>("analysis/aerodynamics/lift_coefficients/C_LgroundRoll", "C_LgroundRoll", 0, "1")), + span(Endnode<double>("analysis/aerodynamics/reference_values/b", "Wing half span", 0, "m")), + back_span(Endnode<double>("analysis/aerodynamics/reference_values/back_b", "Back Wing half span", 0, "m")), + MAC(Endnode<double>("analysis/aerodynamics/reference_values/MAC", "Mean aerodynamic chord", 0, "m")), + back_MAC(Endnode<double>("analysis/aerodynamics/reference_values/back_MAC", "Mean aerodynamic chord of back wing", 0, "m")), + S_ref(Endnode<double>("analysis/aerodynamics/reference_values/S_ref", "Wing reference area", 0, "m^2")), + back_S_ref(Endnode<double>("analysis/aerodynamics/reference_values/back_S_ref", "Back Wing reference area", 0, "m^2")), + neutral_point_xCoordinate(Endnode<double>("analysis/aerodynamics/reference_values/neutral_point/x", "x component of neutral point", 0., "m")), //TODO kayra:overall or wing specific + max_spoiler_factor(Endnode<double>("analysis/aerodynamics/max_spoiler_factor", "max_spoiler_factor", 0, "1")), + back_max_spoiler_factor(Endnode<double>("analysis/aerodynamics/back_max_spoiler_factor", "max_spoiler_factor", 0, "1")), //TODO kayra:bunu ikilemem lazim mi bilemedim + polar_file(Endnode<std::string>("analysis/aerodynamics/polar/polar_file", "Name of polar file")) { //TODO kayra:bunu ikilemem lazim mi bilemedim + // check for reasonable values for the CoG values + if (accuracyCheck(designCoGX, 0., ACCURACY_HIGH)) { + designCoGX = 16.0; + } + if (accuracyCheck(forwardCoGX, 0., ACCURACY_HIGH)) { + forwardCoGX = 15.0; + } + if (accuracyCheck(forwardCoGX, 0., ACCURACY_HIGH)) { + aftCoGX = 17.0; + } + if (accuracyCheck(bestCruiseCL, 0., ACCURACY_HIGH)) { + bestCruiseCL = 0.5; + } + designCoG.xCoordinate = designCoGX; + designCoG.yCoordinate = designCoGY; + designCoG.zCoordinate = designCoGZ; + forwardCoG.xCoordinate = forwardCoGX; + forwardCoG.yCoordinate = forwardCoGY; + forwardCoG.zCoordinate = forwardCoGZ; + aftCoG.xCoordinate = aftCoGX; + aftCoG.yCoordinate = aftCoGY; + aftCoG.zCoordinate = aftCoGZ; + CoGPositions["design"] = designCoG; + CoGPositions["forward"] = forwardCoG; + CoGPositions["aft"] = aftCoG; + numberDevices = rtIO_->acxml.getVector(("wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device"), 3).size(); + back_numberDevices = rtIO_->acxml.getVector(("wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device"), 3).size(); + // read in device names to later distinguish between control and high lift device + for (size_t deviceID(0); deviceID < numberDevices; ++deviceID) { + wingDevice aWingDevice; + aWingDevice.type = + std::string(rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID)).getStringAttrib("description")); + aWingDevice.maxNegativeDeflection = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/deflection/full_negative_deflection/value"); + aWingDevice.maxPositiveDeflection = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/deflection/full_positive_deflection/value"); + aWingDevice.innerRelSpanPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/inner_position/spanwise/value"); + aWingDevice.innerRelFwdChordPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/inner_position/chord/from/value"); + aWingDevice.innerRelAftChordPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/inner_position/chord/to/value"); + aWingDevice.outerRelSpanPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/outer_position/spanwise/value"); + aWingDevice.outerRelFwdChordPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/outer_position/chord/from/value"); + aWingDevice.outerRelAftChordPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@0/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/outer_position/chord/to/value"); + wingDevices.push_back(aWingDevice); + } + for (size_t deviceID(0); deviceID < back_numberDevices; ++deviceID) { + wingDevice aWingDevice; + aWingDevice.type = + std::string(rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID)).getStringAttrib("description")); + aWingDevice.maxNegativeDeflection = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/deflection/full_negative_deflection/value"); + aWingDevice.maxPositiveDeflection = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/deflection/full_positive_deflection/value"); + aWingDevice.innerRelSpanPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/inner_position/spanwise/value"); + aWingDevice.innerRelFwdChordPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/inner_position/chord/from/value"); + aWingDevice.innerRelAftChordPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/inner_position/chord/to/value"); + aWingDevice.outerRelSpanPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/outer_position/spanwise/value"); + aWingDevice.outerRelFwdChordPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/outer_position/chord/from/value"); + aWingDevice.outerRelAftChordPosition = + rtIO_->acxml.at("/aircraft_exchange_file/component_design/wing/specific/geometry/aerodynamic_surface@1/parameters/control_devices/control_device@" + + num2Str(deviceID) + "/position/outer_position/chord/to/value"); + back_wingDevices.push_back(aWingDevice); + } +} + +void tandemDefaultData::updateNodes(std::string mode) { + // reference values + span.update(rtIO_->acxml); + back_span.update(rtIO_->acxml); + MAC.update(rtIO_->acxml); + back_MAC.update(rtIO_->acxml); + S_ref.update(rtIO_->acxml); + back_S_ref.update(rtIO_->acxml); + neutral_point_xCoordinate.update(rtIO_->acxml); + if (mode == "mode_0") { //TODO kayra: execution_mode olmasin mode bulamadim + // lift coefficients + C_L_optimumCruise.update(rtIO_->acxml); + CL_max_landing.update(rtIO_->acxml); + C_LmaxTO.update(rtIO_->acxml); + C_LgroundRoll.update(rtIO_->acxml); + // maximum spoiler factor + max_spoiler_factor.update(rtIO_->acxml); + back_max_spoiler_factor.update(rtIO_->acxml); + // polar file stuff + polar_file.update(rtIO_->acxml); + } +} diff --git a/aerodynamic_analysis/src/tandem/tandemDefaultData.h b/aerodynamic_analysis/src/tandem/tandemDefaultData.h new file mode 100644 index 0000000000000000000000000000000000000000..bb91de445043c89f5d05d434f3ae5f1fd7961fcb --- /dev/null +++ b/aerodynamic_analysis/src/tandem/tandemDefaultData.h @@ -0,0 +1,97 @@ +/* Copyright (C) 2010-2024 Institute of Aerospace Systems, RWTH Aachen University - All rights reserved. + This file is part of UNICADO. + + UNICADO is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UNICADO is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UNICADO. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CALCULATEPOLAR_SRC_TANDEM_TANDEMDEFAULTDATA_H_ +#define CALCULATEPOLAR_SRC_TANDEM_TANDEMDEFAULTDATA_H_ + +#include <atmosphere/atmosphere.h> +#include <standardFiles/typedefs.h> +#include <aixml/endnode.h> + +#include <moduleBasics/runtimeIO.h> + +#include <string> +#include <unordered_map> +#include <vector> +#include <map> + +/** \brief Class contains all properties of calculated aircraft objects +*/ +class tandemDefaultData { + public: + /* Typedefs */ + /** \brief Constructor of aircraft class + * \param &mySettings Reference to calculatePolarSettings object + */ + explicit tandemDefaultData(const std::shared_ptr<RuntimeIO>& rtIO); + /** \brief Virtual destructor of aircraft class + */ + virtual ~tandemDefaultData() {} + + double initialCruiseMachNumber; + std::string engineType; + /* !!! WARNING: All EndnodeReadOnly Values are converted automatically to SI-Units/RADIAN when read in */ + double bestCruiseCL; + double designCoGX; + double designCoGY; + double designCoGZ; + double forwardCoGX; + double forwardCoGY; + double forwardCoGZ; + double aftCoGX; + double aftCoGY; + double aftCoGZ; + Point designCoG; /**< Center of gravity coordinates */ + Point forwardCoG; /**< Forward position of center of gravity */ + Point aftCoG; /**< Average flight time position of center of gravity */ + Point cruiseTrimRefCoG; /**< Cruise reference center of gravity position */ + std::unordered_map <std::string, Point> CoGPositions; /**< Map connecting CoG names with points */ + size_t numberDevices; + size_t back_numberDevices; + struct wingDevice { + std::string type; + double maxPositiveDeflection; + double maxNegativeDeflection; + double innerRelSpanPosition; + double innerRelFwdChordPosition; + double innerRelAftChordPosition; + double outerRelSpanPosition; + double outerRelFwdChordPosition; + double outerRelAftChordPosition; + }; + std::vector<wingDevice> wingDevices; + std::vector<wingDevice> back_wingDevices; + Endnode<double>span; + Endnode<double>back_span; + Endnode<double>MAC; + Endnode<double>back_MAC; + Endnode<double>S_ref; + Endnode<double>back_S_ref; + Endnode<double>neutral_point_xCoordinate; + Endnode<double>C_L_optimumCruise; + Endnode<double>CL_max_landing; + Endnode<double>C_LmaxTO; + Endnode<double>C_LgroundRoll; + Endnode<std::string>polar_file; + Endnode<double>max_spoiler_factor; + Endnode<double>back_max_spoiler_factor; + void updateNodes(std::string mode); + private: + const std::shared_ptr<RuntimeIO>& rtIO_; /**< Pointer to the RuntimeIO */ +}; + +#endif // CALCULATEPOLAR_SRC_TANDEM_TANDEMDEFAULTDATA_H_ diff --git a/aerodynamic_analysis/src/tandem/tandemDefaultStrategy.cpp b/aerodynamic_analysis/src/tandem/tandemDefaultStrategy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc1861771f3eeb67e1875963cbd993f7676c5b8f --- /dev/null +++ b/aerodynamic_analysis/src/tandem/tandemDefaultStrategy.cpp @@ -0,0 +1,939 @@ +/* Copyright (C) 2010-2024 Institute of Aerospace Systems, RWTH Aachen University - All rights reserved. + This file is part of UNICADO. + + UNICADO is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UNICADO is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UNICADO. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "tandemDefaultStrategy.h" + +#include <aircraftGeometry2/fuselage.h> +#include <aircraftGeometry2/hull_surface.h> +#include <aircraftGeometry2/processing/measure.h> +#include <aircraftGeometry2/processing/transform.h> +#include <aixml/node.h> +#include <runtimeInfo/runtimeInfo.h> +#include <moduleBasics/runtimeIO.h> +#include <unitConversion/unitConversion.h> +#include <CGAL/Surface_mesh/IO/PLY.h> +#include <moduleBasics/module.h> + +#include <algorithm> +#include <exception> +#include <iomanip> +#include <string> +#include <memory> +#include <vector> +#include <filesystem> +#include <utility> // make_pair + +#include "../polar.h" +#include "../methods/generalMethods/auxFunctions.h" +#include "../methods/liftingLinePolar.h" +#include "../methods/liftingLineForTAW.h" +#include "../methods/viscDragRaymer.h" +#include "../methods/waveDragMason.h" +#include "../methods/semiEmpiricalHighLiftAdaption.h" +#include "../methods/trimInterpolation.h" + +using std::endl; +using std::exception; +using std::fixed; +using std::ofstream; +using std::setprecision; +using std::string; +using std::stringstream; +using std::pair; +using std::vector; + +/* TODO: - check if acft xml has entries before building the geometry comopnents */ +tandemDefaultStrategy::tandemDefaultStrategy(const std::shared_ptr<RuntimeIO>& rtIO, const std::shared_ptr<tandemCalculatePolarConfig>& config) + : + CoGnames{"design", "front", "aft"}, + HLconfigs{"takeoff", "takeoff_landing_gear_retracted", "climb", "approach", "approach_landing_gear_out", "landing"}, + C_LmaxLanding(0.0), + C_LmaxTO(0.0), + C_LoptimumCruise(0.0), + rtIO_(rtIO), + data_(std::make_shared<tandemDefaultData>(rtIO_)), + config_(config) { +} + +void tandemDefaultStrategy::run() { + // loop over all cg positions and stabilizer angles + for (size_t CGID(0); CGID < config_->CGPositions.size(); ++CGID) { + for (size_t stabID(0); stabID < config_->stabAngles.size(); ++stabID) { + this->clearDataForNextCalculationRun(); + myRuntimeInfo-> out << endl; + myRuntimeInfo->out << "Run aero calculations for " << config_->CGPositions.at(CGID) << + " CoG and stabilizer angle of " << config_->stabAngles.at(stabID) << " deg..." << endl; + myRuntimeInfo-> out << endl; + this->createAircraftGeometry(config_->stabAngles.at(stabID)); + this->runAeroCalculations(data_->CoGPositions.at(config_->CGPositions.at(CGID)), config_->stabAngles.at(stabID)); + this->copyPolarsToCGMap(CGID, stabID); + } + } + // interpolate trimed polars, or just copy polars if trim is disabled + if (config_->doTrim.value()) { + this->doTrimInterpolation(); + if (config_->trimHighLiftPolars.value()) { + this->doTrimInterpolationHighLift(); + } else { + this->copyHighLiftPolars(); + } + } else { + this->copyCleanPolars(); + this->copyHighLiftPolars(); + } + this->calibratePolars(); +} + +void tandemDefaultStrategy::createAircraftGeometry(const double stabAngle) { + auto get_position = [](const node &component) -> geom2::Point_3 { + return geom2::Point_3{double{component.at("position/x/value")}, + double{component.at("position/y/value")}, + double{component.at("position/z/value")}}; + }; + std::filesystem::path file{rtIO_->acxml.getName()}; + std::shared_ptr<node> AcXML = aixml::openDocument(file); + // create wing + this->aircraft_xml = aixml::openDocument(rtIO_->acxmlAccess); + const auto wing_position = get_position(this->aircraft_xml->at("aircraft_exchange_file/component_design/wing")); + geom2::WingFactory wingFactory{AcXML, rtIO_->getAirfoilDataDir()}; + geom2::MultisectionSurface<geom2::AirfoilSection> mainWing = wingFactory.create("wing/specific/geometry/aerodynamic_surface@0"); + auto offset = wing_position - CGAL::ORIGIN; + mainWing.origin += offset; + liftingSurfaces.push_back(mainWing); + // create HTP + const auto htp_position = get_position(this->aircraft_xml->at("aircraft_exchange_file/component_design/empennage")); + geom2::WingFactory HTPFactory{AcXML, rtIO_->getAirfoilDataDir()}; + geom2::MultisectionSurface<geom2::AirfoilSection> HTP = HTPFactory.create("empennage/specific/geometry/aerodynamic_surface@1"); + offset = htp_position - CGAL::ORIGIN; + HTP.origin += offset; + double designStabAngle = HTP.sections.front().get_twist_angle(); + HTP.sections.front().set_twist_angle(designStabAngle + convertUnit(DEGREE, RADIAN, stabAngle)); + liftingSurfaces.push_back(HTP); + // create fuselage + geom2::FuselageFactory fuselageFactory{AcXML, rtIO_->getGeometryDir()}; + fuselage = fuselageFactory.create("fuselage/specific/geometry/fuselage@0"); + // create VTP + const auto vtp_position = get_position(this->aircraft_xml->at("aircraft_exchange_file/component_design/empennage")); + geom2::WingFactory VTPFactory{AcXML, rtIO_->getAirfoilDataDir()}; + VTP = VTPFactory.create("empennage/specific/geometry/aerodynamic_surface@0"); + offset = vtp_position - CGAL::ORIGIN; + VTP.origin += offset; + geom2::Mesh wing_mesh = geom2::transform::to_mesh(mainWing); + geom2::Mesh vtp_mesh = geom2::transform::to_mesh(VTP); + vtp_mesh += wing_mesh; + geom2::Mesh htp_mesh = geom2::transform::to_mesh(HTP); + htp_mesh += vtp_mesh; + geom2::Mesh fuselage_mesh = geom2::transform::to_mesh(fuselage); + fuselage_mesh += htp_mesh; + // create nacelles + const auto nacelle_position = get_position(this->aircraft_xml->at("aircraft_exchange_file/component_design/propulsion")); + offset = nacelle_position - CGAL::ORIGIN; + size_t numberOfPropulsors = rtIO_->acxml.getVector(("aircraft_exchange_file/component_design/propulsion/specific/propulsion"), 1).size(); + geom2::HullFactory nacelleFactory{AcXML, rtIO_->getGeometryDir()}; + for (size_t i(0); i < numberOfPropulsors; ++i) { + geom2::MultisectionSurface<geom2::PolygonSection> aNacelle = nacelleFactory.create("propulsion/specific/propulsion@" + num2Str(i) + "/nacelle"); + aNacelle.origin += offset; + geom2::Mesh aNacelle_mesh = geom2::transform::to_mesh(aNacelle); + fuselage_mesh += aNacelle_mesh; + nacelles.push_back(aNacelle); + } + CGAL::IO::write_STL("TAW_mesh.stl", fuselage_mesh); //TODO kayra: cok yanlis suan:update geldi mi? +} + +void tandemDefaultStrategy::runAeroCalculations(const Point CoGPosition, const double currentIStabAngle) { + // lifting line for TAW + LiLiforTAWInitialization myLiLiInit; + this->initializeLiLiforTAW(&myLiLiInit); + liftingLineForTAW* myLiftingLineForTAW = new liftingLineForTAW(rtIO_, config_->liftingLineFolderPath, myLiLiInit); + myLiftingLineForTAW->run(CoGPosition); + this->getPolarDataFromLiftingLine(*myLiftingLineForTAW); + // viscous drag by raymer + viscDragRaymerInitialization myViscDragInit; + this->initializeViscDragRaymer(&myViscDragInit); + viscDragRaymer* myViscDragRamyer = new viscDragRaymer(rtIO_, myViscDragInit); + this->calculateViscDragRaymer(myViscDragRamyer); + // wave drag by mason + waveDragInitialization myWaveDragInit; + this->initializeWaveDragMason(&myWaveDragInit); + waveDragMason* myWaveDragMason = new waveDragMason(rtIO_, myWaveDragInit); + this->calculateWaveDragMason(myWaveDragMason); + // summation of the drag components + this->sumUpDragComponents(); + // high lift calculation + semiEmpiricalHighLiftAdaption* mySemiEmpHLAdaption = new semiEmpiricalHighLiftAdaption(rtIO_, liftingSurfaces.front()); + this->copyWingDevicesAndStabilizer(mySemiEmpHLAdaption); + this->copyCleanPolarForHLCalculation(mySemiEmpHLAdaption, myLiftingLineForTAW); + mySemiEmpHLAdaption->runHighLiftAdaption(); + this->calculateHighLiftPolars(mySemiEmpHLAdaption, CoGPosition.xCoordinate, currentIStabAngle); +} + +void tandemDefaultStrategy::initializeLiLiforTAW(LiLiforTAWInitialization *myLiLiInit) { + myLiLiInit->CLModeAirfoilSelection = config_->CLModeAirfoilSelection.value(); + myLiLiInit->stepWidthCL = config_->stepWidthCL.value(); + myLiLiInit->CM_corr_fuselage_mode = config_->CM_corr_fuselage_mode.value(); + myLiLiInit->CM_corr_nacelle_mode = config_->CM_corr_nacelle_mode.value(); + myLiLiInit->delta_CM0 = config_->delta_CM0.value(); + myLiLiInit->delta_dCMdCL = config_->delta_dCMdCL.value(); + myLiLiInit->indDragCtCorrForCalibration = config_->indDragCtCorrForCalibration.value(); + myLiLiInit->factorDragCleanPolar = config_->factorIndDragCleanPolar.value(); + myLiLiInit->bestCruiseCL = data_->bestCruiseCL; + myLiLiInit->initialMachCruise = data_->initialCruiseMachNumber; + myLiLiInit->engineType = data_->engineType; + for (size_t flightConditionID(0); flightConditionID < config_->flightConditions.size(); ++flightConditionID) { + flightCondition* aLiLiFlightCondition = new flightCondition; + aLiLiFlightCondition->Mach = config_->flightConditions.at(flightConditionID).Mach; + aLiLiFlightCondition->Altitude = config_->flightConditions.at(flightConditionID).Altitude; + aLiLiFlightCondition->extrapolationMargin = config_->flightConditions.at(flightConditionID).extrapolationMargin; + aLiLiFlightCondition->allowGridChange = config_->flightConditions.at(flightConditionID).allowGridChange; + myLiLiInit->flightConditions.push_back(*aLiLiFlightCondition); + if (accuracyCheck(aLiLiFlightCondition->Mach, data_->initialCruiseMachNumber, ACCURACY_HIGH)) { + myLiLiInit->cruiseMachID = flightConditionID; + } + delete aLiLiFlightCondition; + } + myLiLiInit->liftingSurfaces = liftingSurfaces; + myLiLiInit->theFuselage = fuselage; + myLiLiInit->theNacelles = nacelles; +} + +void tandemDefaultStrategy::initializeViscDragRaymer(viscDragRaymerInitialization *myViscDragInit) { + // copy geometry + myViscDragInit->theWing = liftingSurfaces.at(0); + myViscDragInit->calculateWing = true; + myViscDragInit->theHTP = liftingSurfaces.at(1); + myViscDragInit->calculateHTP = true; + myViscDragInit->theVTP = VTP; + myViscDragInit->calculateVTP = true; + myViscDragInit->theFuselage = fuselage; + myViscDragInit->calculateFuselage = true; + myViscDragInit->theNacelles = nacelles; + myViscDragInit->calculateNacelles = true; + myViscDragInit->calculateMisc = true; + // initialize transition parameters + myViscDragInit->manualTransitionLocation = config_->manualTransition.value(); + myViscDragInit->transitionLocationWing = config_->manualTransitionWing.value(); + myViscDragInit->transitionLocationHTP = config_->manualTransitionStabilizer.value(); + myViscDragInit->transitionLocationVTP = config_->manualTransitionFin.value(); + // initialize calibration parameters + myViscDragInit->doCalibration = config_->doViscDragCalibration.value(); + myViscDragInit->CDvisc_CDsum = config_->CDvisc_CDsum.value(); + myViscDragInit->CDvisc_CLexp = config_->CDvisc_CLexp.value(); + myViscDragInit->CDvisc_CLfact = config_->CDvisc_CLfact.value(); + myViscDragInit->CDvisc_CDsum_lowMa = config_->CDvisc_CDsum_lowMa.value(); + myViscDragInit->CDvisc_CLexp_lowMa = config_->CDvisc_CLexp_lowMa.value(); + myViscDragInit->CDvisc_CLfact_lowMa = config_->CDvisc_CLfact_lowMa.value(); + // calculate parameters that remain static over all polars +} + +void tandemDefaultStrategy::initializeWaveDragMason(waveDragInitialization *myWaveDragInit) { + // fill configuration parameters and values in the wave drag method + myWaveDragInit->CLExp = config_->CDwave_CLExp.value(); + myWaveDragInit->CLFact = config_->CDwave_CLFact.value(); + myWaveDragInit->factorKa = config_->Ka.value(); + myWaveDragInit->initialMachCruise = data_->initialCruiseMachNumber; + myWaveDragInit->numberOfSegments = config_->numberWingStrips.value(); + myWaveDragInit->waveDragCtCorrForCalibration = config_->deltaWaveDragCountWing.value(); + myWaveDragInit->maxAllowedSweep = convertUnit(RADIAN, DEGREE, config_->maximumSegmentSweep.value()); + myWaveDragInit->wFuselage = {geom2::measure::width_max(fuselage) * 0.5, 0}; + myWaveDragInit->liftingSurfaces = liftingSurfaces; +} + +void tandemDefaultStrategy::getPolarDataFromLiftingLine(const liftingLineForTAW& liftingLineForTAW) { + for (size_t machID(0); machID < config_->flightConditions.size(); ++machID) { + tawDefaultPolar aCleanPolar; + aCleanPolar.extrapolationMargin = liftingLineForTAW.theCleanPolars.at(machID).extrapolationMargin; + aCleanPolar.allowGridChange = liftingLineForTAW.theCleanPolars.at(machID).allowGridChange; + aCleanPolar.altitude = liftingLineForTAW.theCleanPolars.at(machID).altitude; + aCleanPolar.MachNumber = liftingLineForTAW.theCleanPolars.at(machID).MachNumber; + aCleanPolar.ReynoldsNumber = liftingLineForTAW.theCleanPolars.at(machID).ReynoldsNumber; + for (size_t pointID(0); pointID < liftingLineForTAW.theCleanPolars.at(machID).Points.size(); ++pointID) { + aCleanPolar.Points.push_back(defaultPolarPoint()); + aCleanPolar.Points.back().CL = liftingLineForTAW.theCleanPolars.at(machID).Points.at(pointID).CL; + aCleanPolar.Points.back().AoA = liftingLineForTAW.theCleanPolars.at(machID).Points.at(pointID).AoA; + aCleanPolar.Points.back().CD_ind = liftingLineForTAW.theCleanPolars.at(machID).Points.at(pointID).CDind; + aCleanPolar.Points.back().CM = liftingLineForTAW.theCleanPolars.at(machID).Points.at(pointID).CM; + aCleanPolar.Points.back().iStabPolar = liftingLineForTAW.theCleanPolars.at(machID).Points.at(pointID).iStabPolar; + aCleanPolar.PointsWing.push_back(defaultPolarPointLiftSurface()); + aCleanPolar.PointsWing.back().yStations = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(0).at(pointID).yStations; + aCleanPolar.PointsWing.back().Cl_distr = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(0).at(pointID).Cl_distr; + aCleanPolar.PointsWing.back().Lift_distr = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(0).at(pointID).Lift_distr; + aCleanPolar.PointsWing.back().CL = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(0).at(pointID).CL; + aCleanPolar.PointsWing.back().CD_ind = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(0).at(pointID).CDind; + aCleanPolar.PointsStab.push_back(defaultPolarPointLiftSurface()); + aCleanPolar.PointsStab.back().yStations = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(1).at(pointID).yStations; + aCleanPolar.PointsStab.back().Cl_distr = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(1).at(pointID).Cl_distr; + aCleanPolar.PointsStab.back().Lift_distr = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(1).at(pointID).Lift_distr; + aCleanPolar.PointsStab.back().CL = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(1).at(pointID).CL; + aCleanPolar.PointsStab.back().CD_ind = liftingLineForTAW.theCleanPolars.at(machID).liftingSurfacePolars.at(1).at(pointID).CDind; + aCleanPolar.PointsNacelles.push_back(defaultPolarPoint()); + aCleanPolar.PointsNacelles.back().CD_ind = liftingLineForTAW.theCleanPolars.at(machID).PointsNacelles.at(pointID).CDind; + aCleanPolar.PointsFuselage.push_back(defaultPolarPoint()); + aCleanPolar.PointsFuselage.back().CD_ind = liftingLineForTAW.theCleanPolars.at(machID).PointsFuselage.at(pointID).CDind; + aCleanPolar.PointsFin.push_back(defaultPolarPoint()); + aCleanPolar.PointsMisc.push_back(defaultPolarPoint()); + } + currentPolarSet.cleanPolars.insert(std::make_pair(machID, aCleanPolar)); + } + LILI_Version = liftingLineForTAW.LILI_version; +} + +void tandemDefaultStrategy::calculateViscDragRaymer(viscDragRaymer *myViscDragRaymer) { + myViscDragRaymer->preprocessGeometry(); + // run viscous drag calculation by Raymer over the current polar set + for (std::pair<size_t, tawDefaultPolar> polarIterator : currentPolarSet.cleanPolars) { + size_t polarID = polarIterator.first; + vector<double> theComponentDrags = myViscDragRaymer->calculateViscDrag(currentPolarSet.cleanPolars.at(polarID), 0.0, 0.0, 0.0); + // loop over all points to calculate CL dependent visc drag correction + for (size_t pointID(0); pointID < currentPolarSet.cleanPolars.at(polarID).Points.size(); ++pointID) { + vector <double> theCorrectedComponentDrags = myViscDragRaymer->calculateCorrectedViscDrag(theComponentDrags, currentPolarSet.cleanPolars.at(polarID).MachNumber, + currentPolarSet.cleanPolars.at(polarID).Points.at(pointID).CL); + // assign total and componentwise viscous drag to the polar map + currentPolarSet.cleanPolars.at(polarID).Points.at(pointID).CD_visc = std::accumulate(theCorrectedComponentDrags.begin(), theCorrectedComponentDrags.end(), 0.0); + currentPolarSet.cleanPolars.at(polarID).PointsWing.at(pointID).CD_visc = theCorrectedComponentDrags.at(0); + currentPolarSet.cleanPolars.at(polarID).PointsStab.at(pointID).CD_visc = theCorrectedComponentDrags.at(1); + currentPolarSet.cleanPolars.at(polarID).PointsFin.at(pointID).CD_visc = theCorrectedComponentDrags.at(2); + currentPolarSet.cleanPolars.at(polarID).PointsFuselage.at(pointID).CD_visc = theCorrectedComponentDrags.at(3); + currentPolarSet.cleanPolars.at(polarID).PointsNacelles.at(pointID).CD_visc = theCorrectedComponentDrags.at(4); + currentPolarSet.cleanPolars.at(polarID).PointsMisc.at(pointID).CD_visc = theCorrectedComponentDrags.at(5); + } + } + myRuntimeInfo->out<< "... Viscous drag has been calculated sucessfully!" << endl; +} + +void tandemDefaultStrategy::calculateWaveDragMason(waveDragMason *myWaveDragMason) { + // run wave drag calculation by Mason over the current polar set + for (size_t polarID(0); polarID < currentPolarSet.cleanPolars.size(); ++polarID) { + double sweepPosition(0.0); + if (currentPolarSet.cleanPolars.at(polarID).MachNumber < 0.7) { + sweepPosition = 0.25; + } else { + sweepPosition = 0.5; + } + for (size_t pointID(0); pointID < currentPolarSet.cleanPolars.at(polarID).Points.size(); ++pointID) { + currentPolarSet.cleanPolars.at(polarID).PointsWing.at(pointID).CD_wave + = myWaveDragMason->calculateWaveDrag(currentPolarSet.cleanPolars.at(polarID).Points.at(pointID), + currentPolarSet.cleanPolars.at(polarID).MachNumber, + 0, sweepPosition, currentPolarSet.cleanPolars.at(polarID).PointsWing.at(pointID).yStations, + currentPolarSet.cleanPolars.at(polarID).PointsWing.at(pointID).Cl_distr, true); + currentPolarSet.cleanPolars.at(polarID).PointsStab.at(pointID).CD_wave + = myWaveDragMason->calculateWaveDrag(currentPolarSet.cleanPolars.at(polarID).Points.at(pointID), + currentPolarSet.cleanPolars.at(polarID).MachNumber, + 1, sweepPosition, currentPolarSet.cleanPolars.at(polarID).PointsStab.at(pointID).yStations, + currentPolarSet.cleanPolars.at(polarID).PointsStab.at(pointID).Cl_distr, false); + currentPolarSet.cleanPolars.at(polarID).Points.at(pointID).CD_wave = currentPolarSet.cleanPolars.at(polarID).PointsWing.at(pointID).CD_wave + + currentPolarSet.cleanPolars.at(polarID).PointsStab.at(pointID).CD_wave; + } + } + myRuntimeInfo->out << "... Wave drag has been calculated sucessfully!" << endl; +} + +void tandemDefaultStrategy::sumUpDragComponents() { + myRuntimeInfo->out << "Sum up drag components" << endl; + for (size_t polarID(0); polarID < currentPolarSet.cleanPolars.size(); ++polarID) { + for (size_t pointID(0); pointID < currentPolarSet.cleanPolars.at(polarID).Points.size(); ++pointID) { + currentPolarSet.cleanPolars.at(polarID).Points.at(pointID).CD = currentPolarSet.cleanPolars.at(polarID).Points.at(pointID).CD_ind + + currentPolarSet.cleanPolars.at(polarID).Points.at(pointID).CD_visc + + currentPolarSet.cleanPolars.at(polarID).Points.at(pointID).CD_wave; + } + } +} + +void tandemDefaultStrategy::copyWingDevicesAndStabilizer(semiEmpiricalHighLiftAdaption *mySemiEmpHLAdaption) { + myRuntimeInfo->out << "Copy wing devices" << endl; + for (size_t deviceID(0); deviceID < data_->numberDevices; ++deviceID) { + semiEmpiricalHighLiftAdaption::WingDevice* aWingDevice = new semiEmpiricalHighLiftAdaption::WingDevice; + aWingDevice->name = data_->wingDevices.at(deviceID).type; + aWingDevice->innerRelFwdChordPosition = data_->wingDevices.at(deviceID).innerRelFwdChordPosition; + aWingDevice->innerRelAftChordPosition = data_->wingDevices.at(deviceID).innerRelAftChordPosition; + aWingDevice->outerRelFwdChordPosition = data_->wingDevices.at(deviceID).outerRelFwdChordPosition; + aWingDevice->outerRelAftChordPosition = data_->wingDevices.at(deviceID).outerRelAftChordPosition; + aWingDevice->innerSpan_rel = data_->wingDevices.at(deviceID).innerRelSpanPosition; + aWingDevice->outerSpan_rel = data_->wingDevices.at(deviceID).outerRelSpanPosition; + mySemiEmpHLAdaption->wingDevices.push_back(*aWingDevice); + } + // stabilizer has to be optional + bool stabilizer = true; + if (stabilizer) { + mySemiEmpHLAdaption->hasStabilizer = true; + mySemiEmpHLAdaption->theStabilizer = liftingSurfaces.at(1); + } +} + +void tandemDefaultStrategy::copyCleanPolarForHLCalculation(semiEmpiricalHighLiftAdaption *mySemiEmpHLAdaption, liftingLineForTAW *myLiftingLineForTAW) { + // find polar with minimum mach number + double minMachNumber(1.0); + size_t minMachID; + for (std::pair<size_t, tawDefaultPolar> polarIterator : currentPolarSet.cleanPolars) { + if (polarIterator.second.MachNumber < minMachNumber) { + minMachID = polarIterator.first; + minMachNumber = polarIterator.second.MachNumber; + } + } + // copy clean polar to HL method + mySemiEmpHLAdaption->theCleanPolar.MachNumber = currentPolarSet.cleanPolars.at(minMachID).MachNumber; + mySemiEmpHLAdaption->theCleanPolar.altitude = currentPolarSet.cleanPolars.at(minMachID).altitude; + mySemiEmpHLAdaption->theCleanPolar.extrapolationMargin = currentPolarSet.cleanPolars.at(minMachID).extrapolationMargin; + mySemiEmpHLAdaption->theCleanPolar.allowGridChange = currentPolarSet.cleanPolars.at(minMachID).allowGridChange; + mySemiEmpHLAdaption->theCleanPolar.ReynoldsNumber = currentPolarSet.cleanPolars.at(minMachID).ReynoldsNumber; + mySemiEmpHLAdaption->theCleanPolar.Config = currentPolarSet.cleanPolars.at(minMachID).Config; + for (size_t pointID(0); pointID < currentPolarSet.cleanPolars.at(minMachID).Points.size(); ++pointID) { + mySemiEmpHLAdaption->theCleanPolar.PolarPoints.push_back(PolarPoint()); + mySemiEmpHLAdaption->theCleanPolar.PolarPoints.back().AoA = currentPolarSet.cleanPolars.at(minMachID).Points.at(pointID).AoA; + mySemiEmpHLAdaption->theCleanPolar.PolarPoints.back().CL = currentPolarSet.cleanPolars.at(minMachID).Points.at(pointID).CL; + mySemiEmpHLAdaption->theCleanPolar.PolarPoints.back().CD = currentPolarSet.cleanPolars.at(minMachID).Points.at(pointID).CD; + mySemiEmpHLAdaption->theCleanPolar.PolarPoints.back().CM = currentPolarSet.cleanPolars.at(minMachID).Points.at(pointID).CM; + mySemiEmpHLAdaption->theCleanPolar.PolarPoints.back().iStabPolar = currentPolarSet.cleanPolars.at(minMachID).Points.at(pointID).iStabPolar; + } + // copy other neccesary values from lifting line calculation + mySemiEmpHLAdaption->CLmaxTO_req = 1.0; + mySemiEmpHLAdaption->CLmaxLDG_req = 1.0; + mySemiEmpHLAdaption->stepWidthCL = config_->stepWidthCL.value(); + mySemiEmpHLAdaption->reductionDragCountsHighLift = config_->deltaTotalDragHL.value(); + mySemiEmpHLAdaption->factorDragHighLift = config_->factorDragHL.value(); + mySemiEmpHLAdaption->CDmin_inc = myLiftingLineForTAW->theAnalyticalPolarData.CDmin_inc.at(0); + mySemiEmpHLAdaption->kFactor_inc = myLiftingLineForTAW->theAnalyticalPolarData.kFactor_inc.at(0); + mySemiEmpHLAdaption->CLatCDmin_inc = myLiftingLineForTAW->theAnalyticalPolarData.CLatCDmin_inc.at(0); + mySemiEmpHLAdaption->dCMtodCL_inc = myLiftingLineForTAW->theAnalyticalPolarData.dCMtodCL_inc.at(0); + mySemiEmpHLAdaption->CMatCL0_inc = myLiftingLineForTAW->theAnalyticalPolarData.CMatCL0_inc.at(0); + mySemiEmpHLAdaption->dCMtodAoA = myLiftingLineForTAW->theAnalyticalPolarData.dCMtodAoA.at(0); + mySemiEmpHLAdaption->dCLtodAoA = myLiftingLineForTAW->theAnalyticalPolarData.dCLtodAoA.at(0); + mySemiEmpHLAdaption->CLatAoA0 = myLiftingLineForTAW->theAnalyticalPolarData.CLatAoA0.at(0); + mySemiEmpHLAdaption->CMatAoA0 = myLiftingLineForTAW->theAnalyticalPolarData.CMatAoA0.at(0); +} + +void tandemDefaultStrategy::calculateHighLiftPolars(semiEmpiricalHighLiftAdaption *mySemiEmpHLAdaption, const double CoG_X_Position, const double currentIStabAngle) { + for (size_t configID(0); configID < HLconfigs.size(); ++configID) { + myRuntimeInfo->out << "Calculate high lift polar for " << HLconfigs.at(configID) << endl; + Polar aPolar = mySemiEmpHLAdaption->calculateHighLiftPolar(HLconfigs.at(configID), CoG_X_Position, currentIStabAngle); + currentPolarSet.highLiftPolars[HLconfigs.at(configID)] = tawDefaultPolar(); + // copy polar data + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).Config = HLconfigs.at(configID); + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).extrapolationMargin = aPolar.extrapolationMargin; + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).allowGridChange = aPolar.allowGridChange; + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).altitude = aPolar.altitude; + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).MachNumber = aPolar.MachNumber; + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).ReynoldsNumber = aPolar.ReynoldsNumber; + for (size_t pointID(0); pointID < aPolar.PolarPoints.size(); ++pointID) { + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).Points.push_back(defaultPolarPoint()); + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).Points.back().AoA = aPolar.PolarPoints.at(pointID).AoA; + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).Points.back().CL = aPolar.PolarPoints.at(pointID).CL; + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).Points.back().CD = aPolar.PolarPoints.at(pointID).CD; + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).Points.back().CM = aPolar.PolarPoints.at(pointID).CM; + currentPolarSet.highLiftPolars.at(HLconfigs.at(configID)).Points.back().iStabPolar = aPolar.PolarPoints.at(pointID).iStabPolar; + } + } +} + +void tandemDefaultStrategy::copyPolarsToCGMap(const size_t CGID, const size_t stabID) { + polarDataCGMap[CGID][stabID] = currentPolarSet; +} + +void tandemDefaultStrategy::clearDataForNextCalculationRun() { + currentPolarSet.cleanPolars.clear(); + currentPolarSet.highLiftPolars.clear(); + liftingSurfaces.clear(); +} + +void tandemDefaultStrategy::doTrimInterpolation() { + for (size_t CGID(0); CGID < config_->CGPositions.size(); ++CGID) { + vector<vector<trimInterpolation::interpolationPoint>> polarSet; + // copy polar data into the generalized interpolation container + for (size_t polarID(0); polarID < polarDataCGMap.at(CGID).at(0).cleanPolars.size(); ++polarID) { + myRuntimeInfo->out << "Interpolate trim for clean polars at " << config_->CGPositions.at(CGID) << " CoG at Ma " << config_->machNumbers.at(polarID) << "..." << endl; + for (size_t stabID(0); stabID < config_->stabAngles.size(); ++stabID) { + vector<trimInterpolation::interpolationPoint> aStabPolar; + for (size_t pointID(0); pointID < polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.size(); ++pointID) { + trimInterpolation::interpolationPoint anInterpolationPoint; + anInterpolationPoint.CL = polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.at(pointID).CL; + anInterpolationPoint.CM = polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.at(pointID).CM; + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.at(pointID).CD); + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.at(pointID).AoA); + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.at(pointID).iStabPolar); + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.at(pointID).CD_ind); + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.at(pointID).CD_visc); + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).Points.at(pointID).CD_wave); + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).PointsWing.at(pointID).CD_wave); + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).PointsStab.at(pointID).CD_ind); + anInterpolationPoint.values.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).PointsStab.at(pointID).CD_wave); + // interpolate additional values for cruise mach polar + if (accuracyCheck(data_->initialCruiseMachNumber, polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).MachNumber, ACCURACY_HIGH)) { + anInterpolationPoint.vectorValues.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).PointsWing.at(pointID).Cl_distr); + anInterpolationPoint.vectorValues.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).PointsWing.at(pointID).Lift_distr); + anInterpolationPoint.vectorValues.push_back(polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(polarID).PointsWing.at(pointID).yStations); + } + aStabPolar.push_back(anInterpolationPoint); + } + polarSet.push_back(aStabPolar); + } + // interpolate the current polar set + trimInterpolation* myTrimInterpolation = new trimInterpolation(); + vector<trimInterpolation::interpolationPoint> interpolatedTrimPolar = myTrimInterpolation->interpolateTrim(polarSet, true); + polarSet.clear(); + // copy data to polarDataTrimMap + polarDataTrimMap[CGID].cleanPolars[polarID].MachNumber = polarDataCGMap.at(CGID).at(0).cleanPolars.at(polarID).MachNumber; + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).ReynoldsNumber = polarDataCGMap.at(CGID).at(0).cleanPolars.at(polarID).ReynoldsNumber; + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).altitude = polarDataCGMap.at(CGID).at(0).cleanPolars.at(polarID).altitude; + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).extrapolationMargin = polarDataCGMap.at(CGID).at(0).cleanPolars.at(polarID).extrapolationMargin; + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).allowGridChange = polarDataCGMap.at(CGID).at(0).cleanPolars.at(polarID).allowGridChange; + for (size_t pointID(0); pointID < interpolatedTrimPolar.size(); ++pointID) { + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).Points.push_back(defaultPolarPoint()); + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).PointsWing.push_back(defaultPolarPointLiftSurface()); + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).Points.back().CL = interpolatedTrimPolar.at(pointID).CL; + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).Points.back().CM = interpolatedTrimPolar.at(pointID).CM; + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).Points.back().CD = interpolatedTrimPolar.at(pointID).values.at(0); + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).Points.back().AoA = interpolatedTrimPolar.at(pointID).values.at(1); + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).Points.back().iStabPolar = interpolatedTrimPolar.at(pointID).values.at(2); + if (accuracyCheck(data_->initialCruiseMachNumber, polarDataTrimMap.at(CGID).cleanPolars.at(polarID).MachNumber, ACCURACY_HIGH)) { + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).PointsWing.back().Cl_distr = interpolatedTrimPolar.at(pointID).vectorValues.at(0); + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).PointsWing.back().Lift_distr = interpolatedTrimPolar.at(pointID).vectorValues.at(1); + polarDataTrimMap.at(CGID).cleanPolars.at(polarID).PointsWing.back().yStations = interpolatedTrimPolar.at(pointID).vectorValues.at(2); + } + } + } + } + myRuntimeInfo->out << "All polars are trimmed!" << endl; +} + +void tandemDefaultStrategy::doTrimInterpolationHighLift() { + // TBA +} + +void tandemDefaultStrategy::copyCleanPolars() { + for (size_t CGID(0); CGID < config_->CGPositions.size(); ++CGID) { + for (size_t polarID(0); polarID < polarDataCGMap.at(CGID).at(0).cleanPolars.size(); ++polarID) { + polarDataTrimMap[CGID].cleanPolars[polarID] = polarDataCGMap.at(CGID).at(0).cleanPolars.at(polarID); + } + } +} + +void tandemDefaultStrategy::copyHighLiftPolars() { + for (size_t CGID(0); CGID < config_->CGPositions.size(); ++CGID) { + for (size_t configID(0); configID < HLconfigs.size(); ++configID) { + polarDataTrimMap[CGID].highLiftPolars[HLconfigs.at(configID)] = polarDataCGMap.at(CGID).at(config_->neutralStabAngleID).highLiftPolars.at(HLconfigs.at(configID)); + } + } +} + +void tandemDefaultStrategy::calibratePolars() { + if (!(accuracyCheck(config_->factorDragCleanPolar.value(), 1.0, ACCURACY_HIGH) && accuracyCheck(config_->deltaTotalDragCleanPolar.value(), 0.0, ACCURACY_HIGH))) { + calibrateCleanPolars(); + } + if (!(accuracyCheck(config_->factorDragHighLiftPolar.value(), 1.0, ACCURACY_HIGH) && accuracyCheck(config_->deltaTotalDragHighLift.value(), 0.0, ACCURACY_HIGH))) { + calibrateHighLiftPolars(); + } +} + +void tandemDefaultStrategy::calibrateCleanPolars() { + myRuntimeInfo->out << "Apply calibration factors for clean polars ..." << endl; + for (size_t CGID(0); CGID < polarDataTrimMap.size(); ++CGID) { + for (size_t machID(0); machID < polarDataTrimMap.at(CGID).cleanPolars.size(); ++machID) { + for (size_t pointID(0); pointID < polarDataTrimMap.at(CGID).cleanPolars.at(machID).Points.size(); ++pointID) { + polarDataTrimMap.at(CGID).cleanPolars.at(machID).Points.at(pointID).CD = + polarDataTrimMap.at(CGID).cleanPolars.at(machID).Points.at(pointID).CD * config_->factorDragCleanPolar.value(); + polarDataTrimMap.at(CGID).cleanPolars.at(machID).Points.at(pointID).CD += config_->deltaTotalDragCleanPolar.value(); + } + } + } +} + +void tandemDefaultStrategy::calibrateHighLiftPolars() { + myRuntimeInfo->out << "Apply calibration factors for high lift polars ..." << endl; + for (size_t CGID(0); CGID < polarDataTrimMap.size(); ++CGID) { + for (size_t configID(0); configID < HLconfigs.size(); ++configID) { + for (size_t pointID(0); pointID < polarDataTrimMap.at(CGID).highLiftPolars.at(HLconfigs.at(configID)).Points.size(); ++pointID) { + polarDataTrimMap.at(CGID).highLiftPolars.at(HLconfigs.at(configID)).Points.at(pointID).CD = + polarDataTrimMap.at(CGID).highLiftPolars.at(HLconfigs.at(configID)).Points.at(pointID).CD * config_->factorDragHighLiftPolar.value(); + polarDataTrimMap.at(CGID).highLiftPolars.at(HLconfigs.at(configID)).Points.at(pointID).CD += config_->deltaTotalDragHighLift.value(); + } + } + } +} + +void tandemDefaultStrategy::writePolarXML() { + myRuntimeInfo->out << "Create XML-Polar file ..." << endl; + // Construct the file path and convert to absolute path + std::filesystem::path filePath = std::filesystem::absolute(this->rtIO_->getAeroDataDir() + "/"); + // Ensure the directory exists + if (!std::filesystem::exists(filePath.parent_path())) { + std::filesystem::create_directories(filePath.parent_path()); + } + for (size_t CGID(0); CGID < polarDataTrimMap.size(); ++CGID) { + polarXMLFilePath = rtIO_->getAeroDataDir() + "/"; + polarXMLFilePath += rtIO_->aircraft_model(); + if (!config_->doTrim.value()) { + this->polarXMLFilePath += "_polar.xml"; + } else { + this->polarXMLFilePath += "_" + config_->CGPositions.at(CGID) + "_trimmed_polar.xml"; + } + // file name for design case and sizing loop + if (CGID == 0) { + this->designPolarXMLFilePath = polarXMLFilePath; + this->designPolarXMLFilePath = designPolarXMLFilePath.substr(designPolarXMLFilePath.find_last_of("/") + 1); + } + ofstream XML; + XML.open(polarXMLFilePath.c_str()); + if (!XML) { + myRuntimeInfo->err << polarXMLFilePath + " could not be opened!" << endl; + exit(1); + } else { + XML << "<?xml version=\"1.0\"?>" << endl; + XML << "<polar-exchange-file version=\"1.0\">" << endl; + XML << " <comment>The 'PEF-Browser' application, a polar file converter is available in the software section at:"; + XML << " http://www.MH-AeroTools.de/airfoils/</comment>" << endl; + XML << " <liftingLineVersion>" << LILI_Version << "</liftingLineVersion>" << endl; + XML << " <dragComponentMethods>" << endl; + XML << " <inducedDrag>Lifting Line + Corrections for fuselage and nacelles</inducedDrag>" << endl; + XML << " <viscousDrag>" << "Raymer" << "</viscousDrag>" << endl; + XML << " <waveDrag>" << "Mason" << "</waveDrag>" << endl; + XML << " </dragComponentMethods>" << endl; + XML << " <configurations>" << endl; + XML << " <name>" << rtIO_->aircraft_model() << "</name>" << endl; + XML << " <comment>Polars for wing configuration</comment>" << endl; + XML << " <configuration ID=\"clean\">" << endl; + XML << " <name>Clean</name>" << endl; + XML << " <comment>Clean Configuration</comment>" << endl; + XML << " <polars>" << endl; + for (size_t MachID(0); MachID < polarDataTrimMap.at(CGID).cleanPolars.size(); MachID++) { + XML << " <polar ID=\"" << MachID + 1 << "\" ExtrapolationMargin=\"" << polarDataTrimMap.at(CGID).cleanPolars.at(MachID).extrapolationMargin + << "\" AllowGridChange=\"" << polarDataTrimMap.at(CGID).cleanPolars.at(MachID).allowGridChange <<"\">" << endl; + XML << " <name>" << "---" << "</name>" << endl; + XML << " <reynoldsnumber>" <<polarDataTrimMap.at(CGID).cleanPolars.at(MachID).ReynoldsNumber << "</reynoldsnumber>" << endl; + XML << " <altitude>" <<polarDataTrimMap.at(CGID).cleanPolars.at(MachID).altitude << "</altitude>" << endl; + XML << " <machnumber>" << polarDataTrimMap.at(CGID).cleanPolars.at(MachID).MachNumber << "</machnumber>" << endl; + std::string Alpha_str(""), Cl_str(""), Cd_str(""), Cd_turb_str(""), Cm_str(""), origin_polar_str(""), i_stab_str(""); + for (size_t i(0); i < polarDataTrimMap.at(CGID).cleanPolars.at(MachID).Points.size(); ++i) { + Alpha_str += num2Str(polarDataTrimMap.at(CGID).cleanPolars.at(MachID).Points.at(i).AoA); + Cl_str += num2Str(polarDataTrimMap.at(CGID).cleanPolars.at(MachID).Points.at(i).CL); + Cd_str += num2Str(polarDataTrimMap.at(CGID).cleanPolars.at(MachID).Points.at(i).CD); + Cd_turb_str += num2Str(polarDataTrimMap.at(CGID).cleanPolars.at(MachID).Points.at(i).CD); + Cm_str += num2Str(polarDataTrimMap.at(CGID).cleanPolars.at(MachID).Points.at(i).CM); + origin_polar_str += "seg0-0.0"; + i_stab_str += num2Str(polarDataTrimMap.at(CGID).cleanPolars.at(MachID).Points.at(i).iStabPolar); + if (i < polarDataTrimMap.at(CGID).cleanPolars.at(MachID).Points.size() - 1) { + Alpha_str += ";"; + Cl_str += ";"; + Cd_str += ";"; + Cd_turb_str += ";"; + Cm_str += ";"; + origin_polar_str += ";"; + i_stab_str += ";"; + } + } + XML << " <Alpha>" << Alpha_str << "</Alpha>" << endl; + XML << " <Cl>" << Cl_str << "</Cl>" << endl; + XML << " <Cd>" <<Cd_str << "</Cd>" << endl; + XML << " <Cd_turb>" << Cd_turb_str << "</Cd_turb>" << endl; + XML << " <Cm>" << Cm_str << "</Cm>" << endl; + XML << " <origin_polar>"<< origin_polar_str << "</origin_polar>" << endl; + XML << " <iStab_polar>"<< i_stab_str << "</iStab_polar>" << endl; + XML << " </polar>" << endl; + } + XML << " </polars>" << endl; + XML << " </configuration>" << endl; + for (const pair<const string, tawDefaultPolar>& thePolarIterator : polarDataTrimMap.at(CGID).highLiftPolars) { + XML << " <configuration ID=\"" << thePolarIterator.first << "\">" << endl; + XML << " <name>" << thePolarIterator.first << "</name>" << endl; + XML << " <comment>" << thePolarIterator.first << " Configuration</comment>" << endl; + XML << " <polars>" << endl; + // Inner config loop: Since the myAcftPt->highLiftPolar elements are ordered by config name, configs can be gathered here until the next one appears. + XML << " <polar ID=\"" << num2Str(1) << "\" ExtrapolationMargin =\"" << thePolarIterator.second.extrapolationMargin + << "\" AllowGridChange=\"" << thePolarIterator.second.allowGridChange << "\">" << endl; + XML << " <name>" << "---" << "</name>" << endl; + XML << " <reynoldsnumber>" << thePolarIterator.second.ReynoldsNumber << "</reynoldsnumber>" << endl; + XML << " <altitude>" << thePolarIterator.second.altitude << "</altitude>" << endl; + XML << " <machnumber>" <<thePolarIterator.second.MachNumber << "</machnumber>" << endl; + std::string Alpha_str(""), Cl_str(""), Cd_str(""), Cm_str(""), origin_polar_str(""), i_stab_str(""); + for (size_t j(0); j < thePolarIterator.second.Points.size(); ++j) { + Alpha_str += num2Str(thePolarIterator.second.Points.at(j).AoA); + Cl_str += num2Str(thePolarIterator.second.Points.at(j).CL); + Cd_str += num2Str(thePolarIterator.second.Points.at(j).CD); + Cm_str += num2Str(thePolarIterator.second.Points.at(j).CM); + origin_polar_str += "seg0-0.0"; + i_stab_str += num2Str(thePolarIterator.second.Points.at(j).iStabPolar); + if (j < thePolarIterator.second.Points.size() - 1) { + Alpha_str += ";"; + Cl_str += ";"; + Cd_str += ";"; + Cm_str += ";"; + origin_polar_str += ";"; + i_stab_str += ";"; + } + } + XML << " <Alpha>" << Alpha_str << "</Alpha>" << endl; + XML << " <Cl>" << Cl_str << "</Cl>" << endl; + XML << " <Cd>" <<Cd_str << "</Cd>" << endl; + XML << " <Cm>" << Cm_str << "</Cm>" << endl; + XML << " <origin_polar>"<< origin_polar_str << "</origin_polar>" << endl; + XML << " <iStab_polar>"<< i_stab_str << "</iStab_polar>" << endl; + XML << " </polar>" << endl; + XML << " </polars>" << endl; + XML << " </configuration>" << endl; + } + XML << " </configurations>" << endl; + XML << "</polar-exchange-file>" << endl; + } + XML.close(); + } +} + +void tandemDefaultStrategy::writePolarData() { + ofstream plot; + /* plot all untrimmed polars */ + for (size_t CGID(0); CGID < polarDataCGMap.size(); ++CGID) { + for (const pair<const double, PolarData>& thePolarIterator : polarDataCGMap.at(CGID)) { + /* plot all clean polars */ + for (const pair<const int, tawDefaultPolar>& theMachIDIterator : thePolarIterator.second.cleanPolars) { + stringstream machNumber; + stringstream iStabStream; + machNumber << setprecision(2) << fixed << theMachIDIterator.second.MachNumber; + iStabStream << setprecision(2) << fixed << Rounding(config_->stabAngles.at(thePolarIterator.first), 2); + std::string csvFiles = "tawCalculatePolar_M" + replaceAll(machNumber.str(), ".", "") + "_" + + CoGnames.at(CGID) + "_" + replaceAll(iStabStream.str(), ".", "") +"_plot.csv"; + plot.open(csvFiles.c_str()); + if (!plot) { + myRuntimeInfo->err << csvFiles + " could not be opened!" << endl; + exit(1); + } else { + plot << "# " + csvFiles << endl; + plot << "# Clean Polar" << endl; + plot << "# Mach Number " << theMachIDIterator.second.MachNumber << endl; + plot << "AoA; C_L; C_Dtotal; C_Dind; C_Dvisc; C_Dwave; C_M; L/D; i_stab; C_Dvisc_wing; " + << "C_Dwave_wing; C_Dvisc_stab; C_Dwave_stab; C_Dind_stab; C_L_stab" << endl; + for (size_t i(0); i < theMachIDIterator.second.Points.size(); ++i) { + plot << setprecision(3) << fixed << theMachIDIterator.second.Points.at(i).AoA << ";"; + plot << setprecision(4) << fixed << theMachIDIterator.second.Points.at(i).CL << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.Points.at(i).CD << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.Points.at(i).CD_ind << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.Points.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.Points.at(i).CD_wave << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.Points.at(i).CM << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.Points.at(i).CL / theMachIDIterator.second.Points.at(i).CD << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.Points.at(i).iStabPolar << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.PointsWing.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.PointsWing.at(i).CD_wave << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.PointsStab.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.PointsStab.at(i).CD_wave << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.PointsStab.at(i).CD_ind << ";"; + plot << setprecision(6) << fixed << theMachIDIterator.second.PointsStab.at(i).CL << ";"; + plot << endl; + } + } + plot.close(); + } + } + } + for (size_t CGID(0); CGID < polarDataCGMap.size(); ++CGID) { + for (const pair<const double, PolarData>& thePolarIterator : polarDataCGMap.at(CGID)) { + /* plot all clean polars */ + for (const pair<const std::string, tawDefaultPolar>& theConfigIterator : thePolarIterator.second.highLiftPolars) { + stringstream machNumber; + stringstream iStabStream; + machNumber << setprecision(2) << fixed << theConfigIterator.second.MachNumber; + iStabStream << setprecision(2) << fixed << Rounding(config_->stabAngles.at(thePolarIterator.first), 2); + std::string csvFiles = "tawCalculatePolar_" + theConfigIterator.first + "_" + + CoGnames.at(CGID) + "_" + replaceAll(iStabStream.str(), ".", "") +"_plot.csv"; + plot.open(csvFiles.c_str()); + if (!plot) { + myRuntimeInfo->err << csvFiles + " could not be opened!" << endl; + exit(1); + } else { + plot << "# " + csvFiles << endl; + plot << "# Clean Polar" << endl; + plot << "# Mach Number " << theConfigIterator.second.MachNumber << endl; + plot << "AoA; C_L; C_Dtotal; C_M; i_stab;" << endl; + for (size_t i(0); i < theConfigIterator.second.Points.size(); ++i) { + plot << setprecision(3) << fixed << theConfigIterator.second.Points.at(i).AoA << ";"; + plot << setprecision(4) << fixed << theConfigIterator.second.Points.at(i).CL << ";"; + plot << setprecision(6) << fixed << theConfigIterator.second.Points.at(i).CD << ";"; + plot << setprecision(6) << fixed << theConfigIterator.second.Points.at(i).CM << ";"; + plot << setprecision(6) << fixed << theConfigIterator.second.Points.at(i).CL / theConfigIterator.second.Points.at(i).CD << ";"; + plot << setprecision(6) << fixed << theConfigIterator.second.Points.at(i).iStabPolar << ";"; + plot << endl; + } + } + plot.close(); + } + } + } + size_t cruiseMachID(0); + stringstream machNumber; + machNumber << setprecision(2) << fixed << data_->initialCruiseMachNumber; + for (size_t machID(0); machID < polarDataTrimMap.at(0).cleanPolars.size(); ++machID) { + if (accuracyCheck(polarDataTrimMap.at(0).cleanPolars.at(machID).MachNumber, data_->initialCruiseMachNumber, ACCURACY_HIGH)) { + cruiseMachID = machID; + break; + } + } + std::string csvFiles = "tawCalculatePolar_liftDistribution_" + replaceAll(machNumber.str(), ".", "") +"_plot.csv"; + plot.open(csvFiles.c_str()); + if (!plot) { + myRuntimeInfo->err << csvFiles + " could not be opened!" << endl; + exit(1); + } else { + plot << "# " + csvFiles << endl; + plot << "# (1)C_L; (2)C_Lw; (3)y, m; (4)C_l; (5)Cl*l, m" << endl; + for (size_t pointID(0); pointID < polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).PointsWing.size(); ++pointID) { + vector <double> clDistribution_tmp = polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).PointsWing.at(pointID).Cl_distr; + vector <double> yStations_tmp = polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).PointsWing.at(pointID).yStations; + reverse(clDistribution_tmp.begin(), clDistribution_tmp.end()); + reverse(yStations_tmp.begin(), yStations_tmp.end()); + // for Cl distr analysis at single CL + double CL_tmp(0.51); + if (true || fabs(polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CL - CL_tmp) < 1e-5) { // uncomment "true || " for analysis + string delimiter(";"); + for (size_t j(0); j < clDistribution_tmp.size(); ++j) { + plot << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CL << delimiter; + plot << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).PointsWing.at(pointID).CL << delimiter; + plot << yStations_tmp.at(j) << delimiter; + plot << clDistribution_tmp.at(j) << delimiter; + plot << getLocalChordLength(liftingSurfaces.front(), yStations_tmp.at(j)) << endl; + } + plot << endl << endl; + } + } + plot.close(); + } + std::string csvFile = "trimmed_designCruisePolar_" + replaceAll(machNumber.str(), ".", "") +"_plot.csv"; + plot.open(csvFile.c_str()); + if (!plot) { + myRuntimeInfo->err << csvFile + " could not be opened!" << endl; + exit(1); + } else { + plot << "# " + csvFile << endl; + plot << "AoA; C_L; C_Dtotal; C_Dind; C_Dvisc; C_Dwave; C_M; L/D; i_stab" << endl; + for (size_t pointID(0); pointID < polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.size(); ++pointID) { + plot << setprecision(3) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).AoA << ";"; + plot << setprecision(4) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CL << ";"; + plot << setprecision(6) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CD << ";"; + plot << setprecision(6) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CD_ind << ";"; + plot << setprecision(6) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CD_visc << ";"; + plot << setprecision(6) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CD_wave << ";"; + plot << setprecision(6) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CM << ";"; + plot << setprecision(6) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CL + / polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).CD << ";"; + plot << setprecision(6) << fixed << polarDataTrimMap.at(0).cleanPolars.at(cruiseMachID).Points.at(pointID).iStabPolar << ";"; + plot << endl; + } + plot.close(); + } +} + +void tandemDefaultStrategy::writeViscDragData() { + ofstream plot; + for (size_t CGID(0); CGID < polarDataCGMap.size(); ++CGID) { + for (size_t stabID(0); stabID < polarDataCGMap.at(CGID).size(); ++stabID) { + for (size_t machID(0); machID < polarDataCGMap.at(CGID).at(stabID).cleanPolars.size(); ++machID) { + stringstream machNumber; + stringstream iStabStream; + machNumber << setprecision(2) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).MachNumber; + iStabStream << setprecision(2) << fixed << Rounding(config_->stabAngles.at(stabID), 2); + std::string csvFile = "viscDrag_M" + replaceAll(machNumber.str(), ".", "") + "_" + + CoGnames.at(CGID) + "_" + replaceAll(iStabStream.str(), ".", "") +"_plot.csv"; + plot.open(csvFile.c_str()); + if (!plot) { + myRuntimeInfo->err << csvFile + " could not be opened!" << endl; + exit(1); + } else { + plot << "# " + csvFile << endl; + plot << "# Reynolds Number" << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).ReynoldsNumber << endl; + plot << "# Clean Polar" << endl; + plot << "# Mach Number " << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).MachNumber << endl; + plot << "AoA; C_L; C_D_visc; C_D_visc_Wing; C_D_visc_Stab; C_D_visc_Fin; C_D_visc_Fuselage; C_D_visc_Nacelles; C_D_visc_Misc;" << endl; + for (size_t i(0); i < polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).Points.size(); ++i) { + plot << setprecision(3) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).Points.at(i).AoA << ";"; + plot << setprecision(3) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).Points.at(i).CL << ";"; + plot << setprecision(6) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).Points.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).PointsWing.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).PointsStab.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).PointsFin.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).PointsFuselage.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).PointsNacelles.at(i).CD_visc << ";"; + plot << setprecision(6) << fixed << polarDataCGMap.at(CGID).at(stabID).cleanPolars.at(machID).PointsMisc.at(i).CD_visc << ";"; + plot << endl; + } + } + plot.close(); + } + } + } +} + +void tandemDefaultStrategy::setReferenceValues() { + data_->span.set_value(getHalfSpan(liftingSurfaces.at(0)) * 2); + data_->MAC.set_value(geom2::measure::mean_aerodynamic_chord(liftingSurfaces.at(0))); + data_->S_ref.set_value(geom2::measure::reference_area(liftingSurfaces.at(0))); + data_->neutral_point_xCoordinate.set_value(getNeutralPointXposition(getTrimmedCruisePolar(polarDataCGMap.at(0).at(0).cleanPolars, data_->initialCruiseMachNumber), + data_->MAC.value(), data_->CoGPositions["design"].xCoordinate)); +} + +void tandemDefaultStrategy::setOutputValues() { + data_->C_L_optimumCruise.set_value(getCLoptCruise()); + data_->CL_max_landing.set_value(getMaxCL(polarDataTrimMap.at(0).highLiftPolars.at("landing"))); + data_->C_LmaxTO.set_value(getMaxCL(polarDataTrimMap.at(0).highLiftPolars.at("takeoff"))); + data_->C_LgroundRoll.set_value(0.4); + data_->max_spoiler_factor.set_value(2.5); + // handle the axcml entries + data_->polar_file.set_value(this->designPolarXMLFilePath); + data_->polar_file.update(rtIO_->acxml); + vector<std::string>types{"cruise", "departure", "departure", "departure", "approach", "approach", "approach"}; + vector<std::string>names{"clean", "takeoff", "takeoff_landing_gear_retracted", "climb", "approach", "approach_landing_gear_out", "landing"}; + //Write aerodynamic node with description and tool level + rtIO_->acxml.at("analysis/aerodynamics").addAttrib("description", "Aerodynamical analysis"); + rtIO_->acxml.at("analysis/aerodynamics").addAttrib("tool_level", EndnodeReadOnly<std::string>("control_settings/own_tool_level").read(rtIO_->moduleConfig).value()); + std::string subPath = "analysis/aerodynamics/polar"; + Endnode<int> configurations(Endnode<int>(subPath + "/configurations", "Number of configurations in the polar file", types.size())); + configurations.update(rtIO_->acxml); + // setup configuration nodes + for (size_t ID = 0; ID < types.size(); ID++) { + rtIO_->acxml.at(subPath)["configuration@" + num2Str(ID)]; + rtIO_->acxml.at(subPath + "/configuration@" + num2Str(ID)).addAttrib("description", "Configuration in polar file marked with ID - name can vary"); + Endnode<string>type(Endnode<string>(subPath + "/configuration@" + num2Str(ID) + "/type", " Type", "cruise")); + Endnode<string>name(Endnode<string>(subPath + "/configuration@" + num2Str(ID) + "/name", " Name", "clean")); + type.set_value(types.at(ID)); + name.set_value(names.at(ID)); + type.update(rtIO_->acxml); + name.update(rtIO_->acxml); + } +} + +void tandemDefaultStrategy::update_xml_entries(std::string mode) { + data_->updateNodes(mode); +} + +double tandemDefaultStrategy::getCLoptCruise() { + double LoverDmax(0.0); + double CLopt(0.0); + std::vector<defaultPolarPoint> theTrimmedCruisePolar(getTrimmedCruisePolar(polarDataTrimMap.at(0).cleanPolars, data_->initialCruiseMachNumber)); + for (size_t pointID(0); pointID < theTrimmedCruisePolar.size(); ++pointID) { + double LoverD = theTrimmedCruisePolar.at(pointID).CL / theTrimmedCruisePolar.at(pointID).CD; + if (LoverD > LoverDmax) { + LoverDmax = LoverD; + CLopt = theTrimmedCruisePolar.at(pointID).CL; + } + } + return CLopt; +} + +double tandemDefaultStrategy::getMaxCL(const tawDefaultPolar& aPolar) { + double maxCL = -10000; + for (size_t ID = 0; ID < aPolar.Points.size(); ++ID) { + if (aPolar.Points.at(ID).CL > maxCL) { + maxCL = aPolar.Points.at(ID).CL; + } + } + return maxCL; +} diff --git a/aerodynamic_analysis/src/tandem/tandemDefaultStrategy.h b/aerodynamic_analysis/src/tandem/tandemDefaultStrategy.h new file mode 100644 index 0000000000000000000000000000000000000000..efb51500ae619648fd5eddbcb43530fe2b38caf2 --- /dev/null +++ b/aerodynamic_analysis/src/tandem/tandemDefaultStrategy.h @@ -0,0 +1,167 @@ +/* Copyright (C) 2010-2024 Institute of Aerospace Systems, RWTH Aachen University - All rights reserved. + This file is part of UNICADO. + + UNICADO is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UNICADO is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UNICADO. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CALCULATEPOLAR_SRC_TANDEM_TANDEMDEFAULTSTRATEGY_H_ +#define CALCULATEPOLAR_SRC_TANDEM_TANDEMDEFAULTSTRATEGY_H_ + +#include <moduleBasics/runtimeIO.h> + +#include <string> +#include <unordered_map> +#include <vector> +#include <map> +#include <memory> + +#include "tandemCalculatePolarConfig.h" +#include "tandemDefaultData.h" +#include "../polar.h" +#include "../methods/liftingLineForTAW.h" +#include "../methods/liftingLinePolar.h" + +#include "../methods/viscDragRaymer.h" +#include "../methods/waveDragMason.h" +#include "../methods/semiEmpiricalHighLiftAdaption.h" + +class tandemDefaultStrategy { + public: + // geometry bools + // containers for the aircraft geometry + std::vector <geom2::MultisectionSurface<geom2::AirfoilSection>> liftingSurfaces; /**< vector which stores all lifting surface geometries (wing and HTP)*/ + geom2::MultisectionSurface<geom2::AirfoilSection> VTP; /**< the VTP geometry */ + geom2::MultisectionSurface<geom2::PolygonSection> fuselage; /**< the fuselage geometry */ + std::vector <geom2::MultisectionSurface<geom2::PolygonSection>> nacelles; /**< vector which stores the nacelle geometries*/ + struct wingDevice { + std::string type; + double maxPositiveDeflection; + double maxNegativeDeflection; + double innerRelSpanPosition; + double innerRelFwdChordPosition; + double innerRelAftChordPosition; + double outerRelSpanPosition; + double outerRelFwdChordPosition; + double outerRelAftChordPosition; + }; + // container for polar data + struct PolarData { /**< struct for handling of the polar data */ + std::unordered_map<size_t, tandemDefaultPolar> cleanPolars; /**< clean polars indexed by MachID */ + std::unordered_map<std::string, tandemDefaultPolar> highLiftPolars; /**< high lift polars indexed by config */ + }; + PolarData currentPolarSet; /**< temporary polar set which gets overwritten for each new calculation run */ + std::unordered_map<size_t, PolarData> polarDataTrimMap; /**< Polar data ordered by stabilizer angle index */ + std::unordered_map<size_t, std::unordered_map<size_t, PolarData>> polarDataCGMap; /**< Polar data ordered by center of gravity index (0: design, 1: forward, 2; aft) */ + // and by stabilizer angle index + std::vector<std::string> CoGnames; + std::vector<std::string> HLconfigs; + std::string polarXMLFilePath; /**< Path to the polar XML output file, derived from the I/O file path */ + std::string designPolarXMLFilePath; + std::string LILI_Version; + // variables for the acftXML output + double C_LmaxLanding; + double C_LmaxTO; + double C_LoptimumCruise; + + void run(); + /** \brief Function initializes liftingLineForTAW with the required variables + * \param myLiLiInit the lifting line initializer for TAW method with gets initialized + */ + void initializeLiLiforTAW(LiLiforTAWInitialization *myLiLiInit); + /** \brief Function initializes viscDragRaymer with the required variables + * \param myViscDragRaymer the viscous drag raymer method with gets initialized + */ + void initializeViscDragRaymer(viscDragRaymerInitialization *myViscDragInit); + /** \brief Function initializes waveDragMason with the required variables + * \param myWaveDragMason the wave drag mason method with gets initialized + */ + void initializeWaveDragMason(waveDragInitialization *myWaveDragInit); + /** \brief Function with builds and saves the entire aircraft geometry + * \param stabAngle the angle of the stabilizer relative to the design angle, which gets altered for the trimm setting [deg] + */ + void createAircraftGeometry(const double stabAngle); + /** \brief Function witch executes all aero calculation methods + * \param CoGPosition the 3D center of gravity coordinate as reference for the aero moments [m] + */ + void runAeroCalculations(const Point CoGPosition, const double currentIStabAngle); + /** \brief Function to copy the polar set from liftingLineForTAW to the strategyClass + * \param liftingLineForTAW the lifting line for TAW method, which generated the clean polar set + */ + void getPolarDataFromLiftingLine(const liftingLineForTAW& liftingLineForTAW); + /** \brief Function to calculate the viscous drag for the current polar set + * \param myViscDragRaymer the viscous drag raymer method to calculate the drag + */ + void calculateViscDragRaymer(viscDragRaymer *myViscDragRaymer); + /** \brief Function to calculate the wave drag for the current polar set + * \param myWaveDragMason the wave drag mason method to calculate the drag + */ + void calculateWaveDragMason(waveDragMason *myWaveDragMason); + void sumUpDragComponents(); + void copyWingDevicesAndStabilizer(semiEmpiricalHighLiftAdaption *mySemiEmpHLAdaption); + void copyCleanPolarForHLCalculation(semiEmpiricalHighLiftAdaption *mySemiEmpHLAdaption, liftingLineForTAW *myLiftingLineForTAW); + void calculateHighLiftPolars(semiEmpiricalHighLiftAdaption *mySemiEmpHLAdaption, const double CoG_X_Position, const double currentIStabAngle); + /** \brief Copy the temporary current polar set to the permanent polarDataCGMap + * \param CGID index of the current center of gravity position + * \param stabID index of the current stabilizer angle + */ + void copyPolarsToCGMap(const size_t CGID, const size_t stabID); + /** \brief Function to delete temporary data befor next aero calculation run + */ + void clearDataForNextCalculationRun(); + /** \brief Function calls and handles the trim interpolation calculations and data transfer + */ + void doTrimInterpolation(); + /** \brief Function calls and handles the high lift trim interpolation calculations and data transfer + */ + void doTrimInterpolationHighLift(); + /** \brief Function copies the clean polars from the temporary current polar set to the permanent trimmed polar data map + */ + void copyCleanPolars(); + /** \brief Function copies the high lift polars from the temporary current polar set to the permanent trimmed polar data map + */ + void copyHighLiftPolars(); + + void calibratePolars(); + + void calibrateCleanPolars(); + + void calibrateHighLiftPolars(); + + void writePolarXML(); + + void writePolarData(); + + void writeViscDragData(); + + double getCLoptCruise(); + + double getMaxCL(const tawDefaultPolar& aPolar); + + void setReferenceValues(); + + void setOutputValues(); + + void update_xml_entries(std::string mode); + + + tandemDefaultStrategy(const std::shared_ptr<RuntimeIO>& rtIO, const std::shared_ptr<tandemCalculatePolarConfig>& config); + virtual ~tandemDefaultStrategy() {} + + private: + std::shared_ptr<node> aircraft_xml; + const std::shared_ptr<RuntimeIO>& rtIO_; /**< Pointer to the RuntimeIO */ + const std::shared_ptr<tandemDefaultData> data_; /**< Pointer to the aircraft data */ + const std::shared_ptr<tandemCalculatePolarConfig>& config_; /**< Pointer to the config data */ +}; +#endif // CALCULATEPOLAR_SRC_TANDEM_TANDEMDEFAULTSTRATEGY_H_