From 62cbf6a4581c1d11f0cb21673aa2c2a827beae2d Mon Sep 17 00:00:00 2001
From: Christopher Ruwisch <christopher.ruwisch@tu-berlin.de>
Date: Mon, 17 Mar 2025 18:00:35 +0100
Subject: [PATCH] updated bwb vertical tails

---
 empennage_design/CMakeLists.txt               |  16 +-
 empennage_design/empennage_design_conf.xml    |  25 +-
 ...g.cpp => bwbVerticalTailsDesignConfig.cpp} |   6 +-
 ...onfig.h => bwbVerticalTailsDesignConfig.h} |   1 +
 ...ata.cpp => bwbVerticalTailsDesignData.cpp} |  34 +-
 ...ilsData.h => bwbVerticalTailsDesignData.h} |   1 +
 .../vertical_tails/low/LowVerticalTailsBwb.h  |  63 ----
 ...sBwb.cpp => lowBwbVerticalTailsDesign.cpp} | 117 ++++++-
 .../low/lowBwbVerticalTailsDesign.h           | 176 ++++++++++
 .../low/lowBwbVerticalTailsDesignPlot.cpp     | 231 ++++++++++++
 .../low/lowBwbVerticalTailsDesignReport.cpp   | 328 ++++++++++++++++++
 empennage_design/src/empennageDesign.cpp      |   5 +-
 12 files changed, 906 insertions(+), 97 deletions(-)
 rename empennage_design/src/bwb/vertical_tails/{bwbVerticalTailsConfig.cpp => bwbVerticalTailsDesignConfig.cpp} (88%)
 rename empennage_design/src/bwb/vertical_tails/{bwbVerticalTailsConfig.h => bwbVerticalTailsDesignConfig.h} (96%)
 rename empennage_design/src/bwb/vertical_tails/{bwbVerticalTailsData.cpp => bwbVerticalTailsDesignData.cpp} (61%)
 rename empennage_design/src/bwb/vertical_tails/{bwbVerticalTailsData.h => bwbVerticalTailsDesignData.h} (96%)
 delete mode 100644 empennage_design/src/bwb/vertical_tails/low/LowVerticalTailsBwb.h
 rename empennage_design/src/bwb/vertical_tails/low/{LowVerticalTailsBwb.cpp => lowBwbVerticalTailsDesign.cpp} (64%)
 create mode 100644 empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesign.h
 create mode 100644 empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignPlot.cpp
 create mode 100644 empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignReport.cpp

