def __init__(self, name, becas_hash, config, input_folder, s): """ parameters ---------- config: dict dictionary with inputs to BECASWrapper input_folder: list list with becas input folders s: array spanwise location of the cross-section """ super(BECASCSStructureKM, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash # add outputs self.add_output('%s:k_matrix' % name, shape=(6, 6)) self.add_output('%s:m_matrix' % name, shape=(6, 6)) self.workdir = 'becas_%s_%i' % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ':hash', float(self.becas_hash)) config['BECASWrapper']['path_input'] = os.path.join( self.basedir, input_folder) self.becas = BECASWrapper(s, **config['BECASWrapper']) self.s = s
class BECASCSStressRecovery(Component): """ component for calling BECAS on individual sections to compute stresses and strains. """ def __init__(self, name, config, s, ncases): super(BECASCSStressRecovery, self).__init__() self.name = name self.s = s self.basedir = os.getcwd() # not so nice hack to ensure unique directory names when # running parallel FD # the hash is generated in the upstream BECASBeamStructure class self.add_param(name + ':hash', 0.) self.add_param('load_cases_%s' % name, np.zeros((ncases, 6))) self.add_output('blade_failure_index_%s' % name, np.zeros(ncases)) self.becas = BECASWrapper(s, **config['BECASWrapper']) self.becas.analysis_mode = 'stress_recovery' def solve_nonlinear(self, params, unknowns, resids): becas_hash = params[self.name + ':hash'] workdir = 'becas_%s_%i' % (self.name, int(becas_hash)) print 'workdir', workdir os.chdir(workdir) self.becas.load_cases = params['load_cases_%s' % self.name] self.becas.compute() unknowns['blade_failure_index_%s' % self.name] = self.becas.max_failure_ks os.chdir(self.basedir)
class BECASCSStructureKM(Component): def __init__(self, name, becas_hash, config, input_folder, s): """ parameters ---------- config: dict dictionary with inputs to BECASWrapper input_folder: list list with becas input folders s: array spanwise location of the cross-section """ super(BECASCSStructureKM, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash # add outputs self.add_output('%s:k_matrix' % name, shape=(6, 6)) self.add_output('%s:m_matrix' % name, shape=(6, 6)) self.workdir = 'becas_%s_%i' % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ':hash', float(self.becas_hash)) config['BECASWrapper']['path_input'] = os.path.join( self.basedir, input_folder) self.becas = BECASWrapper(s, **config['BECASWrapper']) self.s = s def solve_nonlinear(self, params, unknowns, resids): """ calls BECAS to compute the stiffness and mass terms """ try: os.mkdir(self.workdir) except: pass os.chdir(self.workdir) self.becas.compute() self.unknowns['%s:k_matrix' % self.name] = self.becas.k_matrix self.unknowns['%s:m_matrix' % self.name] = self.becas.m_matrix #remove becas output files and folders related to hash # os.remove('becas_section.m') # os.remove('BECAS_SetupPath.m') # os.remove('becas_utils%.3f.mat' % self.s) # os.rmdir(os.getcwd()) os.chdir(self.basedir)
class BECASCSStructureKM(Component): def __init__(self, name, becas_hash, config, input_folder, s): """ parameters ---------- config: dict dictionary with inputs to BECASWrapper input_folder: list list with becas input folders s: array spanwise location of the cross-section """ super(BECASCSStructureKM, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash # add outputs self.add_output('%s:k_matrix' % name, shape=(6,6)) self.add_output('%s:m_matrix' % name, shape=(6,6)) self.workdir = 'becas_%s_%i' % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ':hash', float(self.becas_hash)) config['BECASWrapper']['path_input'] = os.path.join(self.basedir, input_folder) self.becas = BECASWrapper(s, **config['BECASWrapper']) self.s = s def solve_nonlinear(self, params, unknowns, resids): """ calls BECAS to compute the stiffness and mass terms """ try: os.mkdir(self.workdir) except: pass os.chdir(self.workdir) self.becas.compute() self.unknowns['%s:k_matrix' % self.name] = self.becas.k_matrix self.unknowns['%s:m_matrix' % self.name] = self.becas.m_matrix #remove becas output files and folders related to hash # os.remove('becas_section.m') # os.remove('BECAS_SetupPath.m') # os.remove('becas_utils%.3f.mat' % self.s) # os.rmdir(os.getcwd()) os.chdir(self.basedir)
def __init__(self, name, becas_hash, config, input_folder, s): """ parameters ---------- config: dict dictionary with inputs to BECASWrapper input_folder: list list with becas input folders s: array spanwise location of the cross-section """ super(BECASCSStructureKM, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash # add outputs self.add_output('%s:k_matrix' % name, shape=(6,6)) self.add_output('%s:m_matrix' % name, shape=(6,6)) self.workdir = 'becas_%s_%i' % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ':hash', float(self.becas_hash)) config['BECASWrapper']['path_input'] = os.path.join(self.basedir, input_folder) self.becas = BECASWrapper(s, **config['BECASWrapper']) self.s = s
def __init__(self, name, config, s, ncases): super(BECASCSStressRecovery, self).__init__() self.name = name self.s = s self.basedir = os.getcwd() # not so nice hack to ensure unique directory names when # running parallel FD # the hash is generated in the upstream BECASBeamStructure class self.add_param(name + ':hash', 0.) self.add_param('load_cases_%s' % name, np.zeros((ncases, 6))) self.add_output('blade_failure_index_%s' % name, np.zeros(ncases)) self.becas = BECASWrapper(s, **config['BECASWrapper']) self.becas.analysis_mode = 'stress_recovery'
def becas_configure_stress_recovery(kls): # uncomment to keep Sim-* directories # import os # os.environ['OPENMDAO_KEEPDIRS'] = '1' kls.add('blade_strength', BECASStressRecovery()) kls.driver.workflow.add('blade_strength') cls = kls.blade_strength cls.add('cid', CaseIteratorDriver()) cls.driver.workflow.add('cid') cls.create_passthrough('cid.sequential') cls.sequential = False # add becas cls.add('becas', BECASWrapper()) cls.cid.workflow.add('becas') cls.becas.exec_mode = 'octave' cls.becas.analysis_mode = 'stress_recovery' cls.create_passthrough('becas.path_becas') # add parameters and responses cls.cid.add_parameter('becas.load_cases') cls.cid.add_response('becas.max_failure') cls.cid.add_response('becas.max_failure_ks') cls.connect('load_cases', 'cid.case_inputs.becas.load_cases') # cls.create_passthrough('cid.case_inputs.becas.load_cases') # cls.cid.add_response('becas.stress') # cls.cid.add_response('becas.strain') # add postprocessing components cls.add('process_failure', ProcessFailures()) cls.add('process_failure_ks', ProcessFailures()) cls.driver.workflow.add(['process_failure', 'process_failure_ks']) cls.connect('cid.case_outputs.becas.max_failure', 'process_failure.failureIn') cls.connect('cid.case_outputs.becas.max_failure_ks', 'process_failure_ks.failureIn') cls.connect('process_failure.max_failure', 'failure') cls.create_passthrough('process_failure_ks.max_failure', alias='failure_ks') cls.log_level = logging.DEBUG cls.becas.log_level = logging.DEBUG
def becas_configure_stiffness_calc(kls): # uncomment to keep Sim-* directories # import os # os.environ['OPENMDAO_KEEPDIRS'] = '1' kls.add('blade_beam_st', BECASBeamStructure()) kls.driver.workflow.add('blade_beam_st') cls = kls.blade_beam_st cls.add('cid', CaseIteratorDriver()) cls.driver.workflow.add('cid') cls.create_passthrough('cid.sequential') cls.sequential = False cls.add('a2b', CS2DtoBECAS()) cls.cid.workflow.add('a2b') cls.create_passthrough('a2b.path_shellexpander') cls.connect('becas_inputs', 'a2b.becas_inputs') cls.connect('section_name', 'a2b.section_name') # add BECAS mesh parameters cls.create_passthrough('a2b.total_points') cls.create_passthrough('a2b.max_layers') # add the CrossSectionStructureVT as parameter to the cid cls.cid.add_parameter('a2b.cs2d') # the parent assembly will connect to this with a list of cases # for each radial position cls.connect('cs2d', 'cid.case_inputs.a2b.cs2d') # declare outputs cls.cid.add_response('a2b.te_ratio') cls.create_passthrough('cid.case_outputs.a2b.te_ratio') # add becas cls.add('becas', BECASWrapper()) cls.cid.workflow.add('becas') cls.becas.exec_mode = 'octave' cls.becas.analysis_mode = 'stiffness' # connect path_input constructed by a2b to becas cls.connect('a2b.path_input', 'becas.path_input') cls.connect('a2b.cs2d.s/pf.blade_length', 'becas.spanpos') # path_becas needs to be set at runtime cls.create_passthrough('becas.path_becas') # declare outputs cls.cid.add_response('becas.hawc2_crossVT') cls.create_passthrough('cid.case_outputs.becas.hawc2_crossVT') # postprocess each case to generate the BeamStructureVT output # moved to parent assembly to avoid pickling error cls.add('postpro', ComputeHAWC2BeamProps()) cls.driver.workflow.add('postpro') cls.connect('pf', 'postpro.pf') cls.connect('cid.case_outputs.becas.hawc2_crossVT', 'postpro.cs2d_cases') cls.connect('postpro.beam_structure', 'beam_structure') cls.create_passthrough('postpro.mass') cls.create_passthrough('postpro.mass_moment') cls.create_passthrough('postpro.hub_radius') # uncomment to get full debug output cls.log_level = logging.DEBUG cls.a2b.log_level = logging.DEBUG cls.becas.log_level = logging.DEBUG
def __init__(self, name, becas_hash, config, st3d, s, ni_chord, cs_size, cs_size_ref): """ parameters ---------- config: dict dictionary with inputs to CS2DtoBECAS and BECASWrapper st3d: dict dictionary with blade structural definition s: array spanwise location of the cross-section ni_chord: int number of points definiting the cross-section shape cs_size: int size of blade_beam_structure array (19 or 30) cs_size_ref: int size of blade_beam_csprops_ref array (18) """ super(BECASCSStructure, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash self.nr = len(st3d['regions']) self.ni_chord = ni_chord # fix mesh distribution function after first run # defaults to True try: self.fix_mesh_distribution = config['fix_mesh_distribution'] except: self.fix_mesh_distribution = True # add materials properties array ((10, nmat)) self.add_param('matprops', st3d['matprops']) # add materials strength properties array ((18, nmat)) self.add_param('failmat', st3d['failmat']) # add DPs array self.add_param('%s:DPs' % name, np.zeros(self.nr + 1)) # add coords coords self._varnames = [] self.add_param('%s:coords' % name, np.zeros((ni_chord, 3))) self.cs2di = {} self.cs2di['materials'] = st3d['materials'] self.cs2di['matprops'] = st3d['matprops'] self.cs2di['failcrit'] = st3d['failcrit'] self.cs2di['failmat'] = st3d['failmat'] self.cs2di['web_def'] = st3d['web_def'] self.cs2di['s'] = s self.cs2di['DPs'] = np.zeros(self.nr + 1) self.cs2di['regions'] = [] self.cs2di['webs'] = [] for ireg, reg in enumerate(st3d['regions']): r = {} r['layers'] = reg['layers'] nl = len(reg['layers']) r['thicknesses'] = np.zeros(nl) r['angles'] = np.zeros(nl) self.cs2di['regions'].append(r) for i, lname in enumerate(reg['layers']): varname = '%s:r%02d%s' % (name, ireg, lname) self._varnames.append(varname) for ireg, reg in enumerate(st3d['webs']): r = {} r['layers'] = reg['layers'] nl = len(reg['layers']) r['thicknesses'] = np.zeros(nl) r['angles'] = np.zeros(nl) self.cs2di['webs'].append(r) for i, lname in enumerate(reg['layers']): varname = '%s:w%02d%s' % (name, ireg, lname) self._varnames.append(varname) self.add_param(name + ':tvec', np.zeros(len(self._varnames) * 2)) # add outputs self.add_output('%s:cs_props' % name, np.zeros(cs_size)) self.add_output('%s:csprops_ref' % name, np.zeros(cs_size_ref)) self.add_output('%s:k_matrix' % name, shape=(6, 6)) self.add_output('%s:m_matrix' % name, shape=(6, 6)) self.cs_props_m1 = np.zeros(cs_size) self.csprops_ref_m1 = np.zeros(cs_size_ref) self.k_matrix_m1 = np.zeros((6, 6)) self.m_matrix_m1 = np.zeros((6, 6)) self.add_output('%s:DPcoords' % name, np.zeros((self.nr + 1, 3))) self.workdir = 'becas_%s_%i' % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ':hash', float(self.becas_hash)) self.mesher = CS2DtoBECAS(self.cs2di, **config['CS2DtoBECAS']) self.becas = BECASWrapper(self.cs2di['s'], **config['BECASWrapper']) self.redistribute_flag = True
class BECASCSStructure(Component): """ Component for computing beam structural properties using the cross-sectional structure code BECAS. The code firstly calls CS2DtoBECAS which is a wrapper around shellexpander that comes with BECAS, and second calls BECAS using a file interface. parameters ---------- config: dict dictionary of model specific inputs coords: array cross-sectional shape. size ((ni_chord, 3)) matprops: array material stiffness properties. Size ((10, nmat)). failmat: array material strength properties. Size ((18, nmat)). DPs: array vector of DPs. Size: (nDP) coords: array blade section coordinates. Size: ((ni_chord, 3)) r<xx><lname>T: float layer thicknesses, e.g. r01triaxT. r<xx><lname>A: float layer angles, e.g. r01triaxA. w<xx><lname>T: float web thicknesses, e.g. r01triaxT. w<xx><lname>A: float web angles, e.g. r01triaxA. returns ------- cs_props: array vector of cross section properties. Size (19) or (30) for standard HAWC2 output or the fully populated stiffness matrix, respectively. csprops_ref: array vector of cross section properties as of BECAS output w.r.t BECAS reference coordinate system. Size (18). """ def __init__(self, name, becas_hash, config, st3d, s, ni_chord, cs_size, cs_size_ref): """ parameters ---------- config: dict dictionary with inputs to CS2DtoBECAS and BECASWrapper st3d: dict dictionary with blade structural definition s: array spanwise location of the cross-section ni_chord: int number of points definiting the cross-section shape cs_size: int size of blade_beam_structure array (19 or 30) cs_size_ref: int size of blade_beam_csprops_ref array (18) """ super(BECASCSStructure, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash self.nr = len(st3d['regions']) self.ni_chord = ni_chord # fix mesh distribution function after first run # defaults to True try: self.fix_mesh_distribution = config['fix_mesh_distribution'] except: self.fix_mesh_distribution = True # add materials properties array ((10, nmat)) self.add_param('matprops', st3d['matprops']) # add materials strength properties array ((18, nmat)) self.add_param('failmat', st3d['failmat']) # add DPs array self.add_param('%s:DPs' % name, np.zeros(self.nr + 1)) # add coords coords self._varnames = [] self.add_param('%s:coords' % name, np.zeros((ni_chord, 3))) self.cs2di = {} self.cs2di['materials'] = st3d['materials'] self.cs2di['matprops'] = st3d['matprops'] self.cs2di['failcrit'] = st3d['failcrit'] self.cs2di['failmat'] = st3d['failmat'] self.cs2di['web_def'] = st3d['web_def'] self.cs2di['s'] = s self.cs2di['DPs'] = np.zeros(self.nr + 1) self.cs2di['regions'] = [] self.cs2di['webs'] = [] for ireg, reg in enumerate(st3d['regions']): r = {} r['layers'] = reg['layers'] nl = len(reg['layers']) r['thicknesses'] = np.zeros(nl) r['angles'] = np.zeros(nl) self.cs2di['regions'].append(r) for i, lname in enumerate(reg['layers']): varname = '%s:r%02d%s' % (name, ireg, lname) self._varnames.append(varname) for ireg, reg in enumerate(st3d['webs']): r = {} r['layers'] = reg['layers'] nl = len(reg['layers']) r['thicknesses'] = np.zeros(nl) r['angles'] = np.zeros(nl) self.cs2di['webs'].append(r) for i, lname in enumerate(reg['layers']): varname = '%s:w%02d%s' % (name, ireg, lname) self._varnames.append(varname) self.add_param(name + ':tvec', np.zeros(len(self._varnames) * 2)) # add outputs self.add_output('%s:cs_props' % name, np.zeros(cs_size)) self.add_output('%s:csprops_ref' % name, np.zeros(cs_size_ref)) self.add_output('%s:k_matrix' % name, shape=(6, 6)) self.add_output('%s:m_matrix' % name, shape=(6, 6)) self.cs_props_m1 = np.zeros(cs_size) self.csprops_ref_m1 = np.zeros(cs_size_ref) self.k_matrix_m1 = np.zeros((6, 6)) self.m_matrix_m1 = np.zeros((6, 6)) self.add_output('%s:DPcoords' % name, np.zeros((self.nr + 1, 3))) self.workdir = 'becas_%s_%i' % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ':hash', float(self.becas_hash)) self.mesher = CS2DtoBECAS(self.cs2di, **config['CS2DtoBECAS']) self.becas = BECASWrapper(self.cs2di['s'], **config['BECASWrapper']) self.redistribute_flag = True def _params2dict(self, params): """ convert the OpenMDAO params dictionary into the dictionary format used in CS2DtoBECAS. """ tvec = params[self.name + ':tvec'] self.cs2d = {} # constants self.cs2d['s'] = self.cs2di['s'] self.cs2d['web_def'] = self.cs2di['web_def'] self.cs2d['failcrit'] = self.cs2di['failcrit'] self.cs2d['materials'] = self.cs2di['materials'] # params self.cs2d['coords'] = params['%s:coords' % self.name][:, :2] self.cs2d['matprops'] = params['matprops'] self.cs2d['failmat'] = params['failmat'] self.cs2d['DPs'] = params['%s:DPs' % self.name] self.cs2d['regions'] = [] self.cs2d['webs'] = [] counter = 0 nvar = len(self._varnames) for ireg, reg in enumerate(self.cs2di['regions']): self.cs2d['regions'].append({}) Ts = [] As = [] layers = [] for i, lname in enumerate(reg['layers']): if tvec[counter] > 0.: Ts.append(tvec[counter]) As.append(tvec[nvar + counter]) layers.append(lname) counter += 1 self.cs2d['regions'][ireg]['thicknesses'] = np.asarray(Ts) self.cs2d['regions'][ireg]['angles'] = np.asarray(As) self.cs2d['regions'][ireg]['layers'] = layers for ireg, reg in enumerate(self.cs2di['webs']): self.cs2d['webs'].append({}) Ts = [] As = [] layers = [] for i, lname in enumerate(reg['layers']): if tvec[counter] > 0.: Ts.append(tvec[counter]) As.append(tvec[nvar + counter]) layers.append(lname) counter += 1 self.cs2d['webs'][ireg]['thicknesses'] = np.asarray(Ts) self.cs2d['webs'][ireg]['angles'] = np.asarray(As) self.cs2d['webs'][ireg]['layers'] = layers def solve_nonlinear(self, params, unknowns, resids): """ calls CS2DtoBECAS/shellexpander to generate mesh and BECAS to compute the cs_props and csprops """ try: os.mkdir(self.workdir) except: pass os.chdir(self.workdir) self._params2dict(params) self.mesher.cs2d = self.cs2d try: self.mesher.compute(self.redistribute_flag) self.becas.compute() if self.becas.success: self.unknowns['%s:DPcoords' % self.name][:, 0:2] = np.array( self.mesher.DPcoords) self.unknowns['%s:cs_props' % self.name] = self.becas.cs_props self.unknowns['%s:csprops_ref' % self.name] = self.becas.csprops self.unknowns['%s:k_matrix' % self.name] = self.becas.k_matrix self.unknowns['%s:m_matrix' % self.name] = self.becas.m_matrix self.cs_props_m1 = self.becas.cs_props.copy() self.csprops_ref_m1 = self.becas.csprops.copy() self.k_matrix_m1 = self.becas.k_matrix.copy() self.m_matrix_m1 = self.becas.m_matrix.copy() else: self.unknowns['%s:cs_props' % self.name] = self.cs_props_m1 self.unknowns['%s:csprops_ref' % self.name] = self.csprops_ref_m1 self.unknowns['%s:k_matrix' % self.name] = self.k_matrix_m1 self.unknowns['%s:m_matrix' % self.name] = self.m_matrix_m1 print('BECAS crashed for section %f' % self.cs2d['s']) except: self.unknowns['%s:cs_props' % self.name] = self.cs_props_m1 self.unknowns['%s:csprops_ref' % self.name] = self.csprops_ref_m1 self.unknowns['%s:k_matrix' % self.name] = self.k_matrix_m1 self.unknowns['%s:m_matrix' % self.name] = self.m_matrix_m1 print('BECAS crashed for section %f' % self.cs2d['s']) os.chdir(self.basedir) if self.fix_mesh_distribution: self.redistribute_flag = False
def __init__(self, name, becas_hash, config, st3d, s, ni_chord, cs_size, cs_size_ref): """ parameters ---------- config: dict dictionary with inputs to CS2DtoBECAS and BECASWrapper st3d: dict dictionary with blade structural definition s: array spanwise location of the cross-section ni_chord: int number of points definiting the cross-section shape cs_size: int size of blade_beam_structure array (19 or 30) cs_size_ref: int size of blade_beam_csprops_ref array (18) """ super(BECASCSStructure, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash self.nr = len(st3d['regions']) self.ni_chord = ni_chord # add materials properties array ((10, nmat)) self.add_param('matprops', st3d['matprops']) # add materials strength properties array ((18, nmat)) self.add_param('failmat', st3d['failmat']) # add DPs array self.add_param('%s:DPs' % name, np.zeros(self.nr + 1)) # add coords coords self._varnames = [] self.add_param('%s:coords' % name, np.zeros((ni_chord, 3))) self.cs2di = {} self.cs2di['materials'] = st3d['materials'] self.cs2di['matprops'] = st3d['matprops'] self.cs2di['failcrit'] = st3d['failcrit'] self.cs2di['failmat'] = st3d['failmat'] self.cs2di['web_def'] = st3d['web_def'] self.cs2di['s'] = s self.cs2di['DPs'] = np.zeros(self.nr + 1) self.cs2di['regions'] = [] self.cs2di['webs'] = [] for ireg, reg in enumerate(st3d['regions']): r = {} r['layers'] = reg['layers'] nl = len(reg['layers']) r['thicknesses'] = np.zeros(nl) r['angles'] = np.zeros(nl) self.cs2di['regions'].append(r) for i, lname in enumerate(reg['layers']): varname = '%s:r%02d%s' % (name, ireg, lname) self._varnames.append(varname) for ireg, reg in enumerate(st3d['webs']): r = {} r['layers'] = reg['layers'] nl = len(reg['layers']) r['thicknesses'] = np.zeros(nl) r['angles'] = np.zeros(nl) self.cs2di['webs'].append(r) for i, lname in enumerate(reg['layers']): varname = '%s:w%02d%s' % (name, ireg, lname) self._varnames.append(varname) self.add_param(name + ':tvec', np.zeros(len(self._varnames)*2)) # add outputs self.add_output('%s:cs_props' % name, np.zeros(cs_size)) self.add_output('%s:csprops_ref' % name, np.zeros(cs_size_ref)) self.add_output('%s:k_matrix' % name, shape=(6,6)) self.add_output('%s:m_matrix' % name, shape=(6,6)) self.cs_props_m1 = np.zeros(cs_size) self.csprops_ref_m1 = np.zeros(cs_size_ref) self.k_matrix_m1 = np.zeros((6,6)) self.m_matrix_m1 = np.zeros((6,6)) self.add_output('%s:DPcoords' % name, np.zeros((self.nr + 1, 3))) self.workdir = 'becas_%s_%i' % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ':hash', float(self.becas_hash)) self.mesher = CS2DtoBECAS(self.cs2di, **config['CS2DtoBECAS']) self.becas = BECASWrapper(self.cs2di['s'], **config['BECASWrapper'])
class BECASCSStructure(Component): """ Component for computing beam structural properties using the cross-sectional structure code BECAS. The code firstly calls CS2DtoBECAS which is a wrapper around shellexpander that comes with BECAS, and second calls BECAS using a file interface. parameters ---------- config: dict dictionary of model specific inputs coords: array cross-sectional shape. size ((ni_chord, 3)) matprops: array material stiffness properties. Size ((10, nmat)). failmat: array material strength properties. Size ((18, nmat)). DPs: array vector of DPs. Size: (nDP) coords: array blade section coordinates. Size: ((ni_chord, 3)) r<xx><lname>T: float layer thicknesses, e.g. r01triaxT. r<xx><lname>A: float layer angles, e.g. r01triaxA. w<xx><lname>T: float web thicknesses, e.g. r01triaxT. w<xx><lname>A: float web angles, e.g. r01triaxA. returns ------- cs_props: array vector of cross section properties. Size (19) or (30) for standard HAWC2 output or the fully populated stiffness matrix, respectively. csprops_ref: array vector of cross section properties as of BECAS output w.r.t BECAS reference coordinate system. Size (18). """ def __init__(self, name, becas_hash, config, st3d, s, ni_chord, cs_size, cs_size_ref): """ parameters ---------- config: dict dictionary with inputs to CS2DtoBECAS and BECASWrapper st3d: dict dictionary with blade structural definition s: array spanwise location of the cross-section ni_chord: int number of points definiting the cross-section shape cs_size: int size of blade_beam_structure array (19 or 30) cs_size_ref: int size of blade_beam_csprops_ref array (18) """ super(BECASCSStructure, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash self.nr = len(st3d['regions']) self.ni_chord = ni_chord # add materials properties array ((10, nmat)) self.add_param('matprops', st3d['matprops']) # add materials strength properties array ((18, nmat)) self.add_param('failmat', st3d['failmat']) # add DPs array self.add_param('%s:DPs' % name, np.zeros(self.nr + 1)) # add coords coords self._varnames = [] self.add_param('%s:coords' % name, np.zeros((ni_chord, 3))) self.cs2di = {} self.cs2di['materials'] = st3d['materials'] self.cs2di['matprops'] = st3d['matprops'] self.cs2di['failcrit'] = st3d['failcrit'] self.cs2di['failmat'] = st3d['failmat'] self.cs2di['web_def'] = st3d['web_def'] self.cs2di['s'] = s self.cs2di['DPs'] = np.zeros(self.nr + 1) self.cs2di['regions'] = [] self.cs2di['webs'] = [] for ireg, reg in enumerate(st3d['regions']): r = {} r['layers'] = reg['layers'] nl = len(reg['layers']) r['thicknesses'] = np.zeros(nl) r['angles'] = np.zeros(nl) self.cs2di['regions'].append(r) for i, lname in enumerate(reg['layers']): varname = '%s:r%02d%s' % (name, ireg, lname) self._varnames.append(varname) for ireg, reg in enumerate(st3d['webs']): r = {} r['layers'] = reg['layers'] nl = len(reg['layers']) r['thicknesses'] = np.zeros(nl) r['angles'] = np.zeros(nl) self.cs2di['webs'].append(r) for i, lname in enumerate(reg['layers']): varname = '%s:w%02d%s' % (name, ireg, lname) self._varnames.append(varname) self.add_param(name + ':tvec', np.zeros(len(self._varnames)*2)) # add outputs self.add_output('%s:cs_props' % name, np.zeros(cs_size)) self.add_output('%s:csprops_ref' % name, np.zeros(cs_size_ref)) self.add_output('%s:k_matrix' % name, shape=(6,6)) self.add_output('%s:m_matrix' % name, shape=(6,6)) self.cs_props_m1 = np.zeros(cs_size) self.csprops_ref_m1 = np.zeros(cs_size_ref) self.k_matrix_m1 = np.zeros((6,6)) self.m_matrix_m1 = np.zeros((6,6)) self.add_output('%s:DPcoords' % name, np.zeros((self.nr + 1, 3))) self.workdir = 'becas_%s_%i' % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ':hash', float(self.becas_hash)) self.mesher = CS2DtoBECAS(self.cs2di, **config['CS2DtoBECAS']) self.becas = BECASWrapper(self.cs2di['s'], **config['BECASWrapper']) def _params2dict(self, params): """ convert the OpenMDAO params dictionary into the dictionary format used in CS2DtoBECAS. """ tvec = params[self.name+':tvec'] self.cs2d = {} # constants self.cs2d['s'] = self.cs2di['s'] self.cs2d['web_def'] = self.cs2di['web_def'] self.cs2d['failcrit'] = self.cs2di['failcrit'] self.cs2d['materials'] = self.cs2di['materials'] # params self.cs2d['coords'] = params['%s:coords' % self.name][:, :2] self.cs2d['matprops'] = params['matprops'] self.cs2d['failmat'] = params['failmat'] self.cs2d['DPs'] = params['%s:DPs' % self.name] self.cs2d['regions'] = [] self.cs2d['webs'] = [] counter = 0 nvar = len(self._varnames) for ireg, reg in enumerate(self.cs2di['regions']): self.cs2d['regions'].append({}) Ts = [] As = [] layers = [] for i, lname in enumerate(reg['layers']): if tvec[counter] > 0.: Ts.append(tvec[counter]) As.append(tvec[nvar+counter]) layers.append(lname) counter += 1 self.cs2d['regions'][ireg]['thicknesses'] = np.asarray(Ts) self.cs2d['regions'][ireg]['angles'] = np.asarray(As) self.cs2d['regions'][ireg]['layers'] = layers for ireg, reg in enumerate(self.cs2di['webs']): self.cs2d['webs'].append({}) Ts = [] As = [] layers = [] for i, lname in enumerate(reg['layers']): if tvec[counter] > 0.: Ts.append(tvec[counter]) As.append(tvec[nvar+counter]) layers.append(lname) counter += 1 self.cs2d['webs'][ireg]['thicknesses'] = np.asarray(Ts) self.cs2d['webs'][ireg]['angles'] = np.asarray(As) self.cs2d['webs'][ireg]['layers'] = layers def solve_nonlinear(self, params, unknowns, resids): """ calls CS2DtoBECAS/shellexpander to generate mesh and BECAS to compute the cs_props and csprops """ try: os.mkdir(self.workdir) except: pass os.chdir(self.workdir) self._params2dict(params) self.mesher.cs2d = self.cs2d try: self.mesher.compute() self.becas.compute() if self.becas.success: self.unknowns['%s:DPcoords' % self.name][:,0:2] = np.array(self.mesher.DPcoords) self.unknowns['%s:cs_props' % self.name] = self.becas.cs_props self.unknowns['%s:csprops_ref' % self.name] = self.becas.csprops self.unknowns['%s:k_matrix' % self.name] = self.becas.k_matrix self.unknowns['%s:m_matrix' % self.name] = self.becas.m_matrix self.cs_props_m1 = self.becas.cs_props.copy() self.csprops_ref_m1 = self.becas.csprops.copy() self.k_matrix_m1 = self.becas.k_matrix.copy() self.m_matrix_m1 = self.becas.m_matrix.copy() else: self.unknowns['%s:cs_props' % self.name] = self.cs_props_m1 self.unknowns['%s:csprops_ref' % self.name] = self.csprops_ref_m1 self.unknowns['%s:k_matrix' % self.name] = self.k_matrix_m1 self.unknowns['%s:m_matrix' % self.name] = self.m_matrix_m1 print('BECAS crashed for section %f' % self.cs2d['s']) except: self.unknowns['%s:cs_props' % self.name] = self.cs_props_m1 self.unknowns['%s:csprops_ref' % self.name] = self.csprops_ref_m1 self.unknowns['%s:k_matrix' % self.name] = self.k_matrix_m1 self.unknowns['%s:m_matrix' % self.name] = self.m_matrix_m1 print('BECAS crashed for section %f' % self.cs2d['s']) os.chdir(self.basedir)
def __init__(self, name, becas_hash, config, st3d, s, ni_chord, cs_size): """ parameters ---------- config: dict dictionary with inputs to CS2DtoBECAS and BECASWrapper st3d: dict dictionary with blade structural definition s: array spanwise location of the cross-section ni_chord: int number of points definiting the cross-section shape cs_size: int size of blade_beam_structure array (19 or 30) """ super(BECASCSStructure, self).__init__() self.basedir = os.getcwd() self.becas_hash = becas_hash self.nr = len(st3d["regions"]) self.ni_chord = ni_chord # add materials properties array ((10, nmat)) self.add_param("matprops", st3d["matprops"]) # add materials strength properties array ((18, nmat)) self.add_param("failmat", st3d["failmat"]) # add DPs array self.add_param("%s:DPs" % name, np.zeros(self.nr + 1)) # add coords coords self._varnames = [] self.add_param("%s:coords" % name, np.zeros((ni_chord, 3))) self.cs2di = {} self.cs2di["materials"] = st3d["materials"] self.cs2di["matprops"] = st3d["matprops"] self.cs2di["failcrit"] = st3d["failcrit"] self.cs2di["failmat"] = st3d["failmat"] self.cs2di["web_def"] = st3d["web_def"] self.cs2di["s"] = s self.cs2di["DPs"] = np.zeros(self.nr + 1) self.cs2di["regions"] = [] self.cs2di["webs"] = [] for ireg, reg in enumerate(st3d["regions"]): r = {} r["layers"] = reg["layers"] nl = len(reg["layers"]) r["thicknesses"] = np.zeros(nl) r["angles"] = np.zeros(nl) self.cs2di["regions"].append(r) for i, lname in enumerate(reg["layers"]): varname = "%s:r%02d%s" % (name, ireg, lname) self._varnames.append(varname) for ireg, reg in enumerate(st3d["webs"]): r = {} r["layers"] = reg["layers"] nl = len(reg["layers"]) r["thicknesses"] = np.zeros(nl) r["angles"] = np.zeros(nl) self.cs2di["webs"].append(r) for i, lname in enumerate(reg["layers"]): varname = "%s:w%02d%s" % (name, ireg, lname) self._varnames.append(varname) self.add_param(name + ":tvec", np.zeros(len(self._varnames) * 2)) # add outputs self.add_output("%s:cs_props" % name, np.zeros(cs_size)) self.cs_props_m1 = np.zeros(cs_size) self.workdir = "becas_%s_%i" % (name, self.becas_hash) # not so nice hack to ensure unique directory names when # running parallel FD # the hash is passed to downstream BECASStressRecovery class self.add_output(name + ":hash", float(self.becas_hash)) self.mesher = CS2DtoBECAS(self.cs2di, **config["CS2DtoBECAS"]) self.becas = BECASWrapper(self.cs2di["s"], **config["BECASWrapper"])