public static double[] fem3d_transfer(int sample_node_num, int sample_element_order,
                                          int sample_element_num, int sample_value_dim, int sample_value_num,
                                          double[] sample_node_xyz, int[] sample_element_node,
                                          int[] sample_element_neighbor, double[] sample_value, int fem_node_num,
                                          int fem_element_order, int fem_element_num, int fem_value_dim,
                                          int fem_value_num, double[] fem_node_xyz, int[] fem_element_node)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    FEM3D_TRANSFER "transfers" from one finite element mesh to another.
    //
    //  BAD THINGS:
    //
    //    1) the linear system A*X=B is defined with A being a full storage matrix.
    //    2) the quadrature rule used is low order.
    //    3) the elements are assumed to be linear.
    //
    //  Discussion:
    //
    //    We are also given a set of "sample" finite element function defined
    //    by SAMPLE_NODE_XYZ, SAMPLE_ELEMENT, and SAMPLE_VALUE.
    //
    //    We are given a second finite element mesh, FEM_NODE_XYZ and
    //    FEM_ELEMENT_NODE.
    //
    //    Our aim is to "project" the sample data values into the finite element
    //    space, that is, to come up with a finite element function FEM_VALUE which
    //    well approximates the sample data.
    //
    //    Now let W(x,y,z) represent a function interpolating the sample data, and
    //    let Vijk(x,y,z) represent the finite element basis function associated with
    //    node IJK.
    //
    //    Then we seek the coefficient vector U corresponding to a finite element
    //    function U(x,y,z) of the form:
    //
    //      U(x,y,z) = sum ( 1 <= IJK <= N ) Uijk * Vijk(x,y,z)
    //
    //    To determine the coefficent vector entries U, we form a set of
    //    projection equations.  For node IJK at grid point (I,J,K), the associated
    //    basis function Vk(x,y,z) is used to pose the equation:
    //
    //      Integral U(x,y,z) Vijk(x,y,z) dx dy dz
    //        = Integral W(x,y,z) Vijk(x,y,z) dx dy dz
    //
    //    The left hand side is the usual stiffness matrix times the desired
    //    coefficient vector U.  To complete the system, we simply need to
    //    determine the right hand side, that is, the integral of the data function
    //    W against the basis function Vk.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    27 August 2009
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int SAMPLE_NODE_NUM, the number of nodes.
    //
    //    Input, int SAMPLE_ELEMENT_ORDER, the element order.
    //
    //    Input, int SAMPLE_ELEMENT_NUM, the number of elements.
    //
    //    Input, int SAMPLE_VALUE_DIM, the value dimension.
    //
    //    Input, int SAMPLE_VALUE_NUM, the number of values.
    //
    //    Input, double SAMPLE_NODE_XYZ[3*SAMPLE_NODE_NUM], the nodes.
    //
    //    Input, int SAMPLE_ELEMENT_NODE[SAMPLE_ELEMENT_ORDER*SAMPLE_ELEMENT_NUM],
    //    the nodes that make up each element.
    //
    //    Input, int SAMPLE_ELEMENT_NEIGHBOR[3*SAMPLE_ELEMENT_NUM],
    //    the neighbor triangles.
    //
    //    Input, double SAMPLE_VALUE[SAMPLE_VALUE_DIM*SAMPLE_NODE_NUM],
    //    the values.
    //
    //    Input, int FEM_NODE_NUM, the number of nodes.
    //
    //    Input, int FEM_ELEMENT_ORDER, the element order.
    //
    //    Input, int FEM_ELEMENT_NUM, the number of elements.
    //
    //    Input, int FEM_VALUE_DIM, the value dimension.
    //
    //    Input, int FEM_VALUE_NUM, the number of values.
    //
    //    Input, double FEM_NODE_XYZ[3*FEM_NODE_NUM], the nodes.
    //
    //    Input, int FEM_ELEMENT_NODE[FEM_ELEMENT_ORDER*FEM_ELEMENT_NUM],
    //    the nodes that make up each element.
    //
    //    Output, double FEM3D_TRANSFER[FEM_VALUE_DIM*FEM_VALUE_NUM],
    //    the values.
    //
    {
        int       element;
        int       i;
        int       j;
        const int project_node_num = 1;

        double[]  project_node_xyz = new double[3 * 1];
        const int quad_num         = 4;

        //
        //  Assemble the coefficient matrix A and the right-hand side B.
        //
        double[] b = typeMethods.r8mat_zero_new(fem_node_num, fem_value_dim);
        double[] a = typeMethods.r8mat_zero_new(fem_node_num, fem_node_num);

        double[] phi        = new double[4];
        double[] ref_weight = new double[quad_num];
        double[] ref_quad   = new double[4 * quad_num];
        double[] tet_quad   = new double[3 * quad_num];
        double[] tet_xyz    = new double[3 * 4];

        // Upstream doesn't initialize the arrays and seems to rely on weird default values.
        // Mimic here.
        for (int shim = 0; shim < phi.Length; shim++)
        {
            phi[shim] = -6.2774385622041925e+66;
        }
        for (int shim = 0; shim < ref_weight.Length; shim++)
        {
            ref_weight[shim] = -6.2774385622041925e+66;
        }
        for (int shim = 0; shim < ref_quad.Length; shim++)
        {
            ref_quad[shim] = -6.2774385622041925e+66;
        }
        for (int shim = 0; shim < tet_quad.Length; shim++)
        {
            tet_quad[shim] = -6.2774385622041925e+66;
        }
        for (int shim = 0; shim < tet_xyz.Length; shim++)
        {
            tet_xyz[shim] = -6.2774385622041925e+66;
        }

        for (element = 0; element < fem_element_num; element++)
        {
            for (j = 0; j < 4; j++)
            {
                for (i = 0; i < 3; i++)
                {
                    int j2 = fem_element_node[j + element * 4];
                    tet_xyz[i + j * 3] = fem_node_xyz[i + j2 * 3];
                }
            }

            double volume = Tetrahedron.tetrahedron_volume(tet_xyz);

            for (j = 0; j < quad_num; j++)
            {
                for (i = 0; i < 3; i++)
                {
                    tet_quad[i + j * 3] = 0.0;
                    int k;
                    for (k = 0; k < 4; k++)
                    {
                        double tq = tet_quad[i + j * 3];
                        double tx = tet_xyz[i + k * 3];
                        double rq = ref_quad[k + j * 4];

                        tet_quad[i + j * 3] = tq + tx * rq;
                    }
                }
            }

            //
            //  Consider each quadrature point.
            //  Here, we use the midside nodes as quadrature points.
            //
            int quad;
            for (quad = 0; quad < quad_num; quad++)
            {
                for (i = 0; i < 3; i++)
                {
                    project_node_xyz[i + 0 * 3] = tet_quad[i + quad * 3];
                }

                Basis_mn.basis_mn_tet4(tet_xyz, 1, project_node_xyz, ref phi);

                for (i = 0; i < 4; i++)
                {
                    int ni = fem_element_node[i + element * fem_element_order];
                    //
                    //  The projection takes place here.  The finite element code needs the value
                    //  of the sample function at the point (XQ,YQ).  The call to PROJECTION
                    //  locates (XQ,YQ) in the triangulated mesh of sample data, and returns a
                    //  value produced by piecewise linear interpolation.
                    //
                    double[] project_value = FEM_3D_Projection.projection(sample_node_num, sample_node_xyz,
                                                                          sample_element_order, sample_element_num, sample_element_node,
                                                                          sample_element_neighbor, sample_value_dim, sample_value,
                                                                          project_node_num, project_node_xyz);

                    for (j = 0; j < fem_value_dim; j++)
                    {
                        b[ni + j * fem_node_num] += volume * ref_weight[quad] *
                                                    (project_value[j + 0 * fem_value_dim] * phi[i]);
                    }

                    //
                    //  Consider each basis function in the element.
                    //
                    for (j = 0; j < 4; j++)
                    {
                        int nj = fem_element_node[j + element * fem_element_order];

                        a[ni + nj * fem_node_num] += volume * ref_weight[quad] * (phi[i] * phi[j]);
                    }
                }
            }
        }

        //
        //  SOLVE the linear system A * X = B.
        //
        double[] x = Solve.r8ge_fss_new(fem_node_num, a, fem_value_dim, b);
        //
        //  Copy solution.
        //
        double[] fem_value = new double[fem_value_dim * fem_value_num];

        for (j = 0; j < fem_value_num; j++)
        {
            for (i = 0; i < fem_value_dim; i++)
            {
                fem_value[(i + j * fem_value_dim + fem_value.Length) % fem_value.Length] = x[(j + i * fem_value_num + x.Length) % x.Length];
            }
        }

        return(fem_value);
    }
