示例#1
0
def PeriodicIntervalMesh(ncells, length):
    """Generate a periodic mesh of an interval.

    :arg ncells: The number of cells over the interval.
    :arg length: The length the interval."""

    m = CircleManifoldMesh(ncells)
    coord_fs = VectorFunctionSpace(m, 'DG', 1, dim=1)
    old_coordinates = Function(m.coordinates)
    new_coordinates = Function(coord_fs)

    periodic_kernel = """double Y,pi;
            Y = 0.5*(old_coords[0][1]-old_coords[1][1]);
            pi=3.141592653589793;
            for(int i=0;i<2;i++){
            new_coords[i][0] = atan2(old_coords[i][1],old_coords[i][0])/pi/2;
            if(new_coords[i][0]<0.) new_coords[i][0] += 1;
            if(new_coords[i][0]==0 && Y<0.) new_coords[i][0] = 1.0;
            new_coords[i][0] *= L;
            }"""

    periodic_kernel = periodic_kernel.replace('L', str(length))

    par_loop(periodic_kernel, dx,
             {"new_coords": (new_coordinates, WRITE),
              "old_coords": (old_coordinates, READ)})

    m.coordinates = new_coordinates
    return m
示例#2
0
def PeriodicIntervalMesh(ncells, length):
    """Generate a periodic mesh of an interval.

    :arg ncells: The number of cells over the interval.
    :arg length: The length the interval."""

    if ncells < 3:
        raise ValueError("1D periodic meshes with fewer than 3 \
cells are not currently supported")

    m = CircleManifoldMesh(ncells)
    coord_fs = VectorFunctionSpace(m, 'DG', 1, dim=1)
    old_coordinates = m.coordinates
    new_coordinates = Function(coord_fs)

    periodic_kernel = """double Y,pi;
            Y = 0.5*(old_coords[0][1]-old_coords[1][1]);
            pi=3.141592653589793;
            for(int i=0;i<2;i++){
            new_coords[i][0] = atan2(old_coords[i][1],old_coords[i][0])/pi/2;
            if(new_coords[i][0]<0.) new_coords[i][0] += 1;
            if(new_coords[i][0]==0 && Y<0.) new_coords[i][0] = 1.0;
            new_coords[i][0] *= L[0];
            }"""

    cL = Constant(length)

    par_loop(periodic_kernel, dx,
             {"new_coords": (new_coordinates, WRITE),
              "old_coords": (old_coordinates, READ),
              "L": (cL, READ)})

    return mesh.Mesh(new_coordinates)
示例#3
0
def get_latlon_mesh(mesh):
    coords_orig = mesh.coordinates
    mesh_dg_fs = VectorFunctionSpace(mesh, "DG", 1)
    coords_dg = Function(mesh_dg_fs)
    coords_latlon = Function(mesh_dg_fs)
    par_loop("""
    for (int i=0; i<3; i++) {
    for (int j=0; j<3; j++) {
    dg[i][j] = cg[i][j];
    }
    }
    """, dx, {'dg': (coords_dg, WRITE),
              'cg': (coords_orig, READ)})

    # lat-lon 'x' = atan2(y, x)
    coords_latlon.dat.data[:,0] = np.arctan2(coords_dg.dat.data[:,1], coords_dg.dat.data[:,0])
    # lat-lon 'y' = asin(z/sqrt(x^2 + y^2 + z^2))
    coords_latlon.dat.data[:,1] = np.arcsin(coords_dg.dat.data[:,2]/np.sqrt(coords_dg.dat.data[:,0]**2 + coords_dg.dat.data[:,1]**2 + coords_dg.dat.data[:,2]**2))
    coords_latlon.dat.data[:,2] = 0.0

    kernel = op2.Kernel("""
    #define PI 3.141592653589793
    #define TWO_PI 6.283185307179586
    void splat_coords(double **coords) {
        double diff0 = (coords[0][0] - coords[1][0]);
        double diff1 = (coords[0][0] - coords[2][0]);
        double diff2 = (coords[1][0] - coords[2][0]);

        if (fabs(diff0) > PI || fabs(diff1) > PI || fabs(diff2) > PI) {
            const int sign0 = coords[0][0] < 0 ? -1 : 1;
            const int sign1 = coords[1][0] < 0 ? -1 : 1;
            const int sign2 = coords[2][0] < 0 ? -1 : 1;
            if (sign0 < 0) {
                coords[0][0] += TWO_PI;
            }
            if (sign1 < 0) {
                coords[1][0] += TWO_PI;
            }
            if (sign2 < 0) {
                coords[2][0] += TWO_PI;
            }
        }
    }""", "splat_coords")

    op2.par_loop(kernel, coords_latlon.cell_set,
                 coords_latlon.dat(op2.RW, coords_latlon.cell_node_map()))
    return Mesh(coords_latlon)
