From 09cdd2f9c5e4ce34a3c7e2ff8f5385ff0342f6a8 Mon Sep 17 00:00:00 2001
From: Meric Taneri <meric.taneri@tum.de>
Date: Fri, 28 Mar 2025 10:15:57 +0100
Subject: [PATCH] bwb integration added

---
 .../integration/default/default_integration.h |   3 +
 .../src/integration/default/turbofan.cpp      | 119 +++++++++++++++++-
 propulsion_design/src/propulsion.h            |   3 +-
 3 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/propulsion_design/src/integration/default/default_integration.h b/propulsion_design/src/integration/default/default_integration.h
index 051b777c..a353d560 100644
--- a/propulsion_design/src/integration/default/default_integration.h
+++ b/propulsion_design/src/integration/default/default_integration.h
@@ -98,6 +98,9 @@ namespace design
             template <EnergyCarrier EC>
             void integrate_into_empennage(Turbofan<EC> &engine); // NOLINT runtime/references
 
+            template <EnergyCarrier EC>
+            void integrate_into_wing_body(Turbofan<EC> &engine); // NOLINT runtime/references
+
             template <EnergyCarrier EC>
             void guess_position(Turbofan<EC> &engine); // NOLINT runtime/references
 
diff --git a/propulsion_design/src/integration/default/turbofan.cpp b/propulsion_design/src/integration/default/turbofan.cpp
index c01bb083..99d14956 100644
--- a/propulsion_design/src/integration/default/turbofan.cpp
+++ b/propulsion_design/src/integration/default/turbofan.cpp
@@ -44,7 +44,9 @@ namespace design
                 {Parent::Wing, Lateral::Left, Longitudinal::Front, Vertical::Over},
                 {Parent::Fuselage, Lateral::Right, Longitudinal::Rear, Vertical::Mid},
                 {Parent::Fuselage, Lateral::Left, Longitudinal::Rear, Vertical::Mid},
-                {Parent::Empennage, Lateral::Mid, Longitudinal::Front, Vertical::In}};
+                {Parent::Empennage, Lateral::Mid, Longitudinal::Front, Vertical::In},
+                {Parent::WingBody, Lateral::Right, Longitudinal::Rear, Vertical::Over},
+                {Parent::WingBody, Lateral::Left, Longitudinal::Rear, Vertical::Over} };
         } // namespace detail
 
         template <EnergyCarrier EC>
@@ -74,6 +76,10 @@ namespace design
                         /* Integrate the engine into the empennage */
                         integrate_into_empennage(engine);
                         break;
+                    case Parent::WingBody:
+                        /* Integrate the engine into the wing-body */
+                        integrate_into_wing_body(engine);
+                        break;
                     default:
                         throw std::runtime_error("[design::integrator::Default] The parent component of the engine is not supported.");
                 }
@@ -275,6 +281,116 @@ namespace design
             ++this->engines_done.empennage;
         }
 
