6. Drivetrain Model Example

This example optimizes the sizing of key drivetrain components, assuming their overall length and height have already been determined by a target blade tip deflection and hub height, respectively. Only Python-scripts are supported for now, as a yaml-based input using only hub and nacelle parameters is not yet available.

Direct-Drive Design

This example is for design sizing (diameter and thickness) of the shaft, nose/turret, and bedplate wall thickness of the direct-drive layout shown in Fig. 12 and in Fig. 13.

../../_images/layout_diagram.png

Fig. 12 Direct-drive configuration layout diagram

../../_images/layout_detail.png

Fig. 13 Detailed direct-drive configuration with key user inputs and derived values.

Specifically, the design variables are,

  • \(L_{h1}\)

  • \(L_{12}\)

  • \(D_{hub}\)

  • \(D_{lss}\)

  • \(D_{nose}\)

  • \(t_{lss}\)

  • \(t_{nose}\)

  • \(t_{bed}\)

The design script starts with importing the required libraries,

import numpy as np
import openmdao.api as om

from wisdem.commonse.fileIO import save_data
from wisdem.drivetrainse.drivetrain import DrivetrainSE

opt_flag = True

The modeling options dictionary sets the partial safety factors, the vector sizes, and specifies that a detailed generator design will not be run.

opt = {}
opt["WISDEM"] = {}
opt["WISDEM"]["n_dlc"] = 1
opt["WISDEM"]["DriveSE"] = {}
opt["WISDEM"]["DriveSE"]["direct"] = True
opt["WISDEM"]["DriveSE"]["hub"] = {}
opt["WISDEM"]["DriveSE"]["hub"]["hub_gamma"] = 2.0
opt["WISDEM"]["DriveSE"]["hub"]["spinner_gamma"] = 1.5
opt["WISDEM"]["DriveSE"]["gamma_f"] = 1.35
opt["WISDEM"]["DriveSE"]["gamma_m"] = 1.3
opt["WISDEM"]["DriveSE"]["gamma_n"] = 1.0
opt["WISDEM"]["RotorSE"] = {}
opt["WISDEM"]["RotorSE"]["n_pc"] = 20
opt["materials"] = {}
opt["materials"]["n_mat"] = 4
opt["flags"] = {}
opt["flags"]["generator"] = False

Next, we instantiate the OpenMDAO problem and assign the drivetrain as the model of the problem,

prob = om.Problem(reports=False)
prob.model = DrivetrainSE(modeling_options=opt)

Next, the script proceeds to set-up the design optimization problem if opt_flag is set to True. In this case, the optimization driver is first be selected and configured. We then set the objective, in this case nacelle mass, and scale it so it is of order 1 for better convergence behavior. The drivetrain diameters and thicknesses are added as design variables, as well as the lengths that determine the shaft, nose, and bedplate lengths to reach the intended overhang distance. Finally, a number of constraints are added, which fall into the categories of,

  • von Mises stress utilizations: These constraints must be less than 1 and capture that the von Mises stress in the load-bearing components, multiplied by a safety factor must be less than the shear stress of the material.

  • Main bearing deflection utilizations: Each bearing type has an associated maximum deflection, measured as an angle. These constraints ensure that the shaft and nose/turret deflections at the bearing attachment points do not exceed those limits.

  • Minimum allowable hub diameter: For a given blade root radius and number of blades, this is the minimum hub radius that can safely accommodate those dimensions.

  • Satisfy target overhang and hub height: Ensure that the shaft, turret, and bedplate lengths are sufficient to meet the desired overhang and hub height

  • Allow maintenance access: Specify the minimum height required to allow human access into the nose/turret for maintenance activities.