示例#4
0
    def V_dof_weights(self, V):
        """Dof weights for Fortin projection.

        :arg V: function space to compute weights for.
        :returns: A PETSc Vec.
        """
        key = V.dim()
        try:
            return self._V_dof_weights[key]
        except KeyError:
            # Compute dof multiplicity for V
            # Spin over all (owned) cells incrementing visible dofs by 1.
            # After halo exchange, the Vec representation is the
            # global Vector counting the number of cells that see each
            # dof.
            f = firedrake.Function(V)
            firedrake.par_loop(("{[i, j]: 0 <= i < A.dofs and 0 <= j < %d}" % V.value_size,
                               "A[i, j] = A[i, j] + 1"),
                               firedrake.dx,
                               {"A": (f, firedrake.INC)},
                               is_loopy_kernel=True)
            with f.dat.vec_ro as fv:
                return self._V_dof_weights.setdefault(key, fv.copy())
示例#5
0
def PartiallyPeriodicRectangleMesh(nx, ny, Lx, Ly, direction="x", quadrilateral=False, reorder=None, comm=COMM_WORLD):
    """Generates RectangleMesh that is periodic in the x or y direction.

    :arg nx: The number of cells in the x direction
    :arg ny: The number of cells in the y direction
    :arg Lx: The extent in the x direction
    :arg Ly: The extent in the y direction
    :kwarg direction: The direction of the periodicity (default x).
    :kwarg quadrilateral: (optional), creates quadrilateral mesh, defaults to False
    :kwarg reorder: (optional), should the mesh be reordered
    :kwarg comm: Optional communicator to build the mesh on (defaults to
        COMM_WORLD).

    If direction == "x" the boundary edges in this mesh are numbered as follows:

    * 1: plane y == 0
    * 2: plane y == Ly

    If direction == "y" the boundary edges are:

    * 1: plane x == 0
    * 2: plane x == Lx
    """

    if direction not in ("x", "y"):
        raise ValueError("Unsupported periodic direction '%s'" % direction)

    # handle x/y directions: na, La are for the periodic axis
    na, nb, La, Lb = nx, ny, Lx, Ly
    if direction == "y":
        na, nb, La, Lb = ny, nx, Ly, Lx

    if na < 3:
        raise ValueError("2D periodic meshes with fewer than 3 \
cells in each direction are not currently supported")

    m = CylinderMesh(na, nb, 1.0, 1.0, longitudinal_direction="z",
                     quadrilateral=quadrilateral, reorder=reorder, comm=comm)
    coord_fs = VectorFunctionSpace(m, 'DG', 1, dim=2)
    old_coordinates = m.coordinates
    new_coordinates = Function(coord_fs)

    # make x-periodic mesh
    # unravel x coordinates like in periodic interval
    # set y coordinates to z coordinates
    periodic_kernel = """double Y,pi;
            Y = 0.0;
            for(int i=0; i<old_coords.dofs; i++) {
                Y += old_coords[i][1];
            }

            pi=3.141592653589793;
            for(int i=0;i<new_coords.dofs;i++){
            new_coords[i][0] = atan2(old_coords[i][1],old_coords[i][0])/pi/2;
            if(new_coords[i][0]<0.) new_coords[i][0] += 1;
            if(new_coords[i][0]==0 && Y<0.) new_coords[i][0] = 1.0;
            new_coords[i][0] *= Lx[0];
            new_coords[i][1] = old_coords[i][2]*Ly[0];
            }"""

    cLx = Constant(La)
    cLy = Constant(Lb)

    par_loop(periodic_kernel, dx,
             {"new_coords": (new_coordinates, WRITE),
              "old_coords": (old_coordinates, READ),
              "Lx": (cLx, READ),
              "Ly": (cLy, READ)})

    if direction == "y":
        # flip x and y coordinates
        operator = np.asarray([[0, 1],
                               [1, 0]])
        new_coordinates.dat.data[:] = np.dot(new_coordinates.dat.data, operator.T)

    return mesh.Mesh(new_coordinates)