예제 #2
0
    public static void derivative_average_t3(int node_num, double[] node_xy, int element_num,
                                             int[] element_node, double[] c, double[] dcdx, double[] dcdy)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    DERIVATIVE_AVERAGE_T3 averages derivatives at the nodes of a T3 mesh.
    //
    //  Discussion:
    //
    //    This routine can be used to compute an averaged nodal value of any
    //    quantity associated with the finite element function.  At a node
    //    that is shared by several elements, the fundamental function
    //    U will be continuous, but its spatial derivatives, for instance,
    //    will generally be discontinuous.  This routine computes the
    //    value of the spatial derivatives in each element, and averages
    //    them, to make a reasonable assignment of a nodal value.
    //
    //    Note that the ELEMENT_NODE array is assumed to be 1-based, rather
    //    than 0-based.  Thus, entries from this array must be decreased by
    //    1 before being used!
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    10 June 2006
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int NODE_NUM, the number of nodes.
    //
    //    Input, double NODE_XY[2*NODE_NUM], the coordinates of the nodes.
    //
    //    Input, int ELEMENT_NUM, the number of elements.
    //
    //    Input, int ELEMENT_NODE[3*ELEMENT_NUM], the element->node data.
    //
    //    Input, double C[NODE_NUM], the finite element coefficient vector.
    //
    //    Output, double DCDX[NODE_NUM], DCDY[NODE_NUM], the averaged
    //    values of dCdX and dCdY at the nodes.
    //
    {
        const int OFFSET = 1;

        double[] dphidx = new double[3 * 3];
        double[] dphidy = new double[3 * 3];
        int      element;
        int      node;

        int[]    node_count = new int[node_num];
        double[] phi        = new double[3 * 3];
        double[] t          = new double[2 * 3];

        for (node = 0; node < node_num; node++)
        {
            node_count[node] = 0;
            dcdx[node]       = 0.0;
            dcdy[node]       = 0.0;
        }

        //
        //  Consider every element.
        //
        for (element = 0; element < element_num; element++)
        {
            //
            //  Get the coordinates of the nodes of the element.
            //
            int j;
            for (j = 0; j < 3; j++)
            {
                int dim;
                for (dim = 0; dim < 2; dim++)
                {
                    t[dim + 2 * j] = node_xy[dim + (element_node[j + element * 3] - OFFSET)];
                }
            }

            //
            //  Evaluate the X and Y derivatives of the 3 basis functions at the
            //  3 nodes.
            //
            Basis_mn.basis_mn_t3(t, 3, t, ref phi, ref dphidx, ref dphidy);
            //
            //  Evaluate dCdX and dCdY at each node in the element, and add
            //  them to the running totals.
            //
            int node_local1;
            for (node_local1 = 0; node_local1 < 3; node_local1++)
            {
                int node_global1 = element_node[node_local1 + element * 3] - OFFSET;

                int node_local2;
                for (node_local2 = 0; node_local2 < 3; node_local2++)
                {
                    int node_global2 = element_node[node_local2 + element * 3] - OFFSET;

                    dcdx[node_global1] += c[node_global2] * dphidx[node_local2 + node_local1 * 3];

                    dcdy[node_global1] += c[node_global2] * dphidy[node_local2 + node_local1 * 3];
                }

                node_count[node_global1] += 1;
            }
        }

        //
        //  Average the running totals.
        //
        for (node = 0; node < node_num; node++)
        {
            dcdx[node] /= node_count[node];
            dcdy[node] /= node_count[node];
        }
    }
    public static double[] fem3d_evaluate(int fem_node_num, double[] fem_node_xyz,
                                          int fem_element_order, int fem_element_num, int[] fem_element_node,
                                          int[] fem_element_neighbor, int fem_value_dim, double[] fem_value,
                                          int sample_node_num, double[] sample_node_xyz)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    FEM3D_EVALUATE samples an FEM function on a T4 tet mesh.
    //
    //  Discussion:
    //
    //    Note that the sample values returned are true values of the underlying
    //    finite element function.  They are NOT produced by constructing some
    //    other function that interpolates the data at the finite element nodes
    //    (something which MATLAB's griddata function can easily do.)  Instead,
    //    each sampling node is located within one of the associated finite
    //    element tetrahedrons, and the finite element function is developed and
    //    evaluated there.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    08 August 2009
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int FEM_NODE_NUM, the number of nodes.
    //
    //    Input, double FEM_NODE_XYZ[3*FEM_NODE_NUM], the coordinates
    //    of the nodes.
    //
    //    Input, int FEM_ELEMENT_ORDER, the order of the elements,
    //    which should be 4.
    //
    //    Input, int FEM_ELEMENT_NUM, the number of elements.
    //
    //    Input, int FEM_ELEMENT_NODE[FEM_ELEMENT_ORDER*FEM_ELEMENT_NUM], the
    //    nodes that make up each element.
    //
    //    Input, int FEM_ELEMENT_NEIGHBOR[4*FEM_ELEMENT_NUM], the
    //    index of the neighboring element on each side, or -1 if no neighbor there.
    //
    //    Input, int FEM_VALUE_DIM, the "dimension" of the values.
    //
    //    Input, double FEM_VALUE[FEM_VALUE_DIM*FEM_NODE_NUM], the
    //    finite element coefficient values at each node.
    //
    //    Input, int SAMPLE_NODE_NUM, the number of sample nodes.
    //
    //    Input, double SAMPLE_NODE_XYZ[3*SAMPLE_NODE_NUM], the sample nodes.
    //
    //    Output, double) FEM3D_EVALUATE[FEM_VALUE_DIM*SAMPLE_NODE_NUM],
    //    the sampled values.
    //
    {
        int j;

        double[] p_xyz = new double[3];

        double[] b            = new double[fem_element_order];
        double[] sample_value = new double[fem_value_dim * sample_node_num];
        int[]    t_node       = new int[fem_element_order];
        double[] t_xyz        = new double[3 * fem_element_order];
        //
        //  For each sample point: find the element T that contains it,
        //  and evaluate the finite element function there.
        //
        for (j = 0; j < sample_node_num; j++)
        {
            p_xyz[0] = sample_node_xyz[0 + j * 3];
            p_xyz[1] = sample_node_xyz[1 + j * 3];
            p_xyz[2] = sample_node_xyz[2 + j * 3];
            //
            //  Find the element T that contains the point.
            //
            int step_num = 0;
            int t        = TetMesh.tet_mesh_search_naive(fem_node_num, fem_node_xyz,
                                                         fem_element_order, fem_element_num, fem_element_node,
                                                         p_xyz, ref step_num);
            //
            //  Evaluate the finite element basis functions at the point in T.
            //
            int i;
            for (i = 0; i < fem_element_order; i++)
            {
                t_node[i] = fem_element_node[i + t * fem_element_order];
            }

            for (i = 0; i < fem_element_order; i++)
            {
                t_xyz[0 + i * 3] = fem_node_xyz[0 + t_node[i] * 3];
                t_xyz[1 + i * 3] = fem_node_xyz[1 + t_node[i] * 3];
                t_xyz[2 + i * 3] = fem_node_xyz[2 + t_node[i] * 3];
            }

            Basis_mn.basis_mn_tet4(t_xyz, 1, p_xyz, ref b);
            //
            //  Multiply by the finite element values to get the sample values.
            //
            for (i = 0; i < fem_value_dim; i++)
            {
                sample_value[i + j * fem_value_dim] = 0.0;
                int k;
                for (k = 0; k < fem_element_order; k++)
                {
                    sample_value[i + j * fem_value_dim] += fem_value[i + t_node[k] * fem_value_dim] * b[k];
                }
            }
        }

        return(sample_value);
    }