if opt_flag:
    # Choose the optimizer to use
    prob.driver = om.ScipyOptimizeDriver()
    prob.driver.options["optimizer"] = "SLSQP"
    prob.driver.options["tol"] = 1e-5

    # Add objective
    prob.model.add_objective("nacelle_mass", scaler=1e-6)

    # Add design variables, in this case the tower diameter and wall thicknesses
    prob.model.add_design_var("L_12", lower=0.1, upper=5.0)
    prob.model.add_design_var("L_h1", lower=0.1, upper=5.0)
    prob.model.add_design_var("hub_diameter", lower=3.0, upper=15.0)
    prob.model.add_design_var("lss_diameter", lower=0.5, upper=6.0)
    prob.model.add_design_var("lss_wall_thickness", lower=4e-3, upper=5e-1, ref=1e-2)
    prob.model.add_design_var("nose_diameter", lower=0.5, upper=6.0)
    prob.model.add_design_var("nose_wall_thickness", lower=4e-3, upper=5e-1, ref=1e-2)
    prob.model.add_design_var("bedplate_wall_thickness", lower=4e-3, upper=5e-1, ref=1e-2)

    # Add constraints on the tower design
    prob.model.add_constraint("constr_lss_vonmises", upper=1.0)
    prob.model.add_constraint("constr_bedplate_vonmises", upper=1.0)
    prob.model.add_constraint("constr_mb1_defl", upper=1.0)
    prob.model.add_constraint("constr_mb2_defl", upper=1.0)
    prob.model.add_constraint("constr_shaft_deflection", upper=1.0)
    prob.model.add_constraint("constr_shaft_angle", upper=1.0)
    prob.model.add_constraint("constr_stator_deflection", upper=1.0)
    prob.model.add_constraint("constr_stator_angle", upper=1.0)
    prob.model.add_constraint("constr_hub_diameter", lower=0.0)
    prob.model.add_constraint("constr_length", lower=0.0)
    prob.model.add_constraint("constr_height", lower=0.0)
    prob.model.add_constraint("constr_access", lower=0.0)
    prob.model.add_constraint("constr_ecc", lower=0.0)
    prob.model.add_constraint("L_lss", lower=0.1)
    prob.model.add_constraint("L_nose", lower=0.1)

With the optimization problem defined, the OpenMDAO problem is activated

prob.setup()

Now we can specify the high level inputs that describe the turbine

opt = {}
opt["WISDEM"] = {}
opt["WISDEM"]["n_dlc"] = 1
opt["WISDEM"]["DriveSE"] = {}
opt["WISDEM"]["DriveSE"]["direct"] = True
opt["WISDEM"]["DriveSE"]["hub"] = {}
opt["WISDEM"]["DriveSE"]["hub"]["hub_gamma"] = 2.0
opt["WISDEM"]["DriveSE"]["hub"]["spinner_gamma"] = 1.5
opt["WISDEM"]["DriveSE"]["gamma_f"] = 1.35
opt["WISDEM"]["DriveSE"]["gamma_m"] = 1.3
opt["WISDEM"]["DriveSE"]["gamma_n"] = 1.0
opt["WISDEM"]["RotorSE"] = {}
opt["WISDEM"]["RotorSE"]["n_pc"] = 20
opt["materials"] = {}
opt["materials"]["n_mat"] = 4
opt["flags"] = {}
opt["flags"]["generator"] = False

A number of blade properties and other parameters are needed for the hub and spinner designs,

prob["blade_mass"] = 65252.0
prob["blades_mass"] = 3 * prob["blade_mass"]
prob["pitch_system.BRFM"] = 26648449.0
prob["pitch_system_scaling_factor"] = 0.75
prob["blade_root_diameter"] = 5.2
prob["flange_t2shell_t"] = 6.0
prob["flange_OD2hub_D"] = 0.6
prob["flange_ID2flange_OD"] = 0.8
prob["hub_in2out_circ"] = 1.2
prob["hub_stress_concentration"] = 3.0
prob["n_front_brackets"] = 5
prob["n_rear_brackets"] = 5
prob["clearance_hub_spinner"] = 0.5
prob["spin_hole_incr"] = 1.2
prob["spinner_gust_ws"] = 70.0
prob["hub_diameter"] = 7.94
prob["blades_I"] = np.r_[4.12747714e08, 1.97149973e08, 1.54854398e08, np.zeros(3)]

Next is the layout of the drivetrain and the initial conditions of some of the design variables,