示例#6
0
def PeriodicRectangleMesh(nx, ny, Lx, Ly, direction="both",
                          quadrilateral=False, reorder=None, comm=COMM_WORLD):
    """Generate a periodic rectangular mesh

    :arg nx: The number of cells in the x direction
    :arg ny: The number of cells in the y direction
    :arg Lx: The extent in the x direction
    :arg Ly: The extent in the y direction
    :arg direction: The direction of the periodicity, one of
        ``"both"``, ``"x"`` or ``"y"``.
    :kwarg quadrilateral: (optional), creates quadrilateral mesh, defaults to False
    :kwarg reorder: (optional), should the mesh be reordered
    :kwarg comm: Optional communicator to build the mesh on (defaults to
        COMM_WORLD).

    If direction == "x" the boundary edges in this mesh are numbered as follows:

    * 1: plane y == 0
    * 2: plane y == Ly

    If direction == "y" the boundary edges are:

    * 1: plane x == 0
    * 2: plane x == Lx
    """

    if direction not in ("both", "x", "y"):
        raise ValueError("Cannot have a periodic mesh with periodicity '%s'" % direction)
    if direction != "both":
        return PartiallyPeriodicRectangleMesh(nx, ny, Lx, Ly, direction=direction,
                                              quadrilateral=quadrilateral,
                                              reorder=reorder,
                                              comm=comm)
    if nx < 3 or ny < 3:
        raise ValueError("2D periodic meshes with fewer than 3 \
cells in each direction are not currently supported")

    m = TorusMesh(nx, ny, 1.0, 0.5, quadrilateral=quadrilateral, reorder=reorder,
                  comm=comm)
    coord_fs = VectorFunctionSpace(m, 'DG', 1, dim=2)
    old_coordinates = m.coordinates
    new_coordinates = Function(coord_fs)

    periodic_kernel = """
double pi = 3.141592653589793;
double eps = 1e-12;
double bigeps = 1e-1;
double phi, theta, Y, Z;
Y = 0.0;
Z = 0.0;

for(int i=0; i<old_coords.dofs; i++) {
    Y += old_coords[i][1];
    Z += old_coords[i][2];
}

for(int i=0; i<new_coords.dofs; i++) {
    phi = atan2(old_coords[i][1], old_coords[i][0]);
    if (fabs(sin(phi)) > bigeps)
        theta = atan2(old_coords[i][2], old_coords[i][1]/sin(phi) - 1.0);
    else
        theta = atan2(old_coords[i][2], old_coords[i][0]/cos(phi) - 1.0);

    new_coords[i][0] = phi/(2.0*pi);
    if(new_coords[i][0] < -eps) {
        new_coords[i][0] += 1.0;
    }
    if(fabs(new_coords[i][0]) < eps && Y < 0.0) {
        new_coords[i][0] = 1.0;
    }

    new_coords[i][1] = theta/(2.0*pi);
    if(new_coords[i][1] < -eps) {
        new_coords[i][1] += 1.0;
    }
    if(fabs(new_coords[i][1]) < eps && Z < 0.0) {
        new_coords[i][1] = 1.0;
    }

    new_coords[i][0] *= Lx[0];
    new_coords[i][1] *= Ly[0];
}
"""

    cLx = Constant(Lx)
    cLy = Constant(Ly)

    par_loop(periodic_kernel, dx,
             {"new_coords": (new_coordinates, WRITE),
              "old_coords": (old_coordinates, READ),
              "Lx": (cLx, READ),
              "Ly": (cLy, READ)})

    return mesh.Mesh(new_coordinates)
