Example #1
0
    def __init__(
            self,
            nx,  # target number of points in x
            ny,  # target number of points in y
            rho,  # density profile, must be 1D function
            xmin,  # (xmin, ymin) coordinates
            xmax,  # (xmax, ymax) coordinates
            nNodePerh=2.01,
            numbins=10000,
            SPH=False):

        assert nx > 0
        assert ny > 0
        assert xmin[0] < xmax[0]
        assert xmin[1] < xmax[1]
        assert nNodePerh > 0.0

        # First use the 1D generator to generate a 1D slice profile along x.
        gen1d = GenerateNodeProfile1d(nx=nx,
                                      rho=rho,
                                      xmin=xmin[0],
                                      xmax=xmax[0],
                                      nNodePerh=nNodePerh,
                                      numbins=numbins)

        # Stitch the 1D profiles back into serial data.
        gen1d.x = mpi.allreduce(gen1d.x, mpi.SUM)
        gen1d.m = mpi.allreduce(gen1d.m, mpi.SUM)
        gen1d.rho = mpi.allreduce(gen1d.rho, mpi.SUM)
        gen1d.H = mpi.allreduce(gen1d.H, mpi.SUM)
        n1d = len(gen1d.x)

        # Replicate the 1D slices into the full 2D data.
        self.x = []
        self.y = []
        self.m = []
        self.rho = []
        self.H = []
        dy = (xmax[1] - xmin[1]) / ny
        hyinv = 1.0 / (nNodePerh * dy)
        for iy in xrange(ny):
            self.x += gen1d.x
            self.y += [xmin[1] + (iy + 0.5) * dy] * n1d
            self.m += [mi * (xmax[1] - xmin[1]) / ny for mi in gen1d.m]
            self.rho += gen1d.rho
            self.H += [SymTensor2d(H1d.xx, 0.0, 0.0, hyinv) for H1d in gen1d.H]

        # Have the base class break up the serial node distribution
        # for parallel cases.
        NodeGeneratorBase.__init__(self, True, self.x, self.y, self.m,
                                   self.rho, self.H)

        # If we're forcing round H tensors, do it.
        if SPH:
            self.makeHround()

        return
    def latticeDistribution(self,
                            nx,
                            ny,
                            rho,
                            xmin=(0.0, 0.0),
                            xmax=(1.0, 1.0),
                            rmin=None,
                            rmax=None,
                            nNodePerh=2.01,
                            xlmin=1e30,
                            xlmax=-1e30):

        dx = (xmax[0] - xmin[0]) / nx
        dy = (xmax[1] - xmin[1]) / ny

        hx = 1.0 / (nNodePerh * dx)
        hy = 1.0 / (nNodePerh * dy)
        H0 = SymTensor2d(hx, 0.0, 0.0, hy)

        x = []
        y = []
        m = []
        H = []

        for j in xrange(ny):
            for i in xrange(nx):
                if i * dx < xlmin or i * dx > xlmax:
                    xx = xmin[0] + (i + 0.5) * dx
                    yy = xmin[1] + (j + 0.5) * dy
                    r = sqrt(xx * xx + yy * yy)
                    m0 = dx * dy * rho(Vector2d(xx, yy))
                    if ((r >= rmin or rmin is None)
                            and (r <= rmax or rmax is None)):
                        x.append(xx)
                        y.append(yy)
                        m.append(m0)
                        H.append(H0)
        dx = dx * 0.5
        dy = dy * 0.5
        xx = xlmin + 0.5 * dx
        while (xx <= xlmax):
            for j in range(ny * 2):
                yy = xmin[1] + (j + 0.5) * dy
                r = sqrt(xx * xx + yy * yy)
                m0 = dx * dy * rho(Vector2d(xx, yy))
                if ((r >= rmin or rmin is None)
                        and (r <= rmax or rmax is None)):
                    x.append(xx)
                    y.append(yy)
                    m.append(m0)
                    H.append(H0)
            xx += dx

        return x, y, m, H
Example #3
0
    def __init__(
            self,
            boundary,  # Some object that has "xmin", "xmax", & "contains"
            dx,  # Nominal linear resolution
            rho,  # initial mass density: constant, list, or function
            nNodePerh=2.01,  # desired nPerh for H tensors
            jitter=0.0,  # (fraction of dx) any randomness to initial positions
            SPH=False,  # Should we force round H tensors?
    ):
        assert dx > 0.0
        assert nNodePerh > 0.0
        self.nNodePerh = nNodePerh

        # Start by clipping a lattice.
        xmin, xmax = boundary.xmin, boundary.xmax
        nx = max(1, int((xmax.x - xmin.x) / dx + 0.5))
        ny = max(1, int((xmax.y - xmin.y) / dx + 0.5))
        self.x, self.y = [], []
        for iy in xrange(ny):
            for ix in xrange(nx):
                posi = Vector2d(
                    xmin.x + (ix + 0.5 + jitter * rangen.uniform(0, 1)) * dx,
                    xmin.y + (iy + 0.5 + jitter * rangen.uniform(0, 1)) * dx)
                if boundary.contains(posi):
                    self.x.append(posi.x)
                    self.y.append(posi.y)
        n = len(self.x)
        assert len(self.y) == n

        # Density and mass.
        if type(rho) is float:
            self.rho = ConstantRho(rho)
        else:
            self.rho = rho

        # Mass per node.
        self.m = [self.rho(Vector2d(self.x[i], self.y[i])) for i in xrange(n)]

        # Set H.
        h0 = nNodePerh * dx
        H0 = SymTensor2d(1.0 / h0, 0.0, 0.0, 1.0 / h0)
        self.H = [H0] * len(self.x)

        # Have the base class break up the serial node distribution
        # for parallel cases.
        NodeGeneratorBase.__init__(self, True, self.x, self.y, self.m, self.H)

        return
