/*****************************************************************************1*2* Elmer, A Finite Element Software for Multiphysical Problems3*4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU General Public License8* as published by the Free Software Foundation; either version 29* of the License, or (at your option) any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program (in file fem/GPL-2); if not, write to the18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,19* Boston, MA 02110-1301, USA.20*21*****************************************************************************/2223/*******************************************************************************24*25* Definition of 10 node tetra element26*27*******************************************************************************28*29* Author: Juha Ruokolainen30*31* Address: CSC - IT Center for Science Ltd.32* Keilaranta 14, P.O. BOX 40533* 02101 Espoo, Finland34* Tel. +358 0 457 272335* Telefax: +358 0 457 230236* EMail: [email protected]37*38* Date: 4 Oct 199539*40******************************************************************************/4142#include "../elmerpost.h"43#include "elements.h"444546/*47* 10 node tetra volume element.48*49*/5051static double A[10][10],N[10][10];5253static double NodeU[] = { 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.5, 0.0 };54static double NodeV[] = { 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.5 };55static double NodeW[] = { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5 };5657/*******************************************************************************58*59* Name: elm_10node_tetra_triangulate60*61* Purpose: Triangulate an element. The process also builds up an edge62* table and adds new nodes to node table. The triangulation63* and edge table is stored in geometry_t *geom-structure.64*65* Parameters:66*67* Input: (geometry_t *) pointer to structure holding triangulation68* (element_t *) element to triangulate69*70* Output: (geometry_t *) structure is modified71*72* Return value: FALSE if malloc() fails, TRUE otherwise73*74******************************************************************************/75static int elm_10node_tetra_triangulate( geometry_t *geom,element_t *tetra )76{77element_t triangle;78int i,j;7980if ( GlobalOptions.VolumeSides )81{82int topo[7];8384triangle.DisplayFlag = TRUE;85triangle.Topology = topo;86for( i=0; i<MAX_GROUP_IDS; i++ ) triangle.GroupIds[i] = tetra->GroupIds[i];8788for( i=0; i<4; i++ )89{90int elm_6node_triangle_triangulate();91for( j=0; j<6; j++ )92{93triangle.Topology[j] = tetra->Topology[ElmTetraFace[i][j]];94}95if ( !elm_6node_triangle_triangulate( geom, &triangle, tetra ) ) return FALSE;96}97} else {98int geo_add_edge();99if ( !geo_add_edge( geom, tetra->Topology[0],tetra->Topology[4],tetra ) ) return FALSE;100if ( !geo_add_edge( geom, tetra->Topology[4],tetra->Topology[1],tetra ) ) return FALSE;101if ( !geo_add_edge( geom, tetra->Topology[1],tetra->Topology[5],tetra ) ) return FALSE;102if ( !geo_add_edge( geom, tetra->Topology[5],tetra->Topology[2],tetra ) ) return FALSE;103if ( !geo_add_edge( geom, tetra->Topology[2],tetra->Topology[6],tetra ) ) return FALSE;104if ( !geo_add_edge( geom, tetra->Topology[6],tetra->Topology[0],tetra ) ) return FALSE;105if ( !geo_add_edge( geom, tetra->Topology[0],tetra->Topology[7],tetra ) ) return FALSE;106if ( !geo_add_edge( geom, tetra->Topology[7],tetra->Topology[3],tetra ) ) return FALSE;107if ( !geo_add_edge( geom, tetra->Topology[1],tetra->Topology[8],tetra ) ) return FALSE;108if ( !geo_add_edge( geom, tetra->Topology[8],tetra->Topology[3],tetra ) ) return FALSE;109if ( !geo_add_edge( geom, tetra->Topology[2],tetra->Topology[9],tetra ) ) return FALSE;110if ( !geo_add_edge( geom, tetra->Topology[9],tetra->Topology[3],tetra ) ) return FALSE;111}112113return TRUE;114}115116/*******************************************************************************117*118* Name: elm_10node_tetra_point_inside119* (120* double *nx,double *ny,double *nz,121* double px,double py,double pz,122* double *u, double *v, double *w123* )124*125* Purpose: Find if point (px,py,pz) is inside the element, and return126* element coordinates of the point.127*128* Parameters:129*130* Input: (double *) nx,ny,nz n coordinates131* (double) px,py,pz point to consider132*133* Output: (double *) u,v,w point in element coordinates if inside134*135* Return value: in/out status136*137* NOTES: the goal here can be hard for more involved element types.138* TODO: SUBDIVISION...139*140******************************************************************************/141int elm_10node_tetra_point_inside142(143double *nx, double *ny, double *nz,144double px, double py, double pz, double *u,double *v,double *w145)146{147int elm_4node_tetra_point_inside();148return elm_4node_tetra_point_inside( nx,ny,nz,px,py,pz,u,v,w );149}150151/*******************************************************************************152*153* Name: elm_10node_tetra_isosurface154*155* Purpose: Extract isosurfaces for element156*157* Parameters:158*159* Input: (double ) K: contour threshold160* (double *) F: contour quantity values at nodes161* (double *) C: color quantity values at nodes162* (double *) X,Y,Z: node coordinates163* (double *) U,V,W: normal vector at nodes164*165* Output: (polygon_t *)Polygon, output triangles (0,1 or 2) triangles166*167* Return value: How many triangles we've got..., TODO: SUBDIVISION168*169******************************************************************************/170int elm_10node_tetra_isosurface171(172double K,double *F,double *C, double *X,double *Y,double *Z,173double *U,double *V,double *W, polygon_t *Polygon174)175{176int elm_4node_tetra_isosurface();177return elm_4node_tetra_isosurface( K,F,C,X,Y,Z,U,V,W,Polygon );178}179180/*******************************************************************************181*182* Name: elm_10node_tetra_shape_functions183*184* Purpose: Initialize element shape function array. Internal only.185*186* Parameters:187*188* Input: Global (filewise) variables NodeU,NodeV,NodeW189*190* Output: Global (filewise) variable N[4][4], will contain191* shape function coefficients192*193* Return value: void194*195******************************************************************************/196static void elm_10node_tetra_shape_functions()197{198double u,v,w;199int i,j;200201for( i=0; i<10; i++ )202{203u = NodeU[i];204v = NodeV[i];205w = NodeW[i];206207A[i][0] = 1;208A[i][1] = u;209A[i][2] = v;210A[i][3] = w;211A[i][4] = u*u;212A[i][5] = v*v;213A[i][6] = w*w;214A[i][7] = u*v;215A[i][8] = u*w;216A[i][9] = v*w;217}218219lu_mtrinv( (double *)A,10 );220221for( i=0; i<10; i++ )222for( j=0; j<10; j++ ) N[i][j] = A[j][i];223}224225/*******************************************************************************226*227* Name: elm_10node_tetra_fvalue228*229* Purpose: return value of a quantity given on nodes at point (u,v)230* Use trough (element_type_t *) structure.231*232* Parameters:233*234* Input: (double *) quantity values at nodes235* (double u,double v) point where values are evaluated236*237* Output: none238*239* Return value: quantity value240*241******************************************************************************/242static double elm_10node_tetra_fvalue(double *F,double u,double v,double w)243{244double R=0.0,uu=u*u,vv=v*v,ww=w*w,uv=u*v,uw=u*w,vw=v*w;245int i;246247for( i=0; i<10; i++ )248{249R += F[i]*( N[i][0] +250N[i][1]*u +251N[i][2]*v +252N[i][3]*w +253N[i][4]*uu +254N[i][5]*vv +255N[i][6]*ww +256N[i][7]*uv +257N[i][8]*uw +258N[i][9]*vw );259}260261return R;262}263264/*******************************************************************************265*266* Name: elm_10node_tetra_dndu_fvalue267*268* Purpose: return value of a first partial derivate in (v) of a269* quantity given on nodes at point (u,v).270* Use trough (element_type_t *) structure.271*272*273* Parameters:274*275* Input: (double *) quantity values at nodes276* (double u,double v,double w) point where values are evaluated277*278* Output: none279*280* Return value: quantity value281*282******************************************************************************/283static double elm_10node_tetra_dndu_fvalue(double *F,double u,double v,double w)284{285double R=0.0,u2=2*u;286int i;287288for( i=0; i<10; i++ )289{290R += F[i]*( N[i][1]+291N[i][4]*u2 +292N[i][7]*v +293N[i][8]*w );294}295296return R;297}298299/*******************************************************************************300*301* Name: elm_10node_tetra_dndv_fvalue302*303* Purpose: return value of a first partial derivate in (v) of a304* quantity given on nodes at point (u,v,w).305* Use trough (element_type_t *) structure.306*307*308* Parameters:309*310* Input: (double *) quantity values at nodes311* (double u,double v,double w) point where values are evaluated312*313* Output: none314*315* Return value: quantity value316*317******************************************************************************/318static double elm_10node_tetra_dndv_fvalue(double *F,double u,double v,double w)319{320double R=0.0,v2=2*v;321int i;322323for( i=0; i<10; i++ )324{325R += F[i]*( N[i][2] +326N[i][5]*v2 +327N[i][7]*u +328N[i][9]*w );329}330331return R;332}333334/*******************************************************************************335*336* Name: elm_10node_tetra_dndw_fvalue337*338* Purpose: return value of a first partial derivate in (w) of a339* quantity given on nodes at point (u,v,w)340* Use trough (element_type_t *) structure.341*342*343* Parameters:344*345* Input: (double *) quantity values at nodes346* (double u,double v,double w) point where values are evaluated347*348* Output: none349*350* Return value: quantity value351*352******************************************************************************/353static double elm_10node_tetra_dndw_fvalue(double *F,double u,double v,double w)354{355double R=0.0,w2=2*w;356int i;357358for( i=0; i<10; i++ )359{360R += F[i]*( N[i][3] +361N[i][6]*w2 +362N[i][8]*u +363N[i][9]*v );364}365366return R;367}368369/*******************************************************************************370*371* Name: elm_10node_tetra_isoline372*373* Purpose: Extract a iso line from triangle with given threshold374*375* Parameters:376*377* Input: (double) K, contour threshold378* (double *) F, contour quantity379* (double *) C, color quantity380* (double *) X,Y,Z vertex coords.381*382* Output: (line_t *) place to store the line383*384* Return value: number of lines generated (0,...,24)385*386******************************************************************************/387static int elm_10node_tetra_isoline388(389double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line390)391{392double f[6],c[6],x[6],y[6],z[6];393394int i, j, k, n=0, above=0;395396for( i=0; i<10; i++ ) above += F[i]>K;397if ( above == 0 || above == 10 ) return 0;398399for( i=0; i<4; i++ )400{401int elm_6node_triangle_isoline();402for( j=0; j<6; j++ )403{404k = ElmTetraFace[i][j];405f[j] = F[k];406c[j] = C[k];407x[j] = X[k];408y[j] = Y[k];409z[j] = Z[k];410}411n += elm_6node_triangle_isoline( K,f,c,x,y,z,&Line[n] );412}413414return n;415}416417418/******************************************************************************419*420* Name: elm_10node_tetra_initialize421*422* Purpose: Register the element type423*424* Parameters:425*426* Input: (char *) description of the element427* (int) numeric code for the element428*429* Output: Global list of element types is modified430*431* Return value: malloc() success432*433******************************************************************************/434int elm_10node_tetra_initialize()435{436static char *Name = "ELM_10NODE_TETRA";437438element_type_t ElementDef;439440int elm_add_element_type();441442elm_10node_tetra_shape_functions();443444ElementDef.ElementName = Name;445ElementDef.ElementCode = 510;446447ElementDef.NumberOfNodes = 10;448449ElementDef.NodeU = NodeU;450ElementDef.NodeV = NodeV;451ElementDef.NodeW = NodeW;452453ElementDef.PartialU = (double (*)())elm_10node_tetra_dndu_fvalue;454ElementDef.PartialV = (double (*)())elm_10node_tetra_dndv_fvalue;455ElementDef.PartialW = (double (*)())elm_10node_tetra_dndw_fvalue;456457ElementDef.FunctionValue = (double (*)())elm_10node_tetra_fvalue;458ElementDef.Triangulate = (int (*)())elm_10node_tetra_triangulate;459ElementDef.PointInside = (int (*)())elm_10node_tetra_point_inside;460ElementDef.IsoLine = (int (*)())elm_10node_tetra_isoline;461ElementDef.IsoSurface = (int (*)())elm_10node_tetra_isosurface;462463return elm_add_element_type( &ElementDef );464}465466467