#ifndef _TETRA_VZ_H #define _TETRA_VZ_H #include "cmath" #define ZERO 1e-20 #define G0 6.67408e-11 /** * Define the point structure in 3D space */ struct point3d { double x, y, z; double module() const; // module point3d normal() const; // normal vector }; double point3d::module() const { return sqrt(x*x + y*y + z*z); } point3d point3d::normal() const { point3d nor_v; double length = module(); if (length <= ZERO) { nor_v.x = nor_v.y = nor_v.z = 0.0; } else { nor_v.x = x/length; nor_v.y = y/length; nor_v.z = z/length; } return nor_v; } point3d operator+(const point3d &a, const point3d &b) // Add { point3d m; m.x = a.x+b.x; m.y = a.y+b.y; m.z = a.z+b.z; return m; } point3d operator-(const point3d &a, const point3d &b) // Minus { point3d m; m.x = a.x-b.x; m.y = a.y-b.y; m.z = a.z-b.z; return m; } point3d operator*(double scale, const point3d &b) // Multiply { point3d m; m.x = scale*b.x; m.y = scale*b.y; m.z = scale*b.z; return m; } double dot(const point3d &a, const point3d &b) // Dot { return a.x*b.x+a.y*b.y+a.z*b.z; } double distance(const point3d &a, const point3d &b) // Distance { return (a - b).module(); } point3d cross(const point3d &a, const point3d &b) // Cross { point3d v; v.x = a.y*b.z-a.z*b.y; v.y = a.z*b.x-a.x*b.z; v.z = a.x*b.y-a.y*b.x; if (fabs(v.x) <= ZERO) v.x = 0; if (fabs(v.y) <= ZERO) v.y = 0; if (fabs(v.z) <= ZERO) v.z = 0; return v; } /** * Define the tensor structure */ struct tensor { double val[3][3]; }; tensor kron(const point3d &a, const point3d &b) // tensor product { tensor t; t.val[0][0]=a.x*b.x; t.val[0][1]=a.x*b.y; t.val[0][2]=a.x*b.z; t.val[1][0]=a.y*b.x; t.val[1][1]=a.y*b.y; t.val[1][2]=a.y*b.z; t.val[2][0]=a.z*b.x; t.val[2][1]=a.z*b.y; t.val[2][2]=a.z*b.z; return t; } /** * Define the tetrahedron structure * * regular type of tetrahedron * 3 * /|\ * / | \ y * z / | \ / * | / 1 \ * | / / \ \ * |/ / \ \ * 0-------------2----> x * * triangle list (anti-clockwise) * 0 1 2 * 0 2 3 * 0 3 1 * 1 3 2 * * inverse type of tetrahedron * 3 * /|\ * / | \ y * z / | \ / * | / 2 \ * | / / \ \ * |/ / \ \ * 0-------------1----> x * * triangle list (anti-clockwise) * 0 1 3 * 0 2 1 * 0 3 2 * 1 2 3 */ static int regular_order[12] = {0,1,2,0,2,3,0,3,1,1,3,2}; static int inverse_order[12] = {0,1,3,0,2,1,0,3,2,1,2,3}; struct tetrahedron { bool regular_type; point3d *vec_ptr[4]; tensor F[4]; tensor E[12]; double rho; double edglen[12]; void initialize_tensors(); }; void tetrahedron::initialize_tensors() { point3d v1, v2, v3, nf, ne; v1 = *vec_ptr[1] - *vec_ptr[0]; v2 = *vec_ptr[2] - *vec_ptr[0]; v3 = *vec_ptr[3] - *vec_ptr[0]; int *triangle_order; if (dot(v3, cross(v1, v2)) <= 0.0) { regular_type = true; triangle_order = regular_order; } else { regular_type = false; triangle_order = inverse_order; } for (int i = 0; i < 4; i++) { v1 = *vec_ptr[triangle_order[1+i*3]] - *vec_ptr[triangle_order[i*3]]; v2 = *vec_ptr[triangle_order[2+i*3]] - *vec_ptr[triangle_order[i*3]]; nf = cross(v1, v2).normal(); F[i] = kron(nf, nf); for (int j = 0; j < 3; j++) { edglen[j+i*3] = distance(*vec_ptr[triangle_order[j+i*3]], *vec_ptr[triangle_order[(j+1)%3+i*3]]); v3 = *vec_ptr[triangle_order[(j+1)%3+i*3]] - *vec_ptr[triangle_order[j+i*3]]; ne = cross(v3, nf).normal(); E[j+i*3] = kron(nf, ne); } } return; } double tetra_vz(tetrahedron *ele_ptr, point3d *op_ptr) { int f,e; double Le,wf; double dv1,dv2; double face_sum,edge_sum; point3d re; point3d r_ijk[3]; double L_ijk[3]; int *triangle_order; if (ele_ptr->regular_type) triangle_order = regular_order; else triangle_order = inverse_order; face_sum = edge_sum = 0.0; for (f = 0; f < 4; f++) { r_ijk[0] = *ele_ptr->vec_ptr[triangle_order[3*f]] - *op_ptr; r_ijk[1] = *ele_ptr->vec_ptr[triangle_order[3*f+1]] - *op_ptr; r_ijk[2] = *ele_ptr->vec_ptr[triangle_order[3*f+2]] - *op_ptr; L_ijk[0] = r_ijk[0].module(); L_ijk[1] = r_ijk[1].module(); L_ijk[2] = r_ijk[2].module(); wf =2*atan2(dot(r_ijk[0], cross(r_ijk[1],r_ijk[2])), L_ijk[0]*L_ijk[1]*L_ijk[2] + L_ijk[0]*dot(r_ijk[1],r_ijk[2]) + L_ijk[1]*dot(r_ijk[2],r_ijk[0]) + L_ijk[2]*dot(r_ijk[0],r_ijk[1])); face_sum += (ele_ptr->F[f].val[2][0]*r_ijk[0].x + ele_ptr->F[f].val[2][1]*r_ijk[0].y + ele_ptr->F[f].val[2][2]*r_ijk[0].z) * wf; for (e = 0; e < 3; e++) { dv1 = distance(*ele_ptr->vec_ptr[triangle_order[e+3*f]], *op_ptr); dv2 = distance(*ele_ptr->vec_ptr[triangle_order[(e+1)%3+3*f]], *op_ptr); re = 0.5*(*ele_ptr->vec_ptr[triangle_order[e+3*f]] + *ele_ptr->vec_ptr[triangle_order[(e+1)%3+3*f]]) - *op_ptr; Le = log((dv1+dv2+ele_ptr->edglen[e+3*f])/(dv1+dv2-ele_ptr->edglen[e+3*f])); edge_sum += (ele_ptr->E[e+3*f].val[2][0]*re.x + ele_ptr->E[e+3*f].val[2][1]*re.y + ele_ptr->E[e+3*f].val[2][2]*re.z) * Le; } } return 1.0e+8*G0*(ele_ptr->rho)*(edge_sum - face_sum); } #endif // _TETRA_VZ_H