Example #4
0
    def latticeDistribution(self, nr, rho0, m0,
                            xmin,
                            xmax,
                            rmax,
                            nNodePerh = 2.01):
        
        assert nr > 0
        assert rho0 > 0
        
        nx = 2*nr+1
        ny = 2*nr+1
        
        dx = (xmax[0] - xmin[0])/nx
        dy = (xmax[1] - xmin[1])/ny
        
        n = nx*ny

        hx = 1.0/(nNodePerh*dx)
        hy = 1.0/(nNodePerh*dy)
        H0 = SymTensor2d(hx, 0.0,
                         0.0, hy)
                       
        x = []
        y = []
        m = []
        H = []

        for j in xrange(ny):
            for i in xrange(nx):
                xx = xmin[0] + (i + 0.5)*dx
                yy = xmin[1] + (j + 0.5)*dy
                x.append(xx)
                y.append(yy)
                m.append(m0)
                H.append(H0)
       
        return x, y, m, H
def _string2SymTensor2d(x):
    return SymTensor2d(*tuple(x.split()))
    def __init__(self,
                 filename,
                 materialName,
                 nNodePerh=2.01,
                 SPH=False,
                 precision=20,
                 Hscalefactor=1.0,
                 extraFields=[],
                 initializeBase=True,
                 readFileToMemory=False,
                 refineNodes=0):

        self.filename = filename
        self.nPerh = nNodePerh
        self.SPH = SPH
        self.extraFields = extraFields

        self.precision = "%" + "%i.%ie" % (precision + 3, precision)

        # For now we restrict to reading from a single (serial) file.
        allfiles = mpi.allreduce([filename], mpi.SUM)
        assert min([x == filename for x in allfiles])
        self.serialfile = True

        # Open the file.
        if mpi.rank == 0:
            f = gzip.open(filename, "r")
            if readFileToMemory:
                self.f = f.readlines()
                f.close()
            else:
                self.f = f
        else:
            self.f = None

        # Read the positions.
        vals = readField2String(materialName, "positions", self.f)
        n = len(vals)
        self.x = []
        self.y = []
        for val in vals:
            x, y = tuple([float(x) for x in val.split()])
            self.x.append(x)
            self.y.append(y)
        assert len(self.x) == n
        assert len(self.y) == n

        # Read the masses.
        vals = readField2String(materialName, "mass", self.f)
        assert len(vals) == n
        self.m = [float(x) for x in vals]
        assert len(self.m) == n

        # Read the mass densities.
        vals = readField2String(materialName, "density", self.f)
        assert len(vals) == n
        self.rho = [float(x) for x in vals]
        assert len(self.rho) == n

        # Read the velocities.
        vals = readField2String(materialName, "velocity", self.f)
        assert len(vals) == n
        self.vx = []
        self.vy = []
        for val in vals:
            vx, vy = tuple([float(x) for x in val.split()])
            self.vx.append(vx)
            self.vy.append(vy)
        assert len(self.vx) == n
        assert len(self.vy) == n

        # Read the specific thermal energies.
        vals = readField2String(materialName, "specificThermalEnergy", self.f)
        assert len(vals) == n
        self.eps = [float(x) for x in vals]
        assert len(self.eps) == n

        # Read the H tensors.
        vals = readField2String(materialName, "Hinverse2", self.f)
        assert len(vals) == n
        self.H = []
        for val in vals:
            Hi2 = SymTensor2d(*tuple([float(x)
                                      for x in val.split()])) * Hscalefactor
            H = Hi2.Inverse().sqrt()
            if SPH:
                hxy = sqrt(H.Determinant())
                H = SymTensor2d.one * hxy
            self.H.append(H)
        assert len(self.H) == n

        # Read in any extra fields the user requested.
        # Note we make the assumption here that any extra fields are in fact scalar fields.
        for fname in extraFields:
            vals = readField2String(materialName, fname, self.f)
            assert len(vals) == n
            self.__dict__[fname] = [float(x) for x in vals]

        # Initialize the base class.
        if initializeBase:
            fields = tuple([
                self.x, self.y, self.m, self.rho, self.vx, self.vy, self.eps,
                self.H
            ] + [self.__dict__[x] for x in extraFields])
            NodeGeneratorBase.__init__(self, self.serialfile, *fields)

        if mpi.rank == 0:
            self.f.close()

        # Apply the requested number of refinements.
        for i in xrange(refineNodes):
            refineNodes2d(self)

        return
