Example #1
0
    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)
Example #3
0
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'
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)
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 __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_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
Example #11
0
    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
Example #12
0
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"])