prob["bear1.bearing_type"] = "CARB"
prob["bear2.bearing_type"] = "SRB"
prob["L_12"] = 1.2
prob["L_h1"] = 1.0
prob["L_generator"] = 2.15  # 2.75
prob["overhang"] = 12.0313
prob["drive_height"] = 5.614
prob["tilt"] = 6.0
prob["access_diameter"] = 2.0
prob["shaft_deflection_allowable"] = 1e-4
prob["shaft_angle_allowable"] = 1e-3
prob["stator_deflection_allowable"] = 1e-4
prob["stator_angle_allowable"] = 1e-3

myones = np.ones(2)
prob["lss_diameter"] = 3.0 * myones
prob["nose_diameter"] = 2.2 * myones
prob["lss_wall_thickness"] = 0.1 * myones
prob["nose_wall_thickness"] = 0.1 * myones
prob["bedplate_wall_thickness"] = 0.05 * np.ones(4)
prob["bear1.D_shaft"] = 2.2
prob["bear2.D_shaft"] = 2.2

Finally, the material properties that are used in the design are set. Here we assume that the shaft and nose/turret are made of a steel with a slightly higher carbon content than the bedplate. The hub is cast iron and the spinner is made of glass fiber.

prob["E_mat"] = np.c_[200e9 * np.ones(3), 205e9 * np.ones(3), 118e9 * np.ones(3), [4.46e10, 1.7e10, 1.67e10]].T
prob["G_mat"] = np.c_[79.3e9 * np.ones(3), 80e9 * np.ones(3), 47.6e9 * np.ones(3), [3.27e9, 3.48e9, 3.5e9]].T
prob["Xt_mat"] = np.c_[450e6 * np.ones(3), 814e6 * np.ones(3), 310e6 * np.ones(3), [6.092e8, 3.81e7, 1.529e7]].T
prob["rho_mat"] = np.r_[7800.0, 7850.0, 7200.0, 1940.0]
prob["Xy_mat"] = np.r_[345e6, 485e6, 265e6, 18.9e6]
prob["wohler_exp_mat"] = 1e1 * np.ones(4)
prob["wohler_A_mat"] = 1e1 * np.ones(4)
prob["unit_cost_mat"] = np.r_[0.7, 0.9, 0.5, 1.9]
prob["lss_material"] = prob["hss_material"] = "steel_drive"
prob["bedplate_material"] = "steel"
prob["hub_material"] = "cast_iron"
prob["spinner_material"] = "glass_uni"
prob["material_names"] = ["steel", "steel_drive", "cast_iron", "glass_uni"]

The simulation can now be run. If doing an optimization, we select finite differencing around the total derivatives instead of the partial derivatives.

if opt_flag:
    prob.model.approx_totals()
    prob.run_driver()
else:
    prob.run_model()
save_data("drivetrain_example", prob)

All of the inputs and outputs are displayed on the screen, followed by a curated list of values relating to the optimization problem.

# prob.model.list_inputs(units=True)
# prob.model.list_outputs(units=True)

# Print out the objective, design variables and constraints
print("nacelle_mass:", prob["nacelle_mass"])
print("")
print("L_h1:", prob["L_h1"])
print("L_12:", prob["L_12"])
print("L_lss:", prob["L_lss"])
print("L_nose:", prob["L_nose"])
print("L_generator:", prob["L_generator"])
print("L_bedplate:", prob["L_bedplate"])
print("H_bedplate:", prob["H_bedplate"])
print("hub_diameter:", prob["hub_diameter"])
print("lss_diameter:", prob["lss_diameter"])
print("lss_wall_thickness:", prob["lss_wall_thickness"])
print("nose_diameter:", prob["nose_diameter"])
print("nose_wall_thickness:", prob["nose_wall_thickness"])
print("bedplate_wall_thickness:", prob["bedplate_wall_thickness"])
print("")
print("constr_lss_vonmises:", prob["constr_lss_vonmises"].flatten())
print("constr_bedplate_vonmises:", prob["constr_bedplate_vonmises"].flatten())
print("constr_mb1_defl:", prob["constr_mb1_defl"])
print("constr_mb2_defl:", prob["constr_mb2_defl"])
print("constr_shaft_deflection:", prob["constr_shaft_deflection"])
print("constr_shaft_angle:", prob["constr_shaft_angle"])
print("constr_stator_deflection:", prob["constr_stator_deflection"])
print("constr_stator_angle:", prob["constr_stator_angle"])
print("constr_hub_diameter:", prob["constr_hub_diameter"])
print("constr_length:", prob["constr_length"])
print("constr_height:", prob["constr_height"])
print("constr_access:", prob["constr_access"])
print("constr_ecc:", prob["constr_ecc"])

