Skip to content

Conversation

@xjjiang
Copy link
Contributor

@xjjiang xjjiang commented Nov 25, 2025

Summary

This PR addresses two tasks: (task 1) BWB components in mass/flops_based subsysterms and (task 2) FLOPS based premission for BWB. The original PR for (task 1) BWB components in mass/flops_based subsysterms is closed.

For task 1, this PR implements the mass subsystem for BWB aircraft. The BWB components are:

  • BWBFurnishingsGroupMass (vs. TransportFurnishingsGroupMass)
  • BWBFuselageMass (vs. TransportFuselageMass)
  • BWBAftBodyMass (new for BWB)
  • BWBWingMiscMass (vs. WingMiscMass)
  • BWBDetailedWingBendingFact (vs. DetailedWingBendingFact)

Unit testings against these new components are added. All the results are compared to FLOPS Fortran code runs.

There are two features to know:

  1. In a previous PR (BWB components in Geometry/flops_based subsysterms #872) we created the fuselage layout algorithms (simple layout and detailed layout). Other scenarios can be added if needed.
  2. For BWB, there are always detailed wings. They are either given (BWBUpdateDetailedWingDist) or created (BWBComputeDetailedWingDist). This means that number of input wing stations is always positive. If input wing stations are not provided, FLOPS adds three points. We call this case the simple wing case. Otherwise, we say that we have a detailed wing case.

So, theoretically, we should have four test cases: simple layout + simple wing, simple layout + detailed wing, detailed layout + simple wing, and detailed layout + detailed wing. In this PR, however, we only created two test cases: simple layout + simple wing (see models/aircraft/blended_wing_body/bwb_simple_FLOPS_data.py), and detailed layout + detailed wing (see models/aircraft/blended_wing_body/bwb_detailed_FLOPS_data.py).

In anti_icing.py and starter.py, nacelle average diameter (Aircraft.Nacelle.AVG_DIAMETER) is scaled by thrust ratio defined by:

Aircraft.Engine.SCALED_SLS_THRUST / Aircraft.Engine.REFERENCE_SLS_THRUST

in order to match with FLOPS runs. In the current Aviary test cases, this ratio has been always 1.

For task 2, this PR adds unit tests for FLOPS based subsystems with BWB configuration (see BWBPreMissionGroupTest BWBPreMissionGroupCSVTest1 and BWBPreMissionGroupCSVTest2 classes in test_flops_based_premission.py). This PR assumes that geometry and mass subsystems are already implemented using BWB using FLOPS code. Since there is no specific code in FLOPS based aerodynamics subsystem for BWB, this unit test covers all four basic subsystems: propulsion, geometry, aerodynamics and mass.

As in PR #889 for mass subsystem, we prepare two cases for the testing: Case 1 with simple fuselage layout and simple wing layout (see bwb_simple_FLOPS_data.py) and case 2 with detailed fuselage layout and detailed wing layout (see bwb_detailed_FLOPS_data.py) in aircraft model directory.

Almost all results match with FLOPS outputs. But the computation algorithm of bending material factor is a little bit different in the second case. As a result, wing mass and structure mass are a little different too. The comparison is as follows:

Aviary Variable Name Value FLOPS Variable Name Value
Aircraft.Wing.BENDING_MATERIAL_FACTOR 3.93743732 BT 3.972479625
Aircraft.Wing.MASS 68922.20579045 WWING 68995.460470895763
Aircraft.Design.STRUCTURE_MASS 240915.88664709 WSTRCT 240989.14132753

CSV data input based unit tests are added. This is the first time that we use CSV input deck for premission unit test in test_flops_based_premission.py.

Related Issues

  • Resolves #

Backwards incompatibilities

None

New Dependencies

None

xjjiang and others added 30 commits September 23, 2025 12:04
…ASS, set 'WTIN.NPT' for FLOPS for Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS. In this way, fortran_to_aviary can read in NPF and NPT.
# Temporarily add extra stuff here, probably patched soon
if mission_method is HEIGHT_ENERGY:
# add a check for traj using hasattr for pre-mission tests.
if mission_method is HEIGHT_ENERGY and hasattr(self, 'traj'):
Copy link
Contributor

@jkirk5 jkirk5 Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What scenario did the AviaryGroup not have 'traj'? That seems like a bug we should look into!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ken said: "The code section in aviary_group will eventually go away once dymos change are finally made, but until then Just change the line at the start of that block to add hasattr(self, 'traj')".

@Kenneth-T-Moore Can you answer Jason's question? I made the change based on your suggestion. It seemed to me that you were planning to do something about it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the scenario was just a partial integration test that only had pre_mission in it because we never added any phases. I thought this might be cleaner than sticking a mission in the aviary_group just for that test.

@jkirk5 jkirk5 added this pull request to the merge queue Jan 14, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 14, 2026
@Kenneth-T-Moore
Copy link
Member

Kenneth-T-Moore commented Jan 14, 2026

I investigated the failure of test_bench_multiengine.py, and found something interesting. In nacelle.py, we compute the wetted areas for the each nacelle, but the values are different now.

Old
aircraft:nacelle:wetted_area: array([228.34, 228.34]) ft**2
New
aircraft:nacelle:wetted_area: array([ 87.61830512, 148.76787358]) ft**2

This is due to the inclusion of the ratio of scaled to reference SLS thrust in the calculation, which is how it is done in FLOPS.

    thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST]
    ref_sls_thrust, _ = self.options[Aircraft.Engine.REFERENCE_SLS_THRUST]
    thrust_rat = thrust / ref_sls_thrust
    adjusted_avg_diam = avg_diam * np.sqrt(thrust_rat)
    adjusted_avg_length = avg_length * np.sqrt(thrust_rat)

