Example #1
0
    def set_functions(self,scenario,bodies):
        if self.tacs_proc:
            self.funclist = []
            self.functag = []
            for func in scenario.functions:
                if func.analysis_type != 'structural':
                    # use mass as a placeholder for nonstructural functions
                    self.funclist.append(functions.StructuralMass(self.tacs))
                    self.functag.append(0)

                elif func.name.lower() == 'ksfailure':
                    if func.options:
                        ksweight = func.options['ksweight'] if 'ksweight' in func.options else 50.0
                    else:
                        ksweight = 50.0
                    self.funclist.append(functions.KSFailure(self.tacs, ksweight))
                    self.functag.append(1)

                elif func.name.lower() == 'compliance':
                    self.funclist.append(functions.Compliance(self.tacs))
                    self.functag.append(1)

                elif func.name == 'mass':
                    self.funclist.append(functions.StructuralMass(self.tacs))
                    self.functag.append(-1)

                else:
                    print('WARNING: Unknown function being set into TACS set to mass')
                    self.funclist.append(functions.StructuralMass(self.tacs))
                    self.functag.append(-1)
Example #2
0
    def get_coordinate_derivatives(self, scenario, bodies, step):
        """ Evaluate gradients with respect to structural design variables"""

        if self.tacs_proc:
            fXptSens_vec = self.tacs.createNodeVec()

            # get the list of indices for this body
            for ibody, body in enumerate(bodies):
                if body.shape:
                    nodes = self.tacs_flex_bodies[ibody].dist_nodes

                    # TACS does the summation over steps internally, so only get the values when evaluating initial conditions
                    if step == 0:

                        # find the coordinate derivatives for each function
                        for nfunc, func in enumerate(scenario.functions):
                            if func.adjoint:
                                fXptSens_vec = self.integrator[
                                    scenario.id].getXptGradient(nfunc)
                            elif func.name == 'mass':
                                tacsfunc = functions.StructuralMass(self.tacs)
                                self.tacs.evalXptSens(tacsfunc, fXptSens_vec)

                            # pick out the points for this body
                            fxptSens = fXptSens_vec.getArray()
                            for i, n in enumerate(nodes):
                                body.struct_shape_term[3 * i:3 * i + 3,
                                                       nfunc] += fxptSens[3 *
                                                                          n:3 *
                                                                          n +
                                                                          3]

        return
Example #3
0
    def set_functions(self, scenario, bodies):
        if self.tacs_proc:
            self.funclist = []
            self.functag = []
            for func in scenario.functions:
                if func.analysis_type != 'structural':
                    self.funclist.append(None)
                    self.functag.append(0)

                elif func.name.lower() == 'ksfailure':
                    if func.options:
                        ksweight = func.options[
                            'ksweight'] if 'ksweight' in func.options else 50.0
                    else:
                        ksweight = 50.0
                    self.funclist.append(
                        functions.KSFailure(self.assembler, ksWeight=ksweight))
                    self.functag.append(1)

                elif func.name.lower() == 'compliance':
                    self.funclist.append(functions.Compliance(self.assembler))
                    self.functag.append(1)

                elif func.name.lower() == 'temperature':
                    self.funclist.append(
                        functions.AverageTemperature(self.assembler,
                                                     volume=self.vol))
                    self.functag.append(1)

                elif func.name.lower() == 'heatflux':
                    self.funclist.append(functions.HeatFlux(self.assembler))
                    self.functag.append(1)

                elif func.name == 'mass':
                    self.funclist.append(
                        functions.StructuralMass(self.assembler))
                    self.functag.append(-1)

                else:
                    print(
                        'WARNING: Unknown function being set into TACS set to mass'
                    )
                    self.funclist.append(
                        functions.StructuralMass(self.assembler))
                    self.functag.append(-1)

        return