Example #7
0
    def __init__(self, nx, ny, rho, xmin, xmax, nNodePerh=2.01, SPH=False):
        assert nx > 0
        assert ny > 0
        assert len(xmin) == 2
        assert len(xmax) == 2
        assert xmax[0] >= xmin[0]
        assert xmax[1] >= xmin[1]
        assert nNodePerh > 0.0

        # Remember the input.
        self.nx = nx
        self.ny = ny
        self.xmin = xmin
        self.xmax = xmax

        # If the user provided a constant for rho, then use the constantRho
        # class to provide this value.
        if type(rho) == type(1.0):
            self.rho = ConstantRho(rho)
        else:
            self.rho = rho

        # Compute the number of domains in each direction.
        lx = xmax[0] - xmin[0]
        ly = xmax[1] - xmin[1]
        nxdomains = int(sqrt(lx / ly * mpi.procs) + 0.1)
        nydomains = int(mpi.procs / nxdomains + 0.1)
        assert nxdomains * nydomains == mpi.procs

        # The number of nodes per domain.
        nxperdomain = nx / nxdomains
        nxremainder = nx % nxdomains
        nyperdomain = ny / nydomains
        nyremainder = ny % nydomains
        assert nxremainder < nxdomains
        assert nyremainder < nydomains

        # Compute the value for H.
        dx = lx / nx
        dy = ly / ny
        hx = nNodePerh * dx
        hy = nNodePerh * dy
        assert hx > 0.0 and hy > 0.0
        H0 = SymTensor2d(1.0 / hx, 0.0, 0.0, 1.0 / hy)
        if SPH:
            hxy = sqrt(hx * hy)
            H0 = SymTensor2d.one / hxy

        # The mass per node.
        m0 = lx * ly * rho / (nx * ny)
        assert m0 > 0.0

        # Compute our domain indicies.
        ixdomain = mpi.rank % nxdomains
        iydomain = mpi.rank / nxdomains
        ixmin = nodeindex(ixdomain, nxperdomain, nxremainder)
        ixmax = nodeindex(ixdomain + 1, nxperdomain, nxremainder)
        iymin = nodeindex(iydomain, nyperdomain, nyremainder)
        iymax = nodeindex(iydomain + 1, nyperdomain, nyremainder)
        assert ixmin < ixmax
        assert ixmin >= 0 and ixmax <= nx
        assert iymin < iymax
        assert iymin >= 0 and iymax <= ny

        # Now fill in the node values for this domain.
        self.x = []
        self.y = []
        self.m = []
        self.H = []
        for iy in xrange(iymin, iymax):
            for ix in xrange(ixmin, ixmax):
                self.x.append(xmin[0] + (ix + 0.5) * dx)
                self.y.append(xmin[1] + (iy + 0.5) * dy)
                self.m.append(m0)
                self.H.append(H0)
        assert mpi.allreduce(len(self.x), mpi.SUM) == nx * ny

        # Initialize the base class.
        NodeGeneratorBase.__init__(self, False)

        return
Example #8
0
def refineNodes3d(gen,
                  deta = 0.25):
    n = gen.localNumNodes()
    x = []
    y = []
    z = []
    m = []
    rho = []
    vx = []
    vy = []
    vz = []
    eps = []
    H = []
    extras = {}
    for name in gen.extraFields:
        extras[name] = []

    etas = [Vector3d(-1, -1, -1) * deta,
            Vector3d(-1, -1,  1) * deta,
            Vector3d(-1,  1, -1) * deta,
            Vector3d(-1,  1,  1) * deta,
            Vector3d( 1, -1, -1) * deta,
            Vector3d( 1, -1,  1) * deta,
            Vector3d( 1,  1, -1) * deta,
            Vector3d( 1,  1,  1) * deta]

    for i in xrange(n):
        ri = gen.localPosition(i)
        mi = gen.localMass(i)
        Hi = gen.localHtensor(i)
        Hinv = Hi.Inverse()
        eigen = Hinv.eigenVectors()
        R = rotationMatrix3d(eigen.eigenVectors.getColumn(0))
        T = SymTensor2d(eigen.eigenValues.x, 0.0,                 0.0,
                        0.0,                 eigen.eigenValues.y, 0.0,
                        0.0,                 0.0,                 eigen.eigenValues.z)
        T.rotationalTransform(eigen.eigenVectors)
        T = T*R.Inverse()

        mj = mi/8.0
        Hj = Hi*2.0
        for eta in etas:
            rj = ri + T*eta
            x.append(rj.x)
            y.append(rj.y)
            z.append(rj.z)
            m.append(mj)
            rho.append(gen.rho[i])
            vx.append(gen.vx[i])
            vy.append(gen.vy[i])
            vz.append(gen.vz[i])
            eps.append(gen.eps[i])
            H.append(Hj)
            for name in gen.extraFields:
                extras[name].append(gen.__dict__[name][i])

    gen.x = x
    gen.y = y
    gen.z = z
    gen.m = m
    gen.rho = rho
    gen.vx = vx
    gen.vy = vy
    gen.vz = vz
    gen.eps = eps
    gen.H = H
    for name in gen.extraFields:
        gen.__dict__[name] = extras[name]

    for f in ([gen.x, gen.y, gen.z, gen.m, gen.vx, gen.vy, gen.vz, gen.eps, gen.H] +
              [gen.__dict__[x] for x in gen.extraFields]):
        assert len(f) == len(etas)*n
    return