The screen output should look something like the following,

Optimization terminated successfully    (Exit mode 0)
        Current function value: [0.22768958]
        Iterations: 31
        Function evaluations: 47
        Gradient evaluations: 31
Optimization Complete
-----------------------------------

...

nacelle_mass: [227689.58069311]

L_h1: [0.1]
L_12: [1.04818685]
L_lss: [1.14818685]
L_nose: [3.15181315]
L_generator: [2.15]
L_bedplate: [4.92501211]
H_bedplate: [4.86709905]
hub_diameter: [7.78723633]
lss_diameter: [2.67134366 2.67189989]
lss_wall_thickness: [0.08664636 0.08664614]
nose_diameter: [2.08469731 2.08525375]
nose_wall_thickness: [0.08469731 0.08525375]
bedplate_wall_thickness: [0.004      0.004      0.004      0.03417892]

constr_lss_vonmises: [0.07861671 0.0784489  0.09307185 0.19116645]
constr_bedplate_vonmises: [0.93281517 0.85272928 0.77435574 0.69658358 0.62163064 0.56099155
0.55110369 0.41195844 0.31955169 0.3206749  0.34412109 0.17707953
0.20135497 0.07195264 0.06577744]
constr_mb1_defl: [0.18394075]
constr_mb2_defl: [0.02072981]
constr_hub_diameter: [0.58190497]
constr_length: [1.67501211]
constr_height: [4.86709905]
constr_access: [[0.00000000e+00 1.35447209e-13]
[1.56319402e-13 4.44089210e-16]]
constr_ecc: [0.05791306]

Geared Design

This example is for design sizing (diameter and thickness) of the shaft, nose/turret, and bedplate wall thickness of the direct-drive layout shown in Fig. 14 and in Fig. 15.

../../_images/geared_diagram.png

Fig. 14 Geared configuration layout diagram

../../_images/geared_detail.png

Fig. 15 Geared configuration layout diagram

Specifically, the design variables are,

  • \(L_{h1}\)

  • \(L_{12}\)

  • \(L_{hss}\)

  • \(D_{hub}\)

  • \(D_{lss}\)

  • \(D_{hss}\)

  • \(t_{lss}\)

  • \(t_{hss}\)

  • \(t_{web}\) (bedplate I-beam dimension)

  • \(t_{flange}\) (bedplate I-beam dimension)

  • \(w_{flange}\) (bedplate I-beam dimension)

The design script is quite similar to the direct-drive version, so we will walk through it more succinctly, noting distinctions with the example above. The design script starts with importing the required libraries,

import numpy as np
import openmdao.api as om

from wisdem.commonse.fileIO import save_data
from wisdem.drivetrainse.drivetrain import DrivetrainSE

opt_flag = True

The only difference in the modeling options is to set the direct drive flag to False,

opt = {}
opt["WISDEM"] = {}
opt["WISDEM"]["n_dlc"] = 1
opt["WISDEM"]["DriveSE"] = {}
opt["WISDEM"]["DriveSE"]["direct"] = False
opt["WISDEM"]["DriveSE"]["hub"] = {}
opt["WISDEM"]["DriveSE"]["hub"]["hub_gamma"] = 2.0
opt["WISDEM"]["DriveSE"]["hub"]["spinner_gamma"] = 1.5
opt["WISDEM"]["DriveSE"]["gamma_f"] = 1.35
opt["WISDEM"]["DriveSE"]["gamma_m"] = 1.3
opt["WISDEM"]["DriveSE"]["gamma_n"] = 1.0
opt["WISDEM"]["RotorSE"] = {}
opt["WISDEM"]["RotorSE"]["n_pc"] = 20
opt["materials"] = {}
opt["materials"]["n_mat"] = 4
opt["flags"] = {}
opt["flags"]["generator"] = False