Example #4
0
def create_problem(forest, bcs, props, nlevels):
    """
    Create the TMRTopoProblem object and set up the topology optimization problem.

    This code is given the forest, boundary conditions, material properties and
    the number of multigrid levels. Based on this info, it creates the TMRTopoProblem
    and sets up the mass-constrained compliance minimization problem. Before
    the problem class is returned it is initialized so that it can be used for
    optimization.

    Args:
        forest (OctForest): Forest object
        bcs (BoundaryConditions): Boundary condition object
        props (StiffnessProperties): Material properties object
        nlevels (int): number of multigrid levels

    Returns:
        TopoProblem: Topology optimization problem instance
    """

    # Create the problem and filter object
    obj = CreatorCallback(bcs, props)
    problem = TopOptUtils.createTopoProblem(forest,
        obj.creator_callback, filter_type, nlevels=nlevels)

    # Get the assembler object we just created
    assembler = problem.getAssembler()

    # Set the load
    P = 1.0e3
    force = TopOptUtils.computeVertexLoad('pt1', forest, assembler, [0, P, 0])
    temp = TopOptUtils.computeVertexLoad('pt2', forest, assembler, [0, 0, P])
    force.axpy(1.0, temp)

    # Set the load cases into the topology optimization problem
    problem.setLoadCases([force])

    # Compute the fixed mass target
    lx = 50.0 # mm
    ly = 10.0 # mm
    lz = 10.0 # mm
    vol = lx*ly*lz
    vol_frac = 0.25
    density = 2600.0
    m_fixed = vol_frac*(vol*density)

    # Set the mass constraint
    funcs = [functions.StructuralMass(assembler)]
    problem.addConstraints(0, funcs, [-m_fixed], [-1.0/m_fixed])

    # Set the objective (scale the compliance objective)
    problem.setObjective([1.0e3])

    # Initialize the problem and set the prefix
    problem.initialize()

    return problem
Example #5
0
 def get_functions(self, scenario, bodies):
     if self.tacs_proc:
         feval = self.integrator[scenario.id].evalFunctions(self.funclist)
         for i, func in enumerate(scenario.functions):
             if func.analysis_type == 'structural' and func.adjoint:
                 func.value = feval[i]
             if func.analysis_type == 'structural' and func.name == 'mass':
                 funclist = [functions.StructuralMass(self.tacs)]
                 value = self.tacs.evalFunctions(funclist)
                 func.value = value[0]
     for func in scenario.functions:
         func.value = self.comm.bcast(func.value, root=0)
     return functions
Example #6
0
    def eval_gradients(self, scenario):
        """ Evaluate gradients with respect to structural design variables"""
        if self.tacs_proc:
            self.func_grad = []

            for func in range(len(self.funclist)):
                dfdx = self.integrator[scenario.id].getGradient(func, )
                dfdx_arr = dfdx.getArray()
                self.func_grad.append(dfdx_arr.copy())
                #self.func_grad.append(dfdx_arr[func*self.ndvs:(func+1)*self.ndvs].copy())

            for func in scenario.functions:
                if func.analysis_type == 'structural' and func.name == 'mass':
                    funclist = [functions.StructuralMass(self.assembler)]
                    dvsens = np.zeros(self.num_components)
                    self.assembler.addDVSens([funclist[0]], [dvsens])
                    self.func_grad.append(dvsens.copy())

        return
Example #7
0
    def __init__(self, tacs, f5):
        # Set the communicator pointer
        self.comm = MPI.COMM_WORLD

        self.rank = self.comm.Get_rank()
        self.size = self.comm.Get_size()
        self.nvars = num_components / self.size
        if num_components % self.size != 0 and self.rank == self.size - 1:
            self.nvars += num_components % self.size
        self.ncon = 1

        # Initialize the base class
        super(CRMSizing, self).__init__(self.comm, self.nvars, self.ncon)

        self.tacs = tacs
        self.f5 = f5
        self.res = self.tacs.createVec()
        self.ans = self.tacs.createVec()
        self.mat = self.tacs.createFEMat()
        self.pc = TACS.Pc(self.mat)

        # Create list of required TACS functions (mass, ksfailure)
        self.mass = functions.StructuralMass(self.tacs)
        ksweight = 50.0
        alpha = 1.0
        self.ksfailure = functions.KSFailure(self.tacs, ksweight, alpha)
        self.ksfailure.setLoadFactor(1.5)
        self.funclist = [self.mass, self.ksfailure]

        self.svsens = self.tacs.createVec()
        self.adj = self.tacs.createVec()

        self.adjSensProdArray = np.zeros(num_components)
        self.tempdvsens = np.zeros(num_components)

        # Get initial mass for scaling
        self.initmass = self.tacs.evalFunctions([self.funclist[0]])
        self.xscale = 0.0025

        # Keep track of the number of gradient evaluations
        self.gevals = 0

        return
