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)
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
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)