Example #9
0
    def __init__(self, 
                 drCenter, drRatio,
                 rho,
                 rmin,
                 rmax,
                 startFromCenter = True,
                 thetamin = 0.0,
                 thetamax = 0.5*pi,
                 phi = pi,
                 ntheta = 1,
                 center = (0.0, 0.0, 0.0),
                 distributionType = "constantDTheta",   # one of (constantDTheta, constantNTheta)
                 aspectRatio = 1.0,                     # only for constantDTheta
                 nNodePerh = 2.01,
                 SPH = False,
                 rejecter = None):

        assert thetamax <= pi

        self.gen2d = GenerateRatioSphere2d(drStart = drCenter, 
                                           drRatio = drRatio, 
                                           rho = rho, 
                                           rmin = rmin, 
                                           rmax = rmax, 
                                           startFromCenter = startFromCenter, 
                                           thetamin = thetamin, 
                                           thetamax = thetamax, 
                                           ntheta = ntheta, 
                                           center = (0.0, 0.0), 
                                           distributionType = distributionType, 
                                           aspectRatio = aspectRatio,
                                           nNodePerh = nNodePerh, 
                                           SPH = SPH)

        # The 2D class already split the nodes up between processors, but
        # we want to handle that ourselves.  Distribute the full set of RZ
        # nodes to every process, then redecompose them below.
        self.x = mpi.allreduce(self.gen2d.x[:], mpi.SUM)
        self.y = mpi.allreduce(self.gen2d.y[:], mpi.SUM)
        self.m = mpi.allreduce(self.gen2d.m[:], mpi.SUM)
        self.H = mpi.allreduce(self.gen2d.H[:], mpi.SUM)
        n = len(self.x)
        self.z = [0.0]*n
        self.globalIDs = [0]*n

        # Convert the 2-D H tensors to 3-D, and correct the masses.
        for i in xrange(n):
            xi = self.x[i]
            yi = self.y[i]
            H2d = SymTensor2d(self.H[i])
            H2dinv = H2d.Inverse()

            hxy0 = 0.5*(H2dinv.Trace())
            dphi = CylindricalBoundary.angularSpacing(yi, hxy0, nNodePerh, 2.0)
            assert dphi > 0.0
            nsegment = max(1, int(phi/dphi + 0.5))
            dphi = phi/nsegment

            hz = dphi*yi*nNodePerh
            self.H[i] = SymTensor3d(H2d.xx, H2d.xy, 0.0,
                                    H2d.yx, H2d.yy, 0.0,
                                    0.0,    0.0,    1.0/hz)
            if SPH:
                h0 = self.H[i].Determinant()**(1.0/3.0)
                self.H[-1] = SymTensor3d(h0, 0.0, 0.0,
                                         0.0, h0, 0.0,
                                         0.0, 0.0, h0)

            # Convert the mass to the full hoop mass, which will then be used in
            # generateCylDistributionFromRZ to compute the actual nodal masses.
            mi = self.m[i]
            circ = 2.0*pi*yi
            mhoop = mi*circ
            self.m[i] = mhoop

        assert len(self.m) == n
        assert len(self.H) == n

        # Duplicate the nodes from the xy-plane, creating rings of nodes about
        # the x-axis.  We use a C++ helper method for the sake of speed.
        kernelExtent = 2.0
        extras = []
        xvec = self.vectorFromList(self.x, vector_of_double)
        yvec = self.vectorFromList(self.y, vector_of_double)
        zvec = self.vectorFromList(self.z, vector_of_double)
        mvec = self.vectorFromList(self.m, vector_of_double)
        Hvec = self.vectorFromList(self.H, vector_of_SymTensor3d)
        globalIDsvec = self.vectorFromList(self.globalIDs, vector_of_int)
        extrasVec = vector_of_vector_of_double()
        for extra in extras:
            extrasVec.append(self.vectorFromList(extra, vector_of_double))
        generateCylDistributionFromRZ(xvec, yvec, zvec, mvec, Hvec, globalIDsvec,
                                      extrasVec,
                                      nNodePerh, kernelExtent, phi,
                                      mpi.rank, mpi.procs)
        self.x = [x + center[0] for x in xvec]
        self.y = [x + center[1] for x in yvec]
        self.z = [z + center[2] for z in zvec]
        self.m = list(mvec)
        self.H = [SymTensor3d(x) for x in Hvec]
        self.globalIDs = list(globalIDsvec)
        for i in xrange(len(extras)):
            extras[i] = list(extrasVec[i])

        self.center = Vector2d(*center)

        # If the user provided a "rejecter", give it a pass
        # at the nodes.
        if rejecter:
            self.x, self.y, self.z, self.m, self.H = rejecter(self.x,
                                                              self.y,
                                                              self.z,
                                                              self.m,
                                                              self.H)
        # Initialize the base class.
        NodeGeneratorBase.__init__(self, False,
                                   self.x, self.y, self.z, self.m, self.H)
        return
