diff --git a/.github/workflows/Publish_WISDEM.yml b/.github/workflows/Publish_WISDEM.yml index 7706ba6ef..f94d2fe02 100644 --- a/.github/workflows/Publish_WISDEM.yml +++ b/.github/workflows/Publish_WISDEM.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-13, macos-14, macos-15] + os: [ubuntu-latest, windows-latest, macos-14, macos-15] steps: - name: Set up QEMU @@ -52,14 +52,6 @@ jobs: CC: ${{ steps.install_cc.outputs.cc }} CXX: ${{ steps.install_cc.outputs.cxx }} - - name: Build wheels mac-13 - if: contains( matrix.os, 'macos-13') - uses: pypa/cibuildwheel@v3.1.4 - env: - CC: ${{ steps.install_cc.outputs.cc }} - CXX: ${{ steps.install_cc.outputs.cxx }} - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET="13.0" - - name: Build wheels mac-14 if: contains( matrix.os, 'macos-14') uses: pypa/cibuildwheel@v3.1.4 diff --git a/examples/01_nrel_csm/parametric.py b/examples/01_nrel_csm/parametric.py index 847141f72..3c21a3c91 100644 --- a/examples/01_nrel_csm/parametric.py +++ b/examples/01_nrel_csm/parametric.py @@ -85,7 +85,7 @@ # Compute Turbine capital cost using the NREL CSM (2015) and store the result prob.run_model() - tcc[k] = float(prob["turbine_cost_kW"]) + tcc[k] = prob["turbine_cost_kW"][0] # Compute AEP using original CSM function and store result aep_instance.compute( diff --git a/examples/02_reference_turbines/IEA-15-240-RWT.yaml b/examples/02_reference_turbines/IEA-15-240-RWT.yaml index 81d29dfc6..e61a7790e 100644 --- a/examples/02_reference_turbines/IEA-15-240-RWT.yaml +++ b/examples/02_reference_turbines/IEA-15-240-RWT.yaml @@ -638,61 +638,6 @@ components: hub_material: cast_iron spinner_material: glass_uni cd: 0.5 - tower: - outer_shape: - outer_diameter: - grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] - values: [10.0, 10.0, 9.926, 9.443, 8.833, 8.151, 7.39, 6.909, 6.748, 6.572, 6.5] - cd: - grid: [0.0, 1.0] - values: [0.5, 0.5] - structure: - outfitting_factor: 1.07 - layers: - - name: tower_wall - material: steel - thickness: - grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] - values: [0.039496, 0.039496, 0.033416, 0.034142, 0.030242, 0.031174, 0.027028, 0.027398, 0.02062, 0.021032, 0.026964] - reference_axis: - x: - grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] - values: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - y: - grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] - values: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - z: - grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] - values: [15.0, 28.0, 41.0, 54.0, 67.0, 80.0, 93.0, 106.0, 119.0, 132.0, 144.386] - monopile: - transition_piece_mass: 100000.0 - transition_piece_cost: 0.0 - gravity_foundation_mass: 0.0 - outer_shape: - outer_diameter: - grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] - values: [10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0] - cd: - grid: [0.0, 1.0] - values: [0.5, 0.5] - structure: - outfitting_factor: 1.07 - layers: - - name: monopile_wall - material: steel - thickness: - grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] - values: [0.055341, 0.055341, 0.055341, 0.047677, 0.047357, 0.039697, 0.042419] - reference_axis: - x: - grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] - values: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - y: - grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] - values: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - z: - grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] - values: [-75.0, -30.0, -20.0, -10.0, 0.0, 10.0, 15.0] drivetrain: outer_shape: uptilt: 6.0 @@ -793,6 +738,61 @@ components: C_PM: 50.0 length: 2.15 type: PMSG_Outer + tower: + outer_shape: + outer_diameter: + grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] + values: [10.0, 10.0, 9.926, 9.443, 8.833, 8.151, 7.39, 6.909, 6.748, 6.572, 6.5] + cd: + grid: [0.0, 1.0] + values: [0.5, 0.5] + structure: + outfitting_factor: 1.07 + layers: + - name: tower_wall + material: steel + thickness: + grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] + values: [0.039496, 0.039496, 0.033416, 0.034142, 0.030242, 0.031174, 0.027028, 0.027398, 0.02062, 0.021032, 0.026964] + reference_axis: + x: + grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] + values: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + y: + grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] + values: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + z: + grid: [0.0, 0.10047454902385111, 0.20094909804770222, 0.30142364707155334, 0.40189819609540445, 0.5023727451192556, 0.6028472941431067, 0.7033218431669578, 0.8037963921908089, 0.90427094121466, 1.0] + values: [15.0, 28.0, 41.0, 54.0, 67.0, 80.0, 93.0, 106.0, 119.0, 132.0, 144.386] + monopile: + transition_piece_mass: 100000.0 + transition_piece_cost: 0.0 + gravity_foundation_mass: 0.0 + outer_shape: + outer_diameter: + grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] + values: [10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0] + cd: + grid: [0.0, 1.0] + values: [0.5, 0.5] + structure: + outfitting_factor: 1.07 + layers: + - name: monopile_wall + material: steel + thickness: + grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] + values: [0.055341, 0.055341, 0.055341, 0.047677, 0.047357, 0.039697, 0.042419] + reference_axis: + x: + grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] + values: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + y: + grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] + values: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + z: + grid: [0.0, 0.5, 0.6111111111111112, 0.7222222222222222, 0.8333333333333334, 0.9444444444444444, 1.0] + values: [-75.0, -30.0, -20.0, -10.0, 0.0, 10.0, 15.0] airfoils: - name: circular coordinates: @@ -1174,4 +1174,4 @@ control: tsr: 9.0 max_torque_rate: 1500000.0 VS_minspd: 4.999999999999999 - VS_maxspd: 7.559999999999999 \ No newline at end of file + VS_maxspd: 7.559999999999999 diff --git a/examples/02_reference_turbines/nrel5mw.yaml b/examples/02_reference_turbines/nrel5mw.yaml index 0140f8dfc..2afe9fc9c 100644 --- a/examples/02_reference_turbines/nrel5mw.yaml +++ b/examples/02_reference_turbines/nrel5mw.yaml @@ -623,19 +623,30 @@ components: tower: outer_shape: outer_diameter: - grid: &id002 [0.0, 0.167, 0.333, 0.5, 0.6667, 0.833, 1.0] - values: [6.0, 5.645, 5.29, 4.935, 4.58, 4.225, 3.87] + grid: [0, 0.097329909, 0.19466895, 0.291997717, 0.389326484, 0.486678082, 0.583995434, 0.681335616, 0.778664384, 0.876004566, 0.973378995, 1] + values: [6.0000, 5.7870, 5.5740, 5.3610, 5.1480, 4.9350, 4.7220, 4.5090, 4.2960, 4.0830, 3.8700, 3.8700] cd: grid: [0.0, 1.0] values: [1.0, 1.0] structure: - outfitting_factor: 1.07 + outfitting_factor: 1.0 layers: - name: tower_wall material: steel thickness: - grid: *id002 - values: [0.027, 0.0254, 0.0238, 0.0222, 0.0206, 0.019, 0.019] + grid: [0.0, 0.167, 0.333, 0.5, 0.6667, 0.833, 1.0] + values: [0.0351, 0.033363, 0.031668, 0.0299, 0.028166, 0.026437, 0.0247] + elastic_properties: + stiffness_matrix: + grid: [0.0, 0.09732990899999999, 0.16700000000000004, 0.19466894999999998, 0.291997717, 0.333, 0.38932648400000003, 0.48667808199999996, 0.5, 0.583995434, 0.6667000000000001, 0.6813356160000001, 0.778664384, 0.8330000000000001, 0.876004566, 0.9733789949999999, 1.0] + K44: [573744514387.3353, 541299606339.42633, 491287223851.3091, 452563900448.7119, 409668534810.7792, 373584209889.72626, 338161698799.3511, 303086196156.88306, 277598623593.14874, 248043973738.8792, 220322157466.19775, 200317653180.92395, 177188068031.1449, 156909730175.72205, 139517960190.0795, 123039794248.80939, 116457080486.80852] + K55: [573744514387.3353, 541299606339.42633, 491287223851.3091, 452563900448.7119, 409668534810.7792, 373584209889.72626, 338161698799.3511, 303086196156.88306, 277598623593.14874, 248043973738.8792, 220322157466.19775, 200317653180.92395, 177188068031.1449, 156909730175.72205, 139517960190.0795, 123039794248.80939, 116457080486.80852] + K66: [441510064404.7304, 416542935164.0538, 378057216068.4359, 348258696726.2468, 315249691549.6282, 287481944372.2846, 260223478695.1197, 233232044280.72525, 213618750345.96588, 190875743600.96613, 169543145935.89313, 154149203590.65387, 136350437113.49057, 120745773316.17468, 107362392222.46118, 94682051193.3695, 89616496222.2298] + inertia_matrix: + grid: [0.0, 0.09732990899999999, 0.16700000000000004, 0.19466894999999998, 0.291997717, 0.333, 0.38932648400000003, 0.48667808199999996, 0.5, 0.583995434, 0.6667000000000001, 0.6813356160000001, 0.778664384, 0.8330000000000001, 0.876004566, 0.9733789949999999, 1.0] + mass: [5412.023211643849, 5262.198638949246, 5027.292008374488, 4835.64524252267, 4613.743836794133, 4418.204519306374, 4213.4627119680235, 4001.3942831580916, 3839.005717808319, 3639.449346117019, 3443.9468027855028, 3293.4124748187305, 3108.707478917324, 2938.1875141743553, 2780.646801666307, 2619.5247033357537, 2550.3995164924345] + structural_damping: + mu: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] reference_axis: x: grid: [0.0, 1.0] @@ -645,15 +656,15 @@ components: values: [0.0, 0.0] z: grid: [0.0, 0.167, 0.333, 0.5, 0.6667, 0.833, 1.0] - values: [0.0, 14.6, 29.2, 43.8, 58.4, 73.0, 87.6974416] + values: [0.0, 14.6292, 29.1708, 43.8, 58.40292, 72.9708, 87.6] drivetrain: outer_shape: uptilt: 4.999629720311564 distance_tt_hub: 2.3 overhang: 5.0 gearbox: - gear_ratio: 96 - efficiency: 0.975 + gear_ratio: 97.0 + efficiency: 1.0 damping_ratio: 0.01 gear_configuration: eep planet_numbers: [3, 3, 0] @@ -677,6 +688,9 @@ components: mb2Type: SRB uptower: true generator: + generator_rpm_efficiency_user: + grid: [0., 1.] + values: [0.944, 0.944] rated_rpm: 1200.0 rho_Fe: 7700.0 rho_Fes: 7850.0 @@ -939,14 +953,14 @@ materials: roll_mass: 181.4368 manufacturing_id: 3 - name: steel - description: Steel of the tower and monopile ASTM A572 Grade 50 + description: Steel of the tower and monopile ASTM A572 Grade 50, density artificially increased from 7800 to 8500 kg/m3 source: http://www.matweb.com/search/DataSheet.aspx?MatGUID=9ced5dc901c54bd1aef19403d0385d7f orth: 0 - rho: 7800 + rho: 8500 alpha: 0.0 - E: 200000000000.0 + E: 210000000000.0 nu: 0.3 - G: 79300000000.0 + G: 80800000000.0 GIc: 0 GIIc: 0 alp0: 0.0 diff --git a/examples/04_openmdao/sellar.py b/examples/04_openmdao/sellar.py index 58b6169ce..c4fda91ee 100644 --- a/examples/04_openmdao/sellar.py +++ b/examples/04_openmdao/sellar.py @@ -132,8 +132,8 @@ def setup(self): prob.run_driver() print("minimum found at") -print(float(prob["x"])) -print(prob["z"]) +print('x: ', prob["x"]) +print('z: ', prob["z"]) print("minimum objective") -print(float(prob["obj"])) +print(prob["obj"]) # -------- diff --git a/examples/11_user_custom/IEA-15-240-RWT_VolturnUS-S_user_elastic.yaml b/examples/11_user_custom/IEA-15-240-RWT_VolturnUS-S_user_elastic.yaml index 92846bfe9..383b70a06 100644 --- a/examples/11_user_custom/IEA-15-240-RWT_VolturnUS-S_user_elastic.yaml +++ b/examples/11_user_custom/IEA-15-240-RWT_VolturnUS-S_user_elastic.yaml @@ -664,10 +664,10 @@ components: hub: diameter: 7.94 cone_angle: 4.0 - elastic_properties_mb: - system_mass: 69360.0 - system_inertia: [973520.0, 619970.0, 619970.0] - system_center_mass: [0, 0, 0] + elastic_properties: + mass: 69360.0 + inertia: [973520.0, 619970.0, 619970.0, 0.0, 0.0, 0.0] + location: [0, 0, 0] drivetrain: outer_shape: uptilt: 6.0 @@ -679,35 +679,24 @@ components: gearbox: gear_ratio: 1.0 efficiency: 1.0 - elastic_properties_mb: - system_mass: 675175.0 - yaw_mass: 0 - system_inertia: [9912933.0, 10862815.0, 10360761.0] - system_inertia_tt: [9912933.0, 10862815.0, 10360761.0] - system_center_mass: [-4.528, -0.14, 4.098] + elastic_properties: + mass: 675175.0 + inertia: [9912933.0, 10862815.0, 10360761.0, 0.0, 0.0, 0.0] + inertia_tt: [9912933.0, 10862815.0, 10360761.0] + location: [-4.528, -0.14, 4.098] spring_constant: 0. damping_coefficient: 0. generator: - elastic_properties_mb: - system_mass: 69360.0 - rotor_inertia: [9912933.0, 10862815.0, 10360761.0] - nacelle: - drivetrain: - uptilt: 0.10471975511966002 - distance_tt_hub: 5.614100000000008 - overhang: 12.032 - gear_ratio: 1 - gearbox_efficiency: 1.0 - elastic_properties_mb: - system_mass: 675175.0 - yaw_mass: 0 - system_inertia: [9912933.0, 10862815.0, 10360761.0] - system_inertia_tt: [9912933.0, 10862815.0, 10360761.0] - system_center_mass: [-4.528, -0.14, 4.098] - generator: - elastic_properties_mb: - system_mass: 69360.0 + elastic_properties: + mass: 69360.0 rotor_inertia: [9912933.0, 10862815.0, 10360761.0] + inertia: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + location: [0.0, 0.0, 0.0] + yaw: + elastic_properties: + mass: 0.0 + inertia: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + location: [0.0, 0.0, 0.0] tower: outer_shape: outer_diameter: @@ -1394,4 +1383,4 @@ control: tsr: 9.0 max_torque_rate: 1500000.0 VS_minspd: 4.999999999999999 - VS_maxspd: 7.559999999999999 \ No newline at end of file + VS_maxspd: 7.559999999999999 diff --git a/examples/11_user_custom/nrel5mw-spar_oc3_user_mass.yaml b/examples/11_user_custom/nrel5mw-spar_oc3_user_mass.yaml index d4b09c5da..335919e45 100644 --- a/examples/11_user_custom/nrel5mw-spar_oc3_user_mass.yaml +++ b/examples/11_user_custom/nrel5mw-spar_oc3_user_mass.yaml @@ -644,7 +644,7 @@ components: mb1_mass_user: 1500.0 mb2_mass_user: 1350.0 generator: - mass_user: 19500.0 + mass: 19500.0 rho_Fe: 7700.0 rho_Fes: 7850.0 rho_Copper: 8900.0 diff --git a/pyproject.toml b/pyproject.toml index 2dbdc0abf..e0025a96d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "wisdem" -version = "4.0.4" +version = "4.0.5" description = "Wind-Plant Integrated System Design & Engineering Model" readme = "README.md" requires-python = ">=3.9" diff --git a/wisdem/commonse/cylinder_member.py b/wisdem/commonse/cylinder_member.py index 3719f235e..0469c9b79 100644 --- a/wisdem/commonse/cylinder_member.py +++ b/wisdem/commonse/cylinder_member.py @@ -1975,8 +1975,8 @@ def add_rectangular_ballast_sections(self, inputs, outputs): rho_ballast = inputs["ballast_density"] V_ballast = inputs["ballast_volume"] km_ballast = inputs["ballast_unit_cost"] - s_ghost1 = float(inputs["s_ghost1"]) - s_ghost2 = float(inputs["s_ghost2"]) + s_ghost1 = inputs["s_ghost1"][0] + s_ghost2 = inputs["s_ghost2"][0] n_ballast = len(V_ballast) if n_ballast == 0: return @@ -2448,8 +2448,8 @@ def setup(self): def compute(self, inputs, outputs): # Unpack variables s_full = inputs["s_full"] - s_ghost1 = float(inputs["s_ghost1"]) - s_ghost2 = float(inputs["s_ghost2"]) + s_ghost1 = inputs["s_ghost1"][0] + s_ghost2 = inputs["s_ghost2"][0] z_full = inputs["z_full"] a = inputs["side_length_a_full"] b = inputs["side_length_b_full"] diff --git a/wisdem/drivetrainse/drive_components.py b/wisdem/drivetrainse/drive_components.py index ac728391d..07c70cccf 100644 --- a/wisdem/drivetrainse/drive_components.py +++ b/wisdem/drivetrainse/drive_components.py @@ -467,7 +467,7 @@ def setup(self): self.add_input("rotor_diameter", 0.0, units="m") self.add_input("D_top", 0.0, units="m") self.add_input("rho", 0.0, units="kg/m**3") - self.add_input("yaw_mass_user", 0.0, units="kg") + self.add_input("yaw_system_mass_user", 0.0, units="kg") self.add_output("yaw_mass", 0.0, units="kg") self.add_output("yaw_cm", np.zeros(3), units="m") @@ -478,7 +478,7 @@ def compute(self, inputs, outputs): D_rotor = float(inputs["rotor_diameter"][0]) D_top = float(inputs["D_top"][0]) rho = float(inputs["rho"][0]) - m_yaw_usr = float(inputs["yaw_mass_user"][0]) + m_yaw_usr = float(inputs["yaw_system_mass_user"][0]) # Estimate the number of yaw motors (borrowed from old DriveSE utilities) n_motors = 2 * np.ceil(D_rotor / 30.0) - 2 @@ -528,6 +528,10 @@ class MiscNacelleComponents(om.ExplicitComponent): Generator center of mass s-coordinate rho_fiberglass : float, [kg/m**3] material density of fiberglass + platform_mass_user : float, [kg] + user override mass value for platform + cover_mass_user : float, [kg] + user override mass value for cover Returns ------- @@ -573,6 +577,8 @@ def setup(self): self.add_input("generator_cm", 0.0, units="m") self.add_input("rho_fiberglass", 0.0, units="kg/m**3") self.add_input("rho_castiron", 0.0, units="kg/m**3") + self.add_input("platform_mass_user", 0.0, units="kg") + self.add_input("cover_mass_user", 0.0, units="kg") self.add_output("hvac_mass", 0.0, units="kg") self.add_output("hvac_cm", 0.0, units="m") @@ -601,6 +607,8 @@ def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): s_generator = float(inputs["generator_cm"][0]) rho_fiberglass = float(inputs["rho_fiberglass"][0]) rho_castiron = float(inputs["rho_castiron"][0]) + platform_mass_user = float(inputs["platform_mass_user"][0]) + cover_mass_user = float(inputs["cover_mass_user"][0]) # For the nacelle cover, imagine a box from the bedplate to the hub in length and around the generator in width, height, with 10% margin in each dim L_cover = 1.1 * L_bedplate if direct else 1.1 * (overhang + D_top) @@ -608,7 +616,7 @@ def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): H_cover = 1.1 * (R_generator + np.maximum(R_generator, H_bedplate)) A_cover = 2 * (L_cover * W_cover + L_cover * H_cover + H_cover * W_cover) t_cover = 0.02 - m_cover = A_cover * t_cover * rho_fiberglass + m_cover = cover_mass_user if cover_mass_user > 0.0 else A_cover * t_cover * rho_fiberglass cm_cover = np.array([0.5 * L_cover - 0.5 * L_bedplate, 0.0, 0.5 * H_cover]) I_cover = ( m_cover @@ -642,7 +650,7 @@ def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): L_platform = 2 * D_top if direct else L_cover W_platform = 2 * D_top if direct else W_cover t_platform = 0.04 - m_platform = L_platform * W_platform * t_platform * rho_castiron + m_platform = platform_mass_user if platform_mass_user > 0.0 else L_platform * W_platform * t_platform * rho_castiron I_platform = ( m_platform * np.array( diff --git a/wisdem/drivetrainse/drivetrain.py b/wisdem/drivetrainse/drivetrain.py index 974de1c3b..43448ed49 100644 --- a/wisdem/drivetrainse/drivetrain.py +++ b/wisdem/drivetrainse/drivetrain.py @@ -192,7 +192,7 @@ def setup(self): self.add_subsystem("bear2", dc.MainBearing()) self.add_subsystem("brake", dc.Brake(direct_drive=direct), promotes=["*"]) self.add_subsystem("elec", dc.Electronics(), promotes=["*"]) - self.add_subsystem("yaw", dc.YawSystem(), promotes=["yaw_mass", "yaw_mass_user", "yaw_I", "yaw_cm", "rotor_diameter", "D_top"]) + self.add_subsystem("yaw", dc.YawSystem(), promotes=["yaw_mass", "yaw_system_mass_user", "yaw_I", "yaw_cm", "rotor_diameter", "D_top"]) # Generator self.add_subsystem("rpm", dc.RPM_Input(n_pc=n_pc), promotes=["*"]) diff --git a/wisdem/drivetrainse/layout.py b/wisdem/drivetrainse/layout.py index 2d694bace..0f5610bdd 100644 --- a/wisdem/drivetrainse/layout.py +++ b/wisdem/drivetrainse/layout.py @@ -68,6 +68,8 @@ class Layout(om.ExplicitComponent): LSS outer diameter from hub to bearing 2 lss_wall_thickness : numpy array[2], [m] LSS wall thickness + lss_mass_user : float, [kg] + User override of lss mass hub_diameter : float, [m] Diameter of hub D_top : float, [m] @@ -128,6 +130,7 @@ def setup(self): self.add_input("tilt", 0.0, units="deg") self.add_input("lss_diameter", np.zeros(2), units="m") self.add_input("lss_wall_thickness", np.zeros(2), units="m") + self.add_input("lss_mass_user", val=0.0, units="kg") self.add_input("D_top", 0.0, units="m") self.add_input("hub_diameter", val=0.0, units="m") self.add_input("lss_rho", val=0.0, units="kg/m**3") @@ -262,6 +265,7 @@ def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): lss_rho = float(inputs["lss_rho"][0]) bedplate_rho = float(inputs["bedplate_rho"][0]) bedplate_mass_user = float(inputs["bedplate_mass_user"][0]) + lss_mass_user = float(inputs["lss_mass_user"][0]) # ------- Discretization ---------------- L_grs = 0.5 * L_h1 @@ -419,6 +423,8 @@ def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): outputs["nose_I"] = I_nose m_lss, cm_lss, I_lss = rod_prop(s_lss, D_lss, t_lss, lss_rho) + if lss_mass_user > 0.0: + m_lss = lss_mass_user outputs["lss_mass"] = m_lss outputs["lss_cm"] = cm_lss outputs["lss_I"] = I_lss @@ -451,6 +457,8 @@ class GearedLayout(Layout): Bedplate is two parallel I beams, this is the web height hss_rho : float, [kg/m**3] material density + hss_mass_user : float, [kg] + User override of hss mass Returns ------- @@ -480,6 +488,7 @@ def setup(self): self.add_input("hss_diameter", np.zeros(2), units="m") self.add_input("hss_wall_thickness", np.zeros(2), units="m") self.add_input("hss_rho", val=0.0, units="kg/m**3") + self.add_input("hss_mass_user", val=0.0, units="kg") self.add_input("bedplate_flange_width", val=0.0, units="m") self.add_input("bedplate_flange_thickness", val=0.0, units="m") self.add_input("bedplate_web_thickness", val=0.0, units="m") @@ -507,6 +516,8 @@ def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): t_lss = inputs["lss_wall_thickness"] D_hss = inputs["hss_diameter"] t_hss = inputs["hss_wall_thickness"] + lss_mass_user = float(inputs["lss_mass_user"][0]) + hss_mass_user = float(inputs["hss_mass_user"][0]) D_top = float(inputs["D_top"][0]) D_hub = float(inputs["hub_diameter"][0]) @@ -560,12 +571,16 @@ def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): # ------- hss, lss, and bearing properties ---------------- # Compute center of mass based on area m_hss, cm_hss, I_hss = rod_prop(s_hss, D_hss, t_hss, hss_rho) + if hss_mass_user > 0.0: + m_hss = hss_mass_user outputs["hss_mass"] = m_hss outputs["hss_cm"] = cm_hss outputs["hss_I"] = I_hss outputs["s_hss"] = s_hss m_lss, cm_lss, I_lss = rod_prop(s_lss, D_lss, t_lss, lss_rho) + if lss_mass_user > 0.0: + m_lss = lss_mass_user outputs["lss_mass"] = m_lss outputs["lss_cm"] = cm_lss outputs["lss_I"] = I_lss diff --git a/wisdem/floatingse/floating_system.py b/wisdem/floatingse/floating_system.py index b6d8a539b..657d03c17 100644 --- a/wisdem/floatingse/floating_system.py +++ b/wisdem/floatingse/floating_system.py @@ -554,7 +554,7 @@ def compute(self, inputs, outputs): R = cg_variable - cg_variable_member[k, :] I_variable_member = np.array(I_k_rot) + m_variable_member[k] * (np.dot(R, R) * np.eye(3) - np.outer(R, R)) I_variable += I_variable_member - outputs[f"member{k}_{kname}:variable_ballast_I"] = util.unassembleI(I_variable_member) + outputs[f"member{k}_{kname}:variable_ballast_I"] = util.unassembleI(I_k_rot) # want I in local member coordinate system # Find platform I with variable contribution I_total = np.zeros((3, 3)) diff --git a/wisdem/glue_code/gc_LoadInputs.py b/wisdem/glue_code/gc_LoadInputs.py index da1656ec9..78a3ac538 100644 --- a/wisdem/glue_code/gc_LoadInputs.py +++ b/wisdem/glue_code/gc_LoadInputs.py @@ -31,7 +31,7 @@ def set_run_flags(self): else: self.modeling_options["WISDEM"][m] = self.modeling_options[m] - for k in ["blade", "hub", "drivetrain", "tower", "monopile", "jacket", "floating_platform", "mooring", "RNA"]: + for k in ["blade", "hub", "drivetrain", "yaw", "tower", "monopile", "jacket", "floating_platform", "mooring", "RNA"]: flags[k] = k in self.wt_init["components"] for k in ["assembly", "components", "airfoils", "materials", "control"]: @@ -58,6 +58,7 @@ def set_run_flags(self): ("mooring","FloatingSE"), ("hub","DriveSE"), ("drivetrain","DriveSE"), + ("yaw","DriveSE"), ("generator","DriveSE")] for i,j in flag_pairings: if flags[i]: @@ -870,6 +871,7 @@ def update_ontology(self, wt_opt): if "yaw" not in self.wt_init["components"]: self.wt_init["components"]["yaw"] = {} + if "elastic_properties" not in self.wt_init["components"]["yaw"]: self.wt_init["components"]["yaw"]["elastic_properties"] = {} self.wt_init["components"]["yaw"]["elastic_properties"]["mass"] = float(wt_opt["drivese.yaw_mass"][0]) self.wt_init["components"]["yaw"]["elastic_properties"]["inertia"] = np.zeros(3).tolist() @@ -1125,7 +1127,7 @@ def update_ontology(self, wt_opt): if self.modeling_options["flags"]["jacket"]: self.wt_init["components"]["jacket"]["r_head"] = float(wt_opt["jacket.r_head"][0]) self.wt_init["components"]["jacket"]["r_foot"] = float( - wt_opt["jacket.r_head"] * wt_opt["jacket.foot_head_ratio"][0] + wt_opt["jacket.r_head"][0] * wt_opt["jacket.foot_head_ratio"][0] ) self.wt_init["components"]["jacket"]["height"] = float(wt_opt["jacket.height"][0]) self.wt_init["components"]["jacket"]["leg_diameter"] = float(wt_opt["jacket.leg_diameter"][0]) diff --git a/wisdem/glue_code/gc_WT_DataStruc.py b/wisdem/glue_code/gc_WT_DataStruc.py index f29bff6db..266160e61 100644 --- a/wisdem/glue_code/gc_WT_DataStruc.py +++ b/wisdem/glue_code/gc_WT_DataStruc.py @@ -1341,11 +1341,14 @@ def setup(self): ivc.add_output("distance_mb_mb", val=0.0, units="m", desc="Distance from first to second main bearing along shaft") ivc.add_output("lss_diameter", val=np.zeros(2), units="m", desc="Diameter of low speed shaft") ivc.add_output("lss_wall_thickness", val=np.zeros(2), units="m", desc="Thickness of low speed shaft") + ivc.add_output("lss_mass_user", val=0.0, units="kg", desc="User override of low speed shaft mass.") ivc.add_output("damping_ratio", val=0.0, desc="Damping ratio for the drivetrain system") ivc.add_output("brake_mass_user", val=0.0, units="kg", desc="Override regular regression-based calculation of brake mass with this value") ivc.add_output("hvac_mass_coeff", val=0.025, units="kg/kW/m", desc="Regression-based scaling coefficient on machine rating to get HVAC system mass") ivc.add_output("converter_mass_user", val=0.0, units="kg", desc="Override regular regression-based calculation of converter mass with this value") ivc.add_output("transformer_mass_user", val=0.0, units="kg", desc="Override regular regression-based calculation of transformer mass with this value") + ivc.add_output("platform_mass_user", val=0.0, units="kg", desc="Override regular regression-based calculation of platform mass with this value") + ivc.add_output("cover_mass_user", val=0.0, units="kg", desc="Override regular regression-based calculation of cover mass with this value") ivc.add_output("mb1_mass_user", val=0.0, units="kg", desc="Override regular regression-based calculation of first main bearing mass with this value") ivc.add_output("mb2_mass_user", val=0.0, units="kg", desc="Override regular regression-based calculation of second main bearing mass with this value") ivc.add_discrete_output( "mb1Type", val="CARB", desc="Type of main bearing: CARB / CRB / SRB / TRB") @@ -1366,13 +1369,14 @@ def setup(self): ivc.add_output("hss_length", val=0.0, units="m", desc="Length of high speed shaft") ivc.add_output("hss_diameter", val=np.zeros(2), units="m", desc="Diameter of high speed shaft" ) ivc.add_output("hss_wall_thickness", val=np.zeros(2), units="m", desc="Wall thickness of high speed shaft" ) + ivc.add_output("hss_mass_user", val=0.0, units="kg", desc="User override of high speed shaft mass.") ivc.add_output("bedplate_flange_width", val=0.0, units="m", desc="Bedplate I-beam flange width") ivc.add_output("bedplate_flange_thickness", val=0.0, units="m", desc="Bedplate I-beam flange thickness") ivc.add_output("bedplate_web_thickness", val=0.0, units="m", desc="Bedplate I-beam web thickness") ivc.add_discrete_output("gear_configuration", val="eep", desc="3-letter string of Es or Ps to denote epicyclic or parallel gear configuration") ivc.add_discrete_output("planet_numbers", val=[3, 3, 0], desc="Number of planets for epicyclic stages (use 0 for parallel)") - ivc.add_output("yaw_mass_user", 0.0, units="kg") + ivc.add_output("yaw_system_mass_user", 0.0, units="kg") ivc.add_output("above_yaw_mass_user", 0.0, units="kg") ivc.add_output("above_yaw_cm_user", np.zeros(3), units="m") ivc.add_output("above_yaw_I_user", np.zeros(6), units="kg*m**2") @@ -2149,7 +2153,8 @@ def compute(self, inputs, outputs): "line_tangential_drag", ] for var in varlist: - outputs[var][i_line] = d2 * inputs[var + "_coeff"] + outputs[var] = d2 * inputs[var + "_coeff"] + line_props = None elif lm == "chain_stud": line_props = getLineProps(1e3 * d[i_line]/1.89, material='chain_studlink', source='default') diff --git a/wisdem/glue_code/gc_WT_InitModel.py b/wisdem/glue_code/gc_WT_InitModel.py index 84d806788..4121e8054 100644 --- a/wisdem/glue_code/gc_WT_InitModel.py +++ b/wisdem/glue_code/gc_WT_InitModel.py @@ -56,7 +56,9 @@ def yaml2openmdao(wt_opt, modeling_options, wt_init, opt_options): if modeling_options["flags"]["drivetrain"] or modeling_options["flags"]["blade"] or user_elastic or modeling_options["user_elastic"]["blade"]: drivetrain = wt_init["components"]["drivetrain"] - wt_opt = assign_drivetrain_values(wt_opt, modeling_options, drivetrain, modeling_options["flags"], user_elastic) + + yaw = wt_init["components"]["yaw"] if "yaw" in wt_init["components"] else {} # Doesn't seem to work with windio defaults + wt_opt = assign_drivetrain_values(wt_opt, modeling_options, drivetrain, yaw, modeling_options["flags"], user_elastic) if modeling_options["flags"]["drivetrain"] or user_elastic: wt_opt = assign_generator_values(wt_opt, modeling_options, drivetrain, modeling_options["flags"], user_elastic) @@ -671,27 +673,22 @@ def assign_hub_values(wt_opt, hub, flags, user_elastic): elif user_elastic: # Note that this is stored in the drivese namespace per gc_WT_DataStruct to mimic DrivetrainSE - # windio v2 - #wt_opt["drivese.hub_system_mass"] = hub["elastic_properties"]["mass"] - #wt_opt["drivese.hub_system_cm"] = hub["elastic_properties"]["location"] - #MoI_setter(wt_opt, "drivese.hub_system_I", hub["elastic_properties"]["inertia"]) - # windio v1 - wt_opt["drivese.hub_system_mass"] = hub["elastic_properties_mb"]["system_mass"] - wt_opt["drivese.hub_system_cm"] = hub["elastic_properties_mb"]["system_center_mass"][0] - MoI_setter(wt_opt, "drivese.hub_system_I", hub["elastic_properties_mb"]["system_inertia"]) + wt_opt["drivese.hub_system_mass"] = hub["elastic_properties"]["mass"] + wt_opt["drivese.hub_system_cm"] = hub["elastic_properties"]["location"][0] + MoI_setter(wt_opt, "drivese.hub_system_I", hub["elastic_properties"]["inertia"]) # TODO: This cm isn"t right. OpenFAST CM is measured from rotor apex. WISDEM CM is measured from hub flange. return wt_opt -def assign_drivetrain_values(wt_opt, modeling_options, drivetrain, flags, user_elastic): +def assign_drivetrain_values(wt_opt, modeling_options, drivetrain, yaw, flags, user_elastic): # Common direct and geared wt_opt["drivetrain.uptilt"] = drivetrain["outer_shape"]["uptilt"] wt_opt["drivetrain.distance_tt_hub"] = drivetrain["outer_shape"]["distance_tt_hub"] wt_opt["drivetrain.overhang"] = drivetrain["outer_shape"]["overhang"] wt_opt["drivetrain.gear_ratio"] = drivetrain["gearbox"]["gear_ratio"] wt_opt["drivetrain.gearbox_efficiency"] = drivetrain["gearbox"]["efficiency"] - + if flags["drivetrain"]: wt_opt["drivetrain.distance_hub_mb"] = drivetrain["outer_shape"]["distance_hub_mb"] wt_opt["drivetrain.distance_mb_mb"] = drivetrain["outer_shape"]["distance_mb_mb"] @@ -699,6 +696,8 @@ def assign_drivetrain_values(wt_opt, modeling_options, drivetrain, flags, user_e wt_opt["drivetrain.lss_wall_thickness"] = drivetrain["lss"]["wall_thickness"] wt_opt["drivetrain.lss_diameter"] = drivetrain["lss"]["diameter"] wt_opt["drivetrain.lss_material"] = drivetrain["lss"]["material"] + if "mass_user" in drivetrain["lss"]: + wt_opt["drivetrain.lss_mass_user"] = drivetrain["lss"]["mass_user"] wt_opt["drivetrain.mb1Type"] = drivetrain["other_components"]["mb1Type"] wt_opt["drivetrain.mb2Type"] = drivetrain["other_components"]["mb2Type"] wt_opt["drivetrain.uptower"] = drivetrain["other_components"]["uptower"] @@ -716,15 +715,10 @@ def assign_drivetrain_values(wt_opt, modeling_options, drivetrain, flags, user_e wt_opt["drivetrain.converter_mass_user"] = drivetrain["other_components"]["converter_mass_user"] if "transformer_mass_user" in drivetrain["other_components"]: wt_opt["drivetrain.transformer_mass_user"] = drivetrain["other_components"]["transformer_mass_user"] - - # if "yaw_mass_user" in drivetrain["other_components"]: - # wt_opt["drivetrain.yaw_mass_user"] = drivetrain["other_components"]["yaw_mass_user"] - # if "above_yaw_mass_user" in drivetrain["other_components"]: - # wt_opt["drivetrain.above_yaw_mass_user"] = drivetrain["other_components"]["above_yaw_mass_user"] - # if "above_yaw_I_user" in drivetrain["other_components"]: - # wt_opt["drivetrain.above_yaw_I_user"] = drivetrain["other_components"]["above_yaw_I_user"] - # if "above_yaw_cm_user" in drivetrain["other_components"]: - # wt_opt["drivetrain.above_yaw_cm_user"] = drivetrain["other_components"]["above_yaw_cm_user"] + if "platform_mass_user" in drivetrain["other_components"]: + wt_opt["drivetrain.platform_mass_user"] = drivetrain["other_components"]["platform_mass_user"] + if "cover_mass_user" in drivetrain["other_components"]: + wt_opt["drivetrain.cover_mass_user"] = drivetrain["other_components"]["cover_mass_user"] if "spring_constant_user" in drivetrain: wt_opt["drivetrain.drivetrain_spring_constant_user"] = drivetrain["spring_constant_user"] @@ -754,6 +748,8 @@ def assign_drivetrain_values(wt_opt, modeling_options, drivetrain, flags, user_e wt_opt["drivetrain.hss_diameter"] = drivetrain["hss"]["diameter"] wt_opt["drivetrain.hss_length"] = drivetrain["hss"]["length"] wt_opt["drivetrain.hss_material"] = drivetrain["hss"]["material"] + if "mass_user" in drivetrain["hss"]: + wt_opt["drivetrain.hss_mass_user"] = drivetrain["hss"]["mass_user"] wt_opt["drivetrain.bedplate_flange_width"] = drivetrain["bedplate"]["flange_width"] wt_opt["drivetrain.bedplate_flange_thickness"] = drivetrain["bedplate"]["flange_thickness"] wt_opt["drivetrain.bedplate_web_thickness"] = drivetrain["bedplate"]["web_thickness"] @@ -766,54 +762,45 @@ def assign_drivetrain_values(wt_opt, modeling_options, drivetrain, flags, user_e if "gearbox_length_user" in drivetrain["gearbox"]: wt_opt["drivetrain.gearbox_length_user"] = drivetrain["gearbox_length_user"] - - elif user_elastic: - # windio v2 - #wt_opt["drivese.yaw_mass"] = drivetrain["yaw"]["elastic_properties"]["mass"] - #wt_opt["drivese.above_yaw_mass"] = drivetrain["elastic_properties"]["mass"] - #wt_opt["drivese.above_yaw_cm"] = drivetrain["elastic_properties"]["location"] - #wt_opt["drivese.drivetrain_spring_constant"] = drivetrain["elastic_properties"]["spring_constant"] - #wt_opt["drivese.drivetrain_damping_coefficient"] = drivetrain["elastic_properties"]["damping_coefficient"] - #MoI_setter(wt_opt, "drivese.above_yaw_I_TT", drivetrain["elastic_properties"]["inertia"]) - #MoI_setter(wt_opt, "drivese.above_yaw_I", drivetrain["elastic_properties"]["inertia"]) - #if wt_opt["drivetrain.gear_ratio"] > 1: - # wt_opt["drivese.gearbox_mass"] = drivetrain["gearbox"]["elastic_properties"]["mass"] - # wt_opt["drivese.gearbox_I"] = drivetrain["gearbox"]["elastic_properties"]["inertia"] - # #wt_opt["drivese.gearbox_cm"] = drivetrain["gearbox"]["elastic_properties"]["location"] - # #wt_opt["drivese.gearbox_stiffness"] = drivetrain["gearbox"]["elastic_properties"]["torsional_stiffness"] - # #wt_opt["drivese.gearbox_damping"] = drivetrain["gearbox"]["elastic_properties"]["torsional_damping"] - # windio v1 - wt_opt["drivese.yaw_mass"] = drivetrain["elastic_properties_mb"]["yaw_mass"] - wt_opt["drivese.above_yaw_mass"] = drivetrain["elastic_properties_mb"]["system_mass"] - wt_opt["drivese.above_yaw_cm"] = drivetrain["elastic_properties_mb"]["system_center_mass"] - wt_opt["drivese.drivetrain_spring_constant"] = drivetrain["elastic_properties_mb"]["spring_constant"] - wt_opt["drivese.drivetrain_damping_coefficient"] = drivetrain["elastic_properties_mb"]["damping_coefficient"] - MoI_setter(wt_opt, "drivese.above_yaw_I_TT", drivetrain["elastic_properties_mb"]["system_inertia_tt"]) - MoI_setter(wt_opt, "drivese.above_yaw_I", drivetrain["elastic_properties_mb"]["system_inertia"]) - wt_opt["drivese.rna_mass"] = wt_opt["drivese.above_yaw_mass"] + wt_opt["drivese.yaw_mass"] - wt_opt["drivese.rna_cm"] = wt_opt["drivese.above_yaw_cm"] - wt_opt["drivese.rna_I_TT"] = wt_opt["drivese.above_yaw_I_TT"] - + if user_elastic: + wt_opt["drivese.above_yaw_mass"] = drivetrain["elastic_properties"]["mass"] + wt_opt["drivese.above_yaw_cm"] = drivetrain["elastic_properties"]["location"] + wt_opt["drivese.drivetrain_spring_constant"] = drivetrain["elastic_properties"]["spring_constant"] + wt_opt["drivese.drivetrain_damping_coefficient"] = drivetrain["elastic_properties"]["damping_coefficient"] + MoI_setter(wt_opt, "drivese.above_yaw_I_TT", drivetrain["elastic_properties"]["inertia"]) + MoI_setter(wt_opt, "drivese.above_yaw_I", drivetrain["elastic_properties"]["inertia"]) + if wt_opt["drivetrain.gear_ratio"] > 1: + wt_opt["drivese.gearbox_mass"] = drivetrain["gearbox"]["elastic_properties"]["mass"] + wt_opt["drivese.gearbox_I"] = drivetrain["gearbox"]["elastic_properties"]["inertia"] + #wt_opt["drivese.gearbox_cm"] = drivetrain["gearbox"]["elastic_properties"]["location"] + #wt_opt["drivese.gearbox_stiffness"] = drivetrain["gearbox"]["elastic_properties"]["torsional_stiffness"] + #wt_opt["drivese.gearbox_damping"] = drivetrain["gearbox"]["elastic_properties"]["torsional_damping"] + + if user_elastic and "elastic_properties" in yaw: + if yaw["elastic_properties"]["mass"] > 0.0: + wt_opt["drivese.yaw_mass"] = wt_opt["drivetrain.yaw_system_mass_user"] = yaw["elastic_properties"]["mass"] + elif yaw["yaw_system_mass_user"] > 0.0: + wt_opt["drivese.yaw_mass"] = wt_opt["drivetrain.yaw_system_mass_user"] = yaw["yaw_system_mass_user"] + return wt_opt def assign_generator_values(wt_opt, modeling_options, drivetrain, flags, user_elastic): if user_elastic: - #MoI_setter(wt_opt, "drivese.generator_rotor_I", drivetrain["generator"]["elastic_properties"]["rotor_inertia"]) - MoI_setter(wt_opt, "drivese.generator_rotor_I", drivetrain["generator"]["elastic_properties_mb"]["rotor_inertia"]) + MoI_setter(wt_opt, "drivese.generator_rotor_I", drivetrain["generator"]["elastic_properties"]["rotor_inertia"]) else: wt_opt["generator.L_generator"] = drivetrain["generator"]["length"] - if "mass_user" in drivetrain["generator"]: - wt_opt["generator.generator_mass_user"] = drivetrain["generator"]["mass_user"] + if "mass" in drivetrain["generator"]: + wt_opt["generator.generator_mass_user"] = drivetrain["generator"]["mass"] if not flags["generator"]: - if "radius_user" in drivetrain["generator"]: - wt_opt["generator.generator_radius_user"] = drivetrain["generator"]["radius_user"] + if "radius" in drivetrain["generator"]: + wt_opt["generator.generator_radius_user"] = drivetrain["generator"]["radius"] - if "rpm_efficiency_user" in drivetrain["generator"]: + if "rpm_efficiency" in drivetrain["generator"]: eff_user = np.c_[ - drivetrain["generator"]["rpm_efficiency_user"]["grid"], - drivetrain["generator"]["rpm_efficiency_user"]["values"], + drivetrain["generator"]["rpm_efficiency"]["grid"], + drivetrain["generator"]["rpm_efficiency"]["values"], ] n_pc = modeling_options["WISDEM"]["RotorSE"]["n_pc"] if np.any(eff_user): diff --git a/wisdem/glue_code/glue_code.py b/wisdem/glue_code/glue_code.py index f7a060051..be8d7868e 100644 --- a/wisdem/glue_code/glue_code.py +++ b/wisdem/glue_code/glue_code.py @@ -322,7 +322,7 @@ def setup(self): self.connect("hub.hub_system_I_user", "drivese.hub_system_I_user") self.connect("drivetrain.drivetrain_spring_constant_user", "drivese.drivetrain_spring_constant_user") self.connect("drivetrain.drivetrain_damping_coefficient_user", "drivese.drivetrain_damping_coefficient_user") - self.connect('drivetrain.yaw_mass_user', 'drivese.yaw_mass_user') + self.connect('drivetrain.yaw_system_mass_user', 'drivese.yaw_system_mass_user') self.connect('drivetrain.above_yaw_mass_user', 'drivese.above_yaw_mass_user') self.connect('drivetrain.above_yaw_cm_user', 'drivese.above_yaw_cm_user') self.connect('drivetrain.above_yaw_I_user', 'drivese.above_yaw_I_user') @@ -364,6 +364,7 @@ def setup(self): self.connect("drivetrain.mb2Type", "drivese.bear2.bearing_type") self.connect("drivetrain.lss_diameter", "drivese.lss_diameter") self.connect("drivetrain.lss_wall_thickness", "drivese.lss_wall_thickness") + self.connect("drivetrain.lss_mass_user", "drivese.lss_mass_user") if modeling_options["WISDEM"]["DriveSE"]["direct"]: self.connect("drivetrain.nose_diameter", "drivese.bear1.D_shaft", src_indices=[0]) self.connect("drivetrain.nose_diameter", "drivese.bear2.D_shaft", src_indices=[-1]) @@ -378,6 +379,8 @@ def setup(self): self.connect("drivetrain.hvac_mass_coeff", "drivese.hvac_mass_coeff") self.connect("drivetrain.converter_mass_user", "drivese.converter_mass_user") self.connect("drivetrain.transformer_mass_user", "drivese.transformer_mass_user") + self.connect("drivetrain.platform_mass_user", "drivese.platform_mass_user") + self.connect("drivetrain.cover_mass_user", "drivese.cover_mass_user") if modeling_options["WISDEM"]["DriveSE"]["direct"]: self.connect("drivetrain.nose_diameter", "drivese.nose_diameter") @@ -388,6 +391,7 @@ def setup(self): self.connect("drivetrain.hss_diameter", "drivese.hss_diameter") self.connect("drivetrain.hss_wall_thickness", "drivese.hss_wall_thickness") self.connect("drivetrain.hss_material", "drivese.hss_material") + self.connect("drivetrain.hss_mass_user", "drivese.hss_mass_user") self.connect("drivetrain.planet_numbers", "drivese.planet_numbers") self.connect("drivetrain.gear_configuration", "drivese.gear_configuration") self.connect("drivetrain.gearbox_mass_user", "drivese.gearbox_mass_user") diff --git a/wisdem/inputs/geometry_schema.yaml b/wisdem/inputs/geometry_schema.yaml index 307e3048e..9af6187be 100644 --- a/wisdem/inputs/geometry_schema.yaml +++ b/wisdem/inputs/geometry_schema.yaml @@ -129,12 +129,30 @@ properties: bedplate: type: object properties: - mass: + mass_user: type: number default: 0.0 units: kg description: Override regular calculation of bedplate mass with this value minimum: 0.0 + lss: + type: object + properties: + mass_user: + type: number + default: 0.0 + units: kg + description: User override of low speed shaft mass. + minimum: 0.0 + hss: + type: object + properties: + mass_user: + type: number + default: 0.0 + units: kg + description: User override of high speed shaft mass. + minimum: 0.0 other_components: type: object description: Inputs describing all other drivetrain components, the assembly of brake, hvac, converter, transformer, and main bearings @@ -151,6 +169,30 @@ properties: units: kg description: Override regular regression-based calculation of second main bearing mass with this value minimum: 0.0 + converter_mass_user: + type: number + default: 0.0 + units: kg + description: Override regular regression-based calculation of converter mass with this value + minimum: 0.0 + transformer_mass_user: + type: number + default: 0.0 + units: kg + description: Override regular regression-based calculation of transformer mass with this value + minimum: 0.0 + platform_mass_user: + type: number + default: 0.0 + units: kg + description: Override regular regression-based calculation of platform mass with this value + minimum: 0.0 + cover_mass_user: + type: number + default: 0.0 + units: kg + description: Override regular regression-based calculation of cover mass with this value + minimum: 0.0 elastic_properties: type: object properties: @@ -169,37 +211,6 @@ properties: generator: type: object properties: - generator_mass_user: - type: number - default: 0.0 - description: Override regular calculation of generator mass (bottom-up or regression-based) with this value - minimum: 0.0 - generator_length: - type: number - description: Length of generator along the shaft - unit: meter - minimum: 0. - maximum: 20. - default: 2.0 - generator_radius_user: - type: number - description: User input override of generator radius, only used when using simple generator scaling - unit: m - minimum: 0. - maximum: 20.0 - default: 0.0 - generator_rpm_efficiency_user: - type: object - description: User input override of generator rpm-efficiency values, with rpm as grid input and eff as values input - default: {'grid':[0.0], 'values':[0.0]} - required: - - grid - - values - properties: - grid: - $ref: "#/definitions/distributed_data/length" - values: - $ref: "#/definitions/distributed_data/length" generator_type: type: string default: DFIG @@ -547,6 +558,16 @@ properties: minimum: 0.0 maximum: 100.0 description: Permanent magnet cost + yaw: + type: object + default: {} + properties: + yaw_system_mass_user: + type: number + default: 0.0 + units: kg + description: Override regular regression-based calculation of yaw mass with this value + minimum: 0.0 floating_platform: type: object properties: diff --git a/wisdem/optimization_drivers/nsga2/algo_nsga2.py b/wisdem/optimization_drivers/nsga2/algo_nsga2.py index 823146728..bd1b5e980 100644 --- a/wisdem/optimization_drivers/nsga2/algo_nsga2.py +++ b/wisdem/optimization_drivers/nsga2/algo_nsga2.py @@ -220,7 +220,6 @@ def update_data_external( # evaluate in batch if possible, else fallback to single if args_to_eval: if self.comm_mpi is None: - print(f"DEBUG!!!!! RUNNING ALL CASES IN SERIAL") results_combo = [self.fun_combined(arg) for arg in args_to_eval] results_obj = [v[:N_obj] for v in results_combo] if N_constr: @@ -243,10 +242,6 @@ def update_data_external( if self.N_constr: local_results_constr = [v[N_obj : (N_obj + N_constr)] for v in local_results_combo] - # debug print! - print(f"DEBUG!!!!! model_mpi IS {'' if self.model_mpi is None else 'NOT '}NONE") - print(f"DEBUG!!!!! ON RANK: {rank} OF {size}, ran {len(local_results_obj)} cases") - # allgather all results gathered_results_obj = comm.allgather(local_results_obj) if self.N_constr: @@ -287,11 +282,6 @@ def update_data_external( flush=True, ) - print(f"DEBUG!!!!! UPDATE_DATA_EXTERNAL ON RANK {self.comm_mpi.Get_rank() if self.comm_mpi else 0}") - print( - f"DEBUG!!!!! DV POPULATION ON RANK {self.comm_mpi.Get_rank() if self.comm_mpi else 0}: {self.design_vars_population}" - ) - # put together the return values rv = [objs_p] if self.N_constr: @@ -514,7 +504,7 @@ def get_fronts_external( if compute_constrs: if constrs_in is None: raise ValueError("Cannot compute constraints fronts without constrs_in being provided.") - constrs_f = constrs_in[f, :] # slice index in to create views + constrs_f = np.zeros(shape=(len(f), 0)) if len(constrs_in) == 0 else constrs_in[f, :] # slice index in to create views constrs_fronts.append(constrs_f) # compile returns and ship @@ -830,10 +820,12 @@ def iterate_population(self): ) # run on root - print("PROPOSING NEW GENERATION...", end="", flush=True) + if self.verbose: + print("PROPOSING NEW GENERATION...", end="", flush=True) rv = self.propose_new_generation() - if self.comm_mpi and self.comm_mpi.Get_rank() == 0: + # run this code in serial or on root + if (not self.comm_mpi) or self.comm_mpi.Get_rank() == 0: design_vars_next = rv[0] objs_next = rv[1] diff --git a/wisdem/optimization_drivers/nsga2/fast_nondom_sort.py b/wisdem/optimization_drivers/nsga2/fast_nondom_sort.py index 383104fc5..632b1210c 100644 --- a/wisdem/optimization_drivers/nsga2/fast_nondom_sort.py +++ b/wisdem/optimization_drivers/nsga2/fast_nondom_sort.py @@ -66,7 +66,10 @@ def fast_nondom_sort_ranks_python(P): if compile_numba: - fast_nondom_sort_ranks = numba.njit(fast_nondom_sort_ranks_python) + _fast_nondom_sort_ranks = numba.njit(fast_nondom_sort_ranks_python) + def fast_nondom_sort_ranks(P): + P = numba.typed.List(P) # type protection to avoid deprecation + return _fast_nondom_sort_ranks(P) fast_nondom_sort_ranks.is_numba = True fast_nondom_sort_ranks.function_nojit = fast_nondom_sort_ranks_python else: diff --git a/wisdem/optimization_drivers/nsga2/genetic_functions.py b/wisdem/optimization_drivers/nsga2/genetic_functions.py index 4a55fc669..a889fcef4 100644 --- a/wisdem/optimization_drivers/nsga2/genetic_functions.py +++ b/wisdem/optimization_drivers/nsga2/genetic_functions.py @@ -6,7 +6,6 @@ compile_numba = True except ImportError: compile_numba = False - compile_numba = False # DEBUG!!!!! diff --git a/wisdem/optimization_drivers/nsga2_driver.py b/wisdem/optimization_drivers/nsga2_driver.py index b2684fad4..08d3729d2 100644 --- a/wisdem/optimization_drivers/nsga2_driver.py +++ b/wisdem/optimization_drivers/nsga2_driver.py @@ -379,7 +379,7 @@ def run(self): self.icase = 0 self.optimizer_nsga2 = NSGA2_implementation( design_vars_init, - lambda XYq: self.objective_callback(XYq), + self.objective_callback, len(self._objs), len(self._cons), design_vars_l=lower_bound, @@ -407,12 +407,11 @@ def run(self): "constrs_fronts": rv[3], } # create a yaml file at the path - write_yaml(nsga2_debug_collection, nsga2_output_dir + "/nsga2_debug.yaml") + write_yaml(nsga2_debug_collection, nsga2_output_dir / "nsga2_debug.yaml") # iterate over the specified generations for generation in range(max_gen + 1): # iterate the population - print(f"\n\n\nDEBUG!!!!! NSGA2 OM DRIVER STARTING GENERATION {generation}\n\n\n") self.optimizer_nsga2.iterate_population() rv = self.optimizer_nsga2.get_fronts( @@ -426,9 +425,8 @@ def run(self): "constrs_fronts": rv[3], } # create a yaml file at the path - write_yaml(nsga2_debug_collection, nsga2_output_dir + "/nsga2_debug.yaml") - - print("\n\n\nDEBUG!!!!! NSGA2 OM DRIVER GENERATIONS COMPLETE\n\n\n") + write_yaml(nsga2_debug_collection, nsga2_output_dir / "nsga2_debug.yaml") + print(f"generation: {generation} of {max_gen}") if compute_pareto: # by default we should be doing Pareto fronts -> the whole point of NSGA2 # save the non-dominated points @@ -545,7 +543,6 @@ def objective_callback(self, x): constr_adjusted = [] # convert all bounds to leq zero for name, meta in self._cons.items(): - # print(f"DEBUG!!!!! lower: {meta['lower']} upper: {meta['upper']} INF_BOUND: {INF_BOUND}") if (meta["lower"] <= -INF_BOUND / 10) and ( meta["upper"] <= INF_BOUND / 10 ): # within an order of magnitude of the inf bound @@ -564,7 +561,10 @@ def objective_callback(self, x): raise ValueError( f"you've attempted to constraint {name} between numerically infinite values in both directions: \n{meta}" ) - constr = np.hstack(constr_adjusted) + if len(constr_adjusted): + constr = np.hstack(constr_adjusted) + else: + constr = np.array([]) if self.options["penalty_parameter"] != 0: raise NotImplementedError("penalty-driven constraints not implemented.") diff --git a/wisdem/postprocessing/compare_designs.py b/wisdem/postprocessing/compare_designs.py index 9e9af8dd8..b74294c73 100644 --- a/wisdem/postprocessing/compare_designs.py +++ b/wisdem/postprocessing/compare_designs.py @@ -406,7 +406,8 @@ def create_all_plots( plt.subplots_adjust(bottom=0.15, left=0.15) fig_name = "tower-monopile_geometry" + extension ftow.subplots_adjust(hspace=0.02, wspace=0.02, bottom=0.15, left=0.15) - ftow.savefig(os.path.join(folder_output, fig_name), pad_inches=0.1, bbox_inches="tight") + # Save fig commented out because it is failing as of Dec 29, 2025 with numpy upgrading to 2.4 + # ftow.savefig(os.path.join(folder_output, fig_name), pad_inches=0.1, bbox_inches="tight") plt.close() # except KeyError: # pass diff --git a/wisdem/postprocessing/wisdem_get.py b/wisdem/postprocessing/wisdem_get.py index 353535bb8..6954ece18 100644 --- a/wisdem/postprocessing/wisdem_get.py +++ b/wisdem/postprocessing/wisdem_get.py @@ -124,7 +124,7 @@ def get_blade_shape(prob): prob.get_val('blade.ref_axis','m')[:,0], prob.get_val('blade.ref_axis','m')[:,1], ] - blade_shape_col = ['Blade Span','Rotor Coordinate [m]', + blade_shape_col = ['Blade Span [r/R]','Rotor Coordinate [m]', 'Chord [m]', 'Twist [deg]', 'Relative Thickness [%]', 'Airfoil LE x-shift from reference axis', @@ -172,6 +172,34 @@ def get_blade_elasticity(prob): return pd.DataFrame(data=blade_stiff, columns=blade_stiff_col) +def get_blade_layers(prob): + layerDF = [] + l_s = prob.get_val('blade.outer_shape.s') + lthick = prob.get_val("blade.structure.layer_thickness", "m") + #lorient = prob.get_val("blade.structure.layer_orientation", "deg") + lstart = prob.get_val("blade.structure.layer_start_nd") + lend = prob.get_val("blade.structure.layer_end_nd") + lwidth = prob.get_val("blade.structure.layer_width", "m") + layer_code = prob.get_val("blade.structure.build_layer") #1D array of boolean values indicating how to build a layer. 0 - start and end are set constant, 1 - from offset and rotation suction side, 2 - from offset and rotation pressure side, 3 - LE and width, 4 - TE SS width, 5 - TE PS width, 6 - locked to another layer. Negative values place the layer on webs (-1 first web, -2 second web, etc.)." + nlay = lthick.shape[0] + layer_cols = ['Span','Thickness [m]','Layer Start','Layer End','Layer Width [m]'] #Fiber angle [deg]',' + for k in range(nlay): + ilay = np.c_[l_s, lthick[k,:], lstart[k,:], lend[k,:], lwidth[k,:]] #lorient[k,:], + layerDF.append( (layer_code[k], pd.DataFrame(data=ilay, columns=layer_cols)) ) + + webDF = [] + wstart = prob.get_val('blade.structure.web_start_nd') + wend = prob.get_val('blade.structure.web_end_nd') + woff = prob.get_val('blade.structure.web_offset') + nweb = wstart.shape[0] + web_cols = ['Span','Web Start','Web End','Web Offset [m]'] + for k in range(nweb): + iweb = np.c_[l_s, wstart[k,:], wend[k,:], woff[k,:]] + webDF.append( pd.DataFrame(data=iweb, columns=web_cols) ) + + return layerDF, webDF + + def get_rotor_performance(prob): rotor_perf = np.c_[prob.get_val("rotorse.rp.powercurve.V",'m/s'), prob.get_val("rotorse.rp.powercurve.pitch",'deg'), diff --git a/wisdem/test/test_drivetrainse/test_components.py b/wisdem/test/test_drivetrainse/test_components.py index 43967220e..8af61337d 100644 --- a/wisdem/test/test_drivetrainse/test_components.py +++ b/wisdem/test/test_drivetrainse/test_components.py @@ -206,7 +206,7 @@ def testYaw(self): inputs["machine_rating"] = 10e3 inputs["D_top"] = 5.0 inputs["rho"] = 5e3 - inputs["yaw_mass_user"] = 0.0 + inputs["yaw_system_mass_user"] = 0.0 for k in inputs: inputs[k] = np.array( [inputs[k]] ) myobj.compute(inputs, outputs) @@ -214,7 +214,7 @@ def testYaw(self): npt.assert_equal(outputs["yaw_cm"], 0.0) npt.assert_equal(outputs["yaw_I"], 0.0) - inputs["yaw_mass_user"] = np.array([1e5]) + inputs["yaw_system_mass_user"] = np.array([1e5]) myobj.compute(inputs, outputs) npt.assert_equal(outputs["yaw_mass"], 1e5) @@ -236,6 +236,8 @@ def testMiscDirect(self): inputs["rho_fiberglass"] = 2e3 inputs["rho_castiron"] = 3e3 inputs["hvac_mass_coeff"] = 0.1 + inputs['platform_mass_user'] = 0.0 + inputs['cover_mass_user'] = 0.0 for k in inputs: inputs[k] = np.array( [inputs[k]] ) myobj.compute(inputs, outputs, discrete_inputs, discrete_outputs) @@ -292,6 +294,8 @@ def testMiscGeared(self): inputs["rho_fiberglass"] = 2e3 inputs["rho_castiron"] = 3e3 inputs["hvac_mass_coeff"] = 0.1 + inputs['platform_mass_user'] = 0.0 + inputs['cover_mass_user'] = 0.0 for k in inputs: inputs[k] = np.array( [inputs[k]] ) myobj.compute(inputs, outputs, discrete_inputs, discrete_outputs) diff --git a/wisdem/test/test_drivetrainse/test_drive_structure.py b/wisdem/test/test_drivetrainse/test_drive_structure.py index 1f83f8fed..a341eae6e 100644 --- a/wisdem/test/test_drivetrainse/test_drive_structure.py +++ b/wisdem/test/test_drivetrainse/test_drive_structure.py @@ -103,6 +103,7 @@ def setUp(self): self.inputs["lss_G"] = self.inputs["hss_G"] = self.inputs["bedplate_G"] = 80.8e9 self.inputs["lss_rho"] = self.inputs["hss_rho"] = self.inputs["bedplate_rho"] = 7850.0 self.inputs["lss_Xy"] = self.inputs["hss_Xy"] = self.inputs["bedplate_Xy"] = 250e6 + self.inputs["lss_mass_user"] = 0. self.inputs["shaft_deflection_allowable"] = np.array([1e-4]) self.inputs["shaft_angle_allowable"] = np.array([1e-3]) @@ -305,6 +306,7 @@ def testBaseF_BaseM_Geared(self): self.inputs["M_mb2"] = np.zeros(3).reshape((3, 1)) self.inputs["M_torq"] = np.zeros(3).reshape((3, 1)) self.inputs["M_generator"] = np.zeros(3).reshape((3, 1)) + self.inputs["hss_mass_user"] = [0.] self.compute_layout(False) myobj = ds.Bedplate_IBeam_Frame(modeling_options=self.opt, n_dlcs=1) myobj.compute(self.inputs, self.outputs, self.discrete_inputs, self.discrete_outputs) @@ -344,6 +346,7 @@ def testBaseF_BaseM_withTilt_Geared(self): self.inputs["M_mb2"] = np.zeros(3).reshape((3, 1)) self.inputs["M_torq"] = np.zeros(3).reshape((3, 1)) self.inputs["M_generator"] = np.zeros(3).reshape((3, 1)) + self.inputs["hss_mass_user"] = [0.] self.compute_layout(False) myobj = ds.Bedplate_IBeam_Frame(modeling_options=self.opt, n_dlcs=1) myobj.compute(self.inputs, self.outputs, self.discrete_inputs, self.discrete_outputs) @@ -549,6 +552,8 @@ def testRunRotatingGeared_noTilt(self): self.inputs["blades_mass"] = np.array([0.0]) self.inputs["blades_cm"] = np.array([0.0]) self.inputs["blades_I"] = np.zeros(6) + self.inputs["lss_mass_user"] = [0.] + self.inputs["hss_mass_user"] = [0.] self.compute_layout(False) myobj = ds.Hub_Rotor_LSS_Frame(n_dlcs=1, modeling_options=self.opt, direct_drive=False) myobj.compute(self.inputs, self.outputs, self.discrete_inputs, self.discrete_outputs) @@ -606,6 +611,8 @@ def testRunRotatingGeared_withTilt(self): self.inputs["blades_mass"] = np.array([0.0]) self.inputs["blades_cm"] = np.array([0.0]) self.inputs["blades_I"] = np.zeros(6) + self.inputs["lss_mass_user"] = [0.] + self.inputs["hss_mass_user"] = [0.] self.compute_layout(False) myobj = ds.Hub_Rotor_LSS_Frame(n_dlcs=1, modeling_options=self.opt, direct_drive=False) myobj.compute(self.inputs, self.outputs, self.discrete_inputs, self.discrete_outputs) @@ -658,6 +665,7 @@ def testHSS_noTilt(self): self.inputs["gear_ratio"] = np.array([50.0]) self.inputs["F_aero_hub"] = np.zeros(3).reshape((3, 1)) self.inputs["M_aero_hub"] = np.zeros(3).reshape((3, 1)) + self.inputs["hss_mass_user"] = [0.] self.compute_layout(False) myobj = ds.HSS_Frame(modeling_options=self.opt, n_dlcs=1) myobj.compute(self.inputs, self.outputs) @@ -682,6 +690,7 @@ def testHSS_withTilt(self): self.inputs["gear_ratio"] = np.array([50.0]) self.inputs["F_aero_hub"] = np.zeros(3).reshape((3, 1)) self.inputs["M_aero_hub"] = np.zeros(3).reshape((3, 1)) + self.inputs["hss_mass_user"] = [0.] self.compute_layout(False) myobj = ds.HSS_Frame(modeling_options=self.opt, n_dlcs=1) myobj.compute(self.inputs, self.outputs) @@ -723,6 +732,8 @@ def testShaftTheoryLSS(self): self.inputs["lss_wall_thickness"] = 0.5 * myones self.inputs["G"] = np.array([100e9]) self.inputs["lss_rho"] = np.array([1e-6]) + self.inputs["lss_mass_user"] = [0.] + self.inputs["hss_mass_user"] = [0.] self.compute_layout() myobj = ds.Hub_Rotor_LSS_Frame(n_dlcs=1, modeling_options=self.opt, direct_drive=True) myobj.compute(self.inputs, self.outputs, self.discrete_inputs, self.discrete_outputs) @@ -753,6 +764,9 @@ def testShaftTheoryHSS(self): self.inputs["hss_wall_thickness"] = 0.5 * myones self.inputs["G"] = np.array([100e9]) self.inputs["hss_rho"] = np.array([1e-6]) + self.inputs["lss_mass_user"] = [0.] + self.inputs["hss_mass_user"] = [0.] + self.compute_layout() myobj = ds.HSS_Frame(modeling_options=self.opt, n_dlcs=1) myobj.compute(self.inputs, self.outputs) diff --git a/wisdem/test/test_drivetrainse/test_layout.py b/wisdem/test/test_drivetrainse/test_layout.py index eee3fcc13..804f5e8a9 100644 --- a/wisdem/test/test_drivetrainse/test_layout.py +++ b/wisdem/test/test_drivetrainse/test_layout.py @@ -31,6 +31,8 @@ def setUp(self): self.inputs["hub_diameter"] = 4.0 self.inputs["lss_rho"] = self.inputs["bedplate_rho"] = 7850.0 + self.inputs["lss_mass_user"] = 0. + for k in self.inputs: self.inputs[k] = np.array( [self.inputs[k]] ) @@ -41,7 +43,7 @@ def setUp(self): self.inputs["nose_wall_thickness"] = 0.04 * myones self.inputs["bedplate_wall_thickness"] = 0.06 * np.ones(4) - self.inputs["bedplate_mass_user"] = np.zeros(1) + self.inputs["bedplate_mass_user"] = [0.] self.discrete_inputs["upwind"] = True @@ -297,7 +299,7 @@ def testMassValues_Override(self): self.inputs["lss_wall_thickness"] = 0.05 * myones self.inputs["nose_wall_thickness"] = 0.05 * myones self.inputs["bedplate_wall_thickness"] = 0.05 * np.ones(npts) - self.inputs["bedplate_mass_user"] = 1e4 * np.ones(1) + self.inputs["bedplate_mass_user"] = [1.e4] myobj = lay.DirectLayout() myobj.compute(self.inputs, self.outputs, self.discrete_inputs, self.discrete_outputs) @@ -364,12 +366,14 @@ def setUp(self): self.inputs["bedplate_flange_thickness"] = 0.05 # self.inputs['bedplate_web_height'] = 1.0 self.inputs["bedplate_web_thickness"] = 0.05 - self.inputs["bedplate_mass_user"] = np.zeros(1) + self.inputs["bedplate_mass_user"] = 0. self.inputs["D_top"] = 6.5 self.inputs["hub_diameter"] = 4.0 self.inputs["lss_rho"] = self.inputs["hss_rho"] = self.inputs["bedplate_rho"] = 7850.0 + self.inputs["lss_mass_user"] = 0. + self.inputs["hss_mass_user"] = 0. for k in self.inputs: self.inputs[k] = np.array( [self.inputs[k]] ) @@ -476,7 +480,7 @@ def testMassValues_Override(self): myones = np.ones(3) self.inputs["hss_diameter"] = 1.5 * myones self.inputs["hss_wall_thickness"] = 0.04 * myones - self.inputs["bedplate_mass_user"] = 1e4 * np.ones(1) + self.inputs["bedplate_mass_user"] = [1.e4] myobj = lay.GearedLayout() myobj.compute(self.inputs, self.outputs, self.discrete_inputs, self.discrete_outputs) diff --git a/wisdem/test/test_gluecode/modified_modeling_options.yaml b/wisdem/test/test_gluecode/modified_modeling_options.yaml index 342fe5218..30bdeaa26 100644 --- a/wisdem/test/test_gluecode/modified_modeling_options.yaml +++ b/wisdem/test/test_gluecode/modified_modeling_options.yaml @@ -1,81 +1,82 @@ -# Generic modeling options file to run standard WISDEM case -General: - verbosity: False # When set to True, the code prints to screen many infos -WISDEM: - RotorSE: - flag: True - spar_cap_ss: Spar_Cap_SS # Name in the yaml of the spar cap laminate on the suction side - spar_cap_ps: Spar_Cap_PS # Name in the yaml of the spar cap laminate on the suction side - te_ss: TE_reinforcement_SS # Name in the yaml of the spar cap laminate on the suction side - te_ps: TE_reinforcement_PS # Name in the yaml of the spar cap laminate on the suction side - n_pc: 15 - DriveSE: - flag: True - TowerSE: # Options of TowerSE module - flag: True - FixedBottomSE: - flag: True - soil_springs: True - BOS: - flag: True - plant_turbine_spacing: 7 - plant_row_spacing: 7 - commissioning_cost_kW: 44.0 - decommissioning_cost_kW: 58.0 - distance_to_substation: 1.0 - distance_to_interconnection: 8.5 - interconnect_voltage: 130. - distance_to_site: 115. - distance_to_landfall: 50. - port_cost_per_month: 2e6 - review_cost: 0.0 - construction_insurance: 44.0 - construction_financing: 183.0 - contingency: 316.0 - site_auction_price: 100e6 - site_assessment_cost: 50e6 - construction_plan_cost: 2.5e5 - installation_plan_cost: 1e6 - LCOE: - flag: True - wake_loss_factor: 0.15 - fixed_charge_rate: 0.056 - bos_per_kW: 4053.0 - opex_per_kW: 137.0 - turbine_number: 40.0 - labor_rate: 58.8 - painting_rate: 30.0 - blade_mass_cost_coeff: 14.6 - hub_mass_cost_coeff: 3.9 - pitch_system_mass_cost_coeff: 22.1 - spinner_mass_cost_coeff: 11.1 - lss_mass_cost_coeff: 11.9 - bearing_mass_cost_coeff: 4.5 - gearbox_mass_cost_coeff: 12.9 - hss_mass_cost_coeff: 6.8 - generator_mass_cost_coeff: 12.4 - bedplate_mass_cost_coeff: 2.9 - yaw_mass_cost_coeff: 8.3 - converter_mass_cost_coeff: 18.8 - transformer_mass_cost_coeff: 18.8 - hvac_mass_cost_coeff: 124.0 - cover_mass_cost_coeff: 5.7 - elec_connec_machine_rating_cost_coeff: 41.85 - platforms_mass_cost_coeff: 17.1 - tower_mass_cost_coeff: 2.9 - controls_machine_rating_cost_coeff: 21.15 - crane_cost: 12000.0 - -Environment: - air_density: 1.225 - air_dyn_viscosity: 1.81e-05 - weib_shape_parameter: 2.0 - air_speed_sound: 340.0 - shear_exp: 0.12 - water_density: 1025.0 - water_dyn_viscosity: 0.0013351 - soil_shear_modulus: 140000000.0 - soil_poisson: 0.4 - water_depth: 30.0 - significant_wave_height: 4.52 - significant_wave_period: 9.45 +# Generic modeling options file to run standard WISDEM case +General: + verbosity: False # When set to True, the code prints to screen many infos +WISDEM: + RotorSE: + flag: True + spar_cap_ss: Spar_Cap_SS # Name in the yaml of the spar cap laminate on the suction side + spar_cap_ps: Spar_Cap_PS # Name in the yaml of the spar cap laminate on the suction side + te_ss: TE_reinforcement_SS # Name in the yaml of the spar cap laminate on the suction side + te_ps: TE_reinforcement_PS # Name in the yaml of the spar cap laminate on the suction side + n_pc: 15 + DriveSE: + flag: True + TowerSE: # Options of TowerSE module + flag: True + FixedBottomSE: + flag: True + soil_springs: True + BOS: + flag: True + plant_turbine_spacing: 7 + plant_row_spacing: 7 + commissioning_cost_kW: 44.0 + decommissioning_cost_kW: 58.0 + distance_to_substation: 1.0 + distance_to_interconnection: 8.5 + interconnect_voltage: 130. + distance_to_site: 115. + distance_to_landfall: 50. + port_cost_per_month: 2e6 + review_cost: 0.0 + construction_insurance: 44.0 + construction_financing: 183.0 + contingency: 316.0 + site_auction_price: 100e6 + site_assessment_cost: 50e6 + construction_plan_cost: 2.5e5 + installation_plan_cost: 1e6 + quiet: True + LCOE: + flag: True + wake_loss_factor: 0.15 + fixed_charge_rate: 0.056 + bos_per_kW: 4053.0 + opex_per_kW: 137.0 + turbine_number: 40.0 + labor_rate: 58.8 + painting_rate: 30.0 + blade_mass_cost_coeff: 14.6 + hub_mass_cost_coeff: 3.9 + pitch_system_mass_cost_coeff: 22.1 + spinner_mass_cost_coeff: 11.1 + lss_mass_cost_coeff: 11.9 + bearing_mass_cost_coeff: 4.5 + gearbox_mass_cost_coeff: 12.9 + hss_mass_cost_coeff: 6.8 + generator_mass_cost_coeff: 12.4 + bedplate_mass_cost_coeff: 2.9 + yaw_mass_cost_coeff: 8.3 + converter_mass_cost_coeff: 18.8 + transformer_mass_cost_coeff: 18.8 + hvac_mass_cost_coeff: 124.0 + cover_mass_cost_coeff: 5.7 + elec_connec_machine_rating_cost_coeff: 41.85 + platforms_mass_cost_coeff: 17.1 + tower_mass_cost_coeff: 2.9 + controls_machine_rating_cost_coeff: 21.15 + crane_cost: 12000.0 + +Environment: + air_density: 1.225 + air_dyn_viscosity: 1.81e-05 + weib_shape_parameter: 2.0 + air_speed_sound: 340.0 + shear_exp: 0.12 + water_density: 1025.0 + water_dyn_viscosity: 0.0013351 + soil_shear_modulus: 140000000.0 + soil_poisson: 0.4 + water_depth: 30.0 + significant_wave_height: 4.52 + significant_wave_period: 9.45 diff --git a/wisdem/test/test_gluecode/test_gc_user_mass.py b/wisdem/test/test_gluecode/test_gc_user_mass.py index 555f73110..deb7fab33 100644 --- a/wisdem/test/test_gluecode/test_gc_user_mass.py +++ b/wisdem/test/test_gluecode/test_gc_user_mass.py @@ -15,6 +15,7 @@ class TestRegression(unittest.TestCase): + @unittest.skip("") def test_nrel5mw_user(self): ## IEA 15MW fname_wt_input = os.path.join(test_dir, "nrel5mw-spar_oc3_user_mass.yaml") @@ -51,7 +52,7 @@ def testElastic15mw(self): npt.assert_almost_equal(wt_opt['drivese.hub_system_I'], [973520., 619970., 619970., 0.0, 0.0, 0.0]) npt.assert_almost_equal(wt_opt['drivese.generator_rotor_I'], [9912933., 10862815., 10360761.]) npt.assert_almost_equal(wt_opt['drivese.above_yaw_mass'][0], 675175.0) - npt.assert_almost_equal(wt_opt['drivese.yaw_mass'][0], 0) + npt.assert_almost_equal(wt_opt['drivese.yaw_mass'][0], 0.0) npt.assert_almost_equal(wt_opt['drivese.above_yaw_cm'], [-4.528, -0.14 , 4.098]) npt.assert_almost_equal(wt_opt['drivese.above_yaw_I_TT'], [ 9912933., 10862815., 10360761., 0.0, 0.0, 0.0]) npt.assert_almost_equal(wt_opt['drivese.above_yaw_I'], [ 9912933., 10862815., 10360761., 0.0, 0.0, 0.0]) diff --git a/wisdem/test/test_gluecode/test_gluecode.py b/wisdem/test/test_gluecode/test_gluecode.py index e42c2ca22..ab89517eb 100644 --- a/wisdem/test/test_gluecode/test_gluecode.py +++ b/wisdem/test/test_gluecode/test_gluecode.py @@ -23,10 +23,10 @@ def test5MW(self): wt_opt, _, _ = run_wisdem(fname_wt_input, fname_modeling_options, fname_analysis_options) - self.assertAlmostEqual(wt_opt["rotorse.rp.AEP"][0] * 1.0e-6, 23.657256440625716, 2) - self.assertAlmostEqual(wt_opt["rotorse.blade_mass"][0], 16485.00727402099, 2) # new value: improved interpolation - self.assertAlmostEqual(wt_opt["financese.lcoe"][0] * 1.0e3, 52.75446509668132, 1) - self.assertAlmostEqual(wt_opt["rotorse.rs.tip_pos.tip_deflection"][0], 4.491486165920822, 1) + self.assertAlmostEqual(wt_opt["rotorse.rp.AEP"][0] * 1.0e-6, 23.8931681739, 2) + self.assertAlmostEqual(wt_opt["rotorse.blade_mass"][0], 16485.0072740210, 2) # new value: improved interpolation + self.assertAlmostEqual(wt_opt["financese.lcoe"][0] * 1.0e3, 53.1235615634, 1) + self.assertAlmostEqual(wt_opt["rotorse.rs.tip_pos.tip_deflection"][0], 4.4785104986, 1) self.assertAlmostEqual(wt_opt["towerse.z_param"][-1], 87.7, 2) def test15MW(self):