From 604bae347b141165b7e9a02bf6618129b627f2f9 Mon Sep 17 00:00:00 2001 From: Alasdair Gray Date: Fri, 24 Oct 2025 12:31:10 -0400 Subject: [PATCH 1/3] Modify BFL residual --- openconcept/mission/phases.py | 66 ++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/openconcept/mission/phases.py b/openconcept/mission/phases.py index 057a7193..c5a6d09e 100644 --- a/openconcept/mission/phases.py +++ b/openconcept/mission/phases.py @@ -148,32 +148,50 @@ class BFLImplicitSolve(ImplicitComponent): def setup(self): self.add_input("distance_continue", units="m") self.add_input("distance_abort", units="m") - self.add_input("takeoff|vr", units="m/s") - self.add_output("takeoff|v1", units="m/s", val=20, lower=10, upper=150) + self.add_input("takeoff|vr", units="m/s", val=30.0) + self.add_output("takeoff|v1", units="m/s", val=20.0, lower=10.0, upper=150.0) self.declare_partials("takeoff|v1", ["distance_continue", "distance_abort", "takeoff|v1", "takeoff|vr"]) + self.speedtol = 1e-1 + self.disttol = 0.0 + self.useOldCode = False + + def useVRes(self, vr, v1, dist_continue, dist_abort): + """Determine whether to use the dist_continue - dist_abort or the vr - v1 residual. + + If vr < v1 + speedtol then we use the vr - v1 residual, as long as dist_abort < dist_continue + disttol. + + Parameters + ---------- + vr : float + Rotation speed + v1 : float + Decision speed + dist_continue : float + engine-out takeoff distance + dist_abort : float + Rejected takeoff distance + """ + return vr < v1 + self.speedtol and dist_abort < dist_continue + self.disttol + def apply_nonlinear(self, inputs, outputs, residuals): - speedtol = 1e-1 - disttol = 0 - # force the decision speed to zero - if inputs["takeoff|vr"] < outputs["takeoff|v1"] + speedtol: - residuals["takeoff|v1"] = inputs["takeoff|vr"] - outputs["takeoff|v1"] - else: - residuals["takeoff|v1"] = inputs["distance_continue"] - inputs["distance_abort"] + vr = inputs["takeoff|vr"] + v1 = outputs["takeoff|v1"] + dist_continue = inputs["distance_continue"] + dist_abort = inputs["distance_abort"] - # if you are within vtol on the correct side but the stopping distance bigger, use the regular mode - if ( - inputs["takeoff|vr"] >= outputs["takeoff|v1"] - and inputs["takeoff|vr"] - outputs["takeoff|v1"] < speedtol - and (inputs["distance_abort"] - inputs["distance_continue"]) > disttol - ): - residuals["takeoff|v1"] = inputs["distance_continue"] - inputs["distance_abort"] + if self.useVRes(vr, v1, dist_continue, dist_abort): + residuals["takeoff|v1"] = vr - v1 + else: + residuals["takeoff|v1"] = dist_continue - dist_abort def linearize(self, inputs, outputs, partials): - speedtol = 1e-1 - disttol = 0 + vr = inputs["takeoff|vr"] + v1 = outputs["takeoff|v1"] + dist_continue = inputs["distance_continue"] + dist_abort = inputs["distance_abort"] - if inputs["takeoff|vr"] < outputs["takeoff|v1"] + speedtol: + if self.useVRes(vr, v1, dist_continue, dist_abort): partials["takeoff|v1", "distance_continue"] = 0 partials["takeoff|v1", "distance_abort"] = 0 partials["takeoff|v1", "takeoff|vr"] = 1 @@ -184,16 +202,6 @@ def linearize(self, inputs, outputs, partials): partials["takeoff|v1", "takeoff|vr"] = 0 partials["takeoff|v1", "takeoff|v1"] = 0 - if ( - inputs["takeoff|vr"] >= outputs["takeoff|v1"] - and inputs["takeoff|vr"] - outputs["takeoff|v1"] < speedtol - and (inputs["distance_abort"] - inputs["distance_continue"]) > disttol - ): - partials["takeoff|v1", "distance_continue"] = 1 - partials["takeoff|v1", "distance_abort"] = -1 - partials["takeoff|v1", "takeoff|vr"] = 0 - partials["takeoff|v1", "takeoff|v1"] = 0 - class Groundspeeds(ExplicitComponent): """ From 78e7ffa006ac9770ced391c26d8e22adc2dc3192 Mon Sep 17 00:00:00 2001 From: Alasdair Gray Date: Thu, 12 Feb 2026 17:03:56 -0500 Subject: [PATCH 2/3] Remove unused code --- openconcept/mission/phases.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openconcept/mission/phases.py b/openconcept/mission/phases.py index c5a6d09e..feb84cb7 100644 --- a/openconcept/mission/phases.py +++ b/openconcept/mission/phases.py @@ -154,7 +154,6 @@ def setup(self): self.speedtol = 1e-1 self.disttol = 0.0 - self.useOldCode = False def useVRes(self, vr, v1, dist_continue, dist_abort): """Determine whether to use the dist_continue - dist_abort or the vr - v1 residual. From d05812aa8c17a7fed70682c89c1729aea3e46c3d Mon Sep 17 00:00:00 2001 From: Alasdair Gray Date: Mon, 16 Feb 2026 11:52:49 -0500 Subject: [PATCH 3/3] Return statement --- openconcept/mission/phases.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openconcept/mission/phases.py b/openconcept/mission/phases.py index feb84cb7..f5f3bbfc 100644 --- a/openconcept/mission/phases.py +++ b/openconcept/mission/phases.py @@ -170,6 +170,11 @@ def useVRes(self, vr, v1, dist_continue, dist_abort): engine-out takeoff distance dist_abort : float Rejected takeoff distance + + Returns + ------- + bool + True if the vr - v1 residual should be used, False if the dist_continue - dist_abort residual should be used. """ return vr < v1 + self.speedtol and dist_abort < dist_continue + self.disttol