Example #8
0
    def eval_gradients(self, scenario):
        """ Evaluate gradients with respect to structural design variables"""
        if self.tacs_proc:
            dfdx = np.zeros(len(self.funclist) * self.ndvs, dtype=TACS.dtype)
            self.integrator[scenario.id].getGradient(dfdx)

            self.func_grad = []
            for func in range(len(self.funclist)):
                self.func_grad.append(dfdx[func * self.ndvs:(func + 1) *
                                           self.ndvs].copy())

            for func in scenario.functions:
                if func.analysis_type == 'structural' and func.name == 'mass':
                    funclist = [functions.StructuralMass(self.tacs)]
                    dvsens = np.zeros(self.num_components)
                    self.tacs.evalDVSens(funclist[0], dvsens)

                    self.func_grad.append(dvsens.copy())

        return
Example #9
0
    def setAssembler(self, assembler, ksfunc):

        # Create tacs assembler object from mesh loader
        self.assembler = assembler

        # Create the list of functions
        self.funcs = [functions.StructuralMass(self.assembler), ksfunc]

        # Set up the solver
        self.ans = self.assembler.createVec()
        self.res = self.assembler.createVec()
        self.adjoint = self.assembler.createVec()
        self.dfdu = self.assembler.createVec()

        self.mat = self.assembler.createFEMat()
        self.pc = TACS.Pc(self.mat)
        self.gmres = TACS.KSM(self.mat, self.pc, 10)

        # For visualization
        flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS
                | TACS.ToFH5.STRAINS | TACS.ToFH5.EXTRAS)
        self.f5 = TACS.ToFH5(self.assembler, TACS.PY_PLANE_STRESS, flag)

        return
Example #10
0
    def __init__(self, comm, bdf_name):
        self.comm = comm
        struct_mesh = TACS.MeshLoader(self.comm)
        struct_mesh.scanBDFFile(bdf_name)

        # Set constitutive properties
        rho = 2500.0  # density, kg/m^3
        E = 70e9  # elastic modulus, Pa
        nu = 0.3  # poisson's ratio
        kcorr = 5.0 / 6.0  # shear correction factor
        ys = 350e6  # yield stress, Pa
        min_thickness = 0.002
        max_thickness = 0.20
        thickness = 0.02

        # Loop over components, creating stiffness and element object for each
        num_components = struct_mesh.getNumComponents()
        for i in range(num_components):
            descriptor = struct_mesh.getElementDescript(i)

            # Set the design variable index
            design_variable_index = i
            stiff = constitutive.isoFSDT(rho, E, nu, kcorr, ys, thickness,
                                         design_variable_index, min_thickness,
                                         max_thickness)
            element = None

            # Create the element object
            if descriptor in ["CQUAD", "CQUADR", "CQUAD4"]:
                element = elements.MITCShell(2, stiff, component_num=i)
            struct_mesh.setElement(i, element)

        # Create tacs assembler object from mesh loader
        self.assembler = struct_mesh.createTACS(6)

        # Create the KS Function
        ksWeight = 50.0
        self.funcs = [
            functions.StructuralMass(self.assembler),
            functions.KSFailure(self.assembler, ksWeight)
        ]

        # Create the forces
        self.forces = self.assembler.createVec()
        force_array = self.forces.getArray()
        force_array[2::6] += 100.0  # uniform load in z direction
        self.assembler.applyBCs(self.forces)

        # Set up the solver
        self.ans = self.assembler.createVec()
        self.res = self.assembler.createVec()
        self.adjoint = self.assembler.createVec()
        self.dfdu = self.assembler.createVec()
        self.mat = self.assembler.createFEMat()
        self.pc = TACS.Pc(self.mat)
        subspace = 100
        restarts = 2
        self.gmres = TACS.KSM(self.mat, self.pc, subspace, restarts)

        # Scale the mass objective so that it is O(10)
        self.mass_scale = 1e-3

        # Scale the thickness variables so that they are measured in
        # mm rather than meters
        self.thickness_scale = 1000.0

        # The number of thickness variables in the problem
        self.nvars = num_components

        # The number of constraints (1 global stress constraint that
        # will use the KS function)
        self.ncon = 1

        # Initialize the base class - this will run the same problem
        # on all processors
        super(uCRM_VonMisesMassMin, self).__init__(MPI.COMM_SELF, self.nvars,
                                                   self.ncon)

        # Set the inequality options for this problem in ParOpt:
        # The dense constraints are inequalities c(x) >= 0 and
        # use both the upper/lower bounds
        self.setInequalityOptions(dense_ineq=True,
                                  use_lower=True,
                                  use_upper=True)

        # For visualization
        flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS
                | TACS.ToFH5.STRAINS | TACS.ToFH5.EXTRAS)
        self.f5 = TACS.ToFH5(self.assembler, TACS.PY_SHELL, flag)
        self.iter_count = 0

        return