예제 #4
0
    public static double[] projection(int fem_node_num, double[] fem_node_xy,
                                      int fem_element_order, int fem_element_num, int[] fem_element_node,
                                      int[] fem_element_neighbor, int fem_value_dim, double[] fem_value,
                                      int sample_node_num, double[] sample_node_xy)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    PROJECTION evaluates an FEM function on a T3 or T6 triangulation.
    //
    //  Discussion:
    //
    //    Note that the sample values returned are true values of the underlying
    //    finite element function.  They are NOT produced by constructing some
    //    other function that interpolates the data at the finite element nodes
    //    (something which MATLAB's griddata function can easily do.)  Instead,
    //    each sampling node is located within one of the associated finite
    //    element triangles, and the finite element function is developed and
    //    evaluated there.
    //
    //    MATLAB's scattered data interpolation is wonderful, but it cannot
    //    be guaranteed to reproduce the finite element function corresponding
    //    to nodal data.  This routine can (or at least tries to//).
    //
    //    So if you are using finite elements, then using THIS routine
    //    (but not MATLAB's griddata function), what you see is what you have//
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    31 July 2009
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int FEM_NODE_NUM, the number of nodes.
    //
    //    Input, double FEM_NODE_XY[2*FEM_NODE_NUM], the coordinates
    //    of the nodes.
    //
    //    Input, int FEM_ELEMENT_ORDER, the order of the elements,
    //    either 3 or 6.
    //
    //    Input, int FEM_ELEMENT_NUM, the number of triangles.
    //
    //    Input, int FEM_ELEMENT_NODE(FEM_ELEMENT_ORDER,FEM_ELEMENT_NUM), the
    //    nodes that make up each triangle.
    //
    //    Input, int FEM_ELEMENT_NEIGHBOR[3*FEM_ELEMENT_NUM], the
    //    index of the neighboring triangle on each side, or -1 if no neighbor there.
    //
    //    Input, int FEM_VALUE_DIM, the "dimension" of the values.
    //
    //    Input, double FEM_VALUE[FEM_VALUE_DIM*FEM_NODE_NUM], the
    //    finite element coefficient values at each node.
    //
    //    Input, int SAMPLE_NODE_NUM, the number of sample nodes.
    //
    //    Input, double SAMPLE_NODE_XY[2*SAMPLE_NODE_NUM], the sample nodes.
    //
    //    Output, double PROJECTION[FEM_VALUE_DIM*SAMPLE_NODE_NUM],
    //    the sampled values.
    //
    {
        int edge = 0;
        int j;

        double[]           p_xy   = new double[2];
        int                t      = 0;
        DelaunaySearchData data   = new();
        double             alpha  = 0;
        double             beta   = 0;
        double             gammaa = 0;
        int                step   = 0;

        double[] b            = new double[fem_element_order];
        double[] dbdx         = new double[fem_element_order];
        double[] dbdy         = new double[fem_element_order];
        double[] sample_value = new double[fem_value_dim * sample_node_num];
        int[]    t_node       = new int[fem_element_order];
        double[] t_xy         = new double[2 * fem_element_order];
        //
        //  For each sample point: find the triangle T that contains it,
        //  and evaluate the finite element function there.
        //
        for (j = 0; j < sample_node_num; j++)
        {
            p_xy[0] = sample_node_xy[0 + 2 * j];
            p_xy[1] = sample_node_xy[1 + 2 * j];
            //
            //  Find the triangle T that contains the point.
            //
            Search.triangulation_search_delaunay_a(ref data, fem_node_num, fem_node_xy,
                                                   fem_element_order, fem_element_num, fem_element_node,
                                                   fem_element_neighbor, p_xy, ref t, ref alpha, ref beta, ref gammaa, ref edge, ref step);

            switch (t)
            {
            case -1:
                Console.WriteLine("");
                Console.WriteLine("PROJECTION - Fatal error!");
                Console.WriteLine("  Triangulation search failed.");
                return(null);
            }

            //
            //  Evaluate the finite element basis functions at the point in T.
            //
            int i;
            for (i = 0; i < fem_element_order; i++)
            {
                t_node[i]       = fem_element_node[(i + t * fem_element_order) % fem_element_node.Length];
                t_xy[0 + i * 2] = fem_node_xy[0 + t_node[i] * 2];
                t_xy[1 + i * 2] = fem_node_xy[1 + t_node[i] * 2];
            }

            switch (fem_element_order)
            {
            case 3:
                Basis_mn.basis_mn_t3(t_xy, 1, p_xy, ref b, ref dbdx, ref dbdy);
                break;

            case 6:
                Basis_mn.basis_mn_t6(t_xy, 1, p_xy, ref b, ref dbdx, ref dbdy);
                break;
            }

            //
            //  Multiply by the finite element values to get the sample values.
            //
            for (i = 0; i < fem_value_dim; i++)
            {
                double dot = 0.0;
                int    k;
                for (k = 0; k < fem_element_order; k++)
                {
                    dot += fem_value[i + t_node[k] * fem_value_dim] * b[k];
                }

                sample_value[i + j * fem_value_dim] = dot;
            }
        }

        return(sample_value);
    }