+        template <EnergyCarrier EC>
+        void Default::integrate_into_wing_body(Turbofan<EC> &engine) {
+
+            if (std::get<Vertical>(engine.parent_component()) == Vertical::Over) {
+                /** @todo Add a warning when the aircraft contains more than one wing or fuselage */
+                const auto& wing = this->select_wing();
+                const double sign_wing_extrusion = std::signbit(wing.sections.back().origin.z()) ? -1.0 : 1.0;
+                if (wing.normal != geom2::Direction_3{ 0, sign_wing_extrusion * 1, 0 })
+                {
+                    throw std::runtime_error("[design::integrator::Default] The wing is not oriented in y-direction. This method is not applicable.");
+                }
+
+                /* Get the relevant measurements from the aircraft */
+                const double span = geom2::measure::span(wing);
+                const double diameter_max = 1.21 * engine.fan().diameter; // \cite Ata10 p. 45
+
+                /* Initiate a vector containing locations of wing mounted entities */
+                std::vector<double> no_placement = { -span / 2 };
+
+                /* For each empennage element, get the spanwise boundaries on the xy plane */
+                for (std::size_t i = 0; i < this->aircraft()->empennage.size(); i++) {
+                    const auto& empennage = this->aircraft()->empennage[i];
+                    if (empennage.sections.size() > 1) {
+                        const geom2::Point_3 back_section = geom2::transform::to_parent(empennage, empennage.sections.back().origin);
+                        const geom2::Point_3 front_section = geom2::transform::to_parent(empennage, empennage.sections.front().origin);
+                        double projected_span = std::abs(front_section.y() - back_section.y());
+                        no_placement.push_back(back_section.y() - projected_span * 0.25);
+                        no_placement.push_back(back_section.y() + 1.5 * projected_span);
+                    };
+                };
+                no_placement.push_back(span / 2);
+                std::sort(no_placement.begin(), no_placement.end());
+
+                /* Check if the wing mounted entities are symmetrical */
+                bool is_symmetrical = std::accumulate(no_placement.begin(), no_placement.end(), 0.0) / no_placement.size() < 1;
+                if (!is_symmetrical) {
+                    throw std::runtime_error("[design::integrator::Default] Non-symmetrical empennage, engine cannot be placed over the wing.");
+                };
+
+                switch (this->n_engines_.wing)
+                {
+                case 1: {
+                    /* If there is a single engine, place it at the middle of the empennage assembly */
+                    /* @todo add valid logic for engine placement*/
+                    std::size_t index = no_placement.size() / 2 - 1;
+                    if (-diameter_max / 2 > no_placement[index] and diameter_max / 2 < no_placement[index + 1]) {
+                        const double span_engine = 0.0;
+                        /* Get the wing spanwise_percentage coordinate at the engine span position */
+                        const double wing_chord = geom2::measure::chord(wing, span_engine);
+                        const auto wing_quarter =
+                            geom2::measure::offset_LE(wing, span_engine);
+
+                        /* Wing local x position of engine */
+                        const double chord_engine = wing_quarter.x() + 0.10 * wing_chord;
+
+                        /* Wing local y position of engine */
+                        const double height_engine = wing_quarter.y() +
+                            0.7 * geom2::measure::height_max(engine.nacelle());
+                        auto position = geom2::Point_3{ chord_engine, height_engine, span_engine };
+                        engine.set_position(geom2::transform::to_parent(wing, position));
+                        ++this->engines_done.wing;
+                    }
+                    else {
+                        throw std::runtime_error("[design::integrator::Default] Empennage-engine collision, engine cannot be placed over the wing.");
+                    };
+                    break;
+                }
+                case 2: {
+                    std::size_t index = no_placement.size() / 2 - 1;
+                    double span_engine = 0.0;
+                    /* @todo add valid logic or engine placement*/
+                    /* If there are two engines, place them symmetrically on the sides of the empennage assembly */
+                    if (no_placement[index + 1] - no_placement[index] >= 3.4 * diameter_max) {
+                        span_engine = 0.80 * diameter_max;
+                    }
+                    else {
+                        std::size_t i = 0;
+                        int available = 0;
+                        while (i < no_placement.size() / 2 - 1) {
+                            double dist = std::abs(no_placement[i] - no_placement[i + 1]);
+                            if (dist >= diameter_max * 1.5) { available++; };
+                            i += 2;
+                        }
+                        if (available == 0) { throw std::runtime_error("[design::integrator::Default] No available space, engine cannot be placed over the wing."); };
+                        span_engine = 0.75 * diameter_max + std::abs(no_placement[2 * available - 1]);
+                    };
+                    if (this->engines_done.wing > 0) { span_engine = -span_engine; };
+                    /* Get the wing 80% coordinate at the engine span position */
+                    const double wing_chord = geom2::measure::chord(wing, span_engine);
+                    const auto wing_quarter =
+                        geom2::measure::offset_LE(wing, span_engine);
+
+                    /* Wing local x position of engine */
+                    const double chord_engine = wing_quarter.x() + 0.10 * wing_chord;
+
+                    /* Wing local y position of engine */
+                    const double height_engine = wing_quarter.y() +
+                        0.7 * geom2::measure::height_max(engine.nacelle());
+
+                    auto position = geom2::Point_3{ chord_engine, height_engine, span_engine };
+                    engine.set_position(geom2::transform::to_parent(wing, position));
+                    ++this->engines_done.wing;
+                    break;
+                };
+                };
+            };
+
+        };
+
+
         template <EnergyCarrier EC>
         void Default::guess_position(Turbofan<EC> &engine)
         {
@@ -285,6 +401,7 @@ namespace design
                 case Parent::Wing:
                 case Parent::Fuselage:
                 case Parent::Empennage:
+                case Parent::WingBody:
                 default:
                     /* Fall back to ORIGIN as the default position */
                     engine.set_position(CGAL::ORIGIN);
diff --git a/propulsion_design/src/propulsion.h b/propulsion_design/src/propulsion.h
index e03b2590..54e1a5e3 100644
--- a/propulsion_design/src/propulsion.h
+++ b/propulsion_design/src/propulsion.h
@@ -60,7 +60,8 @@ enum class Parent
 {
     Fuselage,
     Wing,
-    Empennage
+    Empennage,
+    WingBody
 };
 
 /**
-- 
GitLab