Example #11
0
obj_array = [1.0e2]

for ite in range(max_iterations):
    # Create the TACSAssembler and TMRTopoProblem instance
    nlevs = mg_levels[ite]
    assembler, problem, filtr, varmap = createTopoProblem(forest,
                                                          nlevels=nlevs)

    # Write out just the mesh - for visualization
    flag = (TACS.ToFH5.NODES)

    f5 = TACS.ToFH5(assembler, TACS.PY_PLANE_STRESS, flag)
    f5.writeToFile(os.path.join(args.prefix, 'plate_mesh%d.f5' % (ite)))

    # Set the constraint type
    funcs = [functions.StructuralMass(assembler)]
    # Add the point loads to the vertices
    force1 = addVertexLoad(comm, order, forest, 'pt1', assembler,
                           [0.0, -1000.])

    force1.scale(-1.0)
    # Set the load cases
    forces = [force1]
    problem.setLoadCases(forces)

    # Set the mass constraint
    problem.addConstraints(0, funcs, [-m_fixed], [-1.0 / m_fixed])
    problem.setObjective(obj_array)

    # Initialize the problem and set the prefix
    problem.initialize()
Example #12
0
def create_problem(forest, bcs, props, nlevels):
    """
    Create the TMRTopoProblem object and set up the topology optimization problem.

    This code is given the forest, boundary conditions, material properties and
    the number of multigrid levels. Based on this info, it creates the TMRTopoProblem
    and sets up the mass-constrained compliance minimization problem. Before
    the problem class is returned it is initialized so that it can be used for
    optimization.

    Args:
        forest (OctForest): Forest object
        bcs (BoundaryConditions): Boundary condition object
        props (StiffnessProperties): Material properties object
        nlevels (int): number of multigrid levels

    Returns:
        TopoProblem: Topology optimization problem instance
    """
    # Allocate the creator callback function
    obj = CreatorCallback(bcs, props)

    # Create a conforming filter
    filter_type = 'conform'

    # Create the problem and filter object
    problem = TopOptUtils.createTopoProblem(forest,
        obj.creator_callback, filter_type, nlevels=nlevels, lowest_order=3,
        design_vars_per_node=design_vars_per_node)

    # Get the assembler object we just created
    assembler = problem.getAssembler()

    # Set the constraint type
    funcs = [functions.StructuralMass(assembler)]

    # Create the traction objects that will be used later..
    T = 2.5e6
    tx = np.zeros(args.order)
    ty = T*np.ones(args.order)

    thermal_tractions = []
    for findex in range(4):
        thermal_tractions.append(elements.PSThermoQuadTraction(findex, tx, ty))

    # Allocate a thermal traction boundary condition
    force1 = TopOptUtils.computeTractionLoad('traction', forest, assembler,
        thermal_tractions)

    # Set the load cases
    problem.setLoadCases([force1])

    # Set the mass constraint
    # (m_fixed - m(x))/m_fixed >= 0.0
    problem.addConstraints(0, funcs, [-m_fixed], [-1.0/m_fixed])
    problem.setObjective(obj_array, [functions.Compliance(assembler)])

    # Initialize the problem and set the prefix
    problem.initialize()

    # Set the output file name
    flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.EXTRAS)
    problem.setF5OutputFlags(5, TACS.PY_PLANE_STRESS, flag)

    return problem
Example #13
0
    descriptor  = mesh.getElementDescript(i)
    stiff       = constitutive.isoFSDT(rho, E, nu, kcorr, ys, thickness,
                                      i, min_thickness, max_thickness)
    element     = None
    if descriptor in ["CQUAD"]:
        element = elements.MITC(stiff, gravity, v0, w0)        
        mesh.setElement(i, element)

tacs = mesh.createTACS(8)

#---------------------------------------------------------------------!
# Create the function list for adjoint solve
#---------------------------------------------------------------------!

funcs = []
funcs.append(functions.StructuralMass(tacs))
funcs.append(functions.Compliance(tacs))
funcs.append(functions.InducedFailure(tacs, 20.0))
funcs.append(functions.KSFailure(tacs, 100.0))


#---------------------------------------------------------------------#
# Setup space for function values and their gradients
#---------------------------------------------------------------------#

num_funcs       = len(funcs)
num_design_vars = len(x)

fvals           = np.zeros(num_funcs)
dfdx            = np.zeros(num_funcs*num_design_vars)
Example #14
0
order = 2
bdf = TACS.BDFIntegrator(assembler, t0, tf, num_steps, order)
bdf.setPrintLevel(0) # turn off printing

# Integrate governing equations
bdf.iterate(0)
for step in range(1,num_steps+1):
    bdf.iterate(step)
_, uvec, _, _ = bdf.getStates(num_steps)
u = uvec.getArray().copy()
bdf.writeRawSolution('spring.dat', 0)

# Specify the number of design variables and the function to the integrator
# (use Structural Mass as a dummy function)
num_dvs = 1
funclist = [functions.StructuralMass(assembler)]
bdf.setFunctions(funclist, num_dvs)

# Solve the adjoint equations and compute the gradient
dfdu_vec = assembler.createVec()
for step in range(num_steps, -1, -1):
    bdf.initAdjoint(step)
    dfdu = dfdu_vec.getArray()
    if step == num_steps:
        dfdu[0] = -1.0
    else:
        dfdu[0] = 0.0
    bdf.iterateAdjoint(step, [dfdu_vec])
    bdf.postAdjoint(step)

dfdx = np.array([0.0], dtype=TACS.dtype)
Example #15
0
    def __init__(self,
                 comm,
                 props,
                 tacs,
                 const,
                 num_materials,
                 xpts=None,
                 conn=None,
                 m_fixed=1.0,
                 min_mat_fraction=-1.0):
        '''
        Analysis problem
        '''

        # Keep the communicator
        self.comm = comm

        # Set the TACS object and the constitutive list
        self.props = props
        self.tacs = tacs
        self.const = const

        # Set the material information
        self.num_materials = num_materials
        self.num_elements = self.tacs.getNumElements()

        # Keep the pointer to the connectivity/positions
        self.xpts = xpts
        self.conn = conn

        # Set the target fixed mass
        self.m_fixed = m_fixed

        # Set a fixed material fraction
        self.min_mat_fraction = min_mat_fraction

        # Set the number of constraints
        self.ncon = 1
        if self.min_mat_fraction > 0.0:
            self.ncon += self.num_materials

        # Set the number of design variables
        nwblock = 1
        self.num_design_vars = (self.num_materials + 1) * self.num_elements

        # Initialize the super class
        super(TACSAnalysis,
              self).__init__(comm, self.num_design_vars, self.ncon,
                             self.num_elements, nwblock)

        # Set the size of the design variable 'blocks'
        self.nblock = self.num_materials + 1

        # Create the state variable vectors
        self.res = tacs.createVec()
        self.u = tacs.createVec()
        self.psi = tacs.createVec()
        self.mat = tacs.createFEMat()

        # Create the preconditioner for the corresponding matrix
        self.pc = TACS.Pc(self.mat)

        # Create the KSM object
        subspace_size = 20
        nrestart = 0
        self.ksm = TACS.KSM(self.mat, self.pc, subspace_size, nrestart)
        self.ksm.setTolerances(1e-12, 1e-30)

        # Set the block size
        self.nwblock = self.num_materials + 1

        # Allocate a vector that stores the gradient of the mass
        self.gmass = np.zeros(self.num_design_vars)

        # Create the mass function and evaluate the gradient of the
        # mass. This is assumed to remain constatnt throughout the
        # optimization.
        self.mass_func = functions.StructuralMass(self.tacs)
        self.tacs.evalDVSens(self.mass_func, self.gmass)

        # Set the initial variable values
        self.xinit = np.ones(self.num_design_vars)

        # Set the initial design variable values
        xi = self.m_fixed / np.dot(self.gmass, self.xinit)
        self.xinit[:] = xi

        # Set the penalization
        tval = xi * self.num_materials
        self.xinit[::self.nblock] = tval

        # Create a temporary vector for the hessian-vector products
        self.hvec_tmp = np.zeros(self.xinit.shape)

        # Set the initial linearization/point
        self.RAMP_penalty = 0.0
        self.setNewInitPointPenalty(self.xinit)

        # Set the number of function/gradient/hessian-vector
        # evaluations to zero
        self.fevals = 0
        self.gevals = 0
        self.hevals = 0

        # Evaluate the objective at the initial point
        self.obj_scale = 1.0
        fail, obj, con = self.evalObjCon(self.xinit)
        self.obj_scale = obj_scale_factor * obj

        print('objective scaling = ', self.obj_scale)

        # Create the FH5 file object
        flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS
                | TACS.ToFH5.STRAINS)
        self.f5 = TACS.ToFH5(self.tacs, TACS.PY_PLANE_STRESS, flag)

        return
Example #16
0
def create_problem(forest, bcs, props, nlevels):
    """
    Create a TopoProblem instance for mass and frequency constrained compliance
    minimization.

    This problem takes in a forest at the current refinement level, boundary
    condition information storing the names of the geometric entities to apply
    Dirichlet boundary conditions, the material properties and the number of
    multigrid levels.

    Args:
        forest (OctForest): Forest object
        bcs (BoundaryConditions): Boundary condition object
        props (StiffnessProperties): Material properties object
        nlevels (int): number of multigrid levels

    Returns:
        TopoProblem: Topology optimization problem instance
    """

    # Allocate the creator callback function
    obj = CreatorCallback(bcs, props)

    # Define the filter type
    filter_type = 'conform'

    # Create the problem and filter objects
    problem = TopOptUtils.createTopoProblem(forest, obj.creator_callback,
        filter_type, nlevels=nlevels, lowest_order=2)

    # Get the assembler object we just created
    assembler = problem.getAssembler()

    # Set the load
    P = 1.0e3
    force = TopOptUtils.computeVertexLoad('pt1', forest, assembler, [0, P, 0])
    temp = TopOptUtils.computeVertexLoad('pt2', forest, assembler, [0, 0, P])
    force.axpy(1.0, temp)

    problem.setLoadCases([force])

    # Compute the fixed mass target
    lx = 50.0 # mm
    ly = 10.0 # mm
    lz = 10.0 # mm
    vol = lx*ly*lz
    vol_frac = 0.25
    density = 2600.0
    m_fixed = vol_frac*(vol*density)

    # Add the fixed mass constraint
    # (m_fixed - m(x))/m_fixed >= 0.0
    funcs = [functions.StructuralMass(assembler)]
    problem.addConstraints(0, funcs, [-m_fixed], [-1.0/m_fixed])

    # Add the natural frequency constraint
    omega_min = (0.5/np.pi)*(2e4)**0.5
    freq_opts = {'use_jd':args.use_jd, 'num_eigs':args.num_eigs,
                 'num_recycle':args.num_recycle, 'track_eigen_iters':nlevels}
    TopOptUtils.addNaturalFrequencyConstraint(problem, omega_min, **freq_opts)

    # Set the compliance objective
    problem.setObjective(obj_array)

    # Initialize the problem and set the prefix
    problem.initialize()

    return problem