Example #10
0
    def __init__(self,
                 drStart, drRatio,
                 rho,
                 rmin,
                 rmax,
                 startFromCenter = True,
                 thetamin = 0.0,
                 thetamax = 0.5*pi,
                 ntheta = 1,
                 center = (0.0, 0.0),
                 distributionType = "constantDTheta",   # one of (constantDTheta, constantNTheta)
                 aspectRatio = 1.0,                     # only for constantDTheta
                 nNodePerh = 2.01,
                 SPH = False,
                 rejecter = None,
                 perturbFunc = None):

        assert drStart > 0.0
        assert drRatio > 0.0
        assert nNodePerh > 0.0
        assert rmin >= 0.0
        assert rmax > rmin
        assert thetamax > thetamin
        assert distributionType.lower() in ("constantdtheta", "constantntheta")
        
        self.center = center

        # Did we get passed a function or a constant for the density?
        if type(rho) == type(1.0):
            def rhofunc(posi):
                return rho
        else:
            rhofunc = rho
        self.rhofunc = rhofunc

        # Do we have a perturbation function?
        def zeroPerturbation(posi):
            return posi
        if not perturbFunc:
            perturbFunc = zeroPerturbation

        self.x, self.y, self.m, self.H = [], [], [], []

        constantN = (distributionType.lower() == "constantntheta")
        Dtheta = thetamax - thetamin

        nthetamin = max(2, int(Dtheta/(0.5*pi) + 0.5)*2)

        # Decide the actual drStart we're going to use to arrive at an integer number of radial bins.
        if abs(drRatio - 1.0) > 1e-4:
            neff = max(1, int(log(1.0 - (rmax - rmin)*(1.0 - drRatio)/drStart)/log(drRatio) + 0.5))
            drStart = (rmax - rmin)*(1.0 - drRatio)/(1.0 - drRatio**neff)
        else:
            neff = max(1, int((rmax - rmin)/drStart + 0.5))
            drStart = (rmax - rmin)/neff
        print "Adjusting initial radial spacing to %g in order to create an integer radial number of bins %i." % (drStart, neff)

        # Step in radius (in or out) until we span the full radial range.
        dr = drStart
        for i in xrange(neff):
            if abs(drRatio - 1.0) > 1e-4:
                if startFromCenter:
                    r0 = min(rmax, rmin + drStart*(1.0 - drRatio**i)/(1.0 - drRatio))
                    r1 = min(rmax, rmin + drStart*(1.0 - drRatio**(i + 1))/(1.0 - drRatio))
                else:
                    r0 = max(rmin, rmax - drStart*(1.0 - drRatio**(i + 1))/(1.0 - drRatio))
                    r1 = max(rmin, rmax - drStart*(1.0 - drRatio**i)/(1.0 - drRatio))
            else:
                r0 = min(rmax, rmin + i*drStart)
                r1 = min(rmax, rmin + (i + 1)*drStart)
            dr = r1 - r0
            ri = 0.5*(r0 + r1)
            li = Dtheta*ri
            if constantN:
                ntheta = ntheta
            else:
                ntheta = max(nthetamin, int(li/dr*aspectRatio))
            dtheta = Dtheta/ntheta
            hr = nNodePerh * dr
            ha = nNodePerh * ri*dtheta

            for j in xrange(ntheta):
                theta0 = thetamin + j*dtheta
                theta1 = thetamin + (j + 1)*dtheta
                pos0 = perturbFunc(Vector2d(r0*cos(theta0), r0*sin(theta0)))
                pos1 = perturbFunc(Vector2d(r1*cos(theta0), r1*sin(theta0)))
                pos2 = perturbFunc(Vector2d(r1*cos(theta1), r1*sin(theta1)))
                pos3 = perturbFunc(Vector2d(r0*cos(theta1), r0*sin(theta1)))
                areai = 0.5*((pos1 - pos0).cross(pos2 - pos0).z +
                             (pos2 - pos0).cross(pos3 - pos0).z)
                posi = 0.25*(pos0 + pos1 + pos2 + pos3)
                mi = areai*self.rhofunc(posi)
                xi = posi.x
                yi = posi.y
                self.x.append(xi + center[0])
                self.y.append(yi + center[1])
                self.m.append(mi)
                if SPH:
                    hi = sqrt(hr*ha)
                    self.H.append(SymTensor2d(1.0/hi, 0.0, 0.0, 1.0/hi))
                else:
                    self.H.append(SymTensor2d(1.0/hr, 0.0, 0.0, 1.0/ha))
                    runit = Vector2d(xi, yi).unitVector()
                    T = rotationMatrix2d(runit).Transpose()
                    self.H[-1].rotationalTransform(T)

        # # Do a numerical integral to get the expected total mass.
        # class integfunc(ScalarFunctor):
        #     def __init__(self, rho, Dtheta):
        #         ScalarFunctor.__init__(self)
        #         self.rho = rho
        #         self.Dtheta = Dtheta
        #         return
        #     def __call__(self, ri):
        #         return Dtheta*ri*self.rho(ri)
        # M1 = simpsonsIntegrationDouble(integfunc(rhofunc, Dtheta), rmin, rmax, 10000)

        # # Make sure the total mass is what we intend it to be, by applying
        # # a multiplier to the particle masses.
        # M0 = sum(self.m)
        # assert M0 > 0.0
        # massCorrection = M1/M0
        # for i in xrange(len(self.m)):
        #     self.m[i] *= massCorrection
        # print "Applied a mass correction of %f to ensure total mass is %f." % (massCorrection, M1)

        # If the user provided a "rejecter", give it a pass
        # at the nodes.
        if rejecter:
            self.x, self.y, self.m, self.H = rejecter(self.x,
                                                      self.y,
                                                      self.m,
                                                      self.H)

        # Have the base class break up the serial node distribution
        # for parallel cases.
        NodeGeneratorBase.__init__(self, True,
                                   self.x, self.y, self.m, self.H)
        return
    def __init__(self,
                 n,
                 rho,
                 boundary,
                 holes=[],
                 maxIterations=100,
                 fracTol=1.0e-3,
                 tessellationFileName=None,
                 nNodePerh=2.01,
                 offset=(0.0, 0.0),
                 rejecter=None):

        assert n > 0

        # Did we get passed a function or a constant for the density?
        if type(rho) == type(1.0):

            def rhofunc(posi):
                return rho
        else:
            rhofunc = rho
        self.rhofunc = rhofunc

        # Build a polytope PLC version of the boundary.
        plc = poly.polytope.PLC2d()
        plc_coords = poly.vector_of_double()
        edges = boundary.edges
        vertices = boundary.vertices()
        plc.facets.resize(len(edges))
        for i, edge in enumerate(edges):
            plc.facets[i].append(edge.first)
            plc.facets[i].append(edge.second)
            assert len(plc.facets[i]) == 2
        for p in vertices:
            plc_coords.append(p[0])
            plc_coords.append(p[1])
        assert len(plc_coords) == 2 * len(vertices)

        # Add any holes to the boundary PLC.
        plc.holes.resize(len(holes))
        for ihole, hole in enumerate(holes):
            offlast = len(plc_coords) / 2
            edges = hole.edges
            vertices = hole.vertices()
            plc.holes[ihole].resize(len(edges))
            for i, edge in enumerate(edges):
                plc.holes[ihole][i].append(offlast + edge.first)
                plc.holes[ihole][i].append(offlast + edge.second)
                assert len(plc.holes[ihole][i]) == 2
            for p in vertices:
                plc_coords.append(p[0])
                plc_coords.append(p[1])
            assert len(plc_coords) % 2 == 0

        # Initialize the desired number of generators in the boundary using the Sobol sequence.
        generators = poly.vector_of_double()
        seed = 0
        length = max(boundary.xmax.x - boundary.xmin.x,
                     boundary.xmax.y - boundary.xmin.y)
        while len(generators) < 2 * n:
            [coords, seed] = i4_sobol(2, seed)
            p = boundary.xmin + length * Vector2d(coords[0], coords[1])
            ihole = 0
            use = boundary.contains(p, False)
            if use:
                while use and ihole < len(holes):
                    use = not holes[ihole].contains(p, False)
                    ihole += 1
            if use:
                generators.append(p.x)
                generators.append(p.y)
        assert len(generators) == 2 * n

        # Iterate the points toward centroidal relaxation.
        self.tessellation = poly.polytope.Tessellation2d()
        tessellator = poly.polytope.BoostTessellator2d()
        iteration = 0
        maxDelta = 2.0 * fracTol
        while iteration < maxIterations and maxDelta > fracTol:
            tessellator.tessellate(points=generators,
                                   PLCpoints=plc_coords,
                                   geometry=plc,
                                   mesh=self.tessellation)
            new_generators = self.computeWeightedCentroids(self.tessellation)
            assert len(new_generators) == len(generators)
            maxDelta = 0.0
            for i in xrange(len(generators) / 2):
                deltai = sqrt((generators[2 * i] - new_generators[2 * i])**2 +
                              (generators[2 * i + 1] -
                               new_generators[2 * i + 1])**2)
                maxDelta = max(maxDelta, deltai / length)
                generators[2 * i] = 0.5 * (generators[2 * i] +
                                           new_generators[2 * i])
                generators[2 * i + 1] = 0.5 * (generators[2 * i + 1] +
                                               new_generators[2 * i + 1])
            iteration += 1
            print "CentroidalGenerator2d: Iteration %i, maxDelta=%g" % (
                iteration, maxDelta)

        # If requested, write out the final tessellation to a silo file.
        if tessellationFileName:
            poly.polytope.writeTessellation2d(mesh=self.tessellation,
                                              filePrefix=tessellationFileName,
                                              nodeFields=None,
                                              edgeFields=None,
                                              faceFields=None,
                                              cellFields=None,
                                              cycle=iteration)

        # Now we can fill out the usual Spheral generator info.
        assert len(self.tessellation.cells) == n
        self.x, self.y, self.m, self.H = [], [], [], []
        centroids = self.computeWeightedCentroids(self.tessellation)
        masses = self.computeMasses(self.tessellation)
        areas = self.computeAreas(self.tessellation)
        assert len(centroids) == 2 * n
        assert len(masses) == n
        assert len(areas) == n
        for i in xrange(n):
            self.x.append(centroids[2 * i] + offset[0])
            self.y.append(centroids[2 * i + 1] + offset[1])
            self.m.append(masses[i])
            hi = nNodePerh * sqrt(areas[i] / pi)
            assert hi > 0.0
            self.H.append(SymTensor2d(1.0 / hi, 0.0, 0.0, 1.0 / hi))
        assert len(self.x) == n
        assert len(self.y) == n
        assert len(self.m) == n
        assert len(self.H) == n

        # If the user provided a "rejecter", give it a pass
        # at the nodes.
        if rejecter:
            self.x, self.y, self.m, self.H = rejecter(self.x, self.y, self.m,
                                                      self.H)

        # Have the base class break up the serial node distribution
        # for parallel cases.
        NodeGeneratorBase.__init__(self, True, self.x, self.y, self.m, self.H)
        return
    def latticeCylindricalDistribution(self,
                                       nx,
                                       ny,
                                       rho,
                                       xmin=(0.0, 0.0),
                                       xmax=(1.0, 1.0),
                                       rmin=None,
                                       rmax=None,
                                       nNodePerh=2.01):
        k = 0
        np = 0
        deltar = rmax - rmin
        dx = (xmax[0] - xmin[0]) / nx
        dy = (xmax[1] - xmin[1]) / ny

        hx = 1.0 / (nNodePerh * dx)
        hy = 1.0 / (nNodePerh * dy)
        H0 = SymTensor2d(hx, 0.0, 0.0, hy)

        x = []
        y = []
        m = []
        H = []

        ml = []
        Hl = []
        xl = []
        yl = []

        xc = []
        yc = []
        mc = []
        Hc = []

        for j in xrange(ny):
            for i in xrange(nx):
                xx = xmin[0] + (i + 0.5) * dx
                yy = xmin[1] + (j + 0.5) * dy
                r = sqrt(xx * xx + yy * yy)
                m0 = dx * dy * rho(Vector2d(xx, yy))
                if (r >= rmin * 0.8):
                    xl.append(xx)
                    yl.append(yy)
                    ml.append(m0)
                    Hl.append(H0)
                    k = k + 1
                if (r >= rmax):
                    x.append(xx)
                    y.append(yy)
                    m.append(m0)
                    H.append(H0)
                    np = np + 1

        # Start at the outermost radius, and work our way inward.
        theta = 2 * 3.14159
        ri = rmax + 2.0 * nNodePerh / nx

        #import random
        #random.seed()

        while ri > 0:

            # Get the nominal delta r, delta theta, number of nodes, and mass per
            # node at this radius.
            rhoi = rho(Vector2d(ri, 0.0))
            dr = sqrt(m0 / rhoi)
            arclength = theta * ri
            arcmass = arclength * dr * rhoi
            nTheta = max(1, int(arcmass / m0))
            dTheta = theta / nTheta
            mi = arcmass / nTheta
            hi = nNodePerh * 0.5 * (dr + ri * dTheta)
            Hi = SymTensor2d(1.0 / hi, 0.0, 0.0, 1.0 / hi)

            # Now assign the nodes for this radius.
            for i in xrange(nTheta):
                thetai = (i + 0.5) * dTheta
                xc.append(ri * cos(thetai))
                yc.append(ri * sin(thetai))
                mc.append(mi)
                Hc.append(Hi)
                xi = ri * cos(thetai)
                yi = ri * sin(thetai)

                if (ri < rmin):
                    x.append(xi)
                    y.append(yi)
                    m.append(mi)
                    H.append(Hi)
                    np = np + 1
                elif (ri >= rmin):
                    #eps = random.random()
                    #func = ((ri-rmin)/deltar)**2
                    func = 1 - ri / (rmin - rmax) - rmax / (rmax - rmin)
                    if (func > 1.0):
                        func = 1.0
                    if (func < 0.0):
                        func = 0.0
                    #if (eps <= func):
                    #x.append(ri*cos(thetai))
                    #y.append(ri*sin(thetai))
                    #m.append(mi)
                    #H.append(Hi)
                    #else:
                    minddr = nx
                    mink = 2 * k
                    for j in xrange(k):
                        ddr = sqrt((xl[j] - xi)**2 + (yl[j] - yi)**2)
                        if (ddr < minddr):
                            minddr = ddr
                            mink = j
                    xi = xi + (xl[mink] - xi) * func
                    yi = yi + (yl[mink] - yi) * func

                    minddr = nx
                    for j in xrange(np):
                        ddr = sqrt((x[j] - xi)**2 + (y[j] - yi)**2)
                        if (ddr < minddr):
                            minddr = ddr
                    if (minddr > (1.0 / hx) * 0.5):
                        x.append(xi + (xl[mink] - xi) * func)
                        y.append(yi + (yl[mink] - yi) * func)
                        m.append(ml[mink])
                        H.append(Hl[mink])

            # Decrement to the next radial bin inward.
            ri = max(0.0, ri - dr)

        return x, y, m, H
