diff --git a/empennage_design/CMakeLists.txt b/empennage_design/CMakeLists.txt index 3cadc1056d825d5370fbd2821a5c8883f7a30c61..8a3fcfc1909901b6db68c9ae96a290b6f677046b 100644 --- a/empennage_design/CMakeLists.txt +++ b/empennage_design/CMakeLists.txt @@ -11,18 +11,19 @@ set(MODULE_NAME empennage_design) # used for the tests # ============================================== -# Conventional tail files +# BWB - Vertical tails files set(MODULE_SOURCES_BWB_VERTICAL_TAILS # src/bwb/fins/low_fidelity/lowFinsBwb.h # src/conventionaltail/low_/lowConventionaltailPlot.cpp # src/conventionaltail/lowFidelity/lowConventionaltailReport.cpp - # src/conventionaltail/lowFidelity/lowConventionaltail.cpp + # src/conventionaltail/lowFidelity/lowConventionaltail.cpp # src/conventionaltail/higherFidelity/higherConventionaltail.cpp src/bwb/vertical_tails/low/LowVerticalTailsBwb.cpp src/bwb/vertical_tails/bwbVerticalTailsData.cpp src/bwb/vertical_tails/bwbVerticalTailsConfig.cpp ) +# TAW - Conventional tail files set(MODULE_SOURCES_TAW_CONVENTIONAL src/taw/conventional/low/lowConventionalEmpennageDesign.cpp src/taw/conventional/low/lowConventionalEmpennageDesignReport.cpp @@ -31,12 +32,16 @@ set(MODULE_SOURCES_TAW_CONVENTIONAL src/taw/conventional/conventionalEmpennageDesignConfig.cpp ) -# V-tail files -set(MODULE_SOURCES_VTAIL - # src/vtail/lowFidelity/lowVtail.cpp - # src/vtail/higherFidelity/higherVtail.cpp +# TAW - T-Tail files +set(MODULE_SOURCES_TAW_T_TAIL + src/taw/t_tail/low/low_t_tail_empennage_design.cpp + #src/taw/t_tail/low/low_t_tail_empennage_design_report.cpp + #src/taw/t_tail/low/low_t_tail_empennage_design_plot.cpp + src/taw/t_tail/t_tail_empennage_design_data.cpp + src/taw/t_tail/t_tail_empennage_design_config.cpp ) + set(MODULE_SOURCES_LIB src/lib/design_methods/volumeCoefficientMethod.cpp src/lib/mass_methods/flopsMassMethod.cpp @@ -44,7 +49,7 @@ set(MODULE_SOURCES_LIB set(MODULE_SOURCES ${MODULE_SOURCES_TAW_CONVENTIONAL} - ${MODULE_SOURCES_VTAIL} + ${MODULE_SOURCES_TAW_T_TAIL} ${MODULE_SOURCES_BWB_VERTICAL_TAILS} ${MODULE_SOURCES_LIB} src/empennageDesign.cpp @@ -59,7 +64,7 @@ find_package(Eigen3 3.3 REQUIRED NO_MODULE) # Link the runtime libraries target_link_libraries(${MODULE_NAME} - PUBLIC + PUBLIC Eigen3::Eigen PRIVATE UnicadoLibs::moduleBasics @@ -75,6 +80,8 @@ target_include_directories(${MODULE_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/bwb/vertical_tails/low PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/taw/conventional PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/taw/conventional/low # <- This is due to the includes in the conventional tail + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/taw/t_tail + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/taw/t_tail/low # <- This is due to the includes in the conventional tail # PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/vtail/ # <- This is due to the includes in the v-tail # PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/common/ ) @@ -91,8 +98,8 @@ endif() # Add the installation rules install (TARGETS ${MODULE_NAME} DESTINATION ${MODULE_NAME}) -install (FILES - ${MODULE_NAME}_conf.xml +install (FILES + ${MODULE_NAME}_conf.xml gmp-10.dll mpfr-6.dll DESTINATION ${MODULE_NAME}) @@ -101,4 +108,4 @@ install (FILES if(BUILD_SHARED_LIBS) # Install the runtime dependencies install(RUNTIME_DEPENDENCY_SET ${MODULE_NAME}_dependencies) -endif() \ No newline at end of file +endif() diff --git a/empennage_design/empennage_design_conf.xml b/empennage_design/empennage_design_conf.xml index 7d2cd15ae3bbc65e14f3ad97851d620866535e42..8997d82894be0f66a81b08056ebb55ec66454765 100644 --- a/empennage_design/empennage_design_conf.xml +++ b/empennage_design/empennage_design_conf.xml @@ -533,6 +533,476 @@ </control_devices> </tail_element> </conventional> + <t_tail> + <tail_element description="tail element" ID="0"> + <name description="element name - do not change"> + <value>vertical_stabiliser</value> + </name> + <parameter description="parameters for sizing/resizing"> + <offset> + <rear_x_offset description="x offset from rear of fuselage sizing/resizing parameter"> + <value>1.5</value> + <unit>m</unit> + <lower_boundary>1.0</lower_boundary> + <upper_boundary>3</upper_boundary> + </rear_x_offset> + <centerline_y_offset description="y offset from centerline of fuselage"> + <value>0.0</value> + <unit>m</unit> + <lower_boundary>-40.0</lower_boundary> + <upper_boundary>40.0</upper_boundary> + </centerline_y_offset> + <centerline_z_offset description="z offset from centerline of fuselage"> + <value>0.0</value> + <unit>m</unit> + <lower_boundary>-5.0</lower_boundary> + <upper_boundary>5.0</upper_boundary> + </centerline_z_offset> + </offset> + <volume_coefficient description="volumecoefficient sizing/resizing parameter - if 0.0 -> automatic values will be generated"> + <value>0.0</value> <!--0.0855--> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>2.0</upper_boundary> + </volume_coefficient> + <factor_aspect_ratio description= "factor to wing aspect ratio"> + <value>0.1</value> + <unit>1</unit> + <lower_boundary>0.001</lower_boundary> + <upper_boundary>2</upper_boundary> + </factor_aspect_ratio> + <factor_taper_ratio description="factor to wing taper ratio"> + <value>1.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>5</upper_boundary> + </factor_taper_ratio> + <delta_sweep description="additional sweep to wing sweep"> + <value>25</value> + <unit>deg</unit> + <lower_boundary>-90</lower_boundary> + <upper_boundary>90</upper_boundary> + </delta_sweep> + </parameter> + <profiles description="tail profile for both inner and outer section"> + <profile description="tail profile at section 0" ID="0"> + <name description="profile name"> + <value>n0012</value> + </name> + </profile> + <profile description="tail profile at section 0" ID="1"> + <name description="profile name"> + <value>n0012</value> + </name> + </profile> + </profiles> + <spars description="spars"> + <spar description="spar element" ID="0"> + <name description="name of spar"> + <value>front_spar</value> + </name> + <position description="chord relative position of control device"> + <inner_position description="relative inner position"> + <spanwise description="relative spanwise position"> + <value>0.0</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="relative chord position"> + <from description="relative chord position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </from> + <to description="relative chord position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </to> + </chord> + </inner_position> + <outer_position description="relative outer position"> + <spanwise description="relative spanwise position"> + <value>1.0</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="relative chord position"> + <from description="relative chord position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </from> + <to description="relative chord position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </to> + </chord> + </outer_position> + </position> + </spar> + <spar description="spar element" ID="1"> + <name description="name of spar"> + <value>rear_spar</value> + </name> + <position description="chord relative position of control device"> + <inner_position description="relative inner position"> + <spanwise description="relative spanwise position"> + <value>0.</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="relative chord position"> + <from description="relative chord position"> + <value>0.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </from> + <to description="relative chord position"> + <value>0.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </to> + </chord> + </inner_position> + <outer_position description="relative outer position"> + <spanwise description="relative spanwise position"> + <value>1</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="relative chord position"> + <from description="relative chord position"> + <value>0.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </from> + <to description="relative chord position"> + <value>0.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </to> + </chord> + </outer_position> + </position> + </spar> + </spars> + <control_devices description="control devices"> + <control_device description="control device" ID="0"> + <type description="type of control surface"> + <value>rudder</value> + </type> + <deflection description="maximum positive and negative deflection of control device"> + <full_negative_deflection description="full negative deflection"> + <value>-25.0</value> + <unit>deg</unit> + <lower_boundary>-90</lower_boundary> + <upper_boundary>0</upper_boundary> + </full_negative_deflection> + <full_positive_deflection description="full positive deflection"> + <value>25.0</value> + <unit>deg</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>90</upper_boundary> + </full_positive_deflection> + </deflection> + <position description="chord relative position of control device"> + <inner_position description="relative inner position"> + <spanwise description="relative spanwise position"> + <value>0.1</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="control device chord position"> + <from description="relative chord position"> + <value>0.7</value> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </from> + <to description="relative chord position"> + <value>1.0</value> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </to> + </chord> + </inner_position> + <outer_position description="relative outer position"> + <spanwise description="relative spanwise position"> + <value>0.9</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="control device chord position"> + <from description="relative chord position"> + <value>0.7</value> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </from> + <to description="relative chord position"> + <value>1.0</value> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </to> + </chord> + </outer_position> + </position> + </control_device> + </control_devices> + </tail_element> + <tail_element description="tail element" ID="1"> + <name description="element name - do not change"> + <value>horizontal_stabiliser</value> + </name> + <parameter description="parameters for sizing/resizing"> + <offset> + <rear_x_offset description="x offset from vertical stabilizer trailing edge sizing/resizing parameter"> + <value>-1.3</value> + <unit>m</unit> + <lower_boundary>-3.0</lower_boundary> + <upper_boundary>0</upper_boundary> + </rear_x_offset> + <centerline_y_offset description="y offset from centerline of fuselage (not used)"> + <value>0.0</value> + <unit>m</unit> + <lower_boundary>-40.0</lower_boundary> + <upper_boundary>40.0</upper_boundary> + </centerline_y_offset> + <centerline_z_offset description="z offset from centerline of fuselage (not used)"> + <value>0.0</value> + <unit>m</unit> + <lower_boundary>-5.0</lower_boundary> + <upper_boundary>5.0</upper_boundary> + </centerline_z_offset> + </offset> + <volume_coefficient description="VolumeCoefficient - if 0.0 -> automatic values will be generated"> + <value>0.0</value> <!-- 0.95--> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>2</upper_boundary> + </volume_coefficient> + <factor_aspect_ratio description= "factor to wing aspect ratio"> + <value>0.5</value> + <unit>1</unit> + <lower_boundary>0.02</lower_boundary> + <upper_boundary>2</upper_boundary> + </factor_aspect_ratio> + <factor_taper_ratio description="factor to wing taper ratio"> + <value>1.3</value> + <unit>1</unit> + <lower_boundary>0.02</lower_boundary> + <upper_boundary>2</upper_boundary> + </factor_taper_ratio> + <delta_sweep description="additional sweep to wing sweep"> + <value>5.0</value> + <unit>deg</unit> + <lower_boundary>-45</lower_boundary> + <upper_boundary>45</upper_boundary> + </delta_sweep> + </parameter> + <profiles description="tail profile for both inner and outer section"> + <profile description="tail profile at section 0" ID="0"> + <name description="profile name"> + <value>n0012</value> + </name> + </profile> + <profile description="tail profile at section 0" ID="1"> + <name description="profile name"> + <value>n0012</value> + </name> + </profile> + </profiles> + <spars description="spars"> + <spar description="spar element" ID="0"> + <name description="name of spar"> + <value>front_spar</value> + </name> + <position description="chord relative position of control device"> + <inner_position description="relative inner position"> + <spanwise description="relative spanwise position"> + <value>0.0</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="relative chord position"> + <from description="relative chord position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </from> + <to description="relative chord position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </to> + </chord> + </inner_position> + <outer_position description="relative outer position"> + <spanwise description="relative spanwise position"> + <value>1</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="relative chord position"> + <from description="relative chord position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </from> + <to description="relative chord position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </to> + </chord> + </outer_position> + </position> + </spar> + <spar description="spar element" ID="1"> + <name description="name of spar"> + <value>rear_spar</value> + </name> + <position description="chord relative position of control device"> + <inner_position description="relative inner position"> + <spanwise description="relative spanwise position"> + <value>0.0</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="relative chord position"> + <from description="relative chord position"> + <value>0.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </from> + <to description="relative chord position"> + <value>0.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </to> + </chord> + </inner_position> + <outer_position description="relative outer position"> + <spanwise description="relative spanwise position"> + <value>1.0</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="relative chord position"> + <from description="relative chord position"> + <value>0.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </from> + <to description="relative chord position"> + <value>0.6</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1</upper_boundary> + </to> + </chord> + </outer_position> + </position> + </spar> + </spars> + <control_devices description="control devices"> + <control_device description="control device" ID="0"> + <type description="type of control surface"> + <value>elevator</value> + </type> + <deflection description="maximum positive and negative deflection of control device"> + <full_negative_deflection description="full negative deflection"> + <value>-25.0</value> + <unit>deg</unit> + <lower_boundary>-90</lower_boundary> + <upper_boundary>0</upper_boundary> + </full_negative_deflection> + <full_positive_deflection description="full positive deflection"> + <value>25.0</value> + <unit>deg</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>90</upper_boundary> + </full_positive_deflection> + </deflection> + <position description="chord relative position of control device"> + <inner_position description="relative inner position"> + <spanwise description="relative spanwise position"> + <value>0.2</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="control device chord position"> + <from description="relative chord position"> + <value>0.7</value> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </from> + <to description="relative chord position"> + <value>1.0</value> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </to> + </chord> + </inner_position> + <outer_position description="relative outer position"> + <spanwise description="relative spanwise position"> + <value>0.9</value> + <unit>1</unit> + <lower_boundary>0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </spanwise> + <chord description="control device chord position"> + <from description="relative chord position"> + <value>0.7</value> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </from> + <to description="relative chord position"> + <value>1.0</value> + <unit>1</unit> + <lower_boundary>0.0</lower_boundary> + <upper_boundary>1.0</upper_boundary> + </to> + </chord> + </outer_position> + </position> + </control_device> + </control_devices> + </tail_element> + </t_tail> </low_fidelity> </tube_and_wing> <blended_wing_body> @@ -776,4 +1246,4 @@ </low_fidelity> </blended_wing_body> </program_settings> -</module_configuration_file> \ No newline at end of file +</module_configuration_file> diff --git a/empennage_design/src/empennageDesign.cpp b/empennage_design/src/empennageDesign.cpp index e005bb46023a3d1c1bb5f9de7b436cae06fef270..c44017caacf38bef058ac6fbbc2a50ad6993de7b 100644 --- a/empennage_design/src/empennageDesign.cpp +++ b/empennage_design/src/empennageDesign.cpp @@ -20,6 +20,7 @@ #include "bwb/vertical_tails/low/LowVerticalTailsBwb.h" #include "taw/conventional/low/lowConventionalEmpennageDesign.h" +#include "taw/t_tail/low/low_t_tail_empennage_design.h" EmpennageDesign::EmpennageDesign(const int argc, char *argv[], const std::string &toolName, const std::string &toolVersion) @@ -41,6 +42,11 @@ strategyaccess EmpennageDesign::design_routing(const std::vector<std::string> &r {"low", [](const std::shared_ptr<RuntimeIO> &arg) { return std::make_unique<taw::low::Conventional>(arg); }}, }}, + {"t_tail", + std::map<std::string, strategyaccess>{ + {"low", + [](const std::shared_ptr<RuntimeIO> &arg) { return std::make_unique<taw::low::T_Tail>(arg); }}, + }}, }}, {"blended_wing_body", std::map<std::string, std::map<std::string, strategyaccess>>{ diff --git a/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design.cpp b/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca7d455490f783b6338e4a417140e070938ba9f4 --- /dev/null +++ b/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design.cpp @@ -0,0 +1,463 @@ +/** + * \file LowConventionalTaw.cpp + * \author Christopher Ruwisch (christopher.ruwisch@tu-berlin.de) + * \brief + * \version 0.1 + * \date 2023-10-30 + * + * @copyright Copyright (c) 2023 + * + */ + +#include "low_t_tail_empennage_design.h" + +#include <CGAL/Surface_mesh/IO/PLY.h> +#include <aircraftGeometry2/geometry/factory.h> +#include <aircraftGeometry2/io/convert.h> +#include <aircraftGeometry2/io/dat.h> +#include <aircraftGeometry2/processing/measure.h> +#include <aircraftGeometry2/processing/transform.h> + +#include <format> +#include <numbers> + +#include "t_tail_empennage_design_config.h" +#include "t_tail_empennage_design_data.h" +#include "lib/design_methods/volumeCoefficientMethod.h" +#include "lib/mass_methods/flopsMassMethod.h" + +static std::string to_filename(std::string s) { + std::replace(s.begin(), s.end(), ' ', '_'); + return s; +} + +namespace taw { +namespace low { + +T_Tail::T_Tail(const std::shared_ptr<RuntimeIO> &rtIO) + : rtIO(rtIO), + config(std::make_shared<taw::low::T_Tail_Config>()), + data(std::make_shared<taw::low::T_Tail_Data>()), + design_mode_runner({{"mode_0", [this]() { design(); }}, {"mode_1", [this]() { redesign(); }}}), + mass_mode_runner({{"mode_0", [this]() { flops_mass(); }}, {"mode_1", [this]() { raymer_mass(); }}}) {}; + //reporter(rtIO) {}; + +void T_Tail::initialize() { + // Setup methods for mode + myRuntimeInfo->out << "Initializing empennage" << std::endl; + myRuntimeInfo->out << "Empennage type -> T-Tail (vertical_stabilizer/horizontal_stabilizer)" << std::endl; + + /* Read configuration data */ + config->read(rtIO->moduleConfig); + + /* Create airfoils directory in project path (only if non-existing -> e.g. if standalone usage)*/ + rtIO->createAirfoilDataDir(); + + /* Read acxml data - non aircraftgeometry2 */ + data->read(rtIO->acxml); + + /* Read acxml data - aircraftgeometry2 */ + data->read_wing(rtIO->acxmlAccess, rtIO->getAirfoilDataDir()); + data->read_fuselage(rtIO->acxmlAccess, rtIO->getGeometryDir()); + + /* Select modes */ + selected_design_mode = config->design_mode.value(); + selected_mass_mode = config->mass_mode.value(); + + /* Create airfoils library */ + airfoils_library = + std::make_shared<Airfoils>(static_cast<std::filesystem::path>(config->common_airfoil_data_path.value())); + + /* Append runtimeIO airfoils data directory */ + airfoils_library->add_directory_airfoils(rtIO->getAirfoilDataDir()); + + +} + +void T_Tail::run() { + /* Run methods */ + myRuntimeInfo->out << "Running empennage -> T-tail" << std::endl; + /* Run design method */ + design_mode_runner[selected_design_mode](); + + /* Run mass method */ + mass_mode_runner[selected_mass_mode](); +} + +void T_Tail::update() { + myRuntimeInfo->out << "Updating empennage -> T-tail" << std::endl; + /* Update aircraft exchange file */ + data->update(rtIO->acxml); +} + +void T_Tail::report() { + /* Create reports */ + myRuntimeInfo->out << "Reporting empennage -> T-tail" << std::endl; + + /* Set html report data and plots */ + //set_html_body(); + + /* Generate reports */ + //reporter.generateReports(); + + /* Create STL file (only for debugging reasons) */ + data->vertical_stabilizer.origin = + geom2::Point_3(data->empennage_position.x.value() + data->vertical_stabilizer.origin.x(), + data->empennage_position.y.value() + data->vertical_stabilizer.origin.y(), + data->empennage_position.z.value() + data->vertical_stabilizer.origin.z()); + geom2::Mesh vertical_stabilizer_mesh = geom2::transform::to_mesh(data->vertical_stabilizer); + /* Create STL file (vertical stabilizer) */ + CGAL::IO::write_STL(to_filename(data->vertical_stabilizer.name) + ".stl", vertical_stabilizer_mesh); + data->horizontal_stabilizer.origin = + geom2::Point_3(data->empennage_position.x.value() + data->horizontal_stabilizer.origin.x(), + data->empennage_position.y.value() + data->horizontal_stabilizer.origin.y(), + data->empennage_position.z.value() + data->horizontal_stabilizer.origin.z()); + geom2::Mesh horizontal_stabilizer_mesh = geom2::transform::to_mesh(data->horizontal_stabilizer); + + /* Create STL File (horizontal stabilizer (one sided)) */ + CGAL::IO::write_STL(to_filename(data->horizontal_stabilizer.name) + ".stl", horizontal_stabilizer_mesh); +} + +void T_Tail::save() { + // save data if necessary +} + +void T_Tail::design() { + myRuntimeInfo->out << "Mode active -> Design" << std::endl; + + double wing_reference_area = geom2::measure::reference_area(data->wing); + double wing_span = geom2::measure::span(data->wing); + double wing_sweep = fabs(geom2::measure::sweep(data->wing, -0.25 * wing_span, 0.25)); + double wing_taper_ratio = geom2::measure::taper_ratio(data->wing); + double wing_aspect_ratio = geom2::measure::aspect_ratio(data->wing); + double span_position_mac = geom2::measure::mean_aerodynamic_chord_position(data->wing); + double wing_mac = geom2::measure::chord(data->wing, span_position_mac); + geom2::Point_3 wing_neutral_position = geom2::Point_3( + data->wing_position_x.value() + geom2::measure::offset_LE(data->wing, span_position_mac).x() + 0.25 * wing_mac, + 0., 0.); + double fuselage_length = geom2::measure::length(data->fuselage); + + // Vertical stabilizer (vs) computation - data from configuration + design_vertical_stabilizer(wing_sweep, wing_reference_area, wing_span, wing_taper_ratio, wing_aspect_ratio, + wing_neutral_position, fuselage_length); + + for (auto device : config->vertical_stabilizer.control_devices) { + data->vertical_stabilizer_control_devices.push_back(control_device( + device.type.value(), device.position.inner_position_chord_from.value(), + device.position.inner_position_chord_to.value(), device.position.inner_position_spanwise.value(), + device.position.outer_position_chord_from.value(), device.position.outer_position_chord_to.value(), + device.position.outer_position_spanwise.value())); + data->vertical_stabilizer_control_devices_deflections.push_back( + {device.deflection_full_negative.value(), device.deflection_full_positive.value()}); + } + for (auto spar_element : config->vertical_stabilizer.spars) { + data->vertical_stabilizer_spars.push_back(spar( + spar_element.name.value(), spar_element.position.inner_position_chord_from.value(), + spar_element.position.inner_position_chord_to.value(), spar_element.position.inner_position_spanwise.value(), + spar_element.position.outer_position_chord_from.value(), spar_element.position.outer_position_chord_to.value(), + spar_element.position.outer_position_spanwise.value())); + } + + // Horizontal stabilizer (hs) computation - data from configuration + design_horizontal_stabilizer(wing_sweep, wing_reference_area, wing_mac, wing_taper_ratio, wing_aspect_ratio, + wing_neutral_position, fuselage_length); + for (auto device : config->horizontal_stabilizer.control_devices) { + data->horizontal_stabilizer_control_devices.push_back(control_device( + device.type.value(), device.position.inner_position_chord_from.value(), + device.position.inner_position_chord_to.value(), device.position.inner_position_spanwise.value(), + device.position.outer_position_chord_from.value(), device.position.outer_position_chord_to.value(), + device.position.outer_position_spanwise.value())); + data->horizontal_stabilizer_control_devices_deflections.push_back( + {device.deflection_full_negative.value(), device.deflection_full_positive.value()}); + } + for (auto spar_element : config->horizontal_stabilizer.spars) { + data->horizontal_stabilizer_spars.push_back(spar( + spar_element.name.value(), spar_element.position.inner_position_chord_from.value(), + spar_element.position.inner_position_chord_to.value(), spar_element.position.inner_position_spanwise.value(), + spar_element.position.outer_position_chord_from.value(), spar_element.position.outer_position_chord_to.value(), + spar_element.position.outer_position_spanwise.value())); + } + + /* Set empennage position -> vertical and horizontal stabilizer */ + set_empennage_position(); +} + +void T_Tail::redesign() { + myRuntimeInfo->out << "Redesign mode active Conventional Tail" << std::endl; + double wing_sweep = 0.0; // data...; + double wing_reference_area = 0.0; // data...; + double wing_span = 0.0; // data...; + double wing_mac = 0.0; // data...; + double wing_taper_ratio = 0.0; // data...; + double wing_aspect_ratio = 0.0; // data...; + geom2::Point_3 wing_neutral_position = geom2::Point_3(0.0, 0.0, 0.0); //...; + double fuselage_length = 0.0; // data...; +} + +void T_Tail::design_vertical_stabilizer(const double wing_sweep, const double wing_reference_area, + const double wing_span, const double wing_taper_ratio, + const double wing_aspect_ratio, geom2::Point_3 &wing_neutral_position, + const double fuselage_length) { + geom2::Direction_3 orientation = geom2::Direction_3(0.0, 0.0, -1.0); + data->vertical_stabilizer = + design_stabilizer(wing_sweep, wing_reference_area, wing_span, wing_taper_ratio, wing_aspect_ratio, + wing_neutral_position, fuselage_length, config->vertical_stabilizer, orientation, false); + data->vertical_stabilizer.name = config->vertical_stabilizer.name.value(); + data->vertical_stabilizer.sections.at(0).name = config->vertical_stabilizer.inner_profile.value(); + data->vertical_stabilizer.sections.at(1).name = config->vertical_stabilizer.outer_profile.value(); + data->vertical_stabilizer.is_symmetric = false; +} + +void T_Tail::design_horizontal_stabilizer(const double wing_sweep, const double wing_reference_area, + const double wing_mac, const double wing_taper_ratio, + const double wing_aspect_ratio, geom2::Point_3 &wing_neutral_position, + const double fuselage_length) { + geom2::Direction_3 orientation = geom2::Direction_3(0.0, -1.0, 0.0); + double vertical_stabilizer_tip_height = geom2::measure::span(data->vertical_stabilizer); + geom2::Point_3 vertical_stabilizer_leading_edge_position_tip = geom2::measure::offset_LE(data->vertical_stabilizer,-vertical_stabilizer_tip_height); + double vertical_stabilizer_chord_chord_at_tip = geom2::measure::chord(data->vertical_stabilizer,-vertical_stabilizer_tip_height); + double reference_length_for_T_tail = data->vertical_stabilizer.origin.x() + vertical_stabilizer_leading_edge_position_tip.x() + vertical_stabilizer_chord_chord_at_tip; + + data->horizontal_stabilizer = + design_stabilizer(wing_sweep, wing_reference_area, wing_mac, wing_taper_ratio, wing_aspect_ratio, + wing_neutral_position, reference_length_for_T_tail, config->horizontal_stabilizer, orientation, true); + //data->horizontal_stabilizer.origin = geom2::Point_3(data->horizontal_stabilizer.origin.x(), data->horizontal_stabilizer.origin.y(), data->horizontal_stabilizer.origin.z() - vertical_stabilizer_tip_height); + data->horizontal_stabilizer.name = config->horizontal_stabilizer.name.value(); + data->horizontal_stabilizer.sections.at(0).name = config->horizontal_stabilizer.inner_profile.value(); + data->horizontal_stabilizer.sections.at(1).name = config->horizontal_stabilizer.outer_profile.value(); + data->horizontal_stabilizer.is_symmetric = true; +} + +void T_Tail::redesign_vertical_stabilizer(const double wing_sweep, const double wing_reference_area, + const double wing_span, geom2::Point_3 &wing_neutral_position, + const double fuselage_length) { + // const double aspect_ratio = geom2::measure:: ... + // const double taper_ratio = geom2::measure:: ... + // geom2::Polygon_2 profile_root = factory.sections.front().shape + // geom2::Polygon_2 profile_tip = factory.sections.back().shape +} + +void T_Tail::redesign_horizontal_stabilizer(const double wing_sweep, const double wing_reference_area, + const double wing_span, geom2::Point_3 &wing_neutral_position, + const double fuselage_length) { + // const double aspect_ratio = geom2::measure:: ... + // const double taper_ratio = geom2::measure:: ... + // geom2::Polygon_2 profile_root = factory.sections.front().shape + // geom2::Polygon_2 profile_tip = factory.sections.back().shape +} + +geom2::MultisectionSurface<geom2::AirfoilSection> T_Tail::design_stabilizer( + const double wing_sweep_rad, const double wing_reference_area, const double reference_length, + geom2::Point_3 &wing_neutral_position, const double fuselage_length, geom2::Direction_3 &orientation, + const double volume_coefficient, const double delta_sweep_rad, const double stabilizer_taper_ratio, + const double stabilizer_aspect_ratio, geom2::Point_3 &offset_position, const std::string &inner_profile_name, + const std::string &outer_profile_name, bool symmetric, int number_of_stabilizers) { + /* Read inner profile */ + geom2::AirfoilSection profile_root(airfoils_library->get_airfoil(inner_profile_name)); + airfoils_library->copy_available_airfoil(inner_profile_name, rtIO->getAirfoilDataDir()); + profile_root.name = inner_profile_name; + + /* Read outer profile */ + geom2::AirfoilSection profile_tip(airfoils_library->get_airfoil(inner_profile_name)); + airfoils_library->copy_available_airfoil(inner_profile_name, rtIO->getAirfoilDataDir()); + profile_tip.name = outer_profile_name; + + /* Create volume coefficient method */ + VolumeCoefficientMethod volume_coefficient_method; + + /* Compute geometry by volume coefficient method */ + volume_coefficient_method.compute_geometry( + number_of_stabilizers, volume_coefficient, wing_sweep_rad + delta_sweep_rad, stabilizer_taper_ratio, + stabilizer_aspect_ratio, wing_reference_area, reference_length, fuselage_length, wing_neutral_position, + offset_position, orientation, symmetric); + + /* Set dihedral to 0 */ + double dihedral = 0.0; + /* check if not direction is in horizontal axis */ + if (orientation.dy() < -0.5) { + dihedral = geom2::measure::dihedral(data->wing, -0.25 * geom2::measure::span(data->wing)); + } + return volume_coefficient_method.get_design(profile_root, profile_tip, dihedral); +} + +geom2::MultisectionSurface<geom2::AirfoilSection> T_Tail::design_stabilizer( + const double wing_sweep_rad, const double wing_reference_area, const double reference_length, + const double wing_taper_ratio, const double wing_aspect_ratio, geom2::Point_3 &wing_neutral_position, + const double fuselage_length, TailElement &tail, geom2::Direction_3 &orientation, bool symmetric) { + geom2::Point_3 offset_position(tail.rear_x_offset.value(), tail.centerline_y_offset.value(), + tail.centerline_z_offset.value()); + double volume_coefficient = tail.volume_coefficient.value(); + + /* Set values if volume_coefficient is set to small */ + if (fabs(volume_coefficient) < 1E-4) { + /* Compute values dependend on orientation - threshold at 0.95 -> empirical */ + if (std::fabs(orientation.dz()) > 0.95) { + /* Vertical stabilizer - Raymer -> P.112 Table 6.4 */ + volume_coefficient = 0.0855; + } else { + /* Horizontal stabilizer - Raymer -> P.112 Table 6.4 */ + volume_coefficient = 0.95; + } + } + return design_stabilizer(wing_sweep_rad, wing_reference_area, reference_length, wing_neutral_position, + fuselage_length, orientation, volume_coefficient, tail.delta_sweep.value(), + wing_taper_ratio * tail.factor_taper_ratio.value(), + wing_aspect_ratio * tail.factor_aspect_ratio.value(), offset_position, + tail.inner_profile.value(), tail.outer_profile.value(), symmetric, 1); +} + +void T_Tail::set_empennage_position(void) { + // Vertical stabilizer and horizontal stabilizer set both to equal vertical position + + data->horizontal_stabilizer.origin = + geom2::Point_3(data->horizontal_stabilizer.origin.x(), data->horizontal_stabilizer.origin.y(), + -data->vertical_stabilizer.sections.back().origin.z()); + + data->vertical_stabilizer.origin = + geom2::Point_3(data->vertical_stabilizer.origin.x(), data->vertical_stabilizer.origin.y(), + data->vertical_stabilizer.origin.z() ); + if (data->vertical_stabilizer.origin.x() < data->horizontal_stabilizer.origin.x()) { + data->empennage_position.set_xyz(data->vertical_stabilizer.origin.x(), data->vertical_stabilizer.origin.y(), + data->vertical_stabilizer.origin.z()); + data->horizontal_stabilizer.origin = + geom2::Point_3(data->horizontal_stabilizer.origin.x() - data->empennage_position.x.value(), + data->horizontal_stabilizer.origin.y() - data->empennage_position.y.value(), + data->horizontal_stabilizer.origin.z() - data->empennage_position.z.value()); + data->vertical_stabilizer.origin = geom2::Point_3(0.0, 0.0, 0.0); + } else { + data->empennage_position.set_xyz(data->horizontal_stabilizer.origin.x(), data->horizontal_stabilizer.origin.y(), + data->horizontal_stabilizer.origin.z()); + data->vertical_stabilizer.origin = + geom2::Point_3(data->vertical_stabilizer.origin.x() - data->empennage_position.x.value(), + data->vertical_stabilizer.origin.y() - data->empennage_position.y.value(), + data->vertical_stabilizer.origin.z() - data->empennage_position.z.value()); + data->horizontal_stabilizer.origin = geom2::Point_3(0.0, 0.0, 0.0); + } + + myRuntimeInfo->out << "Empennage position (x y z) -> " << data->empennage_position.xyz() << std::endl; +} + +// == Spars and Controls ============================================================================================== + +geom2::MultisectionSurface<geom2::PolygonSection> T_Tail::control_device( + const std::string &name, double inner_chord_rel_pos_from, double inner_chord_rel_pos_to, + double inner_spanwise_rel_pos, double outer_chord_rel_pos_from, double outer_chord_rel_pos_to, + double outer_spanwise_rel_pos) { + geom2::MultisectionSurface<geom2::PolygonSection> control_surface; + geom2::Polygon_2 inner_chord; + inner_chord.push_back(geom2::Point_2(inner_chord_rel_pos_from, 0.0)); + inner_chord.push_back(geom2::Point_2(inner_chord_rel_pos_to, 0.0)); + + geom2::Polygon_2 outer_chord; + outer_chord.push_back(geom2::Point_2(outer_chord_rel_pos_from, 0.0)); + outer_chord.push_back(geom2::Point_2(outer_chord_rel_pos_to, 0.0)); + + control_surface.sections.emplace_back(inner_chord); + control_surface.sections.emplace_back(outer_chord); + + control_surface.sections.front().origin = geom2::Point_3(0.0, 0.0, inner_spanwise_rel_pos); + control_surface.sections.back().origin = geom2::Point_3(0.0, 0.0, outer_spanwise_rel_pos); + + control_surface.name = name; + return control_surface; +} + +geom2::MultisectionSurface<geom2::PolygonSection> T_Tail::spar( + const std::string &name, double inner_chord_rel_pos_from, double inner_chord_rel_pos_to, + double inner_spanwise_rel_pos, double outer_chord_rel_pos_from, double outer_chord_rel_pos_to, + double outer_spanwise_rel_pos) { + geom2::MultisectionSurface<geom2::PolygonSection> spar; + geom2::Polygon_2 inner_chord; + inner_chord.push_back(geom2::Point_2(inner_chord_rel_pos_from, 0.0)); + inner_chord.push_back(geom2::Point_2(inner_chord_rel_pos_to, 0.0)); + + geom2::Polygon_2 outer_chord; + outer_chord.push_back(geom2::Point_2(outer_chord_rel_pos_from, 0.0)); + outer_chord.push_back(geom2::Point_2(outer_chord_rel_pos_to, 0.0)); + + spar.sections.emplace_back(inner_chord); + spar.sections.emplace_back(outer_chord); + + spar.sections.front().origin = geom2::Point_3(0.0, 0.0, inner_spanwise_rel_pos); + spar.sections.back().origin = geom2::Point_3(0.0, 0.0, outer_spanwise_rel_pos); + spar.name = name; + + return spar; +} + +// == Mass ============================================================================================================ +void T_Tail::flops_mass() { + myRuntimeInfo->out << "Mode active -> Mass computation - FLOPS" << std::endl; + const double maximum_takeoff_mass = data->maximum_takeoff_mass.value(); + + data->vertical_stabilizer_mass.data["mass"] = + flops::vertical_stabilizer_mass(1, geom2::measure::reference_area(data->vertical_stabilizer), + geom2::measure::taper_ratio(data->vertical_stabilizer), maximum_takeoff_mass); + myRuntimeInfo->out << std::format("Vertical stabilizer mass ... {}", + data->vertical_stabilizer_mass.data["mass"].value()) + << std::endl; + geom2::Point_3 vs_position_mac = geom2::measure::offset_LE( + data->vertical_stabilizer, geom2::measure::mean_aerodynamic_chord_position(data->vertical_stabilizer)); + data->vertical_stabilizer_mass.data["x"] = + data->empennage_position.x.value() + data->vertical_stabilizer.origin.x() + vs_position_mac.x() + + 0.25 * geom2::measure::chord(data->vertical_stabilizer, vs_position_mac.z()) + + 0.1 * geom2::measure::mean_aerodynamic_chord(data->vertical_stabilizer); + data->vertical_stabilizer_mass.data["y"] = data->vertical_stabilizer.origin.y(); /* Assume symmetric mass */ + data->vertical_stabilizer_mass.data["z"] = + data->empennage_position.z.value() + data->vertical_stabilizer.origin.z() + + std::fabs(geom2::measure::mean_aerodynamic_chord_position(data->vertical_stabilizer)); + + /* Horizontal stabilizer mass and cog */ + data->horizontal_stabilizer_mass.data["mass"] = + flops::horizontal_stabilizer_mass(geom2::measure::reference_area(data->horizontal_stabilizer), + geom2::measure::taper_ratio(data->horizontal_stabilizer), maximum_takeoff_mass); + myRuntimeInfo->out << std::format("Horizontal stabilizer mass ... {:.2f}", + data->horizontal_stabilizer_mass.data["mass"].value()) + << std::endl; + + /* Cog calculation */ + geom2::Point_3 hs_position_mac = geom2::measure::offset_LE( + data->horizontal_stabilizer, geom2::measure::mean_aerodynamic_chord_position(data->horizontal_stabilizer)); + + data->horizontal_stabilizer_mass.data["x"] = + data->empennage_position.x.value() + data->horizontal_stabilizer.origin.x() + hs_position_mac.x() + + 0.25 * geom2::measure::chord(data->horizontal_stabilizer, hs_position_mac.z()) + + 0.1 * geom2::measure::mean_aerodynamic_chord(data->vertical_stabilizer); + + data->horizontal_stabilizer_mass.data["y"] = data->horizontal_stabilizer.origin.y(); /* Assume symmetric mass */ + + data->horizontal_stabilizer_mass.data["z"] = + data->empennage_position.z.value() + data->horizontal_stabilizer.origin.z() + -hs_position_mac.z(); + data->empennage_mass.data["mass"] = + data->horizontal_stabilizer_mass.data["mass"].value() + data->vertical_stabilizer_mass.data["mass"].value(); + + /* Compute x direction overall COG_x */ + data->empennage_mass.data["x"] = + (data->vertical_stabilizer_mass.data["mass"].value() * data->vertical_stabilizer_mass.data["x"].value() + + data->horizontal_stabilizer_mass.data["mass"].value() * data->horizontal_stabilizer_mass.data["x"].value()) / + data->empennage_mass.data["mass"].value(); + + /* Compute y direction overall COG_y */ + data->empennage_mass.data["y"] = + (data->vertical_stabilizer_mass.data["mass"].value() * data->vertical_stabilizer_mass.data["y"].value() + + data->horizontal_stabilizer_mass.data["mass"].value() * data->horizontal_stabilizer_mass.data["y"].value()) / + data->empennage_mass.data["mass"].value(); + + /* Compute z direction overall COG_z */ + data->empennage_mass.data["z"] = + (data->vertical_stabilizer_mass.data["mass"].value() * data->vertical_stabilizer_mass.data["z"].value() + + data->horizontal_stabilizer_mass.data["mass"].value() * data->horizontal_stabilizer_mass.data["z"].value()) / + data->empennage_mass.data["mass"].value(); + myRuntimeInfo->out << std::format("Empennage mass ... {}", data->empennage_mass.data["mass"].value()) << std::endl; + myRuntimeInfo->out << std::format("Empennage cog ... {:.2f}, {:.2f}, {:.2f}", data->empennage_mass.data["x"].value(), + data->empennage_mass.data["y"].value(), data->empennage_mass.data["z"].value()) + << std::endl; +} + +void T_Tail::raymer_mass() { + /* ToDo */ + myRuntimeInfo->err << "Method not implemented yet .... -> no output generated"; +} + +} // namespace low +} // namespace taw diff --git a/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design.h b/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design.h new file mode 100644 index 0000000000000000000000000000000000000000..248044872899c68af518bf613d66f4b142cd629a --- /dev/null +++ b/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design.h @@ -0,0 +1,287 @@ +/** + * \file Low_T_Tail_Taw.h + * \author Christopher Ruwisch (christopher.ruwisch@tu-berlin.de) + * \brief + * \version 0.1 + * \date 2023-10-30 + * + * @copyright Copyright (c) 2023 + * + */ +#ifndef LOW_T_Tail_TAW_H_ +#define LOW_T_Tail_TAW_H_ + +#include <aircraftGeometry2/airfoil_surface.h> +#include <airfoils/airfoils.h> +#include <moduleBasics/module.h> +#include <moduleBasics/report.h> +#include <moduleBasics/strategySelector.h> + +#include <functional> +#include <map> +#include <vector> + +#include "t_tail_empennage_design_config.h" +#include "t_tail_empennage_design_data.h" + +namespace taw { +namespace low { +class T_Tail : public Strategy { + public: + T_Tail(const std::shared_ptr<RuntimeIO>& rtIO); + ~T_Tail() = default; + /** + * \brief Initialize T-Tail method + * + */ + void initialize(); + + /** + * \brief Run T-Tail method + * + */ + void run(); + + /** + * \brief Update T-Tail method + * + */ + void update(); + + /** + * \brief Report generation for T-Tail method + * + */ + void report(); + + /** + * \brief Save results for T-Tail method + * + */ + void save(); + + /** + * \brief Design method for T-Tail empennage + * + */ + void design(void); + + /** + * \brief Redesign method for T-Tail empennage + * + */ + void redesign(void); + + /** + * \brief Design of a vertical stabilizer + * + * \param wing_sweep + * \param wing_reference_area + * \param wing_span + * \param wing_taper_ratio + * \param wing_aspect_ratio + * \param wing_neutral_position + * \param fuselage_length + */ + void design_vertical_stabilizer(const double wing_sweep, const double wing_reference_area, const double wing_span, + const double wing_taper_ratio, const double wing_aspect_ratio, + geom2::Point_3& wing_neutral_position, const double fuselage_length); + + /** + * \brief Design of a horizontal stabilizer + * + * \param wing_sweep + * \param wing_reference_area + * \param wing_mac + * \param wing_taper_ratio + * \param wing_aspect_ratio + * \param wing_neutral_position + * \param fuselage_length + */ + void design_horizontal_stabilizer(const double wing_sweep, const double wing_reference_area, const double wing_mac, + const double wing_taper_ratio, const double wing_aspect_ratio, + geom2::Point_3& wing_neutral_position, const double fuselage_length); + + /** + * \brief Redesign of a vertical stabilizer + * + * \param wing_sweep + * \param wing_reference_area + * \param wing_span + * \param wing_neutral_position + * \param fuselage_length + */ + void redesign_vertical_stabilizer(const double wing_sweep, const double wing_reference_area, const double wing_span, + geom2::Point_3& wing_neutral_position, const double fuselage_length); + + /** + * \brief Redesign of a horizontal stabilizer + * + * \param wing_sweep + * \param wing_reference_area + * \param wing_span + * \param wing_neutral_position + * \param fuselage_length + */ + void redesign_horizontal_stabilizer(const double wing_sweep, const double wing_reference_area, const double wing_span, + geom2::Point_3& wing_neutral_position, const double fuselage_length); + + /** + * \brief Design of a stabilizer + * + * \param wing_sweep_rad + * \param wing_reference_area + * \param reference_length + * \param wing_neutral_position + * \param fuselage_length + * \param orientation + * \param volume_coefficient + * \param delta_sweep_rad + * \param stabilizer_taper_ratio + * \param stabilizer_aspect_ratio + * \param offset_position + * \param inner_profile_name + * \param outer_profile_name + * \param symmetric + * \param number_of_stabilizers + * \return geom2::MultisectionSurface<geom2::AirfoilSection> + */ + geom2::MultisectionSurface<geom2::AirfoilSection> design_stabilizer( + const double wing_sweep_rad, const double wing_reference_area, const double reference_length, + geom2::Point_3& wing_neutral_position, const double fuselage_length, geom2::Direction_3& orientation, + const double volume_coefficient, const double delta_sweep_rad, const double stabilizer_taper_ratio, + const double stabilizer_aspect_ratio, geom2::Point_3& offset_position, const std::string& inner_profile_name, + const std::string& outer_profile_name, bool symmetric, int number_of_stabilizers); + + /** + * \brief Design of a stabilizer + * + * \param wing_sweep_rad + * \param wing_reference_area + * \param reference_length + * \param wing_taper_ratio + * \param wing_aspect_ratio + * \param wing_neutral_position + * \param fuselage_length + * \param tail + * \param align + * \param symmetric + * \return geom2::MultisectionSurface<geom2::AirfoilSection> + */ + geom2::MultisectionSurface<geom2::AirfoilSection> design_stabilizer( + const double wing_sweep_rad, const double wing_reference_area, const double reference_length, + const double wing_taper_ratio, const double wing_aspect_ratio, geom2::Point_3& wing_neutral_position, + const double fuselage_length, TailElement& tail, geom2::Direction_3& align, bool symmetric); + + /** + * \brief Set the empennage position + * + */ + void set_empennage_position(void); + + /** + * \brief Method to create shape of a control surface + * + * \param name name of the control surface + * \param inner_chord_rel_pos_from + * \param inner_chord_rel_pos_to + * \param inner_spanwise_rel_pos + * \param outer_chord_rel_pos_from + * \param outer_chord_rel_pos_to + * \param outer_spanwise_rel_pos + * \return geom2::MultisectionSurface<geom2::PolygonSection> + */ + geom2::MultisectionSurface<geom2::PolygonSection> control_device( + const std::string& name, double inner_chord_rel_pos_from, double inner_chord_rel_pos_to, + double inner_spanwise_rel_pos, double outer_chord_rel_pos_from, double outer_chord_rel_pos_to, + double outer_spanwise_rel_pos); + + /** + * \brief Method to create shape of a predefined spar + * + * \param name Name of the spar + * \param inner_chord_rel_pos_from + * \param inner_chord_rel_pos_to + * \param inner_spanwise_rel_pos + * \param outer_chord_rel_pos_from + * \param outer_chord_rel_pos_to + * \param outer_spanwise_rel_pos + * \return geom2::MultisectionSurface<geom2::PolygonSection> spar element as a polygonsection + */ + geom2::MultisectionSurface<geom2::PolygonSection> spar(const std::string& name, double inner_chord_rel_pos_from, + double inner_chord_rel_pos_to, + double inner_spanwise_rel_pos, + double outer_chord_rel_pos_from, + double outer_chord_rel_pos_to, + double outer_spanwise_rel_pos); + /** + * \brief Add spars method + * + */ + void add_spars(); + + /** + * \brief Calculate empennage mass (vertical stabilizer / horizontal stabilizer) and associated center of gravity by + * Flops method + * + */ + void flops_mass(); + + /** + * \brief Calculate empennage mass by raymer method - not implemented yet + * + */ + void raymer_mass(); + + /** + * \brief Set the html body report + * + */ + void set_html_body(); + + /** + * \brief Generates plots for stabilizer planform and returns relative path to plot (svg) + * + * \param surface stabilizer + * \param spars spars vector + * \param devices control devices vector + * \return fs::path relative path between report and plot + */ + fs::path plot_stabilizer_planform(const geom2::MultisectionSurface<geom2::AirfoilSection>& surface, + const std::vector<geom2::MultisectionSurface<geom2::PolygonSection>>& spars, + const std::vector<geom2::MultisectionSurface<geom2::PolygonSection>>& devices); + + /** + * \brief Generate unique plots of airfoils + * + * \param surface stabilizer + * \return std::vector<fs::path> vector of relative paths between report and plots + */ + std::vector<fs::path> plot_airfoils(const geom2::MultisectionSurface<geom2::AirfoilSection>& surface); + + /** + * \brief Generate plot of thickness and twist distribution + * + * \param surface stabilizer + * \return fs::path relative path between report and plot + */ + fs::path plot_thickness_and_twist_distribution(const geom2::MultisectionSurface<geom2::AirfoilSection>& surface); + +public: + std::string selected_design_mode; + std::string selected_mass_mode; + std::map<std::string, std::function<void(void)>> design_mode_runner; + std::map<std::string, std::function<void(void)>> mass_mode_runner; + std::shared_ptr<Airfoils> airfoils_library; + + + const std::shared_ptr<RuntimeIO>& rtIO; + const std::shared_ptr<taw::low::T_Tail_Config> config; + const std::shared_ptr<taw::low::T_Tail_Data> data; + //Report reporter; +}; + +} // namespace low +} // namespace taw + +#endif // LOW_T_TAIL_TAW_H_ diff --git a/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design_plot.cpp b/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design_plot.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c224b970676aa4aff0280ed70e7b5587b139504 --- /dev/null +++ b/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design_plot.cpp @@ -0,0 +1,298 @@ +/** + * \file cantileverWingDesignPlot.cpp + * \author Christopher Ruwisch (christopher.ruwisch@tu-berlin.de) + * \brief Plots for cantileverWingDesign + * \version 0.1 + * \date 2024-05-22 + * + * @copyright Copyright (c) 2024 + * + */ + +#include <aircraftGeometry2/processing/measure.h> +#include <aircraftGeometry2/processing/transform.h> +#include <matplot/matplot.h> + +#include <array> +#include <cstdlib> +#include <deque> +#include <map> +#include <utility> +#include <algorithm> + +#include "low_t_tail_empennage_design.h" + +/** + * \brief Generate polygon from spar or controldevice + * + * \param surface aerodynamic surface object + * \param object spar or control device object + * \return std::tuple<std::vector<double>,std::vector<double>,std::string> coordinates and object name + */ +std::tuple<std::vector<double>, std::vector<double>, std::string> gen_polygon( + const geom2::MultisectionSurface<geom2::AirfoilSection>& surface, + const geom2::MultisectionSurface<geom2::PolygonSection>& object); + +/** + * \brief RGB and alpha values to Matplot++ format + * + * \param r red value between 0 - 255 + * \param b blue value between 0 - 255 + * \param g green alue between 0 - 255 + * \param a alpha value between 0 (invisible) - 1 (solid) + * \return std::array<float,4UL> matplot++ conform color format + */ +//std::array<float, 4UL> rgba(float r, float b, float g, float a) { return {1 - a, r / 255, b / 255, g / 255}; } +// +///* */ +//std::array<float, 4UL> spar_color = rgba(99, 110, 114, 1.0); +// +//std::map<std::string, std::array<float, 4UL>> control_device_colormap = {{"elevator", rgba(108, 92, 231, 1.0)}, +// {"rudder", rgba(232, 67, 147, 1.0)}}; +// +//std::tuple<std::vector<double>, std::vector<double>, std::string> gen_polygon( +// const geom2::MultisectionSurface<geom2::AirfoilSection>& surface, +// const geom2::MultisectionSurface<geom2::PolygonSection>& object) { +// double half_span = surface.is_symmetric ? 0.5 * geom2::measure::span(surface) : geom2::measure::span(surface); +// /* Spar coordinates positive values normally*/ +// double from = object.sections.at(0).origin.z() * half_span; +// double to = object.sections.at(1).origin.z() * half_span; +// +// /* Chordwise coordinates */ +// double chord_from_fwd = object.sections.at(0).get_contour().vertex(0).x(); +// double chord_from_aft = object.sections.at(0).get_contour().vertex(1).x(); +// double chord_to_fwd = object.sections.at(1).get_contour().vertex(0).x(); +// double chord_to_aft = object.sections.at(1).get_contour().vertex(1).x(); +// +// auto f_chord_fwd = [chord_from_fwd, chord_to_fwd, half_span](double span_position) { +// return std::lerp(chord_from_fwd, chord_to_fwd, fabs(span_position) / half_span); +// }; +// auto f_chord_aft = [chord_from_aft, chord_to_aft, half_span](double span_position) { +// return std::lerp(chord_from_aft, chord_to_aft, fabs(span_position) / half_span); +// }; +// /* Add object from */ +// std::vector<double> spanwise_coordinates{-fabs(from)}; +// +// /* Add intermediate sections */ +// for (auto& section : surface.sections) { +// if (fabs(section.origin.z()) > fabs(from) && fabs(section.origin.z()) < fabs(to)) { +// spanwise_coordinates.push_back(section.origin.z()); +// } +// } +// /* Add object to */ +// spanwise_coordinates.push_back(-fabs(to)); +// +// /**/ +// std::vector<double> x; +// std::vector<double> y; +// /* From in to out*/ +// for (auto it = spanwise_coordinates.begin(); it != spanwise_coordinates.end(); ++it) { +// y.push_back(fabs(*it)); +// x.push_back(geom2::measure::offset_LE(surface, *it).x() + f_chord_fwd(*it) * geom2::measure::chord(surface, *it)); +// } +// /* From out to in*/ +// for (auto rit = spanwise_coordinates.rbegin(); rit != spanwise_coordinates.rend(); ++rit) { +// y.push_back(fabs(*rit)); +// x.push_back(geom2::measure::offset_LE(surface, *rit).x() + +// f_chord_aft(*rit) * geom2::measure::chord(surface, *rit)); +// } +// +// /* Close loop */ +// y.push_back(y.front()); +// x.push_back(x.front()); +// +// return {x, y, object.name}; +//} +namespace taw { +namespace low { + +fs::path T_Tail::plot_stabilizer_planform( + const geom2::MultisectionSurface<geom2::AirfoilSection>& surface, + const std::vector<geom2::MultisectionSurface<geom2::PolygonSection>>& spars, + const std::vector<geom2::MultisectionSurface<geom2::PolygonSection>>& devices) { + auto coordinates_xy = geom2::transform::outline_2d(surface, geom2::Direction_3(0, 0, 1)); + std::deque<double> spanwise; + std::deque<double> chordwise; + auto span = geom2::measure::span(surface); + auto half_span = surface.is_symmetric ? span * 0.5 : span; + auto sections = surface.sections; + auto fuselage_max_half = geom2::measure::width_max(data->fuselage) * 0.5; + + /* Check if control surface is oriented vertical */ + bool is_vertical = std::fabs(surface.normal.dz()) > 0.95; + + /* Loop coordinates from out to inside for LE and TE */ + for (auto it = sections.rbegin(); it != sections.rend(); ++it) { + spanwise.push_front(-it->origin.z()); + spanwise.push_back(-it->origin.z()); + chordwise.push_front(it->origin.x()); + chordwise.push_back(it->origin.x() + it->get_chord_length()); + } + + // /* Get mac coordinates */ + // auto mac_position_y = geom2::measure::mean_aerodynamic_chord_position(data->wing); + // auto mac_position = geom2::measure::offset_LE(data->wing,mac_position_y); + // auto mac = geom2::measure::chord(data->wing,mac_position_y); + + /* Generate plot */ + std::string name = surface.name; + std::replace(name.begin(), name.end(), '_', ' '); + std::vector<std::string> legend_strings; + auto f = matplot::figure(true); + f->title(std::format("{} planform", name)); + auto ax = f->add_axes(false); + if (is_vertical) { + ax->plot(std::vector<double>(chordwise.begin(), chordwise.end()), + std::vector<double>(spanwise.begin(), spanwise.end())) + ->color("black") + .line_width(1.5); + } else { + ax->plot(std::vector<double>(spanwise.begin(), spanwise.end()), + std::vector<double>(chordwise.begin(), chordwise.end())) + ->color("black") + .line_width(1.5); + } + + legend_strings.push_back("contour"); + matplot::hold(true); + + /* Plot spars */ + for (auto& spar : spars) { + const auto [x, y, _] = gen_polygon(surface, spar); + (void)_; + if (is_vertical) { + ax->plot(x, y)->color(spar_color).line_width(1).line_style("--"); + } else { + ax->plot(y, x)->color(spar_color).line_width(1).line_style("--"); + } + legend_strings.push_back("spar"); + } + for (auto& device : devices) { + const auto [x, y, name] = gen_polygon(surface, device); + if (is_vertical) { + ax->plot(x, y)->color(control_device_colormap[name]).line_width(1.5); + } else { + ax->plot(y, x)->color(control_device_colormap[name]).line_width(1.5); + } + legend_strings.push_back(device.name); + } + + /* Select if vertical or horizontal element */ + if (std::fabs(surface.normal.dz()) > 0.7) { + ax->xlabel("x [m]"); + ax->ylabel("z [m]"); + } else { + ax->xlabel("y [m]"); + ax->ylabel("x [m]"); + } + + ax->limits_mode(matplot::manual); + ax->axis(matplot::equal); + if (is_vertical) { + ax->ylim({0, *std::max_element(spanwise.begin(), spanwise.end()) * 1.1}); + } else { + ax->xlim({0, *std::max_element(spanwise.begin(), spanwise.end()) * 1.1}); + } + ax->legend(legend_strings); + ax->legend()->location(matplot::legend::general_alignment::bottomright); + ax->legend()->inside(true); + ax->legend()->box(true); + ax->legend()->font_size(8); + + fs::path plot_path = rtIO->getPlotDir() + "/" + surface.name + "_planfrom.svg"; + matplot::save(f, plot_path.string(), "svg"); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + system("pkill gnuplot"); + return fs::relative(plot_path, fs::path(rtIO->getHtmlDir())); +} + +fs::path T_Tail::plot_thickness_and_twist_distribution( + const geom2::MultisectionSurface<geom2::AirfoilSection>& surface) { + std::vector<double> eta; + std::vector<double> thickness_to_chord_ratio; + std::vector<double> twist; + double half_span = surface.is_symmetric ? geom2::measure::span(surface) * 0.5 : geom2::measure::span(surface); + for (auto section : surface.sections) { + eta.push_back(-section.origin.z() / half_span); + thickness_to_chord_ratio.push_back(geom2::measure::thickness_max(section) / section.get_chord_length()); + twist.push_back(section.get_twist_angle()); + } + const auto [t_to_c_min,t_to_c_max] = std::ranges::minmax_element(thickness_to_chord_ratio); + const auto [twist_min,twist_max] = std::ranges::minmax_element(twist); + + auto f = matplot::figure(true); + + auto ax1 = f->add_subplot(2, 1, 0); + ax1->plot(eta, thickness_to_chord_ratio, "g-")->color("black").line_width(1.5); + // ax1->xlabel("\u03B7"); + ax1->x_axis().visible(true); + ax1->grid(true); + ax1->ylabel("t / c [1]"); + ax1->ylim({*t_to_c_min - 0.01,*t_to_c_max + 0.01}); + + auto ax2 = f->add_subplot(2, 1, 1); + ax2->plot(eta, twist, "b-")->color("black").line_style("--").line_width(1.5); + ax2->ylabel("\u03F5 [\u00b0]"); + ax2->xlabel("\u03B7 [1]"); + ax2->grid(true); + ax2->ylim({*twist_min - 0.01, *twist_max + 0.01}); + + fs::path plot_path = rtIO->getPlotDir() + "/" + surface.name + "_thickness_and_twist_distribution.svg"; + matplot::save(f, plot_path.string(), "svg"); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + system("pkill gnuplot"); + return fs::relative(plot_path, fs::path(rtIO->getHtmlDir())); +} + +/** + * \brief Plot airfoils + * + * \return fs::path + */ +std::vector<fs::path> T_Tail::plot_airfoils(const geom2::MultisectionSurface<geom2::AirfoilSection>& surface) { + std::map<std::string, std::vector<geom2::Point_2>> airfoils_data{}; + std::vector<fs::path> airfoil_plots_path; + + for (auto section : surface.sections) { + if (airfoils_data.find(section.name) != airfoils_data.end()) { + continue; + } else { + airfoils_data.insert({section.name, section.get_contour().vertices()}); + } + } + /* loop over airfoils */ + + for (const auto& airfoil_data : airfoils_data) { + std::vector<double> x{}, y{}; + for (auto coord : airfoil_data.second) { + x.push_back(coord.x()); + y.push_back(coord.y()); + } + + { + auto f = matplot::figure(true); + auto h = f->current_axes()->plot(x, y); + h->line_width(1.5).color("black"); + + auto ax = f->current_axes(); + ax->title(std::format("Airfoil - {}", airfoil_data.first)); + matplot::xlabel("\u03B7"); + ax->ylabel("z/c"); + ax->xlabel("\u03B7 [1]"); + ax->grid(true); + ax->ylim({-0.2, 0.2}); + ax->xlim({0, 1}); + ax->axis(matplot::equal); + + fs::path plot_path = rtIO->getPlotDir() + "/" + surface.name + "_" + airfoil_data.first + "_airfoil.svg"; + matplot::save(f, plot_path.string(), "svg"); + airfoil_plots_path.push_back(fs::relative(plot_path, fs::path(rtIO->getHtmlDir()))); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + system("pkill gnuplot"); + } + } + return airfoil_plots_path; +} + +} // namespace low +} // namespace taw diff --git a/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design_report.cpp b/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design_report.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ba7803317e7a676365391a8337be847be2787b2 --- /dev/null +++ b/empennage_design/src/taw/t_tail/low/low_t_tail_empennage_design_report.cpp @@ -0,0 +1,551 @@ +/** + * \file cantileverWingDesignReport.cpp + * \author Christopher Ruwisch (christopher.ruwisch@tu-berlin.de) + * \brief Report for cantilever wing design + * \version 0.1 + * \date 2024-02-14 + * + * @copyright Copyright (c) 2024 + * + */ +#include <aircraftGeometry2/processing/measure.h> +#include <aircraftGeometry2/processing/transform.h> +#include <moduleBasics/html.h> + +#include "low_t_tail_empennage_design.h" + +namespace taw { +namespace low { +void T_Tail::set_html_body() { + /* Add box data */ + reporter.htmlReportStream() << "<div class=\"box data\">\n"; + /* Add headline Data*/ + reporter.htmlReportStream() << "<h2>Data</h2>\n"; + /* Table 1 - General parameters */ + reporter.htmlReportStream() + << "<table class=\"content-table\">\n" + << "<caption>Vertical Stabilizer</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>parameter</th><th>symbol</th><th>unit</th><th>value</th>\n" + << "</tr>\n" + << "</thead>\n" + << "<tbody>\n" + << "<tr>\n" + << std::format("<td>Reference area</td><td>S<sub>ref</sub></td><td>m<sup>2</sup></td><td>{:.2f}</td>\n", + geom2::measure::reference_area(data->vertical_stabilizer)) + << "</tr>\n" + << "<tr>\n" + << std::format("<td>Mean aero. chord</td><td>MAC</td><td>m</td><td>{:.2f}</td>\n", + geom2::measure::mean_aerodynamic_chord(data->vertical_stabilizer)) + << "</tr>\n" + << "<tr>\n" + << std::format("<td>Span</td><td>b</td><td>m</td><td>{:.2f}</td>\n", + geom2::measure::span(data->vertical_stabilizer)) + << "</tr>\n" + << "<tr>\n" + << std::format("<td>Aspect ratio</td><td>AR</td><td>1</td><td>{:.2f}</td>\n", + geom2::measure::aspect_ratio(data->vertical_stabilizer)) + << "</tr>\n" + << "<tr>\n" + << std::format("<td>Taper ratio</td><td>λ</td><td>1</td><td>{:.2f}</td>\n", + geom2::measure::taper_ratio(data->vertical_stabilizer)) + << "</tr>\n" + << std::format("<td>Ref. position</td><td>x<sub>ref</sub></td><td>m</td><td>{:.2f}</td>\n", + data->empennage_position.x.value() + data->vertical_stabilizer.origin.x()) + << "</tr>\n" + << std::format("<td></td><td>y<sub>ref</sub></td><td>m</td><td>{:.2f}</td>\n", + data->empennage_position.y.value() + data->vertical_stabilizer.origin.y()) + << "</tr>\n" + << std::format("<td></td><td>z<sub>ref</sub></td><td>m</td><td>{:.2f}</td>\n", + data->empennage_position.z.value() + -data->vertical_stabilizer.origin.z()) + << "</tr>\n" + << "</tbody>\n" + << "</table>\n"; + + /* Table 2 - Section parameters*/ + reporter.htmlReportStream() << "<table class=\"content-table\">\n" + << "<caption>Section Parameter - Vertical Stabilizer</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>parameter</th><th>symbol</th><th>unit</th>"; + for (int i = 0; i < data->vertical_stabilizer.sections.size(); ++i) { + reporter.htmlReportStream() << std::format("<th>S<sub>{:02d}</sub></th>", i); + } + reporter.htmlReportStream() << "\n</tr>\n" + << "</thead>\n" + << "<tbody>\n" + /* Dimensionless half span - eta*/ + << "<tr>\n" + << "<td>Dimensionless half span</td><td>η</td><td>1</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", std::fabs(section.origin.z() / geom2::measure::span(data->vertical_stabilizer))); + } + /* Spanwise coordinate - y*/ + reporter.htmlReportStream() << "\n</tr>\n" + << "<td>Spanwise coordinate</td><td>y</td><td>m</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format("<td>{:.2f}</td>", std::fabs(section.origin.z())); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Chord - c*/ + << "<tr>\n" + << "<td>Chord</td><td>c</td><td>m</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format("<td>{:.2f}</td>", section.get_chord_length()); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Sweep - Leading edge - phi_LE*/ + << "<tr>\n" + << "<td>Sweep leading edge</td><td>φ<sub>LE</sub></td><td>°</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", + -geom2::detail::to_degrees * geom2::measure::sweep(data->vertical_stabilizer, section.origin.z(), 0.0)); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Sweep - 25 percent - phi_25%*/ + << "<tr>\n" + << "<td>Sweep quarter chord</td><td>φ<sub>25</sub></td><td>°</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", + -geom2::detail::to_degrees * geom2::measure::sweep(data->vertical_stabilizer, section.origin.z(), 0.25)); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Sweep - Trailing edge percent - phi_TE*/ + << "<tr>\n" + << "<td>Sweep Trailing edge</td><td>φ<sub>TE</sub></td><td>°</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", + -geom2::detail::to_degrees * geom2::measure::sweep(data->vertical_stabilizer, section.origin.z(), 1.0)); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Dihedral - nu*/ + << "<tr>\n" + << "<td>Dihedral</td><td>ν</td><td>°</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", + geom2::detail::to_degrees * geom2::measure::dihedral(data->vertical_stabilizer, section.origin.z())); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Twist - epsilon*/ + << "<tr>\n" + << "<td>Twist angle</td><td>ε</td><td>°</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format("<td>{:.2f}</td>", geom2::detail::to_degrees * section.rotation_z); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Thickness to chord - epsilon*/ + << "<tr>\n" + << "<td>Thickness ratio</td><td>t/c</td><td>%</td>"; + for (auto section : data->vertical_stabilizer.sections) { + /* Remove when thickness max is working */ + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", 100 * geom2::measure::thickness_max(section) / section.get_chord_length()); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Airfoil - none */ + << "<tr>\n" + << "<td>Airfoil</td><td>-</td><td>-</td>"; + for (auto section : data->vertical_stabilizer.sections) { + reporter.htmlReportStream() << std::format("<td>{}</td>", section.name); + } + reporter.htmlReportStream() << "\n</tr>\n" + << "</tbody>\n" + << "</table>\n"; + + /* Table 3 - Spar parameters*/ + std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> vertical_stabilizer_spars = + data->vertical_stabilizer_spars; + for (int spar_id = 0; spar_id < vertical_stabilizer_spars.size(); ++spar_id) { + reporter.htmlReportStream() << "<table class=\"content-table\">\n"; + if (spar_id == 0) { + reporter.htmlReportStream() << "<caption>Spar parameters</caption>\n"; + } + reporter.htmlReportStream() << "<thead>\n" + << "<tr>\n" + << std::format("<th>{:<10}</th><th>η [1]<th>x/c [%]</th>", + vertical_stabilizer_spars.at(spar_id).name) + << "\n</tr>\n" + << "</thead>\n" + << "<tbody>\n"; + /* Spar name - eta, x/c*/ + for (int i = 0; i < vertical_stabilizer_spars.at(spar_id).sections.size(); ++i) { + reporter.htmlReportStream() << "<tr>\n"; + std::string tag = ""; + if (i == 0) { + tag = "from"; + } else if (i == vertical_stabilizer_spars.at(spar_id).sections.size() - 1) { + tag = "to"; + } + reporter.htmlReportStream() << std::format( + "<td>{}</td><td>{:.2f}</td><td>{:.2f}</td>\n", tag, + vertical_stabilizer_spars.at(spar_id).sections.at(i).origin.z(), + vertical_stabilizer_spars.at(spar_id).sections.at(i).get_contour().vertex(0).x()); + reporter.htmlReportStream() << "\n</tr>\n"; + } + /* Spanwise coordinate - y*/ + reporter.htmlReportStream() << "</tbody>\n" + << "</table>\n"; + } + + /* Sort devices to leading, trailing and other devices*/ + /* device data - name, eta_from, rel_chord_from_start, rel_chord_from_end, eta_to, rel_chord_to_start, + * rel_chord_to_end */ + using device_data = std::tuple<std::string, double, double, double, double, double, double>; + std::vector<device_data> vertical_stabilizer_devices; + std::vector<device_data> horizontal_stabilizer_devices; + std::vector<device_data> other_devices; + std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> elevators = + data->horizontal_stabilizer_control_devices; + std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> rudders = data->vertical_stabilizer_control_devices; + + for (auto device : rudders) { + /* Device has only two sections (from + to) spanwise */ + double eta_from = device.sections.at(0).origin.z(); + double rel_chord_from_start = device.sections.at(0).get_contour().vertex(0).x(), + rel_chord_from_end = device.sections.at(0).get_contour().vertex(1).x(); + double eta_to = device.sections.at(1).origin.z(); + double rel_chord_to_start = device.sections.at(1).get_contour().vertex(0).x(), + rel_chord_to_end = device.sections.at(1).get_contour().vertex(1).x(); + vertical_stabilizer_devices.push_back({device.name, eta_from, rel_chord_from_start, rel_chord_from_end, eta_to, + rel_chord_to_start, rel_chord_to_end}); + } + + for (auto device : elevators) { + /* Device has only two sections (from + to) spanwise */ + double eta_from = device.sections.at(0).origin.z(); + double rel_chord_from_start = device.sections.at(0).get_contour().vertex(0).x(), + rel_chord_from_end = device.sections.at(0).get_contour().vertex(1).x(); + double eta_to = device.sections.at(1).origin.z(); + double rel_chord_to_start = device.sections.at(1).get_contour().vertex(0).x(), + rel_chord_to_end = device.sections.at(1).get_contour().vertex(1).x(); + horizontal_stabilizer_devices.push_back({device.name, eta_from, rel_chord_from_start, rel_chord_from_end, eta_to, + rel_chord_to_start, rel_chord_to_end}); + } + reporter.htmlReportStream() + << "<table class=\"content-table\">\n" + << "<caption>Vertical stabilizer control devices</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>Device</th><th>η<sub>from</sub></th><th>x/c<sub>from,start</sub></th><th>x/c<sub>from,end</sub></" + "th><th>η<sub>to</sub></th><th>x/c<sub>to,start</sub></th><th>x/c<sub>to,end</sub></th>\n" + << "</tr>\n" + << "</thead>\n" + << "<tbody>\n"; + for (auto device : vertical_stabilizer_devices) { + const auto [name, eta_from, rel_chord_from_start, rel_chord_from_end, eta_to, rel_chord_to_start, + rel_chord_to_end] = device; + reporter.htmlReportStream() << "<tr>\n"; + reporter.htmlReportStream() << std::format( + "<td>{}</td><td>{:.2f}</td><td>{:.2f}</td><td>{:.2f}</td><td>{:.2f}</td><td>{:.2f}</td><td>{:.2f}</td>\n", name, + eta_from, rel_chord_from_start, rel_chord_from_end, eta_to, rel_chord_to_start, rel_chord_to_end); + reporter.htmlReportStream() << "\n</tr>\n"; + } + reporter.htmlReportStream() << "</tbody>\n" + << "</table>\n"; + + reporter.htmlReportStream() + << "<table class=\"content-table\">\n" + << "<caption>Mass and CoG - Vertical stabilizer</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>Mass</th><th>CoG<sub>x</sub></th><th>CoG<sub>y</sub></th><th>CoG<sub>z</sub></th>\n" + << "</tr>\n" + << "</thead>\n" + << "<tbody>\n" + << "<tr>\n" + << std::format("<td>{:.2f}kg</td><td>{:.2f}m</td><td>{:.2f}m</td><td>{:.2f}m</td>", + data->vertical_stabilizer_mass.data["mass"].value(), + data->vertical_stabilizer_mass.data["x"].value(), data->vertical_stabilizer_mass.data["y"].value(), + data->vertical_stabilizer_mass.data["z"].value()) + << "\n<tr>\n" + << "</tbody>\n" + << "</table>\n"; + + /* Horizontal stabilizer */ + reporter.htmlReportStream() + << "<table class=\"content-table\">\n" + << "<caption>Horizontal Stabilizer</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>parameter</th><th>symbol</th><th>unit</th><th>value</th>\n" + << "</tr>\n" + << "</thead>\n" + << "<tbody>\n" + << "<tr>\n" + << std::format("<td>Reference area</td><td>S<sub>ref</sub></td><td>m<sup>2</sup></td><td>{:.2f}</td>\n", + geom2::measure::reference_area(data->horizontal_stabilizer)) + << "</tr>\n" + << "<tr>\n" + << std::format("<td>Mean aero. chord</td><td>MAC</td><td>m</td><td>{:.2f}</td>\n", + geom2::measure::mean_aerodynamic_chord(data->horizontal_stabilizer)) + << "</tr>\n" + << "<tr>\n" + << std::format("<td>Span</td><td>b</td><td>m</td><td>{:.2f}</td>\n", + geom2::measure::span(data->horizontal_stabilizer)) + << "</tr>\n" + << "<tr>\n" + << std::format("<td>Aspect ratio</td><td>AR</td><td>1</td><td>{:.2f}</td>\n", + geom2::measure::aspect_ratio(data->horizontal_stabilizer)) + << "</tr>\n" + << "<tr>\n" + << std::format("<td>Taper ratio</td><td>λ</td><td>1</td><td>{:.2f}</td>\n", + geom2::measure::taper_ratio(data->horizontal_stabilizer)) + << "</tr>\n" + << std::format("<td>Ref. position</td><td>x<sub>ref</sub></td><td>m</td><td>{:.2f}</td>\n", + data->empennage_position.x.value() + data->horizontal_stabilizer.origin.x()) + << "</tr>\n" + << std::format("<td></td><td>y<sub>ref</sub></td><td>m</td><td>{:.2f}</td>\n", + data->empennage_position.y.value() + data->horizontal_stabilizer.origin.y()) + << "</tr>\n" + << std::format("<td></td><td>z<sub>ref</sub></td><td>m</td><td>{:.2f}</td>\n", + data->empennage_position.z.value() + -data->horizontal_stabilizer.origin.z()) + << "</tr>\n" + << "</tbody>\n" + << "</table>\n"; + + /* Table 2 - Section parameters*/ + reporter.htmlReportStream() << "<table class=\"content-table\">\n" + << "<caption>Section Parameter - Horizontal Stabilizer</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>parameter</th><th>symbol</th><th>unit</th>"; + for (int i = 0; i < data->horizontal_stabilizer.sections.size(); ++i) { + reporter.htmlReportStream() << std::format("<th>S<sub>{:02d}</sub></th>", i); + } + reporter.htmlReportStream() << "\n</tr>\n" + << "</thead>\n" + << "<tbody>\n" + /* Dimensionless half span - eta*/ + << "<tr>\n" + << "<td>Dimensionless half span</td><td>η</td><td>1</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", std::fabs(2 * section.origin.z() / geom2::measure::span(data->horizontal_stabilizer))); + } + /* Spanwise coordinate - y*/ + reporter.htmlReportStream() << "\n</tr>\n" + << "<td>Spanwise coordinate</td><td>y</td><td>m</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format("<td>{:.2f}</td>", std::fabs(section.origin.z())); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Chord - c*/ + << "<tr>\n" + << "<td>Chord</td><td>c</td><td>m</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format("<td>{:.2f}</td>", section.get_chord_length()); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Sweep - Leading edge - phi_LE*/ + << "<tr>\n" + << "<td>Sweep leading edge</td><td>φ<sub>LE</sub></td><td>°</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", + -geom2::detail::to_degrees * geom2::measure::sweep(data->horizontal_stabilizer, section.origin.z(), 0.0)); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Sweep - 25 percent - phi_25%*/ + << "<tr>\n" + << "<td>Sweep quarter chord</td><td>φ<sub>25</sub></td><td>°</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", + -geom2::detail::to_degrees * geom2::measure::sweep(data->horizontal_stabilizer, section.origin.z(), 0.25)); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Sweep - Trailing edge percent - phi_TE*/ + << "<tr>\n" + << "<td>Sweep Trailing edge</td><td>φ<sub>TE</sub></td><td>°</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", + -geom2::detail::to_degrees * geom2::measure::sweep(data->horizontal_stabilizer, section.origin.z(), 1.0)); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Dihedral - nu*/ + << "<tr>\n" + << "<td>Dihedral</td><td>ν</td><td>°</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", + geom2::detail::to_degrees * geom2::measure::dihedral(data->horizontal_stabilizer, section.origin.z())); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Twist - epsilon*/ + << "<tr>\n" + << "<td>Twist angle</td><td>ε</td><td>°</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format("<td>{:.2f}</td>", geom2::detail::to_degrees * section.rotation_z); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Thickness to chord - epsilon*/ + << "<tr>\n" + << "<td>Thickness ratio</td><td>t/c</td><td>%</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format( + "<td>{:.2f}</td>", 100 * geom2::measure::thickness_max(section) / section.get_chord_length()); + } + reporter.htmlReportStream() << "\n</tr>\n" + /* Airfoil - none */ + << "<tr>\n" + << "<td>Airfoil</td><td>-</td><td>-</td>"; + for (auto section : data->horizontal_stabilizer.sections) { + reporter.htmlReportStream() << std::format("<td>{}</td>", section.name); + } + reporter.htmlReportStream() << "\n</tr>\n" + << "</tbody>\n" + << "</table>\n"; + + /* Table 3 - Spar parameters*/ + std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> horizontal_stabilizer_spars = + data->horizontal_stabilizer_spars; + for (int spar_id = 0; spar_id < horizontal_stabilizer_spars.size(); ++spar_id) { + reporter.htmlReportStream() << "<table class=\"content-table\">\n"; + if (spar_id == 0) { + reporter.htmlReportStream() << "<caption>Spar parameters</caption>\n"; + } + reporter.htmlReportStream() << "<thead>\n" + << "<tr>\n" + << std::format("<th>{:<10}</th><th>η [1]<th>x/c [%]</th>", + horizontal_stabilizer_spars.at(spar_id).name) + << "\n</tr>\n" + << "</thead>\n" + << "<tbody>\n"; + /* Spar name - eta, x/c*/ + for (int i = 0; i < horizontal_stabilizer_spars.at(spar_id).sections.size(); ++i) { + reporter.htmlReportStream() << "<tr>\n"; + std::string tag = ""; + if (i == 0) { + tag = "from"; + } else if (i == horizontal_stabilizer_spars.at(spar_id).sections.size() - 1) { + tag = "to"; + } + reporter.htmlReportStream() << std::format( + "<td>{}</td><td>{:.2f}</td><td>{:.2f}</td>\n", tag, + horizontal_stabilizer_spars.at(spar_id).sections.at(i).origin.z(), + horizontal_stabilizer_spars.at(spar_id).sections.at(i).get_contour().vertex(0).x()); + reporter.htmlReportStream() << "\n</tr>\n"; + } + /* Spanwise coordinate - y*/ + reporter.htmlReportStream() << "</tbody>\n" + << "</table>\n"; + } + + reporter.htmlReportStream() + << "<table class=\"content-table\">\n" + << "<caption>Horizontal stabilizer control devices</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>Device</th><th>η<sub>from</sub></th><th>x/c<sub>from,start</sub></th><th>x/c<sub>from,end</sub></" + "th><th>η<sub>to</sub></th><th>x/c<sub>to,start</sub></th><th>x/c<sub>to,end</sub></th>\n" + << "</tr>\n" + << "</thead>\n" + << "<tbody>\n"; + for (auto device : horizontal_stabilizer_devices) { + const auto [name, eta_from, rel_chord_from_start, rel_chord_from_end, eta_to, rel_chord_to_start, + rel_chord_to_end] = device; + reporter.htmlReportStream() << "<tr>\n"; + reporter.htmlReportStream() << std::format( + "<td>{}</td><td>{:.2f}</td><td>{:.2f}</td><td>{:.2f}</td><td>{:.2f}</td><td>{:.2f}</td><td>{:.2f}</td>\n", name, + eta_from, rel_chord_from_start, rel_chord_from_end, eta_to, rel_chord_to_start, rel_chord_to_end); + reporter.htmlReportStream() << "\n</tr>\n"; + } + reporter.htmlReportStream() << "</tbody>\n" + << "</table>\n"; + + reporter.htmlReportStream() + << "<table class=\"content-table\">\n" + << "<caption>Mass and CoG - Horizontal stabilizer</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>Mass</th><th>CoG<sub>x</sub></th><th>CoG<sub>y</sub></th><th>CoG<sub>z</sub></th>\n" + << "</tr>\n" + << "</thead>\n" + << "<tbody>\n" + << "<tr>\n" + << std::format( + "<td>{:.2f}kg</td><td>{:.2f}m</td><td>{:.2f}m</td><td>{:.2f}m</td>", + data->horizontal_stabilizer_mass.data["mass"].value(), data->horizontal_stabilizer_mass.data["x"].value(), + data->horizontal_stabilizer_mass.data["y"].value(), data->horizontal_stabilizer_mass.data["z"].value()) + << "\n<tr>\n" + << "</tbody>\n" + << "</table>\n"; + + reporter.htmlReportStream() + << "<table class=\"content-table\">\n" + << "<caption>Mass and CoG - Empennage</caption>\n" + << "<thead>\n" + << "<tr>\n" + << "<th>Mass</th><th>CoG<sub>x</sub></th><th>CoG<sub>y</sub></th><th>CoG<sub>z</sub></th>\n" + << "</tr>\n" + << "</thead>\n" + << "<tbody>\n" + << "<tr>\n" + << std::format("<td>{:.2f}kg</td><td>{:.2f}m</td><td>{:.2f}m</td><td>{:.2f}m</td>", + data->empennage_mass.data["mass"].value(), data->empennage_mass.data["x"].value(), + data->empennage_mass.data["y"].value(), data->empennage_mass.data["z"].value()) + << "\n<tr>\n" + << "</tbody>\n" + << "</table>\n"; + + + /* close box data div */ + reporter.htmlReportStream() << "</div>\n"; + + if (rtIO->plotOn) { + /* open box plot div */ + reporter.htmlReportStream() << "<div class=\"box plot\">\n"; + /* Add headline Data*/ + reporter.htmlReportStream() << "<h2>Plots</h2>\n"; + + /* Add Geometry Headline */ + reporter.htmlReportStream() << "<h3>Geometry</h3>\n"; + + + /* Vertical stabilizer planform plot */ + auto planform_vertical_stabilizer_plot_path = plot_stabilizer_planform( + data->vertical_stabilizer, data->vertical_stabilizer_spars, data->vertical_stabilizer_control_devices); + reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n", + planform_vertical_stabilizer_plot_path.string()); + /* Vertical stabilizer airfoil */ + auto vertical_stabilizer_airfoil_plot_paths = plot_airfoils(data->vertical_stabilizer); + reporter.htmlReportStream() << "<h3>Vertical Stabilizer Airfoils</h3>\n"; + for( auto airfoil_path : vertical_stabilizer_airfoil_plot_paths) { + reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n", airfoil_path.string()); + } + reporter.htmlReportStream() << "<h3>Horizontal Stabilizer Thickness & Geometric Twist</h3>\n"; + auto vertical_stabilizer_thickness_and_twist_plot_path = plot_thickness_and_twist_distribution(data->vertical_stabilizer); + reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n", + vertical_stabilizer_thickness_and_twist_plot_path.string()); + + + /* Horizontal Stabilizer planform plot */ + auto planform_horizontal_stabilizer_plot_path = plot_stabilizer_planform( + data->horizontal_stabilizer, data->horizontal_stabilizer_spars, data->horizontal_stabilizer_control_devices); + reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n", + planform_horizontal_stabilizer_plot_path.string()); + + /* Horizontal stabilizer airfoil */ + auto horizontal_stabilizer_airfoil_plot_paths = plot_airfoils(data->horizontal_stabilizer); + reporter.htmlReportStream() << "<h3>Horizontal Stabilizer Airfoils</h3>\n"; + for( auto airfoil_path : horizontal_stabilizer_airfoil_plot_paths) { + reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n", airfoil_path.string()); + } + reporter.htmlReportStream() << "<h3>Horizontal Stabilizer Thickness & Geometric Twist</h3>\n"; + auto horizontal_stabilizer_thickness_and_twist_plot_path = plot_thickness_and_twist_distribution(data->horizontal_stabilizer); + reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n", + horizontal_stabilizer_thickness_and_twist_plot_path.string()); + + // /* close box plot */ + reporter.htmlReportStream() << "</div>\n"; + } +} +} // namespace low +} // namespace taw diff --git a/empennage_design/src/taw/t_tail/t_tail_empennage_design_config.cpp b/empennage_design/src/taw/t_tail/t_tail_empennage_design_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ccdfe2b9cd101eabc35b9e756c414b4943a41cc --- /dev/null +++ b/empennage_design/src/taw/t_tail/t_tail_empennage_design_config.cpp @@ -0,0 +1,35 @@ +/** + * \file tawConventionalConfig.cpp + * \author Christopher Ruwisch (christopher.ruwisch@tu-berlin.de) + * \brief Tube and Wing Conventional Config source file + * \version 0.1 + * \date 2023-11-24 + * + * @copyright Copyright (c) 2023 + * + */ + +#include "t_tail_empennage_design_config.h" + +namespace taw { +namespace low { + +T_Tail_Config::T_Tail_Config() + : design_mode(EndnodeReadOnly<std::string>("module_configuration_file/program_settings/modes/design_mode")), + mass_mode(EndnodeReadOnly<std::string>("module_configuration_file/program_settings/modes/mass_mode")), + vertical_stabilizer(TailElement( + "module_configuration_file/program_settings/tube_and_wing/low_fidelity/t_tail/tail_element@0/")), + horizontal_stabilizer(TailElement( + "module_configuration_file/program_settings/tube_and_wing/low_fidelity/t_tail/tail_element@1/")), + common_airfoil_data_path(EndnodeReadOnly<std::string>("module_configuration_file/program_settings/common_airfoil_data_path")) {} + +void T_Tail_Config::read(const node& xml) { + design_mode.read(xml); + mass_mode.read(xml); + common_airfoil_data_path.read(xml); + vertical_stabilizer.read(xml); + horizontal_stabilizer.read(xml); +} + +} // namespace low +} // namespace taw diff --git a/empennage_design/src/taw/t_tail/t_tail_empennage_design_config.h b/empennage_design/src/taw/t_tail/t_tail_empennage_design_config.h new file mode 100644 index 0000000000000000000000000000000000000000..0d6ae56c2d4b3a430b180c728342e09a960abe63 --- /dev/null +++ b/empennage_design/src/taw/t_tail/t_tail_empennage_design_config.h @@ -0,0 +1,36 @@ +/** + * \file T_TAILConfig.h + * \author Christopher Ruwisch (christopher.ruwisch@tu-berlin.de) + * \brief T_TAIL tail configuration information + * \version 0.1 + * \date 2023-10-31 + * + * @copyright Copyright (c) 2023 + * + */ +#ifndef EMPENNAGEDESIGN_SRC_TAW_T_TAIL_TAWT_TAILCONFIG_H_ +#define EMPENNAGEDESIGN_SRC_TAW_T_TAIL_TAWT_TAILCONFIG_H_ + +#include <aixml/endnode.h> + +#include "lib/IO_methods/io.h" + +namespace taw { +namespace low { + +class T_Tail_Config { + public: + T_Tail_Config(); + ~T_Tail_Config() = default; + void read(const node& xml); + + EndnodeReadOnly<std::string> common_airfoil_data_path; + EndnodeReadOnly<std::string> design_mode; + EndnodeReadOnly<std::string> mass_mode; + TailElement vertical_stabilizer; + TailElement horizontal_stabilizer; +}; + +} // namespace low +} // namespace taw +#endif // EMPENNAGEDESIGN_SRC_TAW_T_TAIL_TAWT_TAILCONFIG_H_ diff --git a/empennage_design/src/taw/t_tail/t_tail_empennage_design_data.cpp b/empennage_design/src/taw/t_tail/t_tail_empennage_design_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c4982d2cf0c06d320204768fbba9ce96f9bfd19 --- /dev/null +++ b/empennage_design/src/taw/t_tail/t_tail_empennage_design_data.cpp @@ -0,0 +1,153 @@ +/** + * \file T_TAILEmpennageDesignData.cpp + * \author Christopher Ruwisch (christopher.ruwisch@tu-berlin.de) + * \brief Tube and Wing T_TAIL Data source file + * \version 0.1 + * \date 2023-11-24 + * + * @copyright Copyright (c) 2023 + * + */ + +#include "t_tail_empennage_design_data.h" + +#include <aircraftGeometry2/airfoil_surface.h> +#include <aircraftGeometry2/fuselage.h> +#include <aircraftGeometry2/geometry/surface.h> + +namespace taw { +namespace low { + +T_Tail_Data::T_Tail_Data() + : maximum_takeoff_mass( + EndnodeReadOnly<double>("analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/mass")), + empennage_mass(MassPropertiesIO("component_design/empennage/", "T_TAIL tail overall mass")), + vertical_stabilizer_mass(MassPropertiesIO("component_design/empennage/specific/geometry/aerodynamic_surface@0/", + "vertical stabiliser mass")), + horizontal_stabilizer_mass(MassPropertiesIO("component_design/empennage/specific/geometry/aerodynamic_surface@1/", + "horizontal stabiliser mass")), + wing_position_x(EndnodeReadOnly<double>("component_design/wing/position/x")), + empennage_position(PositionIO("component_design/empennage/position", "empennage")) {} + +void T_Tail_Data::read(const node &xml) { + wing_position_x.read(xml); + maximum_takeoff_mass.read(xml); +} + +void T_Tail_Data::read_fuselage(std::filesystem::path path, std::filesystem::path geometry_data_dir) { + std::shared_ptr<node> acxml = aixml::openDocument(path); + geom2::FuselageFactory fuselage_factory{acxml, geometry_data_dir}; + fuselage = fuselage_factory.create("fuselage/specific/geometry/fuselage@0"); +} + +void T_Tail_Data::read_wing(std::filesystem::path path, std::filesystem::path airfoil_data_dir) { + std::shared_ptr<node> acxml = aixml::openDocument(path); + geom2::WingFactory wing_factory{acxml, airfoil_data_dir}; + wing = wing_factory.create("wing/specific/geometry/aerodynamic_surface@0"); +} + +void T_Tail_Data::update_vertical_stabilizer(node &xml) { + geom2::io::SurfaceType io = geom2::io::Wing(vertical_stabilizer); + const std::string path_to_geometry = "component_design/empennage/specific/geometry"; + std::visit(geom2::io::AixmlConverter(xml[path_to_geometry], {"aerodynamic_surface", "0", vertical_stabilizer.name}), + io); +} + +void T_Tail_Data::update_vertical_stabilizer_spars(node &xml) { + int i = 0; + for (auto &spar : vertical_stabilizer_spars) { + geom2::io::SurfaceType io_spar = geom2::io::Spar(spar); + const std::string path_to_spars = + "component_design/empennage/specific/geometry/aerodynamic_surface@0/parameters/spars"; + std::visit(geom2::io::AixmlConverter(xml[path_to_spars], {"spar", std::to_string(i++), spar.name}), io_spar); + } +} + +void T_Tail_Data::update_vertical_stabilizer_control_devices(node &xml) { + int i = 0; + for (auto control_device : vertical_stabilizer_control_devices) { + geom2::io::SurfaceType io_control_device = geom2::io::ControlDevice(control_device); + std::string path_to_device = + "component_design/empennage/specific/geometry/aerodynamic_surface@0/parameters/control_devices"; + std::visit( + geom2::io::AixmlConverter(xml[path_to_device], {"control_device", std::to_string(i), control_device.name}), + io_control_device); + Endnode<double> min_deflection( + path_to_device + "/control_device@" + std::to_string(i) + "/deflection/full_negative_deflection", + "full negative deflection"); + Endnode<double> max_deflection( + path_to_device + "/control_device@" + std::to_string(i) + "/deflection/full_positive_deflection", + "full positive deflection"); + const auto [min, max] = vertical_stabilizer_control_devices_deflections[i]; + min_deflection.set_unit("rad"); + min_deflection.set_value(min); + min_deflection.update(xml); + max_deflection.set_unit("rad"); + max_deflection.set_value(max); + max_deflection.update(xml); + i++; + } +} + +void T_Tail_Data::update_horizontal_stabilizer(node &xml) { + geom2::io::SurfaceType io = geom2::io::Wing(horizontal_stabilizer); + const std::string path_to_geometry = "component_design/empennage/specific/geometry"; + std::visit(geom2::io::AixmlConverter(xml[path_to_geometry], {"aerodynamic_surface", "1", horizontal_stabilizer.name}), + io); +} + +void T_Tail_Data::update_horizontal_stabilizer_spars(node &xml) { + int i = 0; + for (auto &spar : horizontal_stabilizer_spars) { + geom2::io::SurfaceType io_spar = geom2::io::Spar(spar); + const std::string path_to_spars = + "component_design/empennage/specific/geometry/aerodynamic_surface@1/parameters/spars"; + std::visit(geom2::io::AixmlConverter(xml[path_to_spars], {"spar", std::to_string(i++), spar.name}), io_spar); + } +} + +void T_Tail_Data::update_horizontal_stabilizer_control_devices(node &xml) { + int i = 0; + for (auto &control_device : horizontal_stabilizer_control_devices) { + geom2::io::SurfaceType io_control_device = geom2::io::ControlDevice(control_device); + const std::string path_to_device = + "component_design/empennage/specific/geometry/aerodynamic_surface@1/parameters/control_devices"; + std::visit( + geom2::io::AixmlConverter(xml[path_to_device], {"control_device", std::to_string(i), control_device.name}), + io_control_device); + Endnode<double> min_deflection( + path_to_device + "/control_device@" + std::to_string(i) + "/deflection/full_negative_deflection", + "full negative deflection"); + Endnode<double> max_deflection( + path_to_device + "/control_device@" + std::to_string(i) + "/deflection/full_positive_deflection", + "full positive deflection"); + const auto [min, max] = horizontal_stabilizer_control_devices_deflections[i]; + min_deflection.set_unit("rad"); + min_deflection.set_value(min); + min_deflection.update(xml); + max_deflection.set_unit("rad"); + max_deflection.set_value(max); + max_deflection.update(xml); + i++; + } +} + +void T_Tail_Data::update(node &xml) { + auto tmp = xml.find("component_design/empennage"); + if (tmp != nullptr) { + tmp->deleteChildren(); + } + empennage_position.update(xml); + empennage_mass.update(xml); + update_vertical_stabilizer(xml); + update_vertical_stabilizer_spars(xml); + update_vertical_stabilizer_control_devices(xml); + vertical_stabilizer_mass.update(xml); + update_horizontal_stabilizer(xml); + update_horizontal_stabilizer_spars(xml); + update_horizontal_stabilizer_control_devices(xml); + horizontal_stabilizer_mass.update(xml); +} + +} // namespace low +} // namespace taw diff --git a/empennage_design/src/taw/t_tail/t_tail_empennage_design_data.h b/empennage_design/src/taw/t_tail/t_tail_empennage_design_data.h new file mode 100644 index 0000000000000000000000000000000000000000..a555141c76302825a0c8e65fc34e7a9ce5eb888f --- /dev/null +++ b/empennage_design/src/taw/t_tail/t_tail_empennage_design_data.h @@ -0,0 +1,65 @@ +/** + * \file T_TAILData.h + * \author Christopher Ruwisch (christopher.ruwisch@tu-berlin.de) + * \brief + * \version 0.1 + * \date 2023-11-10 + * + * @copyright Copyright (c) 2023 + * + */ +#ifndef EMPENNAGEDESIGN_SRC_TAW_T_TAIL_T_TAILEMPENNAGEDESIGNDATA_H_ +#define EMPENNAGEDESIGN_SRC_TAW_T_TAIL_T_TAILEMPENNAGEDESIGNDATA_H_ + +#include <aircraftGeometry2/geometry/factory.h> +#include <aircraftGeometry2/io/convert.h> + +#include "lib/IO_methods/massPropertiesIO.h" +#include "lib/IO_methods/positionIO.h" +namespace taw +{ + namespace low + { + + class T_Tail_Data + { + public: + T_Tail_Data(); + + void read(const node &xml); + void read_wing(std::filesystem::path path, std::filesystem::path airfoil_data_dir); + void read_fuselage(std::filesystem::path path, std::filesystem::path geometry_data_dir); + + void update(node &xml); + void update_vertical_stabilizer(node &xml); + void update_vertical_stabilizer_spars(node &xml); + void update_vertical_stabilizer_control_devices(node &xml); + + void update_horizontal_stabilizer(node &xml); + void update_horizontal_stabilizer_spars(node &xml); + void update_horizontal_stabilizer_control_devices(node &xml); + + EndnodeReadOnly<double> maximum_takeoff_mass; + EndnodeReadOnly<double> wing_position_x; + + geom2::MultisectionSurface<geom2::PolygonSection> fuselage; + geom2::MultisectionSurface<geom2::AirfoilSection> wing; + geom2::MultisectionSurface<geom2::AirfoilSection> vertical_stabilizer; + std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> vertical_stabilizer_spars; + std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> vertical_stabilizer_control_devices; + std::vector<std::tuple<double,double>> vertical_stabilizer_control_devices_deflections; + + geom2::MultisectionSurface<geom2::AirfoilSection> horizontal_stabilizer; + std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> horizontal_stabilizer_spars; + std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> horizontal_stabilizer_control_devices; + std::vector<std::tuple<double,double>> horizontal_stabilizer_control_devices_deflections; + + MassPropertiesIO vertical_stabilizer_mass; + MassPropertiesIO horizontal_stabilizer_mass; + MassPropertiesIO empennage_mass; + PositionIO empennage_position; + }; + + } // namespace low +} // namespace taw +#endif // EMPENNAGEDESIGN_SRC_TAW_T_TAIL_T_TAILEMPENNAGEDESIGNDATA_H_