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); }
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); }
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); }
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); }
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]; } } }