Example #13
0
    def __init__(self,
                 dxSurface,
                 xratio,
                 dySurface,
                 yratio,
                 rho,
                 xmin,
                 xmax,
                 nNodePerh=2.01,
                 SPH=False,
                 flipx=False,
                 flipy=False):

        assert dxSurface > 0.0
        assert xratio > 0.0
        assert dySurface > 0.0
        assert yratio > 0.0
        assert xmin[0] < xmax[0]
        assert xmin[1] < xmax[1]
        assert nNodePerh > 0.0

        # If the user provided a constant for rho, then use the constantRho
        # class to provide this value.
        if type(rho) == type(1.0):
            self.rhofunc = ConstantRho(rho)
        else:
            self.rhofunc = rho

        self.x, self.y, self.m, self.H, self.rho = [], [], [], [], []

        # Decide the actual ratios we're going to use to arrive at an integer number of radial bins.
        def adjustRatio(drStart, drRatio, rmin, rmax):
            if abs(drRatio - 1.0) > 1e-4:
                neff = max(
                    1,
                    int(
                        log(1.0 - (rmax - rmin) *
                            (1.0 - drRatio) / drStart) / log(drRatio) + 0.5))
                drStart = (rmax - rmin) * (1.0 - drRatio) / (1.0 -
                                                             drRatio**neff)
            else:
                neff = max(1, int((rmax - rmin) / drStart + 0.5))
                drStart = (rmax - rmin) / neff
            return drStart, neff

        dxSurface, nxeff = adjustRatio(dxSurface, xratio, xmin[0], xmax[0])
        dySurface, nyeff = adjustRatio(dySurface, yratio, xmin[1], xmax[1])
        print "Adjusting initial spacing to (%g, %g) in order to create integer numbers of bins (%i, %i) to edges." % (
            dxSurface, dySurface, nxeff, nyeff)

        def flipcoord(xi, x0, x1):
            return x0 + x1 - xi

        # Work our way in from the y surface.
        y1 = xmax[1]
        dy = dySurface
        while y1 > xmin[1] + 0.1 * dy:
            y0 = max(xmin[1], y1 - dy)
            yi = 0.5 * (y0 + y1)
            hy = nNodePerh * dy

            yi0 = y0
            yi1 = y1
            if flipy:
                yi = flipcoord(yi, xmin[1], xmax[1])
                yi0 = flipcoord(yi0, xmin[1], xmax[1])
                yi1 = flipcoord(yi1, xmin[1], xmax[1])

            # Work our way in from the x surface.
            x1 = xmax[0]
            dx = dxSurface
            while x1 > xmin[0] + 0.1 * dx:
                x0 = max(xmin[0], x1 - dx)
                xi = 0.5 * (x0 + x1)
                hx = nNodePerh * dx

                xi0 = x0
                xi1 = x1
                if flipx:
                    xi = flipcoord(xi, xmin[0], xmax[0])
                    xi0 = flipcoord(xi0, xmin[0], xmax[0])
                    xi1 = flipcoord(xi1, xmin[0], xmax[0])

                self.x.append(xi)
                self.y.append(yi)
                rhoi, mi = computeRhoAndMass2d(Vector2d(xi0, yi0),
                                               Vector2d(xi1, yi0),
                                               Vector2d(xi1, yi1),
                                               Vector2d(xi0, yi1),
                                               Vector2d(xi, yi), self.rhofunc)
                self.m.append(mi)
                self.rho.append(rhoi)
                self.H.append(SymTensor2d(1.0 / hx, 0.0, 0.0, 1.0 / hy))

                x1 = x0
                dx *= xratio

            y1 = y0
            dy *= yratio

        # # Make sure the total mass is what we intend it to be, by applying
        # # a multiplier to the particle masses.
        # M0 = 0.0
        # for m in self.m:
        #     M0 += m
        # assert M0 > 0.0
        # M1 = (xmax[0] - xmin[0]) * (xmax[1] - xmin[1]) * rho
        # massCorrection = M1/M0
        # for i in xrange(len(self.m)):
        #     self.m[i] *= massCorrection
        # print "Applied a mass correction of %f to ensure total mass is %f." % (massCorrection, M1)

        # Have the base class break up the serial node distribution
        # for parallel cases.
        NodeGeneratorBase.__init__(self, True, self.x, self.y, self.m, self.H,
                                   self.rho)
        return