diff --git a/empennage_design/CMakeLists.txt b/empennage_design/CMakeLists.txt
index f67040a5..9215e4f2 100644
--- a/empennage_design/CMakeLists.txt
+++ b/empennage_design/CMakeLists.txt
@@ -13,9 +13,11 @@ set(MODULE_NAME empennage_design)
 
 # Conventional tail files
 set(MODULE_SOURCES_BWB_VERTICAL_TAILS
-    src/bwb/vertical_tails/low/LowVerticalTailsBwb.cpp
-    src/bwb/vertical_tails/bwbVerticalTailsData.cpp
-    src/bwb/vertical_tails/bwbVerticalTailsConfig.cpp
+src/bwb/vertical_tails/low/lowBwbVerticalTailsDesign.cpp
+src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignPlot.cpp
+src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignReport.cpp
+src/bwb/vertical_tails/bwbVerticalTailsDesignData.cpp
+src/bwb/vertical_tails/bwbVerticalTailsDesignConfig.cpp
 )
 
 set(MODULE_SOURCES_TAW_CONVENTIONAL
@@ -59,7 +61,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
@@ -94,13 +96,13 @@ endif()
 install (TARGETS ${MODULE_NAME} DESTINATION ${MODULE_NAME})
 if(WIN32)
     install(FILES
-            ${MODULE_NAME}_conf.xml 
+            ${MODULE_NAME}_conf.xml
             gmp-10.dll
             mpfr-6.dll
          DESTINATION ${MODULE_NAME})
 else()
     install(FILES
-        ${MODULE_NAME}_conf.xml 
+        ${MODULE_NAME}_conf.xml
         DESTINATION ${MODULE_NAME})
 endif()
 
@@ -108,4 +110,4 @@ endif()
 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 3c46af7b..c30f2454 100644
--- a/empennage_design/empennage_design_conf.xml
+++ b/empennage_design/empennage_design_conf.xml
@@ -1021,9 +1021,6 @@
 			<fidelity_selection description="selection of fidelity level">
 				<value>low</value>
 			</fidelity_selection>
-			<tailtype_selection description="selection of tailtype">
-				<value>vertical_tails</value>
-			</tailtype_selection>
 			<low_fidelity description="Low fidelity methods">
 				<vertical_tails description="vertical tails method - creates symmetric tails">
 					<tail_element description="tail element" ID="0">
@@ -1090,6 +1087,9 @@
 						</profiles>
 						<spars description="spars">
 							<spar description="front spar" 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">
@@ -1100,13 +1100,13 @@
 										</spanwise>
 										<chord description="control device chord position">
 											<from description="relative chord position">
-												<value>0.7</value>
+												<value>0.2</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>
+												<value>0.2</value>
 												<unit>1</unit>
 												<lower_boundary>0.0</lower_boundary>
 												<upper_boundary>1.0</upper_boundary>
@@ -1115,20 +1115,20 @@
 									</inner_position>
 									<outer_position description="relative outer position">
 										<spanwise description="relative spanwise position">
-											<value>0.9</value>
+											<value>1.0</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>
+												<value>0.2</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>
+												<value>0.2</value>
 												<unit>1</unit>
 												<lower_boundary>0.0</lower_boundary>
 												<upper_boundary>1.0</upper_boundary>
@@ -1138,6 +1138,9 @@
 								</position>
 							</spar>
 							<spar description="rear spar" 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">
@@ -1163,7 +1166,7 @@
 									</inner_position>
 									<outer_position description="relative outer position">
 										<spanwise description="relative spanwise position">
-											<value>0.2</value>
+											<value>1.0</value>
 											<unit>1</unit>
 											<lower_boundary>0</lower_boundary>
 											<upper_boundary>1.0</upper_boundary>
@@ -1208,7 +1211,7 @@
 								<position description="chord relative position of control device">
 									<inner_position description="relative inner position">
 										<spanwise description="relative spanwise position">
-											<value>0.2</value>
+											<value>0.1</value>
 											<unit>1</unit>
 											<lower_boundary>0</lower_boundary>
 											<upper_boundary>1.0</upper_boundary>
@@ -1230,7 +1233,7 @@
 									</inner_position>
 									<outer_position description="relative outer position">
 										<spanwise description="relative spanwise position">
-											<value>0.2</value>
+											<value>0.95</value>
 											<unit>1</unit>
 											<lower_boundary>0</lower_boundary>
 											<upper_boundary>1.0</upper_boundary>
diff --git a/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsConfig.cpp b/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignConfig.cpp
similarity index 88%
rename from empennage_design/src/bwb/vertical_tails/bwbVerticalTailsConfig.cpp
rename to empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignConfig.cpp
index 0e9b882a..bd940ed9 100644
--- a/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsConfig.cpp
+++ b/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignConfig.cpp
@@ -20,7 +20,7 @@
  * This file is part of UNICADO.
  */
 
-#include "bwbVerticalTailsConfig.h"
+#include "bwbVerticalTailsDesignConfig.h"
 
 #include <aircraftGeometry2/airfoil_surface.h>
 
@@ -29,12 +29,14 @@ namespace low {
 VerticalTailsConfig::VerticalTailsConfig()
     : 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/method")),
-      mass_mode_flops_technology_factor(EndnodeReadOnly<double>("module_configuration_file/program_settings/modes/mass_mode/parameters/mode_0/technology_factor")) {}
+      mass_mode_flops_technology_factor(EndnodeReadOnly<double>("module_configuration_file/program_settings/modes/mass_mode/parameters/mode_0/technology_factor")),
+      common_airfoil_data_path(EndnodeReadOnly<std::string>("module_configuration_file/program_settings/common_airfoil_data_path")) {}
 
 void VerticalTailsConfig::read(const node& xml) {
   design_mode.read(xml);
   mass_mode.read(xml);
   mass_mode_flops_technology_factor.read(xml);
+  common_airfoil_data_path.read(xml);
 
   /* List all tail elements */
   std::string path_to_tail_elements =
diff --git a/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsConfig.h b/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignConfig.h
similarity index 96%
rename from empennage_design/src/bwb/vertical_tails/bwbVerticalTailsConfig.h
rename to empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignConfig.h
index 07bdaa82..0a3c44fe 100644
--- a/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsConfig.h
+++ b/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignConfig.h
@@ -39,6 +39,7 @@ class VerticalTailsConfig {
 
   void read(const node& xml);
 
+  EndnodeReadOnly<std::string> common_airfoil_data_path;
   EndnodeReadOnly<std::string> design_mode;
   EndnodeReadOnly<std::string> mass_mode;
   EndnodeReadOnly<double> mass_mode_flops_technology_factor;
diff --git a/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsData.cpp b/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignData.cpp
similarity index 61%
rename from empennage_design/src/bwb/vertical_tails/bwbVerticalTailsData.cpp
rename to empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignData.cpp
index 1542fd07..0c2d00dd 100644
--- a/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsData.cpp
+++ b/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignData.cpp
@@ -24,7 +24,7 @@
 #include <aircraftGeometry2/geometry/surface.h>
 #include <aixml/node.h>
 
-#include "bwbVerticalTailsData.h"
+#include "bwbVerticalTailsDesignData.h"
 
 namespace bwb {
 namespace low {
@@ -47,7 +47,7 @@ void VerticalTailsData::update(node& xml) {
   update_vertical_tails(xml);
   empennage_mass.update(xml);
   empennage_position.update(xml);
-  
+
 }
 void VerticalTailsData::update_vertical_tails(node& xml) {
   for (size_t id = 0; id < tails.size(); ++id) {
@@ -56,6 +56,36 @@ void VerticalTailsData::update_vertical_tails(node& xml) {
                                          {"aerodynamic_surface", std::to_string(id), tails[id].name}),
                io);
     tails_mass[id].update(xml);
+    int i = 0;
+    for (auto &spar : spars) {
+      geom2::io::SurfaceType io_spar = geom2::io::Spar(spar);
+      const std::string path_to_spars =
+          "component_design/empennage/specific/geometry/aerodynamic_surface@" + std::to_string(i) + "/parameters/spars";
+      std::visit(geom2::io::AixmlConverter(xml[path_to_spars], {"spar", std::to_string(i++), spar.name}), io_spar);
+    }
+    i = 0;
+    for (auto control_device : controls) {
+      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] = 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++;
+  }
   }
 }
 }  // namespace low
diff --git a/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsData.h b/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignData.h
similarity index 96%
rename from empennage_design/src/bwb/vertical_tails/bwbVerticalTailsData.h
rename to empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignData.h
index bd8b6a52..5de0e7ad 100644
--- a/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsData.h
+++ b/empennage_design/src/bwb/vertical_tails/bwbVerticalTailsDesignData.h
@@ -45,6 +45,7 @@ class VerticalTailsData {
   std::vector<geom2::MultisectionSurface<geom2::AirfoilSection>> tails;
   std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> controls;
   std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> spars;
+  std::vector<std::tuple<double,double>> control_devices_deflections;
   std::vector<MassPropertiesIO> tails_mass;
   MassPropertiesIO empennage_mass;
   PositionIO empennage_position;
diff --git a/empennage_design/src/bwb/vertical_tails/low/LowVerticalTailsBwb.h b/empennage_design/src/bwb/vertical_tails/low/LowVerticalTailsBwb.h
deleted file mode 100644
index 0909dd6b..00000000
--- a/empennage_design/src/bwb/vertical_tails/low/LowVerticalTailsBwb.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * UNICADO - UNIversity Conceptual Aircraft Design and Optimization
- *
- * Copyright (C) 2025 UNICADO consortium
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * Description:
- * This file is part of UNICADO.
- */
-
-#ifndef LOW_VERTICAL_TAILS_BWB_H_
-#define LOW_VERTICAL_TAILS_BWB_H_
-
-#include <moduleBasics/module.h>
-#include <moduleBasics/strategySelector.h>
-
-#include <functional>
-#include <map>
-
-#include "bwb/vertical_tails/bwbVerticalTailsConfig.h"
-#include "bwb/vertical_tails/bwbVerticalTailsData.h"
-
-namespace bwb {
-namespace low {
-
-class VerticalTails : public Strategy {
- public:
-  VerticalTails(const std::shared_ptr<RuntimeIO>& rtIO);
-  ~VerticalTails() = default;
-  void initialize();
-  void run();
-  void update();
-  void report();
-  void save();
-
-  void design();
-  void redesign();
-
-  void flops_mass();
-
-  const std::shared_ptr<RuntimeIO>& rtIO;
-  const std::shared_ptr<bwb::low::VerticalTailsConfig> config;
-  const std::shared_ptr<bwb::low::VerticalTailsData> data;
-  std::map<std::string, std::function<void(void)>> design_mode;
-  std::map<std::string, std::function<void(void)>> mass_mode;
-};
-
-}  // namespace low
-}  // namespace bwb
-
-#endif  // LOW_VERTICAL_TAILS_H_
\ No newline at end of file
diff --git a/empennage_design/src/bwb/vertical_tails/low/LowVerticalTailsBwb.cpp b/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesign.cpp
similarity index 64%
rename from empennage_design/src/bwb/vertical_tails/low/LowVerticalTailsBwb.cpp
rename to empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesign.cpp
index c0b18e13..51125e7f 100644
--- a/empennage_design/src/bwb/vertical_tails/low/LowVerticalTailsBwb.cpp
+++ b/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesign.cpp
@@ -20,7 +20,7 @@
  * This file is part of UNICADO.
  */
 
-#include "LowVerticalTailsBwb.h"
+#include "lowBwbVerticalTailsDesign.h"
 
 #include <aircraftGeometry2/processing/measure.h>
 #include <cmath>
@@ -36,15 +36,28 @@ VerticalTails::VerticalTails(const std::shared_ptr<RuntimeIO>& rtIO)
       config(std::make_shared<bwb::low::VerticalTailsConfig>()),
       data(std::make_shared<bwb::low::VerticalTailsData>()),
       design_mode({{"mode_0", [this]() { design(); }}, {"mode_1", [this]() { redesign(); }}}),
-      mass_mode({{"mode_0", [this]() { flops_mass(); }}}) {}
+      mass_mode({{"mode_0", [this]() { flops_mass(); }}}),
+      reporter(rtIO) {}
 
 void VerticalTails::initialize() {
   // Setup methods for mode
   myRuntimeInfo->out << "Initializing empennage" << std::endl;
   myRuntimeInfo->out << "Empennage type -> vertical tails (multiple vertical tails - symmetric)" << std::endl;
+
+  /* Read configuration data */
   config->read(rtIO->moduleConfig);
+
+  /* Create airfoils directory in project path (only if non-existing -> e.g. if standalone usage w. given wing and fuselage)*/
+
+  /* Read acxml data - non aircraftgeometry 2 */
   data->read(rtIO->acxml);
+
+  /* Read acxml data - aircraftgeometry2 */
   data->read_wing(rtIO->acxmlAccess, rtIO->getAirfoilDataDir());
+
+  /* Create airfoils library */
+  airfoils_library = std::make_shared<Airfoils>(static_cast<std::filesystem::path>(config->common_airfoil_data_path.value()));
+  airfoils_library->add_directory_airfoils(rtIO->getAirfoilDataDir());
 }
 
 void VerticalTails::run() {
@@ -64,6 +77,12 @@ void VerticalTails::update() {
 void VerticalTails::report() {
   // report sections
   myRuntimeInfo->out << "Reporting empennage -> vertical tails" << std::endl;
+
+  /* Set html report data and plots */
+  set_html_body();
+
+  /* Generate reports */
+  reporter.generateReports();
   for (auto& tail : data->tails) {
     geom2::Mesh mesh = geom2::transform::to_mesh(tail);
     if (tail.origin.y() < 0) {
@@ -110,15 +129,22 @@ void VerticalTails::design() {
                          geom2::measure::chord(data->wing, -vertical_tail.centerline_y_offset.value()) +
                          data->wing_reference_position.x.value();
 
+    std::string inner_profile_name = vertical_tail.inner_profile.value();
+    std::string outer_profile_name = vertical_tail.outer_profile.value();
+
     volume_coefficient_method.compute_geometry(number_of_tails, volume_coefficient, sweep, taper_ratio, aspect_ratio,
                                                wing_reference_area, wing_span, wing_length, wing_neutral_position,
                                                offset_position, orientation, false);
 
     /* Read */
-    geom2::AirfoilSection profile_root(
-        geom2::io::read_dat_file(rtIO->getAirfoilDataDir() + "/" + vertical_tail.inner_profile.value() + ".dat"));
-    geom2::AirfoilSection profile_tip(
-        geom2::io::read_dat_file(rtIO->getAirfoilDataDir() + "/" + vertical_tail.outer_profile.value() + ".dat"));
+    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;
 
     /* Vertical tail */
     data->tails.push_back(volume_coefficient_method.get_design(profile_root, profile_tip, 0.0));
@@ -127,13 +153,35 @@ void VerticalTails::design() {
           geom2::Point_3(0, data->tails.front().origin.y(), data->tails.front().origin.z());
     data->tails.back().name = vertical_tail.name.value() + "_positive";
 
+    /* Vertical tail - controls */
+    for (auto device : vertical_tail.control_devices) {
+      data->controls.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->control_devices_deflections.push_back(
+        {device.deflection_full_negative.value(), device.deflection_full_positive.value()});
+    }
+    /* Vertical tail - spars */
+    for (auto spar_element : vertical_tail.spars) {
+      data->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()));
+    }
+
+
+
     /* Vertical tail (mirrored) */
     data->tails.push_back(data->tails.back());
     data->tails.back().origin =
           geom2::Point_3(0, -data->tails.front().origin.y(), data->tails.front().origin.z());
     data->tails.back().name = vertical_tail.name.value() + "_negative";
-    // set empennage position
 
+
+
+    // set empennage position
     data->empennage_position.y = 0;
     data->empennage_position.z = 0;
   }
@@ -166,6 +214,54 @@ void VerticalTails::redesign() {
   // }
 }
 
+// == Spars and Controls ==============================================================================================
+
+geom2::MultisectionSurface<geom2::PolygonSection> VerticalTails::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> VerticalTails::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 VerticalTails::flops_mass() {
   myRuntimeInfo->out << "Mode active -> Mass computation - FLOPS" << std::endl;
@@ -193,7 +289,6 @@ void VerticalTails::flops_mass() {
       data->tails_mass.back().data["y"] = 0.0;
     }
     overall_empennage_mass += data->tails_mass.back().data["mass"].value();
-    data->tails_mass.back().print();
   }
   data->empennage_mass.data["mass"] = overall_empennage_mass;
   double tmp_x(0), tmp_y(0), tmp_z(0);
@@ -206,7 +301,11 @@ void VerticalTails::flops_mass() {
   data->empennage_mass.data["y"] = tmp_y / data->empennage_mass.data["mass"].value();
   data->empennage_mass.data["z"] = tmp_z / data->empennage_mass.data["mass"].value();
 
-  data->empennage_mass.print();
+  myRuntimeInfo->out << "Mass and CG Position for vertical tails" << std::endl;
+  myRuntimeInfo->out << std::format("Mass   : {:.3f}", data->empennage_mass.data["mass"].value()) << std::endl;
+  myRuntimeInfo->out << std::format("x-cg   : {:.3f}", data->empennage_mass.data["x"].value()) << std::endl;
+  myRuntimeInfo->out << std::format("y-cg   : {:.3f}", data->empennage_mass.data["y"].value()) << std::endl;
+  myRuntimeInfo->out << std::format("z-cg   : {:.3f}", data->empennage_mass.data["z"].value()) << std::endl;
 }
 
 }  // namespace low
diff --git a/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesign.h b/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesign.h
new file mode 100644
index 00000000..b83f55b6
--- /dev/null
+++ b/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesign.h
@@ -0,0 +1,176 @@
+/*
+ * UNICADO - UNIversity Conceptual Aircraft Design and Optimization
+ *
+ * Copyright (C) 2025 UNICADO consortium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Description:
+ * This file is part of UNICADO.
+ */
+
+#ifndef LOW_VERTICAL_TAILS_BWB_H_
+#define LOW_VERTICAL_TAILS_BWB_H_
+
+#include <airfoils/airfoils.h>
+#include <moduleBasics/module.h>
+#include <moduleBasics/report.h>
+#include <moduleBasics/strategySelector.h>
+
+#include <functional>
+#include <map>
+
+#include "bwb/vertical_tails/bwbVerticalTailsDesignConfig.h"
+#include "bwb/vertical_tails/bwbVerticalTailsDesignData.h"
+
+namespace bwb {
+namespace low {
+
+class VerticalTails : public Strategy {
+ public:
+  VerticalTails(const std::shared_ptr<RuntimeIO>& rtIO);
+  ~VerticalTails() = default;
+
+  /**
+   * \brief Initialize method
+   *
+   */
+  void initialize();
+
+  /**
+   * \brief Run method
+   *
+   */
+  void run();
+
+
+  void update();
+
+  /**
+   * \brief Report generation
+   *
+   */
+  void report();
+
+  /**
+   * \brief Save results
+   *
+   */
+  void save();
+
+  /**
+   * \brief Design method
+   *
+   */
+  void design();
+
+  /**
+   * \brief Redesign method for empennage
+   *
+   */
+  void redesign();
+
+  /**
+   * \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 Calculate empennage mass (vertical tails) and associated center of gravity by
+   *        Flops method
+   *
+   */
+  void flops_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::map<std::string, std::function<void(void)>> design_mode;
+  std::map<std::string, std::function<void(void)>> mass_mode;
+  std::shared_ptr<Airfoils> airfoils_library;
+
+  const std::shared_ptr<bwb::low::VerticalTailsConfig> config;
+  const std::shared_ptr<bwb::low::VerticalTailsData> data;
+  const std::shared_ptr<RuntimeIO>& rtIO;
+  Report reporter;
+
+};
+
+}  // namespace low
+}  // namespace bwb
+
+#endif  // LOW_VERTICAL_TAILS_H_
diff --git a/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignPlot.cpp b/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignPlot.cpp
new file mode 100644
index 00000000..21123ff0
--- /dev/null
+++ b/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignPlot.cpp
@@ -0,0 +1,231 @@
+/*
+ * UNICADO - UNIversity Conceptual Aircraft Design and Optimization
+ *
+ * Copyright (C) 2025 UNICADO consortium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Description:
+ * This file is part of UNICADO.
+ */
+
+#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 "lowBwbVerticalTailsDesign.h"
+#include "lib/plot_methods/plot_utility.h"
+namespace bwb {
+namespace low {
+
+fs::path VerticalTails::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) {
+  /* Plot active */
+  if (!rtIO->plotOn) {
+    return "";
+  }
+  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;
+
+  /* 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());
+  }
+
+  /* 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(get_spar_colors()).line_width(1).line_style("--");
+    } else {
+      ax->plot(y, x)->color(get_spar_colors()).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(get_control_device_colors(name)).line_width(1.5);
+    } else {
+      ax->plot(y, x)->color(get_control_device_colors(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() + "/empennage_design_" + surface.name + "_planform.svg";
+  matplot::save(f, plot_path.string(), "svg");
+  std::this_thread::sleep_for(std::chrono::milliseconds(500));
+  return fs::relative(plot_path, fs::path(rtIO->getHtmlDir()));
+}
+
+fs::path VerticalTails::plot_thickness_and_twist_distribution(
+    const geom2::MultisectionSurface<geom2::AirfoilSection>& surface) {
+  /* Plot active */
+  if (!rtIO->plotOn) {
+    return "";
+  }
+  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() + "/empennage_design_" + surface.name + "_thickness_and_twist_distribution.svg";
+  matplot::save(f, plot_path.string(), "svg");
+  std::this_thread::sleep_for(std::chrono::milliseconds(500));
+  return fs::relative(plot_path, fs::path(rtIO->getHtmlDir()));
+}
+
+/**
+ * \brief Plot airfoils
+ *
+ * \return fs::path
+ */
+std::vector<fs::path> VerticalTails::plot_airfoils(const geom2::MultisectionSurface<geom2::AirfoilSection>& surface) {
+  /* Plot active */
+  if (!rtIO->plotOn) {
+    return {""};
+  }
+  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() + "/empennage_design_" + 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));
+    }
+  }
+  return airfoil_plots_path;
+}
+
+}  // namespace low
+}  // namespace bwb
diff --git a/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignReport.cpp b/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignReport.cpp
new file mode 100644
index 00000000..81f606c4
--- /dev/null
+++ b/empennage_design/src/bwb/vertical_tails/low/lowBwbVerticalTailsDesignReport.cpp
@@ -0,0 +1,328 @@
+/*
+ * UNICADO - UNIversity Conceptual Aircraft Design and Optimization
+ *
+ * Copyright (C) 2025 UNICADO consortium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Description:
+ * This file is part of UNICADO.
+ */
+
+#include <aircraftGeometry2/processing/measure.h>
+#include <aircraftGeometry2/processing/transform.h>
+#include <moduleBasics/html.h>
+
+#include "lowBwbVerticalTailsDesign.h"
+
+namespace bwb {
+namespace low {
+void VerticalTails::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>Configuration</caption>\n"
+      << "<thead>\n<th>Type</th><th>Vertical Tails</th></thead>"
+      << "<tbody>\n"
+      << "</tbody>\n"
+      << "</table>"
+      << "<table class=\"content-table\">\n"
+      << "<caption>Data for single vertical tail (symmetric)</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->tails.front()))
+      << "</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->tails.front()))
+      << "</tr>\n"
+      << "<tr>\n"
+      << std::format("<td>Span</td><td>b</td><td>m</td><td>{:.2f}</td>\n",
+                     geom2::measure::span(data->tails.front()))
+      << "</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->tails.front()))
+      << "</tr>\n"
+      << "<tr>\n"
+      << std::format("<td>Taper ratio</td><td>&lambda;</td><td>1</td><td>{:.2f}</td>\n",
+                     geom2::measure::taper_ratio(data->tails.front()))
+      << "</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->tails.front().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->tails.front().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->tails.front().origin.z())
+      << "</tr>\n"
+      << "</tbody>\n"
+      << "</table>\n";
+
+  /* Table 2 - Section parameters*/
+  reporter.htmlReportStream() << "<table class=\"content-table\">\n"
+                              << "<caption>Section Parameter - Vertical tail</caption>\n"
+                              << "<thead>\n"
+                              << "<tr>\n"
+                              << "<th>parameter</th><th>symbol</th><th>unit</th>";
+  for (int i = 0; i < data->tails.front().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>&eta;</td><td>1</td>";
+  for (auto section : data->tails.front().sections) {
+    reporter.htmlReportStream() << std::format(
+        "<td>{:.2f}</td>", std::fabs(section.origin.z() / geom2::measure::span(data->tails.front())));
+  }
+  /* Spanwise coordinate - y*/
+  reporter.htmlReportStream() << "\n</tr>\n"
+                              << "<td>Spanwise coordinate</td><td>y</td><td>m</td>";
+  for (auto section : data->tails.front().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->tails.front().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>&phi;<sub>LE</sub></td><td>&deg;</td>";
+  for (auto section : data->tails.front().sections) {
+    reporter.htmlReportStream() << std::format(
+        "<td>{:.2f}</td>",
+        -geom2::detail::to_degrees * geom2::measure::sweep(data->tails.front(), section.origin.z(), 0.0));
+  }
+  reporter.htmlReportStream() << "\n</tr>\n"
+                              /* Sweep - 25 percent - phi_25%*/
+                              << "<tr>\n"
+                              << "<td>Sweep quarter chord</td><td>&phi;<sub>25</sub></td><td>&deg;</td>";
+  for (auto section : data->tails.front().sections) {
+    reporter.htmlReportStream() << std::format(
+        "<td>{:.2f}</td>",
+        -geom2::detail::to_degrees * geom2::measure::sweep(data->tails.front(), section.origin.z(), 0.25));
+  }
+  reporter.htmlReportStream() << "\n</tr>\n"
+                              /* Sweep - Trailing edge percent - phi_TE*/
+                              << "<tr>\n"
+                              << "<td>Sweep Trailing edge</td><td>&phi;<sub>TE</sub></td><td>&deg;</td>";
+  for (auto section : data->tails.front().sections) {
+    reporter.htmlReportStream() << std::format(
+        "<td>{:.2f}</td>",
+        -geom2::detail::to_degrees * geom2::measure::sweep(data->tails.front(), section.origin.z(), 1.0));
+  }
+  reporter.htmlReportStream() << "\n</tr>\n"
+                              /* Dihedral - nu*/
+                              << "<tr>\n"
+                              << "<td>Dihedral</td><td>&nu;</td><td>&deg;</td>";
+  for (auto section : data->tails.front().sections) {
+    reporter.htmlReportStream() << std::format(
+        "<td>{:.2f}</td>",
+        geom2::detail::to_degrees * geom2::measure::dihedral(data->tails.front(), section.origin.z()));
+  }
+  reporter.htmlReportStream() << "\n</tr>\n"
+                              /* Twist - epsilon*/
+                              << "<tr>\n"
+                              << "<td>Twist angle</td><td>&epsilon;</td><td>&deg;</td>";
+  for (auto section : data->tails.front().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->tails.front().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->tails.front().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_tails_spars =
+      data->spars;
+  for (size_t spar_id = 0; spar_id < vertical_tails_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>&eta; [1]<th>x/c [%]</th>",
+                                               vertical_tails_spars.at(spar_id).name)
+                                << "\n</tr>\n"
+                                << "</thead>\n"
+                                << "<tbody>\n";
+    /* Spar name - eta, x/c*/
+    for (size_t i = 0; i < vertical_tails_spars.at(spar_id).sections.size(); ++i) {
+      reporter.htmlReportStream() << "<tr>\n";
+      std::string tag = "";
+      if (i == 0) {
+        tag = "from";
+      } else if (i == vertical_tails_spars.at(spar_id).sections.size() - 1) {
+        tag = "to";
+      }
+      reporter.htmlReportStream() << std::format(
+          "<td>{}</td><td>{:.2f}</td><td>{:.2f}</td>\n", tag,
+          vertical_tails_spars.at(spar_id).sections.at(i).origin.z(),
+          vertical_tails_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_tails_devices;
+  std::vector<device_data> other_devices;
+
+  std::vector<geom2::MultisectionSurface<geom2::PolygonSection>> rudders = data->controls;
+
+  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_tails_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 tail control devices (single)</caption>\n"
+      << "<thead>\n"
+      << "<tr>\n"
+      << "<th>Device</th><th>&eta;<sub>from</sub></th><th>x/c<sub>from,start</sub></th><th>x/c<sub>from,end</sub></"
+         "th><th>&eta;<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_tails_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 tail (single)</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->tails_mass.front().data["mass"].value(),
+                     data->tails_mass.front().data["x"].value(), data->tails_mass.front().data["y"].value(),
+                     data->tails_mass.front().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_tail_plot_path = plot_stabilizer_planform(
+        data->tails.front(), data->spars, data->controls);
+    reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n",
+      planform_vertical_tail_plot_path.string());
+    /* Vertical stabilizer airfoil */
+    auto vertical_tail_airfoil_plot_paths = plot_airfoils(data->tails.front());
+    reporter.htmlReportStream() << "<h3>Vertical Stabilizer Airfoils</h3>\n";
+    for( auto airfoil_path : vertical_tail_airfoil_plot_paths) {
+      reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n", airfoil_path.string());
+    }
+    reporter.htmlReportStream() << "<h3>Vertical Tail Thickness & Geometric Twist</h3>\n";
+    auto vertical_tail_thickness_and_twist_plot_path = plot_thickness_and_twist_distribution(data->tails.front());
+    reporter.htmlReportStream() << std::format("<img class=\"image-plot\" src=\"{}\"/>\n",
+    vertical_tail_thickness_and_twist_plot_path.string());
+
+    // /* close box plot */
+    reporter.htmlReportStream() << "</div>\n";
+  }
+}
+}  // namespace low
+}  // namespace bwb
diff --git a/empennage_design/src/empennageDesign.cpp b/empennage_design/src/empennageDesign.cpp
index 295c936b..18d7feb2 100644
--- a/empennage_design/src/empennageDesign.cpp
+++ b/empennage_design/src/empennageDesign.cpp
@@ -29,7 +29,7 @@
 #include <vector>
 #include <format>
 
-#include "bwb/vertical_tails/low/LowVerticalTailsBwb.h"
+#include "bwb/vertical_tails/low/lowBwbVerticalTailsDesign.h"
 #include "taw/conventional/low/lowConventionalEmpennageDesign.h"
 #include "taw/t_tail/low/low_t_tail_empennage_design.h"
 
@@ -38,8 +38,7 @@ EmpennageDesign::EmpennageDesign(const int argc, char *argv[], const std::string
     : Module(argc, argv, toolName, toolVersion) {
   std::string configuration = rtIO_->aircraft_configuration_type();
   std::string usedtype = EndnodeReadOnly<std::string>("requirements_and_specifications/design_specification/configuration/empennage_definition/empennage_type").read(rtIO_->acxml).value();
-  std::string fidelity = EndnodeReadOnly<std::string>("program_settings/fidelity_selection").read(rtIO_->moduleConfig).value();
-
+  std::string fidelity = EndnodeReadOnly<std::string>("program_settings/" + configuration + "/fidelity_selection").read(rtIO_->moduleConfig).value();
   /* Register existing strategies */
   /* tube and wing strategies */
   strategy.registerStrategy<taw::low::Conventional>({"tube_and_wing", "conventional", "low"});
-- 
GitLab