• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

WISDEM / WEIS / 12551706651

30 Dec 2024 08:42PM UTC coverage: 78.866% (+0.7%) from 78.185%
12551706651

Pull #330

github

dzalkind
Count elements in each design variable
Pull Request #330: Mpi v2

57 of 178 new or added lines in 6 files covered. (32.02%)

20 existing lines in 4 files now uncovered.

21558 of 27335 relevant lines covered (78.87%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

53.49
/weis/glue_code/gc_PoseOptimization.py
1
from wisdem.glue_code.gc_PoseOptimization import PoseOptimization
1✔
2
import numpy as np
1✔
3

4
class PoseOptimizationWEIS(PoseOptimization):
1✔
5

6
    def __init__(self, wt_init, modeling_options, analysis_options):
1✔
7
        
8
        self.level_flags = np.array([modeling_options[level]['flag'] for level in ['Level1','Level2','Level3']])
1✔
9
        # if sum(self.level_flags) > 1:
10
            # raise Exception('Only one level in WEIS can be enabled at the same time')
11

12
        super(PoseOptimizationWEIS, self).__init__(wt_init, modeling_options, analysis_options)
1✔
13

14
        # Set solve component for some optimization constraints, and merit figures (RAFT or openfast)
15
        if modeling_options['Level3']['flag']:
1✔
16
            self.floating_solve_component = 'aeroelastic'
1✔
17
        elif modeling_options['Level1']['flag']:
1✔
18
            self.floating_solve_component = 'raft'
1✔
19
        else:
20
            self.floating_solve_component = 'floatingse'
×
21

22
        # aeroelastic won't compute floating period, execpt in special sims
23
        if modeling_options['Level1']['flag']:
1✔
24
            self.floating_period_solve_component = 'raft'
1✔
25
        else:
26
            self.floating_period_solve_component = 'floatingse'
1✔
27
        
28
        if modeling_options['Level3']['flag']:
1✔
29
            self.n_OF_runs = modeling_options['DLC_driver']['n_cases']
1✔
30
        elif modeling_options['Level2']['flag']:
1✔
NEW
31
            self.n_OF_runs = modeling_options['Level2']['linearization']['NLinTimes']
×
32
        else:
33
            self.n_OF_runs = 0
1✔
34
    
35
    def set_objective(self, wt_opt):
1✔
36
        # Set merit figure. Each objective has its own scaling.  Check first for user override
37
        if self.opt["merit_figure_user"]["name"] != "":
1✔
38
            coeff = -1.0 if self.opt["merit_figure_user"]["max_flag"] else 1.0
×
39
            wt_opt.model.add_objective(self.opt["merit_figure_user"]["name"],
×
40
                                       ref=coeff*np.abs(self.opt["merit_figure_user"]["ref"]))
41
            
42
        elif self.opt['merit_figure'] == 'blade_tip_deflection':
1✔
43
            wt_opt.model.add_objective('tcons_post.tip_deflection_ratio')
×
44
            
45
        elif self.opt['merit_figure'] == 'DEL_RootMyb':   # for DAC optimization on root-flap-bending moments
1✔
46
            wt_opt.model.add_objective('aeroelastic.DEL_RootMyb', ref = 1.e3)
×
47
            
48
        elif self.opt['merit_figure'] == 'DEL_TwrBsMyt':   # for pitch controller optimization
1✔
49
            wt_opt.model.add_objective('aeroelastic.DEL_TwrBsMyt', ref=1.e4)
1✔
50
            
51
        elif self.opt['merit_figure'] == 'rotor_overspeed':
1✔
52
            if not any(self.level_flags):
×
53
                raise Exception('Please turn on the call to OpenFAST or RAFT if you are trying to optimize rotor overspeed constraints.')
×
54
            wt_opt.model.add_objective(f'{self.floating_solve_component}.rotor_overspeed')
×
55
        
56
        elif self.opt['merit_figure'] == 'Std_PtfmPitch':
1✔
57
            wt_opt.model.add_objective('aeroelastic.Std_PtfmPitch')
1✔
58
        
59
        elif self.opt['merit_figure'] == 'Max_PtfmPitch':
1✔
60
            wt_opt.model.add_objective('aeroelastic.Max_PtfmPitch')
×
61

62
        elif self.opt['merit_figure'] == 'Cp':
1✔
63
            wt_opt.model.add_objective('aeroelastic.Cp_out', ref=-1.)
×
64
        
65
        elif self.opt['merit_figure'] == 'weis_lcoe' or self.opt['merit_figure'].lower() == 'lcoe':
1✔
66
            wt_opt.model.add_objective('financese_post.lcoe')
×
67
        
68
        elif self.opt['merit_figure'] == 'OL2CL_pitch':
1✔
69
            wt_opt.model.add_objective('aeroelastic.OL2CL_pitch')
×
70
        
71
        else:
72
            super(PoseOptimizationWEIS, self).set_objective(wt_opt)
1✔
73
                
74
        return wt_opt
1✔
75

76
    
77
    def set_design_variables(self, wt_opt, wt_init):
1✔
78
        super(PoseOptimizationWEIS, self).set_design_variables(wt_opt, wt_init)
1✔
79

80
        # -- Control --
81
        control_opt = self.opt['design_variables']['control']
1✔
82
        if control_opt['servo']['pitch_control']['omega']['flag']:
1✔
83
            wt_opt.model.add_design_var('tune_rosco_ivc.omega_pc', lower=control_opt['servo']['pitch_control']['omega']['min'], 
1✔
84
                                                            upper=control_opt['servo']['pitch_control']['omega']['max'])
85
        if control_opt['servo']['pitch_control']['zeta']['flag']:                            
1✔
86
            wt_opt.model.add_design_var('tune_rosco_ivc.zeta_pc', lower=control_opt['servo']['pitch_control']['zeta']['min'], 
1✔
87
                                                           upper=control_opt['servo']['pitch_control']['zeta']['max'])
88
        if control_opt['servo']['torque_control']['omega']['flag']:
1✔
89
            wt_opt.model.add_design_var('tune_rosco_ivc.omega_vs', lower=control_opt['servo']['torque_control']['omega']['min'], 
×
90
                                                            upper=control_opt['servo']['torque_control']['omega']['max'])
91
        if control_opt['servo']['torque_control']['zeta']['flag']:                                                    
1✔
92
            wt_opt.model.add_design_var('tune_rosco_ivc.zeta_vs', lower=control_opt['servo']['torque_control']['zeta']['min'], 
×
93
                                                           upper=control_opt['servo']['torque_control']['zeta']['max'])
94
        if control_opt['servo']['ipc_control']['Kp']['flag']:
1✔
95
            wt_opt.model.add_design_var('tune_rosco_ivc.IPC_Kp1p', lower=control_opt['servo']['ipc_control']['Kp']['min'],
×
96
                                                            upper=control_opt['servo']['ipc_control']['Kp']['max'],
97
                                                            ref=control_opt['servo']['ipc_control']['Kp']['ref'])
98
        if control_opt['servo']['ipc_control']['Ki']['flag']:
1✔
99
            wt_opt.model.add_design_var('tune_rosco_ivc.IPC_Ki1p', lower=control_opt['servo']['ipc_control']['Ki']['min'],
×
100
                                                            upper=control_opt['servo']['ipc_control']['Ki']['max'],
101
                                                            ref=control_opt['servo']['ipc_control']['Kp']['ref'])
102
        if control_opt['servo']['pitch_control']['stability_margin']['flag']:
1✔
103
            wt_opt.model.add_design_var('tune_rosco_ivc.stability_margin', lower=control_opt['servo']['pitch_control']['stability_margin']['min'],
×
104
                                                            upper=control_opt['servo']['pitch_control']['stability_margin']['max'])
105
        if control_opt['flaps']['te_flap_end']['flag']:
1✔
106
            wt_opt.model.add_design_var('dac_ivc.te_flap_end', lower=control_opt['flaps']['te_flap_end']['min'],
×
107
                                                            upper=control_opt['flaps']['te_flap_end']['max'])
108
        if control_opt['flaps']['te_flap_ext']['flag']:
1✔
109
            wt_opt.model.add_design_var('dac_ivc.te_flap_ext', lower=control_opt['flaps']['te_flap_ext']['min'],
×
110
                                                            upper=control_opt['flaps']['te_flap_ext']['max'])
111
        if 'flap_control' in control_opt['servo']:
1✔
112
            if control_opt['servo']['flap_control']['flp_kp_norm']['flag']:
1✔
113
                wt_opt.model.add_design_var('tune_rosco_ivc.flp_kp_norm', 
×
114
                                    lower=control_opt['servo']['flap_control']['flp_kp_norm']['min'], 
115
                                    upper=control_opt['servo']['flap_control']['flp_kp_norm']['max'])
116
            if control_opt['servo']['flap_control']['flp_tau']['flag']:
1✔
117
                wt_opt.model.add_design_var('tune_rosco_ivc.flp_tau', 
×
118
                                    lower=control_opt['servo']['flap_control']['flp_tau']['min'], 
119
                                    upper=control_opt['servo']['flap_control']['flp_tau']['max'])
120

121
        if control_opt['ps_percent']['flag']:
1✔
122
            wt_opt.model.add_design_var('tune_rosco_ivc.ps_percent', lower=control_opt['ps_percent']['lower_bound'],
×
123
                                                            upper=control_opt['ps_percent']['upper_bound'])
124

125
        if control_opt['servo']['pitch_control']['Kp_float']['flag']:
1✔
126
            wt_opt.model.add_design_var('tune_rosco_ivc.Kp_float', lower=control_opt['servo']['pitch_control']['Kp_float']['min'], 
1✔
127
                                                           upper=control_opt['servo']['pitch_control']['Kp_float']['max'])
128

129
        if control_opt['servo']['pitch_control']['ptfm_freq']['flag']:
1✔
130
            wt_opt.model.add_design_var('tune_rosco_ivc.ptfm_freq', lower=control_opt['servo']['pitch_control']['ptfm_freq']['min'], 
1✔
131
                                                           upper=control_opt['servo']['pitch_control']['ptfm_freq']['max'])
132

133
        if self.opt['design_variables']['TMDs']['flag']:
1✔
134
            TMD_opt = self.opt['design_variables']['TMDs']
1✔
135

136
            # We only support one TMD for now
137
            for i_group, tmd_group in enumerate(TMD_opt['groups']):
1✔
138
                if 'mass' in tmd_group:
1✔
139
                    wt_opt.model.add_design_var(
1✔
140
                        f'TMDs.TMD_IVCs.group_{i_group}_mass', 
141
                        lower=tmd_group['mass']['lower_bound'],
142
                        upper=tmd_group['mass']['upper_bound'],
143
                        )
144
                if 'stiffness' in tmd_group:
1✔
145
                    wt_opt.model.add_design_var(
×
146
                        f'TMDs.TMD_IVCs.group_{i_group}_stiffness', 
147
                        lower=tmd_group['stiffness']['lower_bound'],
148
                        upper=tmd_group['stiffness']['upper_bound']
149
                        )
150
                    if 'natural_frequency' in tmd_group:
×
151
                        raise Exception("natural_frequency and stiffness can not be design variables in the same group")
×
152
                if 'damping' in tmd_group:
1✔
153
                    wt_opt.model.add_design_var(
×
154
                        f'TMDs.TMD_IVCs.group_{i_group}_damping', 
155
                        lower=tmd_group['damping']['lower_bound'],
156
                        upper=tmd_group['damping']['upper_bound']
157
                        )
158
                    if 'damping_ratio' in tmd_group:
×
159
                        raise Exception("damping_ratio and damping can not be design variables in the same group")
×
160
                if 'natural_frequency' in tmd_group:
1✔
161
                    wt_opt.model.add_design_var(
1✔
162
                        f'TMDs.TMD_IVCs.group_{i_group}_natural_frequency', 
163
                        lower=tmd_group['natural_frequency']['lower_bound'],
164
                        upper=tmd_group['natural_frequency']['upper_bound']
165
                        )
166
                if 'damping_ratio' in tmd_group:
1✔
167
                    wt_opt.model.add_design_var(
1✔
168
                        f'TMDs.TMD_IVCs.group_{i_group}_damping_ratio', 
169
                        lower=tmd_group['damping_ratio']['lower_bound'],
170
                        upper=tmd_group['damping_ratio']['upper_bound']
171
                        )
172
        
173
        return wt_opt
1✔
174

175
    
176
    def set_constraints(self, wt_opt):
1✔
177
        super(PoseOptimizationWEIS, self).set_constraints(wt_opt)
1✔
178

179
        blade_opt = self.opt["design_variables"]["blade"]
1✔
180
        blade_constr = self.opt["constraints"]["blade"]
1✔
181
        if blade_constr['tip_deflection']['flag']:
1✔
182
            # Remove generic WISDEM one
183
            name = 'tcons.tip_deflection_ratio'
×
184
            if name in wt_opt.model._responses:
×
185
                wt_opt.model._responses.pop( name )
×
186
            if name in wt_opt.model._static_responses:
×
187
                wt_opt.model._static_responses.pop( name )
×
188
                
189
            if blade_opt['structure']['spar_cap_ss']['flag'] or blade_opt['structure']['spar_cap_ps']['flag']:
×
190
                wt_opt.model.add_constraint('tcons_post.tip_deflection_ratio', upper=1.0)
×
191
            else:
192
                print('WARNING: the tip deflection is set to be constrained, but spar caps thickness is not an active design variable. The constraint is not enforced.')
×
193

194
        if blade_constr["strains_spar_cap_ss"]["flag"]:
1✔
195
            # Remove generic WISDEM one
196
            name = 'rotorse.rs.constr.constr_max_strainU_spar'
×
197
            if name in wt_opt.model._responses:
×
198
                wt_opt.model._responses.pop( name )
×
199
            if name in wt_opt.model._static_responses:
×
200
                wt_opt.model._static_responses.pop( name )
×
201
            if blade_opt["structure"]["spar_cap_ss"]["flag"]:
×
202
                indices_strains_spar_cap_ss = range(blade_constr["strains_spar_cap_ss"]["index_start"], blade_constr["strains_spar_cap_ss"]["index_end"])
×
203
                wt_opt.model.add_constraint("rlds_post.constr.constr_max_strainU_spar", indices = indices_strains_spar_cap_ss, upper=1.0)
×
204

205
        if blade_constr["strains_spar_cap_ps"]["flag"]:
1✔
206
            if (
×
207
                blade_opt["structure"]["spar_cap_ps"]["flag"]
208
                or blade_opt["structure"]["spar_cap_ps"]["equal_to_suction"]
209
            ):
210
                # Remove generic WISDEM one
211
                name = 'rotorse.rs.constr.constr_max_strainL_spar'
×
212
                if name in wt_opt.model._responses:
×
213
                    wt_opt.model._responses.pop( name )
×
214
                if name in wt_opt.model._static_responses:
×
215
                    wt_opt.model._static_responses.pop( name )
×
216
                indices_strains_spar_cap_ps = range(blade_constr["strains_spar_cap_ps"]["index_start"], blade_constr["strains_spar_cap_ps"]["index_end"])
×
217
                wt_opt.model.add_constraint("rlds_post.constr.constr_max_strainL_spar", indices = indices_strains_spar_cap_ps, upper=1.0)
×
218

219
        ### CONTROL CONSTRAINTS
220
        control_constraints = self.opt['constraints']['control']
1✔
221
        
222
        # Flap control
223
        if control_constraints['flap_control']['flag']:
1✔
224
            if self.modeling['Level3']['flag'] != True:
×
225
                raise Exception('Please turn on the call to OpenFAST if you are trying to optimize trailing edge flaps.')
×
226
            wt_opt.model.add_constraint('sse_tune.tune_rosco.flptune_coeff1',
×
227
                lower = control_constraints['flap_control']['min'],
228
                upper = control_constraints['flap_control']['max'])
229
            wt_opt.model.add_constraint('sse_tune.tune_rosco.flptune_coeff2', 
×
230
                lower = control_constraints['flap_control']['min'],
231
                upper = control_constraints['flap_control']['max'])    
232
        
233
        # Rotor overspeed
234
        if control_constraints['rotor_overspeed']['flag']:
1✔
235
            if not any(self.level_flags):
1✔
236
                raise Exception('Please turn on the call to OpenFAST or RAFT if you are trying to optimize rotor overspeed constraints.')
×
237
            wt_opt.model.add_constraint(f'{self.floating_solve_component}.rotor_overspeed',
1✔
238
                lower = control_constraints['rotor_overspeed']['min'],
239
                upper = control_constraints['rotor_overspeed']['max'])
240
        
241
        # Add PI gains if overspeed is merit_figure or constraint
242
        if control_constraints['rotor_overspeed']['flag'] or self.opt['merit_figure'] == 'rotor_overspeed':
1✔
243
            wt_opt.model.add_constraint('sse_tune.tune_rosco.PC_Kp',
1✔
244
                upper = 0.0)
245
            wt_opt.model.add_constraint('sse_tune.tune_rosco.PC_Ki', 
1✔
246
                upper = 0.0)  
247
        
248
        # Nacelle Accelleration magnitude
249
        if control_constraints['nacelle_acceleration']['flag']:
1✔
250
            if not any(self.level_flags):
×
251
                raise Exception('Please turn on the call to OpenFAST or RAFT if you are trying to optimize with nacelle_acceleration constraint.')
×
252
            wt_opt.model.add_constraint(f'{self.floating_solve_component}.max_nac_accel',
×
253
                    upper = control_constraints['nacelle_acceleration']['max'])
254
        
255
        # Max platform pitch
256
        if control_constraints['Max_PtfmPitch']['flag']:
1✔
257
            if not any(self.level_flags):
1✔
258
                raise Exception('Please turn on the call to OpenFAST or RAFT if you are trying to optimize Max_PtfmPitch constraints.')
×
259
            wt_opt.model.add_constraint(f'{self.floating_solve_component}.Max_PtfmPitch',
1✔
260
                upper = control_constraints['Max_PtfmPitch']['max'])
261
        
262
        # Platform pitch motion
263
        if control_constraints['Std_PtfmPitch']['flag']:
1✔
264
            if not any(self.level_flags):
×
265
                raise Exception('Please turn on the call to OpenFAST or RAFT if you are trying to optimize Std_PtfmPitch constraints.')
×
266
            wt_opt.model.add_constraint(f'{self.floating_solve_component}.Std_PtfmPitch',
×
267
                upper = control_constraints['Std_PtfmPitch']['max'])
268
        if control_constraints['Max_TwrBsMyt']['flag']:
1✔
269
            if self.modeling['Level3']['flag'] != True:
×
270
                raise Exception('Please turn on the call to OpenFAST if you are trying to optimize Max_TwrBsMyt constraints.')
×
271
            wt_opt.model.add_constraint('aeroelastic.max_TwrBsMyt_ratio', 
×
272
                upper = 1.0)
273
        if control_constraints['DEL_TwrBsMyt']['flag']:
1✔
274
            if self.modeling['Level3']['flag'] != True:
×
275
                raise Exception('Please turn on the call to OpenFAST if you are trying to optimize Max_TwrBsMyt constraints.')
×
276
            wt_opt.model.add_constraint('aeroelastic.DEL_TwrBsMyt_ratio', 
×
277
                upper = 1.0)
278
            
279
        # Blade pitch travel
280
        if control_constraints['avg_pitch_travel']['flag']:
1✔
281
            if self.modeling['Level3']['flag'] != True:
×
282
                raise Exception('Please turn on the call to OpenFAST if you are trying to optimize avg_pitch_travel constraints.')
×
283
            wt_opt.model.add_constraint('aeroelastic.avg_pitch_travel',
×
284
                upper = control_constraints['avg_pitch_travel']['max'])
285

286
        # Blade pitch duty cycle (number of direction changes)
287
        if control_constraints['pitch_duty_cycle']['flag']:
1✔
288
            if self.modeling['Level3']['flag'] != True:
×
289
                raise Exception('Please turn on the call to OpenFAST if you are trying to optimize pitch_duty_cycle constraints.')
×
290
            wt_opt.model.add_constraint('aeroelastic.pitch_duty_cycle',
×
291
                upper = control_constraints['pitch_duty_cycle']['max'])
292

293
        # OpenFAST failure
294
        if self.opt['constraints']['openfast_failed']['flag']:
1✔
295
            if self.modeling['Level3']['flag'] != True:
1✔
296
                raise Exception('Please turn on the call to OpenFAST if you are trying to optimize with openfast_failed constraint.')
×
297
            wt_opt.model.add_constraint('aeroelastic.openfast_failed',upper = 1.)
1✔
298

299
        # Max offset
300
        if self.opt['constraints']['floating']['Max_Offset']['flag']:
1✔
301
            if not any(self.level_flags):
×
302
                raise Exception('Please turn on the call to OpenFAST or RAFT if you are trying to optimize with openfast_failed constraint.')
×
303
            wt_opt.model.add_constraint(
×
304
                f'{self.floating_solve_component}.Max_Offset',
305
                upper = self.opt['constraints']['floating']['Max_Offset']['max']
306
                )
307
                
308
        # Tower constraints
309
        tower_opt = self.opt["design_variables"]["tower"]
1✔
310
        tower_constr = self.opt["constraints"]["tower"]
1✔
311
        if tower_constr["global_buckling"]["flag"] and self.modeling['Level3']['flag']:
1✔
312
            # Remove generic WISDEM one
313
            name = 'towerse.post.constr_global_buckling'
×
314
            if name in wt_opt.model._responses:
×
315
                wt_opt.model._responses.pop( name )
×
316
            if name in wt_opt.model._static_responses:
×
317
                wt_opt.model._static_responses.pop( name )
×
318
                
319
            wt_opt.model.add_constraint("towerse_post.constr_global_buckling", upper=1.0)
×
320
        
321
        if tower_constr["shell_buckling"]["flag"] and self.modeling['Level3']['flag']:
1✔
322
            # Remove generic WISDEM one
323
            name = 'towerse.post.constr_shell_buckling'
×
324
            if name in wt_opt.model._responses:
×
325
                wt_opt.model._responses.pop( name )
×
326
            if name in wt_opt.model._static_responses:
×
327
                wt_opt.model._static_responses.pop( name )
×
328
                
329
            wt_opt.model.add_constraint("towerse_post.constr_shell_buckling", upper=1.0)
×
330
        
331
        if tower_constr["stress"]["flag"] and self.modeling['Level3']['flag']:
1✔
332
            # Remove generic WISDEM one
333
            name = 'towerse.post.constr_stress'
×
334
            if name in wt_opt.model._responses:
×
335
                wt_opt.model._responses.pop( name )
×
336
            if name in wt_opt.model._static_responses:
×
337
                wt_opt.model._static_responses.pop( name )
×
338
                
339
            wt_opt.model.add_constraint("towerse_post.constr_stress", upper=1.0)
×
340

341
        # Damage constraints
342
        damage_constraints = self.opt['constraints']['damage']
1✔
343
        if damage_constraints['tower_base']['flag'] and (self.modeling['Level2']['flag'] or self.modeling['Level3']['flag']):
1✔
344
            if self.modeling['Level3']['flag'] != True:
1✔
345
                raise Exception('Please turn on the call to OpenFAST if you are trying to optimize with tower_base damage constraint.')
×
346

347
            tower_base_damage_max = damage_constraints['tower_base']['max']
1✔
348
            if damage_constraints['tower_base']['log']:
1✔
349
                tower_base_damage_max = np.log(tower_base_damage_max)
1✔
350

351
            wt_opt.model.add_constraint('aeroelastic.damage_tower_base',upper = tower_base_damage_max)
1✔
352

353
        return wt_opt
1✔
354

355

356
    def set_initial_weis(self, wt_opt):
1✔
357

358
        if self.modeling["flags"]["blade"]:
1✔
359
            blade_constr = self.opt["constraints"]["blade"]
1✔
360
            wt_opt["rlds_post.constr.max_strainU_spar"] = blade_constr["strains_spar_cap_ss"]["max"]
1✔
361
            wt_opt["rlds_post.constr.max_strainL_spar"] = blade_constr["strains_spar_cap_ps"]["max"]
1✔
362
            wt_opt["stall_check_of.stall_margin"] = blade_constr["stall"]["margin"] * 180.0 / np.pi
1✔
363
            wt_opt["tcons_post.max_allowable_td_ratio"] = blade_constr["tip_deflection"]["margin"]
1✔
364

365
        return wt_opt
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc