def optimize(inputfile, mode=None):
    # ---------- SETUP ----------

    # handle input of data
    with open(inputfile) as datafile:
        data = json.load(datafile)

    geometry = data["geometry"]
    U, V, cpoints, weights, plotrange = gm.nurbs(geometry["shape"],
                                                 geometry["params"])
    tdrefine, sdrefine = geometry["refine"]
    optparams = data["optimization"]
    tarefine, sarefine = optparams["refine"]

    # assume open knot vectors
    p = np.count_nonzero(U == U[0]) - 1
    q = np.count_nonzero(V == V[0]) - 1

    # apply refinement
    projcpoints = np.dstack((cpoints * np.atleast_3d(weights), weights))
    projcpoints, Ud, Vd = al.refine(projcpoints, p, q, U, V, tdrefine,
                                    sdrefine)
    designweights = projcpoints[:, :, -1]
    projcpoints, U, V = al.refine(projcpoints, p, q, Ud, Vd, tarefine,
                                  sarefine)
    cpoints = projcpoints[..., :-1] / projcpoints[..., -1:]
    weights = projcpoints[:, :, -1]

    # geometric properties
    n = U.size - p - 1
    m = V.size - q - 1
    nd = Ud.size - p - 1
    md = Vd.size - q - 1
    nel0 = len(set(U)) - 1
    nel1 = len(set(V)) - 1

    # build localization tools
    C0 = al.bezier_extract(U, p, n)
    C1 = al.bezier_extract(V, q, m)
    Cd0 = al.bezier_extract(Ud, p, nd)
    Cd1 = al.bezier_extract(Vd, q, md)
    INN, IEN = al.build_inc_ien(U, V, p, q, n, m)
    INNd, IENd = al.build_inc_ien(Ud, Vd, p, q, nd, md)

    # handle loading situation
    load = data["load"]
    free, t = gm.load(cpoints, nel0, nel1, load["type"], load["params"])
    ndofs, ID = al.build_id(INN, free)

    # convenience arrays
    IEN0 = INN[IEN][..., 0]
    IEN1 = INN[IEN][..., 1]
    IENd0 = INNd[IENd][..., 0]
    IENd1 = INNd[IENd][..., 1]
    IDE = ID[IEN]

    # determine integration points and weights (map from [-1, 1] to [0, 1])
    intpoints0, intweights0 = np.polynomial.legendre.leggauss(p + 1)
    intpoints1, intweights1 = np.polynomial.legendre.leggauss(q + 1)
    intpoints0 = (intpoints0 + 1.) / 2.
    intpoints1 = (intpoints1 + 1.) / 2.
    intweights0 /= 2
    intweights1 /= 2
    intweights = np.reshape(np.einsum("j, i", intweights0, intweights1), -1)

    # obtain shape arrays
    P = cpoints[IEN1, IEN0, :]
    W = weights[IEN1, IEN0, np.newaxis]
    R, Rb, dRdX, J, Jb = ro.shape(p, q, C0, C1, nel0, P, W, intpoints0,
                                  intpoints1)

    # define a way to calculate the normalized volume in use
    domainvolume = np.einsum("i, ji ->", intweights, J)

    def volume(rho):
        return np.einsum("i, jk, jki, ji", intweights, rho, R,
                         J) / domainvolume

    # set up force vector for analysis
    '''wJ0 = np.einsum("j, ij -> ij", intweights0, J0)
    wJ1 = np.einsum("j, ij -> ij", intweights1, J1)
    wR0 = np.einsum("ijk, ik -> ij", R0, wJ0)
    wR1 = np.einsum("ijk, ik -> ij", R1, wJ1)'''
    f = ro.force(n, m, IDE, IEN0, IEN1, intweights0, intweights1, ndofs, Rb,
                 Jb, t, load["force"])

    # calculate the "B matrices"
    B = ro.computeB(R, dRdX)

    # compute the "ground D matrix", assuming plain stress
    material = data["material"]
    E = material["E"]
    nu = material["nu"]
    Dhat = E / (1 - nu * nu) * np.array([[1, nu, 0], [nu, 1, 0],
                                         [0, 0, (1 - nu) / 2.]])

    # calculate the "ground" stiffness matrices
    Khat = np.einsum("ijmk, mn, ijnl-> ijkl", B, Dhat, B)

    # determine design/analysis conversion array and design basis
    darr = ro.designarray(nel0, nel1, tarefine, sarefine)
    Wd = designweights[IENd1, IENd0, np.newaxis]
    Rd = ro.designbasis(p, q, nel0, nel1, Cd0, Cd1, Wd, intpoints0, intpoints1,
                        tarefine, sarefine, darr)

    # set up a starting density
    if optparams["startdens"]:
        rhod = pickle.load(open(optparams["startdens"], "rb"))
    else:
        rhod = np.full(P.shape[:-1], optparams["volfrac"])

    # compute A matrix for gradient determination
    A = ro.projectionmatrix(nd, md, IENd, intweights, Rd, J, darr)

    # prepare x and y arrays for plotting
    plot = data["plot"]
    plotpoints = np.linspace(0, 1 - 1E-6, plot["npoints"])
    Rdummy, X, Y = ro.plotprepare(p, q, nel0, nel1, C0, C1, P, W, plotpoints)

    # retrieve filenames
    plotfile, densfile, histfile = ro.filenames(optparams["filepath"],
                                                optparams["filename"],
                                                plot["extension"])

    # ---------- OPTIONAL DOMAIN PLOT ----------
    if "domain" in optparams:
        ai.plotdomain(p, q, nel0, nel1, C0, C1, P, W, plotpoints,
                      plot["width"], plotrange, plotfile)
        sys.exit()

    # ---------- OPTIMIZATION ----------

    iteration = 0
    compliances = []
    fullit = (optparams["pmax"] - 1) / optparams["pperit"]
    starttime = datetime.datetime.now()

    rhovals = np.einsum("il, ilj -> ij", rhod, Rd)
    gd = np.empty_like(rhod)
    alpha = None

    while True:
        # compute and assemble stiffness matrix
        simpfac = min(1 + optparams["pperit"] * iteration, optparams["pmax"])
        simpmargin = 1E-6
        prho = (1 - simpmargin) * rhovals**simpfac + simpmargin
        stiffdata = np.einsum("l, il, iljk, il -> ijk", intweights, prho, Khat,
                              J)
        K = ro.stiffness(IEN, IDE, ndofs, stiffdata)

        # solve for displacement (ensuring symmetry for efficiency)
        K = (K + K.transpose()) / 2.
        umat = sl.spsolve(K, f)
        u = umat[IDE]
        u[IDE == -1] = 0

        # determine compliance and matrix/vector for gradient computation
        #eps = np.einsum("ijkl, il -> ijk", B, np.reshape(u, (IEN.shape[0], -1)))
        prhodiff = (1 - simpmargin) * simpfac * rhovals**(simpfac - 1)
        compliance, b = ro.projectionvector(nd, md, IENd, intweights, Rd, J,
                                            Khat, prho, prhodiff, u, darr)
        compliances.append(compliance)
        # alternatively, K could be used to determine compliance

        # solve for gradient
        A = (A + A.transpose()) / 2.
        gdmat = sl.spsolve(A, b)
        gd[darr, ...] = gdmat[IENd][:, np.newaxis, :]

        # update density
        if not alpha:
            # step size
            change_ratio = 1
            #alpha = np.abs(rho.mean() / g.mean() * change_ratio)
            alpha = np.abs(
                np.linalg.norm(rhod) / np.linalg.norm(gd) * change_ratio)
        rhod, rhodold = ro.update(volume, optparams["volfrac"], rhod, gd,
                                  alpha)
        rhovals = np.einsum("il, ilj -> ij", rhod, Rd)

        # temp
        print datetime.datetime.now().strftime(
            "%H:%M:%S"), iteration, compliance

        # provide stop conditions
        if iteration >= optparams["maxit"] - 1:
            break
        if iteration >= fullit + 30:
            if np.max(np.absolute(rhod - rhodold)) <= 1E-3:
                break
            #if np.average(compliances[-10:]) >= np.average(compliances[-30:]):
            #    break

        iteration += 1

    # temp
    totaltime = datetime.datetime.now() - starttime
    print "done in {} seconds".format(totaltime.total_seconds())

    # back up density, write compliance history
    pickle.dump(rhod, open(densfile, "wb"))
    pickle.dump(
        {
            "compliances": compliances,
            "n_it": iteration,
            "time": totaltime
        }, open(histfile, "wb"))

    # calculate basis functions for plotting
    Rp = ro.designbasis(p, q, nel0, nel1, Cd0, Cd1, Wd, plotpoints, plotpoints,
                        tarefine, sarefine, darr)

    # ---------- OPTIONAL GRADIENT PLOT ----------
    #     use only after first iteration
    if "airy" in optparams:
        graddata = np.reshape(np.einsum("il, ilj -> ij", gd, Rp),
                              (-1, plot["npoints"], plot["npoints"]))
        effE = E * (optparams["volfrac"]**2)
        airydata = ai.airystress(X, Y - 0.5, load["force"][3], 0.5, 1, effE,
                                 nu)
        ai.gradplot(X, Y, nel0, nel1, graddata, airydata, plotpoints,
                    plot["width"], plotrange, plotfile)
        sys.exit()

    # plot density
    densdata = np.reshape(np.einsum("il, ilj -> ij", rhod, Rp),
                          (-1, plot["npoints"], plot["npoints"]))
    ro.plot(X, Y, nel0, nel1, densdata, plotpoints, plot["width"], plotrange,
            plotfile)
Пример #2
0
def optimize(inputfile):
    # ---------- SETUP ----------

    # handle input of data
    with open(inputfile) as datafile:
        data = json.load(datafile)

    geometry = data["geometry"]
    U, V, cpoints, weights, plotrange = gm.nurbs(geometry["shape"],
                                                 geometry["params"])
    tdrefine, sdrefine = geometry["refine"]
    optparams = data["optimization"]
    tarefine, sarefine = optparams["refine"]

    # assume open knot vectors
    p = np.count_nonzero(U == U[0]) - 1
    q = np.count_nonzero(V == V[0]) - 1

    # apply refinement
    projcpoints = np.dstack((cpoints * np.atleast_3d(weights), weights))
    projcpoints, U, V = al.refine(projcpoints, p, q, U, V, tdrefine, sdrefine)
    neld0 = len(set(U)) - 1
    neld1 = len(set(V)) - 1
    projcpoints, U, V = al.refine(projcpoints, p, q, U, V, tarefine, sarefine)
    cpoints = projcpoints[..., :-1] / projcpoints[..., -1:]
    weights = projcpoints[:, :, -1]

    # geometric properties
    n = U.size - p - 1
    m = V.size - q - 1
    nel0 = len(set(U)) - 1
    nel1 = len(set(V)) - 1

    # build localization tools
    C0 = al.bezier_extract(U, p, n)
    C1 = al.bezier_extract(V, q, m)
    INN, IEN = al.build_inc_ien(U, V, p, q, n, m)

    # handle loading situation
    load = data["load"]
    free, t = gm.load(cpoints, nel0, nel1, load["type"], load["params"])
    ndofs, ID = al.build_id(INN, free)

    # convenience arrays
    IEN0 = INN[IEN][..., 0]
    IEN1 = INN[IEN][..., 1]
    IDE = ID[IEN]

    # determine integration points and weights (map from [-1, 1] to [0, 1])
    intpoints0, intweights0 = np.polynomial.legendre.leggauss(p + 1)
    intpoints1, intweights1 = np.polynomial.legendre.leggauss(q + 1)
    intpoints0 = (intpoints0 + 1.) / 2.
    intpoints1 = (intpoints1 + 1.) / 2.
    intweights0 /= 2
    intweights1 /= 2
    intweights = np.reshape(np.einsum("j, i", intweights0, intweights1), -1)

    # obtain shape arrays
    P = cpoints[IEN1, IEN0, :]
    W = weights[IEN1, IEN0, np.newaxis]
    R, Rb, dRdX, J, Jb = ro.shape(p, q, C0, C1, nel0, P, W, intpoints0,
                                  intpoints1)
    # it would be more efficient to work with a Rd for plotting as well

    # set up force vector for analysis
    f = ro.force(n, m, IDE, IEN0, IEN1, intweights0, intweights1, ndofs, Rb,
                 Jb, t, load["force"])

    # calculate the "B matrices"
    B = ro.computeB(R, dRdX)

    # compute the "ground D matrix", assuming plain stress
    material = data["material"]
    E = material["E"]
    nu = material["nu"]
    Dhat = E / (1 - nu * nu) * np.array([[1, nu, 0], [nu, 1, 0],
                                         [0, 0, (1 - nu) / 2.]])

    # calculate the "ground" stiffness matrices
    Khat = np.einsum("l, ilmj, mn, ilnk, il -> ijk", intweights, B, Dhat, B, J)

    # set up design/analysis conversion array and starting density
    darr = ro.designarray(nel0, nel1, tarefine, sarefine)
    if optparams["startdens"]:
        rhod = pickle.load(open(optparams["startdens"], "rb"))
    else:
        rhod = np.full(neld0 * neld1, optparams["volfrac"])

    # define a way to calculate the normalized volume in use
    elementvolume = np.einsum("j, ij -> i", intweights, J)
    elementvolume = np.sum(elementvolume[darr], axis=1)
    elementvolume /= np.sum(elementvolume)

    def volume(rhod):
        return np.einsum("i, i", rhod, elementvolume)

    # prepare x and y arrays for plotting
    plot = data["plot"]
    plotpoints = np.linspace(0, 1 - 1E-6, plot["npoints"])
    Rp, X, Y = ro.plotprepare(p, q, nel0, nel1, C0, C1, P, W, plotpoints)

    # define filter method
    if optparams["rmin"]:
        H, Hs = al.density_filter(neld0, neld1, optparams["rmin"])

        def densfilter(x):
            return H.dot(x / Hs)
    else:

        def densfilter(x):
            return x

    # retrieve filenames
    plotfile, densfile, histfile = ro.filenames(optparams["filepath"],
                                                optparams["filename"],
                                                plot["extension"])

    # ---------- OPTIONAL DOMAIN PLOT ----------
    if "domain" in optparams:
        ai.plotdomain(p, q, nel0, nel1, C0, C1, P, W, plotpoints,
                      plot["width"], plotrange, plotfile)
        sys.exit()

    # ---------- OPTIMIZATION ----------

    iteration = 0
    compliances = []
    fullit = (optparams["pmax"] - 1) / optparams["pperit"]
    starttime = datetime.datetime.now()

    rho = np.zeros(P.shape[0])
    rho[darr] = rhod[:, np.newaxis]
    alpha = None

    while True:
        # compute and assemble stiffness matrix
        simpfac = min(1 + optparams["pperit"] * iteration, optparams["pmax"])
        simpmargin = 1E-6
        prho = (1 - simpmargin) * rho**simpfac + simpmargin
        stiffdata = np.einsum("i, ijk -> ijk", prho, Khat)
        K = ro.stiffness(IEN, IDE, ndofs, stiffdata)

        # solve for displacement (ensuring symmetry for efficiency)
        K = (K + K.transpose()) / 2.
        umat = sl.spsolve(K, f)
        u = umat[IDE]
        u[IDE == -1] = 0

        # determine compliance and gradient
        #eps = np.einsum("ijkl, il -> ijk", B, np.reshape(u, (IEN.shape[0], -1)))
        prhodiff = (1 - simpmargin) * simpfac * rho**(simpfac - 1)
        u1d = np.reshape(u, (IEN.shape[0], -1))
        Chat = np.einsum("ij, ijk, ik -> i", u1d, Khat, u1d)
        compliance = np.einsum("i, i", prho, Chat)
        compliances.append(compliance)
        # alternatively, K could be used to determine compliance
        g = -prhodiff * Chat

        # sum up gradients per "design element" and adjust original values accordingly
        gd = densfilter(np.sum(g[darr], axis=1))
        """if iteration > 20:
            densdata = np.reshape(np.einsum("il, ilj -> ij", g, Rp), (-1, 10, 10))
            densdata[np.abs(densdata) < 1E-3*np.abs(densdata).mean()] = 0
            densdata = np.clip(densdata, 0, 3*densdata.mean())
            ro.plot(X, Y, p, q, nel0, nel1, densdata)"""

        #g[np.abs(g) < 1E-3 * np.abs(g).mean()] = 0

        # update density
        if not alpha:
            # step size
            change_ratio = 0.1
            #alpha = np.abs(rho.mean() / g.mean() * change_ratio)
            alpha = np.abs(
                np.linalg.norm(rhod) / np.linalg.norm(gd) * change_ratio)
        rhod, rhodold = ro.update(volume, optparams["volfrac"], rhod, gd,
                                  alpha, densfilter)
        rho[darr] = rhod[:, np.newaxis]

        # temp
        print datetime.datetime.now().strftime(
            "%H:%M:%S"), iteration, compliance

        # provide stop conditions
        if iteration >= optparams["maxit"] - 1:
            break
        if iteration >= fullit + 30:
            if np.max(np.absolute(rhod - rhodold)) <= 1E-3:
                break
            #if np.average(compliances[-10:]) >= np.average(compliances[-30:]):
            #    break

        iteration += 1

    # temp
    totaltime = datetime.datetime.now() - starttime
    print "done in {} seconds".format(totaltime.total_seconds())

    # back up element density, write compliance history
    pickle.dump(rhod, open(densfile, "wb"))
    pickle.dump(
        {
            "compliances": compliances,
            "n_it": iteration,
            "time": totaltime
        }, open(histfile, "wb"))

    # ---------- OPTIONAL GRADIENT PLOT ----------
    #     use only after first iteration
    if "airy" in optparams:
        g[darr] = gd
        graddata = np.tile(g[:, np.newaxis, np.newaxis],
                           (1, plot["npoints"], plot["npoints"]))
        XA, XB, YA, YB = ai.elementlimits(
            nel0, nel1, 1. * geometry["params"]["aspectratio"] / nel0,
            1. / nel1)
        effE = E * (optparams["volfrac"]**2)
        airydata = ai.airystressint(XA, XB, YA - 0.5, YB - 0.5,
                                    load["force"][3], 0.5, 1, effE, nu)
        airydata = np.tile(airydata[:, np.newaxis, np.newaxis],
                           (1, plot["npoints"], plot["npoints"]))
        ai.elgradplot(X, Y, nel0, nel1, graddata, airydata, plotpoints,
                      plot["width"], plotrange, plotfile)
        sys.exit()

    # plot density
    densdata = np.tile(rho[:, np.newaxis, np.newaxis],
                       (1, plot["npoints"], plot["npoints"]))
    ro.plot(X, Y, nel0, nel1, densdata, plotpoints, plot["width"], plotrange,
            plotfile)
Пример #3
0
geometry.set_position((0.01 - box_width / 2, -box_height / 4, 0))
material = rtx.EmissiveMaterial(1.0)
mapping = rtx.SolidColorMapping((1, 1, 1))
light = rtx.Object(geometry, material, mapping)
scene.add(light)

geometry = rtx.PlainGeometry(box_width / 2, box_width / 2)
geometry.set_rotation((0, -math.pi / 2, 0))
geometry.set_position((box_width / 2 - 0.01, -box_height / 4, 0))
material = rtx.EmissiveMaterial(1.0)
mapping = rtx.SolidColorMapping((0, 1, 1))
light = rtx.Object(geometry, material, mapping)
scene.add(light)

# place bunny
faces, vertices = gm.load("../geometries/bunny")
bottom = np.amin(vertices, axis=0)
geometry = rtx.StandardGeometry(faces, vertices, 25)
geometry.set_position((0, -box_height / 2 - (bottom[1] + 0.01) * 3, 0))
geometry.set_scale((3, 3, 3))
material = rtx.LambertMaterial(0.95)
mapping = rtx.SolidColorMapping((1, 1, 1))
bunny = rtx.Object(geometry, material, mapping)
scene.add(bunny)

screen_width = 768
screen_height = 512

rt_args = rtx.RayTracingArguments()
rt_args.num_rays_per_pixel = 128
rt_args.max_bounce = 4
Пример #4
0
import geometry as gm
import matplotlib.pyplot as plt

scene = rtx.Scene()

# floor
geometry = rtx.PlainGeometry(100, 100)
geometry.set_position((0, 0, 0))
geometry.set_rotation((-math.pi / 2, 0, 0))
material = rtx.LambertMaterial(1.0)
mapping = rtx.SolidColorMapping((1, 1, 1))
floor = rtx.Object(geometry, material, mapping)
scene.add(floor)

# place bunny
faces, vertices = gm.load("../geometries/bunny")
bottom = np.amin(vertices, axis=0)
geometry = rtx.StandardGeometry(faces, vertices, 25)
geometry.set_position((-2.25, -bottom[2], 0))
material = rtx.LambertMaterial(1.0)
mapping = rtx.SolidColorMapping((0, 1, 0))
bunny = rtx.Object(geometry, material, mapping)
scene.add(bunny)

# place teapot
faces, vertices = gm.load("../geometries/teapot")
bottom = np.amin(vertices, axis=0)
geometry = rtx.StandardGeometry(faces, vertices, 25)
geometry.set_position((-0.75, -bottom[2] * 1.5, 0))
geometry.set_scale((1.5, 1.5, 1.5))
material = rtx.LambertMaterial(1.0)