Next, we instantiate the OpenMDAO problem and assign the drivetrain as the model of the problem,

prob = om.Problem(reports=False)
prob.model = DrivetrainSE(modeling_options=opt)

For the optimization problem setup, the only differences are swapping in the high speed shaft parameters instead of the nose/turret design variables and constraints. The bedplate I-beam geometry parameters have also been added as design variables. There also are not any constraints for maintenance accessibility because of the easier access already afforded in this layout.

if opt_flag:
    # Choose the optimizer to use
    prob.driver = om.ScipyOptimizeDriver()
    prob.driver.options["optimizer"] = "SLSQP"
    prob.driver.options["tol"] = 1e-2
    prob.driver.options["maxiter"] = 5

    # Add objective
    prob.model.add_objective("nacelle_mass", scaler=1e-6)

    # Add design variables, in this case the tower diameter and wall thicknesses
    prob.model.add_design_var("L_12", lower=0.1, upper=5.0)
    prob.model.add_design_var("L_h1", lower=0.1, upper=5.0)
    prob.model.add_design_var("L_hss", lower=0.1, upper=5.0)
    prob.model.add_design_var("hub_diameter", lower=2.0, upper=5.0)
    prob.model.add_design_var("lss_diameter", lower=0.5, upper=6.0)
    prob.model.add_design_var("lss_wall_thickness", lower=4e-3, upper=5e-1, ref=1e-2)
    prob.model.add_design_var("hss_diameter", lower=0.5, upper=6.0)
    prob.model.add_design_var("hss_wall_thickness", lower=4e-3, upper=5e-1, ref=1e-2)
    prob.model.add_design_var("bedplate_web_thickness", lower=4e-3, upper=5e-1, ref=1e-2)
    prob.model.add_design_var("bedplate_flange_thickness", lower=4e-3, upper=5e-1, ref=1e-2)
    prob.model.add_design_var("bedplate_flange_width", lower=0.1, upper=2.0)

    # Add constraints on the tower design
    prob.model.add_constraint("constr_lss_vonmises", upper=1.0)
    prob.model.add_constraint("constr_hss_vonmises", upper=1.0)
    prob.model.add_constraint("constr_bedplate_vonmises", upper=1.0)
    prob.model.add_constraint("constr_mb1_defl", upper=1.0)
    prob.model.add_constraint("constr_mb2_defl", upper=1.0)
    prob.model.add_constraint("constr_shaft_deflection", upper=1.0)
    prob.model.add_constraint("constr_shaft_angle", upper=1.0)
    prob.model.add_constraint("constr_stator_deflection", upper=1.0)
    prob.model.add_constraint("constr_stator_angle", upper=1.0)
    prob.model.add_constraint("constr_hub_diameter", lower=0.0)
    prob.model.add_constraint("constr_length", lower=0.0)
    prob.model.add_constraint("constr_height", lower=0.0)

With the optimization problem defined, the OpenMDAO problem is activated

prob.setup()

Now we can specify the high level inputs that describe the turbine. Whereas the direct-drive example was for a 15-MW machine, this one is for a 5-MW machine with much smaller components.

opt = {}
opt["WISDEM"] = {}
opt["WISDEM"]["n_dlc"] = 1
opt["WISDEM"]["DriveSE"] = {}
opt["WISDEM"]["DriveSE"]["direct"] = False
opt["WISDEM"]["DriveSE"]["hub"] = {}
opt["WISDEM"]["DriveSE"]["hub"]["hub_gamma"] = 2.0
opt["WISDEM"]["DriveSE"]["hub"]["spinner_gamma"] = 1.5
opt["WISDEM"]["DriveSE"]["gamma_f"] = 1.35
opt["WISDEM"]["DriveSE"]["gamma_m"] = 1.3
opt["WISDEM"]["DriveSE"]["gamma_n"] = 1.0
opt["WISDEM"]["RotorSE"] = {}
opt["WISDEM"]["RotorSE"]["n_pc"] = 20
opt["materials"] = {}
opt["materials"]["n_mat"] = 4
opt["flags"] = {}
opt["flags"]["generator"] = False