예제 #5
0
    public static double[] fem2d_evaluate(int fem_node_num, double[] fem_node_xy,
                                          int fem_element_order, int fem_element_num, int[] fem_element_node,
                                          int[] fem_element_neighbor, int fem_value_dim, double[] fem_value,
                                          int sample_node_num, double[] sample_node_xy)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    GRID_SAMPLE samples a (scalar) FE function on a T3 or T6 triangulation.
    //
    //  Discussion:
    //
    //    Note that the values of U returned are true values of the underlying
    //    finite element function.  They are NOT produced by constructing some
    //    other function that interpolates the data at the finite element nodes
    //    (something which MATLAB's griddata function can easily do.)  Instead,
    //    each sampling node is located within one of the associated finite
    //    element triangles, and the finite element function is developed and
    //    evaluated there.
    //
    //    MATLAB's scattered data interpolation is wonderful, but it cannot
    //    be guaranteed to reproduce the finite element function corresponding
    //    to nodal data.  This routine can.
    //
    //    So if you are using finite elements, then using THIS routine
    //    (but not MATLAB's griddata function), what you see is what you have.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    01 June 2009
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int FEM_NODE_NUM, the number of nodes.
    //
    //    Input, double FEM_NODE_XY[2*FEM_NODE_NUM], the coordinates of the nodes.
    //
    //    Input, int FEM_ELEMENT_ORDER, the order of the triangles, either
    //    3 or 6.
    //
    //    Input, int FEM_ELEMENT_NUM, the number of triangles.
    //
    //    Input, int FEM_ELEMENT_NODE[FEM_ELEMENT_ORDER*FEM_ELEMENT_NUM], the
    //    nodes that make up each element.
    //
    //    Input, int FEM_ELEMENT_NEIGHBOR[3*FEM_ELEMENT_NUM], the index of the
    //    neighboring triangle on each side, or -1 if no neighbor there.
    //
    //    Input, int FEM_VALUE_DIM, the "dimension" of the values.
    //
    //    Input, double FEM_VALUE[FEM_VALUE_DIM*FEM_NODE_NUM], the finite element
    //    coefficient value at each node.
    //
    //    Input, int SAMPLE_NODE_NUM, the number of sample nodes.
    //
    //    Input, double SAMPLE_NODE_XY[2*SAMPLE_NODE_NUM], the sample nodes.
    //
    //    Output, double SAMPLE_VALUE[FEM_VALUE_DIM*SAMPLE_NODE_NUM],
    //    the sampled values.
    //
    {
        int edge = 0;
        int j;

        double[] p_xy = new double[2];
        int      t    = 0;

        double[] b            = new double[fem_element_order];
        double[] dbdx         = new double[fem_element_order];
        double[] dbdy         = new double[fem_element_order];
        double[] sample_value = new double[fem_value_dim * sample_node_num];
        int[]    t_node       = new int[fem_element_order];
        double[] t_xy         = new double[2 * fem_element_order];
        //
        //  For each sample point: find the triangle T that contains it,
        //  and evaluate the finite element function there.
        //
        for (j = 0; j < sample_node_num; j++)
        {
            p_xy[0] = sample_node_xy[0 + j * 2];
            p_xy[1] = sample_node_xy[1 + j * 2];
            //
            //  Find the triangle T that contains the point.
            //

            /*
             * Search.triangulation_search_delaunay(fem_node_num, fem_node_xy,
             *  fem_element_order, fem_element_num, fem_element_node,
             *  fem_element_neighbor, p_xy, ref t, ref edge);
             */

            Search.triangulation_search_delaunay(fem_node_num, fem_node_xy,
                                                 fem_element_order, fem_element_num, fem_element_node,
                                                 fem_element_neighbor, p_xy, ref t, ref edge);

            //
            //  Evaluate the finite element basis functions at the point in T.
            //
            //  Note that in the following loop, we assume that FEM_ELEMENT_NODE
            //  is 1-based, and that for convenience we can get away with making
            //  T_NODE 0-based.
            //
            int order;
            for (order = 0; order < fem_element_order; order++)
            {
                t_node[order] = fem_element_node[order + (t - 1) * fem_element_order] - 1;
            }

            for (order = 0; order < fem_element_order; order++)
            {
                t_xy[0 + order * 2] = fem_node_xy[0 + t_node[order] * 2];
                t_xy[1 + order * 2] = fem_node_xy[1 + t_node[order] * 2];
            }

            switch (fem_element_order)
            {
            case 3:
                Basis_mn.basis_mn_t3(t_xy, 1, p_xy, ref b, ref dbdx, ref dbdy);
                break;

            case 6:
                Basis_mn.basis_mn_t6(t_xy, 1, p_xy, ref b, ref dbdx, ref dbdy);
                break;
            }

            //
            //  Multiply by the finite element values to get the sample values.
            //
            int i;
            for (i = 0; i < fem_value_dim; i++)
            {
                double dot = 0.0;
                for (order = 0; order < fem_element_order; order++)
                {
                    dot += fem_value[i + t_node[order]] * b[order];
                }

                sample_value[i + j * fem_value_dim] = dot;
            }
        }

        return(sample_value);
    }
    public static double[] projection(int fem_node_num, double[] fem_node_xyz,
                                      int fem_element_order, int fem_element_num, int[] fem_element_node,
                                      int[] fem_element_neighbor, int fem_value_dim, double[] fem_value,
                                      int sample_node_num, double[] sample_node_xyz)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    PROJECTION evaluates an FEM function on a T3 or T6 triangulation.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    27 August 2009
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int FEM_NODE_NUM, the number of nodes.
    //
    //    Input, double FEM_NODE_XYZ[3*FEM_NODE_NUM], the coordinates
    //    of the nodes.
    //
    //    Input, int FEM_ELEMENT_ORDER, the order of the elements.
    //
    //    Input, int FEM_ELEMENT_NUM, the number of elements.
    //
    //    Input, int FEM_ELEMENT_NODE(FEM_ELEMENT_ORDER,FEM_ELEMENT_NUM), the
    //    nodes that make up each element.
    //
    //    Input, int FEM_ELEMENT_NEIGHBOR[4*FEM_ELEMENT_NUM], the
    //    index of the neighboring element on each side, or -1 if no neighbor there.
    //
    //    Input, int FEM_VALUE_DIM, the "dimension" of the values.
    //
    //    Input, double FEM_VALUE[FEM_VALUE_DIM*FEM_NODE_NUM], the
    //    finite element coefficient values at each node.
    //
    //    Input, int SAMPLE_NODE_NUM, the number of sample nodes.
    //
    //    Input, double SAMPLE_NODE_XYZ[3*SAMPLE_NODE_NUM], the sample nodes.
    //
    //    Output, double PROJECTION[FEM_VALUE_DIM*SAMPLE_NODE_NUM],
    //    the sampled values.
    //
    {
        int face = 0;
        int j;

        double[] p_xyz    = new double[3];
        int      step_num = 0;

        double[] b            = new double[fem_element_order];
        double[] sample_value = new double[fem_value_dim * sample_node_num];
        double[] t_xyz        = new double[3 * fem_element_order];
        //
        //  For each sample point: find the element T that contains it,
        //  and evaluate the finite element function there.
        //
        for (j = 0; j < sample_node_num; j++)
        {
            p_xyz[0] = sample_node_xyz[0 + 3 * j];
            p_xyz[1] = sample_node_xyz[1 + 3 * j];
            p_xyz[2] = sample_node_xyz[2 + 3 * j];
            //
            //  Find the triangle T that contains the point.
            //
            int t = TetMesh.tet_mesh_search_delaunay(fem_node_num, fem_node_xyz,
                                                     fem_element_order, fem_element_num, fem_element_node,
                                                     fem_element_neighbor, p_xyz, ref face, ref step_num);

            switch (t)
            {
            case -1:
                Console.WriteLine("");
                Console.WriteLine("PROJECTION - Fatal error!");
                Console.WriteLine("  Search failed.");
                return(null);
            }

            //
            //  Evaluate the finite element basis functions at the point in T.
            //
            int t_node;
            int i;
            for (i = 0; i < fem_element_order; i++)
            {
                t_node           = fem_element_node[i + t * fem_element_order];
                t_xyz[0 + i * 3] = fem_node_xyz[0 + t_node * 3];
                t_xyz[1 + i * 3] = fem_node_xyz[1 + t_node * 3];
                t_xyz[2 + i * 3] = fem_node_xyz[2 + t_node * 3];
            }

            Basis_mn.basis_mn_tet4(t_xyz, 1, p_xyz, ref b);
            //
            //  Multiply by the finite element values to get the sample values.
            //
            for (i = 0; i < fem_value_dim; i++)
            {
                double dot = 0.0;
                int    k;
                for (k = 0; k < fem_element_order; k++)
                {
                    t_node = fem_element_node[k + t * fem_element_order];
                    dot   += fem_value[i + t_node * fem_value_dim] * b[k];
                }

                sample_value[i + j * fem_value_dim] = dot;
            }
        }

        return(sample_value);
    }