Example #14
0
    def __init__(self,
                 dxSurface,
                 xratio,
                 dySurface,
                 yratio,
                 rho,
                 xmin,
                 xmax,
                 nNodePerh=2.01,
                 SPH=False,
                 flipx=False,
                 flipy=False):

        assert dxSurface > 0.0
        assert xratio > 0.0
        assert dySurface > 0.0
        assert yratio > 0.0
        assert xmin[0] < xmax[0]
        assert xmin[1] < xmax[1]
        assert nNodePerh > 0.0

        self.rho = rho
        self.x, self.y, self.m, self.H = [], [], [], []

        # Work our way in from the y surface.
        y1 = xmax[1]
        dy = dySurface
        while y1 > xmin[1]:
            y0 = max(xmin[1], y1 - dy)
            yi = 0.5 * (y0 + y1)
            hy = nNodePerh * dy

            if flipy:
                yi = xmin[1] + xmax[1] - yi

            # Work our way in from the x surface.
            x1 = xmax[0]
            dx = dxSurface
            while x1 > xmin[0]:
                x0 = max(xmin[0], x1 - dx)
                xi = 0.5 * (x0 + x1)
                hx = nNodePerh * dx

                if flipx:
                    xi = xmin[0] + xmax[0] - xi

                self.x.append(xi)
                self.y.append(yi)
                self.m.append(rho * dx * dy)
                self.H.append(SymTensor2d(1.0 / hx, 0.0, 0.0, 1.0 / hy))

                x1 = x0
                dx *= xratio

            y1 = y0
            dy *= yratio

        # Make sure the total mass is what we intend it to be, by applying
        # a multiplier to the particle masses.
        M0 = 0.0
        for m in self.m:
            M0 += m
        assert M0 > 0.0
        M1 = (xmax[0] - xmin[0]) * (xmax[1] - xmin[1]) * rho
        massCorrection = M1 / M0
        for i in xrange(len(self.m)):
            self.m[i] *= massCorrection
        print "Applied a mass correction of %f to ensure total mass is %f." % (
            massCorrection, M1)

        # Have the base class break up the serial node distribution
        # for parallel cases.
        NodeGeneratorBase.__init__(self, True, self.x, self.y, self.m, self.H)
        return