The blade properties and other parameters needed for the hub and spinner designs reflect the smaller machine size,

prob["blade_mass"] = 16403.0
prob["blades_mass"] = 3 * prob["blade_mass"]
prob["pitch_system.BRFM"] = 14239550.0
prob["pitch_system_scaling_factor"] = 0.54
prob["blade_root_diameter"] = 3.542
prob["flange_t2shell_t"] = 4.0
prob["flange_OD2hub_D"] = 0.5
prob["flange_ID2flange_OD"] = 0.8
prob["hub_in2out_circ"] = 1.2
prob["hub_stress_concentration"] = 2.5
prob["n_front_brackets"] = 3
prob["n_rear_brackets"] = 3
prob["clearance_hub_spinner"] = 1.0
prob["spin_hole_incr"] = 1.2
prob["spinner_gust_ws"] = 70.0
prob["hub_diameter"] = 3.0
prob["blades_I"] = np.r_[36494351.0, 17549243.0, 14423664.0, np.zeros(3)]

Next is the layout of the drivetrain and the initial conditions of some of the design variables, with additional inputs needed for the gearbox design,

prob["bear1.bearing_type"] = "CARB"
prob["bear2.bearing_type"] = "SRB"
prob["L_12"] = 0.368
prob["L_h1"] = 1.912
prob["L_hss"] = 1.5
prob["L_generator"] = 2.0
prob["L_gearbox"] = 1.5
prob["overhang"] = 5.0
prob["drive_height"] = 2.3
prob["tilt"] = 5.0

prob["planet_numbers"] = np.array([3, 3, 0])
prob["gear_configuration"] = "eep"
prob["gear_ratio"] = 96.0

myones = np.ones(2)
prob["lss_diameter"] = 1.0 * myones
prob["hss_diameter"] = 0.5 * myones
prob["lss_wall_thickness"] = 0.288 * myones
prob["hss_wall_thickness"] = 0.1 * myones
prob["bedplate_web_thickness"] = 0.1
prob["bedplate_flange_thickness"] = 0.1
prob["bedplate_flange_width"] = 1.0
prob["bear1.D_shaft"] = 2.2
prob["bear2.D_shaft"] = 2.2
prob["shaft_deflection_allowable"] = 1e-4
prob["shaft_angle_allowable"] = 1e-3
prob["stator_deflection_allowable"] = 1e-4
prob["stator_angle_allowable"] = 1e-3

Finally, the material properties and assumptions are the same as above,

prob["E_mat"] = np.c_[200e9 * np.ones(3), 205e9 * np.ones(3), 118e9 * np.ones(3), [4.46e10, 1.7e10, 1.67e10]].T
prob["G_mat"] = np.c_[79.3e9 * np.ones(3), 80e9 * np.ones(3), 47.6e9 * np.ones(3), [3.27e9, 3.48e9, 3.5e9]].T
prob["Xt_mat"] = np.c_[450e6 * np.ones(3), 814e6 * np.ones(3), 310e6 * np.ones(3), [6.092e8, 3.81e7, 1.529e7]].T
prob["rho_mat"] = np.r_[7800.0, 7850.0, 7200.0, 1940.0]
prob["Xy_mat"] = np.r_[345e6, 485e6, 265e6, 18.9e6]
prob["wohler_exp_mat"] = 1e1 * np.ones(4)
prob["wohler_A_mat"] = 1e1 * np.ones(4)
prob["unit_cost_mat"] = np.r_[0.7, 0.9, 0.5, 1.9]
prob["lss_material"] = prob["hss_material"] = "steel_drive"
prob["bedplate_material"] = "steel"
prob["hub_material"] = "cast_iron"
prob["spinner_material"] = "glass_uni"
prob["material_names"] = ["steel", "steel_drive", "cast_iron", "glass_uni"]

The simulation can now be run. If doing an optimization, the geared simulation takes longer than the direct-drive version due to the internal design iterations for the gearbox,