Something seems to have gone wrong though:

thrust_rat
array([0.3837186 , 0.65151911])

thrust
array([11100.25003266, 14464.05000155])

self.options[Aircraft.Engine.REFERENCE_SLS_THRUST]
(array([28928.1, 22200.5]), 'lbf')

It looks like there are two problems here.

  1. the sls_thrust in the openmdao vector and the ref_sls_thrust in the options dict are sorted differently. Looks like the ref_sls_thrust 2 belongs with sls_thrust 1 and vice-versa.
  2. I would have expected both thrust_rats to be 1.0, and it looks like they will be 0.5 with the first item corrected, so that makes it seems like maybe we are missing a factor of num_engines somewhere. (Or maybe not? I don't think we have validated vs. FLOPS data for anything multi-engine, have we?)

Note though, this is a multengine case, and our single-engine cases are probably all fine. We have a couple other multi-engine cases too, i think, and they may be affected by this too, since we might not be checking tightly enough to notice a difference in the drag from the nacelles.

@xjjiang
Copy link
Contributor Author

xjjiang commented Jan 14, 2026

I investigated the failure of test_bench_multiengine.py, and found something interesting. In nacelle.py, we compute the wetted areas for the each nacelle, but the values are different now.

Old aircraft:nacelle:wetted_area: array([228.34, 228.34]) ft**2 New aircraft:nacelle:wetted_area: array([ 87.61830512, 148.76787358]) ft**2

This is due to the inclusion of the ratio of scaled to reference SLS thrust in the calculation, which is how it is done in FLOPS.

    thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST]
    ref_sls_thrust, _ = self.options[Aircraft.Engine.REFERENCE_SLS_THRUST]
    thrust_rat = thrust / ref_sls_thrust
    adjusted_avg_diam = avg_diam * np.sqrt(thrust_rat)
    adjusted_avg_length = avg_length * np.sqrt(thrust_rat)

Something seems to have gone wrong though:

thrust_rat
array([0.3837186 , 0.65151911])

thrust
array([11100.25003266, 14464.05000155])

self.options[Aircraft.Engine.REFERENCE_SLS_THRUST]
(array([28928.1, 22200.5]), 'lbf')

It looks like there are two problems here.

1. the sls_thrust in the openmdao vector and the ref_sls_thrust in the options dict are sorted differently. Looks like the ref_sls_thrust 2 belongs with sls_thrust 1 and vice-versa.

2. I would have expected both thrust_rats to be 1.0, and it looks like they will be 0.5 with the first item corrected, so that makes it seems like maybe we are missing a factor of num_engines somewhere.  (Or maybe not? I don't think we have validated vs. FLOPS data for anything multi-engine, have we?)

Note though, this is a multengine case, and our single-engine cases are probably all fine. We have a couple other multi-engine cases too, i think, and they may be affected by this too, since we might not be checking tightly enough to notice a difference in the drag from the nacelles.

The results should remain the same when the ratio (thrust_rat) of the two is 1. I guess for multi-engine case, it is not true. Am I right?

@Kenneth-T-Moore
Copy link
Member

The results should remain the same when the ratio (thrust_rat) of the two is 1. I guess for multi-engine case, it is not true. Am I right?

My first inclination is that the wetted areas should stay the same, but I don't know if there is something in multiengine propulsion that would also trigger FLOPS to use the thrust correction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants