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