예제 #7
0
    public static void div_q4(int m, int n, double[] u, double[] v, double xlo, double xhi,
                              double ylo, double yhi, ref double[] div, ref double[] vort)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    DIV_Q4 estimates the divergence and vorticity of a discrete field.
    //
    //  Discussion:
    //
    //    The routine is given the values of a vector field ( U(X,Y), V(X,Y) ) at
    //    an array of points ( X(1:M), Y(1:N) ).
    //
    //    The routine models the vector field over the interior of this region using
    //    a bilinear interpolant.  It then uses the interpolant to estimate the
    //    value of the divergence:
    //
    //      DIV(X,Y) = dU/dX + dV/dY
    //
    //    and the vorticity:
    //
    //      VORT(X,Y) = dV/dX - dU/dY
    //
    //    at the center point of each of the bilinear elements.
    //
    //        |       |       |
    //      (3,1)---(3,2)---(3,3)---
    //        |       |       |
    //        | [2,1] | [2,2] |
    //        |       |       |
    //      (2,1)---(2,2)---(2,3)---
    //        |       |       |
    //        | [1,1] | [1,2] |
    //        |       |       |
    //      (1,1)---(1,2)---(1,3)---
    //
    //    Here, the nodes labeled with parentheses represent the points at
    //    which the original (U,V) data is given, while the nodes labeled
    //    with square brackets represent the centers of the bilinear
    //    elements, where the approximations to the divergence and vorticity
    //    are made.
    //
    //    The reason for evaluating the divergence and vorticity in this way
    //    is that the bilinear interpolant to the (U,V) data is not
    //    differentiable at the boundaries of the elements, nor especially at
    //    the nodes, but is an (infinitely differentiable) bilinear function
    //    in the interior of each element.  If a value at the original nodes
    //    is strongly desired, then the average at the four surrounding
    //    central nodes may be taken.
    //
    //  Element Q4:
    //
    //    |
    //    1  4-----3
    //    |  |     |
    //    |  |     |
    //    S  |     |
    //    |  |     |
    //    |  |     |
    //    0  1-----2
    //    |
    //    +--0--R--1-->
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    02 February 2006
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Parameters:
    //
    //    Input, int M, the number of data rows.  M must be at least 2.
    //
    //    Input, int N, the number of data columns.  N must be at least 2.
    //
    //    Input, double U[M*N], V[M*N], the value of the components
    //    of a vector quantity whose divergence and vorticity are desired.
    //    A common example would be that U and V are the horizontal and
    //    vertical velocity component of a flow field.
    //
    //    Input, double XLO, XHI, the minimum and maximum X coordinates.
    //
    //    Input, double YLO, YHI, the minimum and maximum Y coordinates.
    //
    //    Output, double DIV[(M-1)*(N-1)], an estimate for
    //    the divergence in the bilinear element that lies between
    //    data rows I and I+1, and data columns J and J+1.
    //
    //    Output, double VORT[(M-1)*(N-1)], an estimate for
    //    the vorticity in the bilinear element that lies between
    //    data rows I and I+1, and data columns J and J+1.
    //
    {
        double[] dphidx = new double[4];
        double[] dphidy = new double[4];
        int      i;

        double[] p   = new double[2];
        double[] phi = new double[4];
        double[] q   = new double[2 * 4];

        switch (m)
        {
        case <= 1:
            Console.WriteLine("");
            Console.WriteLine("DIV_Q4 - Fatal error!");
            Console.WriteLine("  M must be at least 2,");
            Console.WriteLine("  but the input value of M is " + m + "");
            return;
        }

        switch (n)
        {
        case <= 1:
            Console.WriteLine("");
            Console.WriteLine("DIV_Q4 - Fatal error!");
            Console.WriteLine("  N must be at least 2,");
            Console.WriteLine("  but the input value of N is " + n + "");
            return;
        }

        if (Math.Abs(xhi - xlo) <= double.Epsilon)
        {
            Console.WriteLine("");
            Console.WriteLine("DIV_Q4 - Fatal error!");
            Console.WriteLine("  XHI and XLO must be distinct,");
            Console.WriteLine("  but the input value of XLO is " + xlo + "");
            Console.WriteLine("  and the input value of XHI is " + xhi + "");
            return;
        }

        if (Math.Abs(yhi - ylo) <= double.Epsilon)
        {
            Console.WriteLine("");
            Console.WriteLine("DIV_Q4 - Fatal error!");
            Console.WriteLine("  YHI and YLO must be distinct,");
            Console.WriteLine("  but the input value of YLO is " + ylo + "");
            Console.WriteLine("  and the input value of YHI is " + yhi + "");
            return;
        }

        for (i = 1; i <= m - 1; i++)
        {
            double yb = ((2 * m - 2 * i) * ylo
                         + (2 * i - 2) * yhi)
                        / (2 * m - 2);
            p[1] = ((2 * m - 2 * i - 1) * ylo
                    + (2 * i - 1) * yhi)
                   / (2 * m - 2);
            double yt = ((2 * m - 2 * i - 2) * ylo
                         + 2 * i * yhi)
                        / (2 * m - 2);

            q[1 + 0 * 2] = yb;
            q[1 + 1 * 2] = yb;
            q[1 + 2 * 2] = yt;
            q[1 + 3 * 2] = yt;

            int j;
            for (j = 1; j <= n - 1; j++)
            {
                double xl = ((2 * n - 2 * j) * xlo
                             + (2 * j - 2) * xhi)
                            / (2 * n - 2);
                p[0] = ((2 * n - 2 * j - 1) * xlo
                        + (2 * j - 1) * xhi)
                       / (2 * n - 2);
                double xr = ((2 * n - 2 * j - 2) * xlo
                             + 2 * j * xhi)
                            / (2 * n - 2);

                q[0 + 0 * 2] = xl;
                q[0 + 1 * 2] = xr;
                q[0 + 2 * 2] = xr;
                q[0 + 3 * 2] = xl;
                //
                //  Evaluate the basis function and derivatives at the center of the element.
                //
                Basis_mn.basis_mn_q4(q, 1, p, ref phi, ref dphidx, ref dphidy);
                //
                //  Note the following formula for the value of U and V at the same
                //  point that the divergence and vorticity are being evaluated.
                //
                //         umid =  u(i  ,j  ) * phi[0] &
                //               + u(i  ,j+1) * phi[1] &
                //               + u(i+1,j+1) * phi[2] &
                //               + u(i+1,j  ) * phi[3]
                //
                //         vmid =  v(i  ,j  ) * phi[0] &
                //               + v(i  ,j+1) * phi[1] &
                //               + v(i+1,j+1) * phi[2] &
                //               + v(i+1,j  ) * phi[3]
                //
                div[i - 1 + (j - 1) * (m - 1)] =
                    u[i - 1 + (j - 1) * m] * dphidx[0] + v[i - 1 + (j - 1) * m] * dphidy[0]
                    + u[i - 1 + j * m] * dphidx[1] +
                    v[i - 1 + j * m] * dphidy[1]
                    + u[i + j * m] * dphidx[2] + v[i + j * m] * dphidy[2]
                    + u[i + (j - 1) * m] * dphidx[3] +
                    v[i + (j - 1) * m] * dphidy[3];

                vort[i - 1 + (j - 1) * (m - 1)] =
                    v[i - 1 + (j - 1) * m] * dphidx[0] - u[i - 1 + (j - 1) * m] * dphidy[0]
                    + v[i - 1 + j * m] * dphidx[1] - u[i - 1 + j * m] * dphidy[1]
                    + v[i + j * m] * dphidx[2] - u[i + j * m] * dphidy[2]
                    + v[i + (j - 1) * m] * dphidx[3] - u[i + (j - 1) * m] * dphidy[3];
            }
        }
    }