if opt_flag:
    prob.model.approx_totals()
    prob.run_driver()
else:
    prob.run_model()
save_data("drivetrain_example", prob)

All of the inputs and outputs are displayed on the screen, followed by a curated list of values relating to the optimization problem.

# prob.model.list_inputs(units=True)
# prob.model.list_outputs(units=True)

# Print out the objective, design variables and constraints
print("nacelle_mass:", prob["nacelle_mass"])
print("")
print("L_h1:", prob["L_h1"])
print("L_12:", prob["L_12"])
print("L_lss:", prob["L_lss"])
print("L_hss:", prob["L_hss"])
print("L_generator:", prob["L_generator"])
print("L_gearbox:", prob["L_gearbox"])
print("L_bedplate:", prob["L_bedplate"])
print("H_bedplate:", prob["H_bedplate"])
print("hub_diameter:", prob["hub_diameter"])
print("lss_diameter:", prob["lss_diameter"])
print("lss_wall_thickness:", prob["lss_wall_thickness"])
print("hss_diameter:", prob["hss_diameter"])
print("hss_wall_thickness:", prob["hss_wall_thickness"])
print("bedplate_web_thickness:", prob["bedplate_web_thickness"])
print("bedplate_flange_thickness:", prob["bedplate_flange_thickness"])
print("bedplate_flange_width:", prob["bedplate_flange_width"])
print("")
print("constr_lss_vonmises:", prob["constr_lss_vonmises"].flatten())
print("constr_hss_vonmises:", prob["constr_hss_vonmises"].flatten())
print("constr_bedplate_vonmises:", prob["constr_bedplate_vonmises"].flatten())
print("constr_mb1_defl:", prob["constr_mb1_defl"])
print("constr_mb2_defl:", prob["constr_mb2_defl"])
print("constr_shaft_deflection:", prob["constr_shaft_deflection"])
print("constr_shaft_angle:", prob["constr_shaft_angle"])
print("constr_stator_deflection:", prob["constr_stator_deflection"])
print("constr_stator_angle:", prob["constr_stator_angle"])
print("constr_hub_diameter:", prob["constr_hub_diameter"])
print("constr_length:", prob["constr_length"])
print("constr_height:", prob["constr_height"])

The screen output should look something like the following,

Optimization terminated successfully    (Exit mode 0)
            Current function value: [0.14948563]
            Iterations: 12
            Function evaluations: 12
            Gradient evaluations: 12
Optimization Complete

...

nacelle_mass: [149485.62543167]

L_h1: [0.22298585]
L_12: [0.1]
L_lss: [0.42298585]
L_hss: [0.52650472]
L_generator: [2.]
L_gearbox: [1.512]
L_bedplate: [4.44451325]
H_bedplate: [1.69326612]
hub_diameter: [5.]
lss_diameter: [0.69921744 0.70132537]
lss_wall_thickness: [0.2878711  0.28786974]
hss_diameter: [0.5 0.5]
hss_wall_thickness: [0.0998473 0.0998473]
bedplate_web_thickness: [0.09595255]
bedplate_flange_thickness: [0.09892329]
bedplate_flange_width: [0.1]

constr_lss_vonmises: [0.98187486 0.9993906  0.99831682 0.99952247]
constr_hss_vonmises: [0.03251358 0.03215481]
constr_bedplate_vonmises: [1.51989918e-03 9.77245633e-03 6.01676078e-01 5.99836120e-01
 6.33223628e-01 8.63086490e-02 8.72758878e-02 4.39265181e-02
 4.30670107e-02 1.50407068e-04 2.08972837e-07 1.51990174e-03
 2.02074935e-02 6.91033399e-01 6.92826935e-01 7.50983681e-01
 1.07687995e-01 1.12023851e-01 4.39357428e-02 4.30706497e-02
 1.51237490e-04 1.59816568e-07]
constr_mb1_defl: [0.07958005]
constr_mb2_defl: [0.00890625]
constr_hub_diameter: [0.09206083]
constr_length: [-2.18136176e-10]
constr_height: [1.69326612]