par_loop("""
double v0[3];
double v1[3];
double n[3];
double com[3];
double dot;
double norm;
norm = 0.0;
dot = 0.0;
// form "x1 - x0" and "x2 - x0" of cell base
for (int i=0; i<3; ++i) {
    v0[i] = coords[2][i] - coords[0][i];
    v1[i] = coords[4][i] - coords[0][i];
}

for (int i=0; i<3; ++i) {
    com[i] = 0.0;
}

// take cross-product to form normal vector
n[0] = v0[1] * v1[2] - v0[2] * v1[1];
n[1] = v0[2] * v1[0] - v0[0] * v1[2];
n[2] = v0[0] * v1[1] - v0[1] * v1[0];

// get (scaled) centre-of-mass of cell
for (int i=0; i<6; ++i) {
    com[0] += coords[i][0];
    com[1] += coords[i][1];
    com[2] += coords[i][2];
}

// is the normal pointing outwards or inwards w.r.t. origin?
for (int i=0; i<3; ++i) {
    dot += com[i]*n[i];
}

for (int i=0; i<3; ++i) {
    norm += n[i]*n[i];
}

// normalise normal vector and multiply by -1 if dot product was < 0
norm = sqrt(norm);
norm *= (dot < 0.0 ? -1.0 : 1.0);

for (int i=0; i<3; ++i) {
    normals[0][i] = n[i] / norm;
}
""", dx,
         {'normals': (zhat, WRITE),
          'coords': (mesh.coordinates, READ)})
示例#8
0
def PeriodicRectangleMesh(nx, ny, Lx, Ly, quadrilateral=False, reorder=None):
    """Generate a periodic rectangular mesh

    :arg nx: The number of cells in the x direction
    :arg ny: The number of cells in the y direction
    :arg Lx: The extent in the x direction
    :arg Ly: The extent in the y direction
    :kwarg quadrilateral: (optional), creates quadrilateral mesh, defaults to False
    :kwarg reorder: (optional), should the mesh be reordered
    """

    if nx < 3 or ny < 3:
        raise ValueError("2D periodic meshes with fewer than 3 \
cells in each direction are not currently supported")

    m = TorusMesh(nx, ny, 1.0, 0.5, quadrilateral=quadrilateral, reorder=reorder)
    coord_fs = VectorFunctionSpace(m, 'DG', 1, dim=2)
    old_coordinates = m.coordinates
    new_coordinates = Function(coord_fs)

    periodic_kernel = """
double pi = 3.141592653589793;
double eps = 1e-12;
double bigeps = 1e-1;
double phi, theta, Y, Z;
Y = 0.0;
Z = 0.0;

for(int i=0; i<old_coords.dofs; i++) {
    Y += old_coords[i][1];
    Z += old_coords[i][2];
}

for(int i=0; i<new_coords.dofs; i++) {
    phi = atan2(old_coords[i][1], old_coords[i][0]);
    if (fabs(sin(phi)) > bigeps)
        theta = atan2(old_coords[i][2], old_coords[i][1]/sin(phi) - 1.0);
    else
        theta = atan2(old_coords[i][2], old_coords[i][0]/cos(phi) - 1.0);

    new_coords[i][0] = phi/(2.0*pi);
    if(new_coords[i][0] < -eps) {
        new_coords[i][0] += 1.0;
    }
    if(fabs(new_coords[i][0]) < eps && Y < 0.0) {
        new_coords[i][0] = 1.0;
    }

    new_coords[i][1] = theta/(2.0*pi);
    if(new_coords[i][1] < -eps) {
        new_coords[i][1] += 1.0;
    }
    if(fabs(new_coords[i][1]) < eps && Z < 0.0) {
        new_coords[i][1] = 1.0;
    }

    new_coords[i][0] *= Lx[0];
    new_coords[i][1] *= Ly[0];
}
"""

    cLx = Constant(Lx)
    cLy = Constant(Ly)

    par_loop(periodic_kernel, dx,
             {"new_coords": (new_coordinates, WRITE),
              "old_coords": (old_coordinates, READ),
              "Lx": (cLx, READ),
              "Ly": (cLy, READ)})

    return mesh.Mesh(new_coordinates)