/*****************************************************************************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* Definitions for 27 node brick volume element.26*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: 27 Sep 199539*40* Modified by:41*42* Date of modification:43*44******************************************************************************/4546#include "../elmerpost.h"47#include <elements.h>4849/*50* Isoparametric 27 node volume element.51*52* 7------18-------653* 19| 17|54* / | / |55* 4------16-------5 |56* | 15 | 1457* | | | |58* 12 | 13 |59* | 3-----10-----|--260* | 11 | 9 w v61* w|/v |/ |/62* 0-------8-------1 ---u63* u64*65* shape functions: N = (1+u u)(1+v v)(1+w w)(u u+v v+w w-2)/8 i = 0..766* i i i i i i i67* N = (1-u^2)(1+v v)(1+w w)/4 i=8,10,16,18 (u = 0)68* i i i i69* N = (1+u u)(1-v^2)(1+w w)/4 i=9,11,17,19 (v = 0)70* i i i i71* N = (1+u u)(1+v v)(1-w^2)/4 i=12,13,14,15 (w = 0)72* i i i i73*74* @/@u N = u (1+v v)(1+w w)(2u u+v v+w w-1)/8 i = 0..775* i i i i i i i76* @/@u N = -2u(1+v v)(1+w w)/4 i=8,10,16,18 (u = 0)77* i i i i78* @/@u N = u (1-v^2)(1+w w)/4 i=9,11,17,19 (v = 0)79* i i i i80* @/@u N = u (1+v v)(1-w^2)/4 i=12,13,14,15 (w = 0)81* i i i i82*83*/8485static double A[27][27],N[27][27];8687static double NodeU[] = {88-1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.0, 1.0,890.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, -1.0,900.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.091};9293static double NodeV[] = {94-1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.0,951.0, 0.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0,96-1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.097};9899static double NodeW[] = {100-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0,101-1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,1020.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0103};104105106/*******************************************************************************107*108* Name: elm_27node_brick_triangulate( geometry_t *,element_t * )109*110* Purpose: Triangulate an element. The process also builds up an edge111* table and adds new nodes to node table. The triangulation112* and edge table is stored in geometry_t *geom-structure.113*114* Parameters:115*116* Input: (geometry_t *) pointer to structure holding triangulation117* (element_t *) element to triangulate118*119* Output: (geometry_t *) structure is modified120*121* Return value: FALSE if malloc() fails, TRUE otherwise122*123******************************************************************************/124static int elm_27node_brick_triangulate( geometry_t *geom,element_t *brick )125{126element_t quad;127int i,j;128int geo_add_edge();129int elm_4node_quad_triangulate();130131if ( GlobalOptions.VolumeSides )132{133int topo[4];134135quad.DisplayFlag = TRUE;136quad.Topology = topo;137for( i=0; i<MAX_GROUP_IDS; i++ ) quad.GroupIds[i] = brick->GroupIds[i];138139for( i=0; i<6; i++ )140{141for( j=0; j<4; j++ )142{143quad.Topology[j] = brick->Topology[ElmBrickFace[i][j]];144}145if ( !elm_4node_quad_triangulate( geom, &quad, brick ) ) return FALSE;146}147} else {148if ( !geo_add_edge( geom, brick->Topology[0], brick->Topology[8], brick ) ) return FALSE;149if ( !geo_add_edge( geom, brick->Topology[8], brick->Topology[1], brick ) ) return FALSE;150if ( !geo_add_edge( geom, brick->Topology[1], brick->Topology[9], brick ) ) return FALSE;151if ( !geo_add_edge( geom, brick->Topology[9], brick->Topology[2], brick ) ) return FALSE;152if ( !geo_add_edge( geom, brick->Topology[2], brick->Topology[10], brick ) ) return FALSE;153if ( !geo_add_edge( geom, brick->Topology[10], brick->Topology[3], brick ) ) return FALSE;154if ( !geo_add_edge( geom, brick->Topology[3], brick->Topology[11], brick ) ) return FALSE;155if ( !geo_add_edge( geom, brick->Topology[11], brick->Topology[0], brick ) ) return FALSE;156if ( !geo_add_edge( geom, brick->Topology[0], brick->Topology[12], brick ) ) return FALSE;157if ( !geo_add_edge( geom, brick->Topology[12], brick->Topology[4], brick ) ) return FALSE;158if ( !geo_add_edge( geom, brick->Topology[1], brick->Topology[13], brick ) ) return FALSE;159if ( !geo_add_edge( geom, brick->Topology[13], brick->Topology[5], brick ) ) return FALSE;160if ( !geo_add_edge( geom, brick->Topology[2], brick->Topology[14], brick ) ) return FALSE;161if ( !geo_add_edge( geom, brick->Topology[14], brick->Topology[6], brick ) ) return FALSE;162if ( !geo_add_edge( geom, brick->Topology[3], brick->Topology[15], brick ) ) return FALSE;163if ( !geo_add_edge( geom, brick->Topology[15], brick->Topology[7], brick ) ) return FALSE;164if ( !geo_add_edge( geom, brick->Topology[15], brick->Topology[7], brick ) ) return FALSE;165if ( !geo_add_edge( geom, brick->Topology[4], brick->Topology[16], brick ) ) return FALSE;166if ( !geo_add_edge( geom, brick->Topology[16], brick->Topology[5], brick ) ) return FALSE;167if ( !geo_add_edge( geom, brick->Topology[5], brick->Topology[17], brick ) ) return FALSE;168if ( !geo_add_edge( geom, brick->Topology[17], brick->Topology[6], brick ) ) return FALSE;169if ( !geo_add_edge( geom, brick->Topology[6], brick->Topology[18], brick ) ) return FALSE;170if ( !geo_add_edge( geom, brick->Topology[18], brick->Topology[7], brick ) ) return FALSE;171if ( !geo_add_edge( geom, brick->Topology[7], brick->Topology[19], brick ) ) return FALSE;172if ( !geo_add_edge( geom, brick->Topology[19], brick->Topology[4], brick ) ) return FALSE;173}174175return TRUE;176}177178/*******************************************************************************179*180* Name: elm_27node_brick_shape_functions( )181*182* Purpose: Initialize element shape function array. Internal only.183*184* Parameters:185*186* Input: Global (filewise) variables NodeU,NodeV,NodeW187*188* Output: Global (filewise) variable N[8][8], will contain189* shape function coefficients190*191* Return value: void192*193******************************************************************************/194static void elm_27node_brick_shape_functions()195{196double u,v,w;197int i,j;198199for( i=0; i<27; i++ )200{201u = NodeU[i];202v = NodeV[i];203w = NodeW[i];204205A[i][0] = 1;206A[i][1] = u;207A[i][2] = v;208A[i][3] = w;209A[i][4] = u*v;210A[i][5] = u*w;211A[i][6] = v*w;212A[i][7] = u*v*w;213A[i][8] = u*u;214A[i][9] = v*v;215A[i][10] = w*w;216A[i][11] = u*u*v;217A[i][12] = u*u*w;218A[i][13] = u*v*v;219A[i][14] = u*w*w;220A[i][15] = v*v*w;221A[i][16] = v*w*w;222A[i][17] = u*u*v*w;223A[i][18] = u*v*v*w;224A[i][19] = u*v*w*w;225A[i][20] = u*u*v*v;226A[i][21] = u*u*w*w;227A[i][22] = v*v*w*w;228A[i][23] = u*v*v*w*w;229A[i][24] = u*u*v*w*w;230A[i][25] = u*u*v*v*w;231A[i][26] = u*u*v*v*w*w;232}233234lu_mtrinv( (double *)A,27 );235236for( i=0; i<27; i++ )237for( j=0; j<27; j++ ) N[i][j] = A[j][i];238}239240/*******************************************************************************241*242* Name: elm_27node_brick_fvalue( double *,double,double,double )243*244* Purpose: return value of a quantity given on nodes at point (u,v,w)245* Use trough (element_type_t *) structure.246*247* Parameters:248*249* Input: (double *) quantity values at nodes250* (double,double,double) point where values are evaluated251*252* Output: none253*254* Return value: quantity value255*256******************************************************************************/257static double elm_27node_brick_fvalue(double *F,double u,double v,double w)258{259double R=0.0,uv=u*v,uw=u*w,vw=v*w,uvw=u*v*w,uu=u*u,vv=v*v,ww=w*w,260uuv=uu*v,uuw=uu*w,uvv=u*vv,uww=u*ww,vvw=vv*w,vww=v*ww,261uuvw=uu*vw,uvvw=vv*uw,uvww=uv*ww;262int i;263264for( i=0; i<27; i++ )265{266R += F[i]*( N[i][0] +267N[i][1]*u +268N[i][2]*v +269N[i][3]*w +270N[i][4]*uv +271N[i][5]*uw +272N[i][6]*vw +273N[i][7]*uvw +274N[i][8]*uu +275N[i][9]*vv +276N[i][10]*ww +277N[i][11]*uuv +278N[i][12]*uuw +279N[i][13]*uvv +280N[i][14]*uww +281N[i][15]*vvw +282N[i][16]*vww +283N[i][17]*uuvw +284N[i][18]*uvvw +285N[i][19]*uvww +286N[i][20]*u*u*v*v +287N[i][21]*u*u*w*w +288N[i][22]*v*v*w*w +289N[i][23]*u*v*v*w*w +290N[i][24]*u*u*v*w*w +291N[i][25]*u*u*v*v*w +292N[i][26]*u*u*v*v*w*w );293}294295return R;296}297298/*******************************************************************************299*300* Name: elm_27node_brick_dndu_fvalue( double *,double,double,double )301*302* Purpose: return value of a first partial derivate in (v) of a303* quantity given on nodes at point (u,v).304* Use trough (element_type_t *) structure.305*306*307* Parameters:308*309* Input: (double *) quantity values at nodes310* (double u,double v,double w) point where values are evaluated311*312* Output: none313*314* Return value: quantity value315*316******************************************************************************/317static double elm_27node_brick_dndu_fvalue(double *F,double u,double v,double w)318{319double R=0.0,vw=v*w,u2=2*u,u2v=u2*v,u2w=u2*w,vv=v*v,ww=w*w,u2vw=u2*vw,vvw=vv*w,vww=v*ww;320int i;321322for( i=0; i<27; i++ )323{324R += F[i]*( N[i][1] +325N[i][4]*v +326N[i][5]*w +327N[i][7]*vw +328N[i][8]*u2 +329N[i][11]*u2v +330N[i][12]*u2w +331N[i][13]*vv +332N[i][14]*ww +333N[i][17]*u2vw +334N[i][18]*vvw +335N[i][19]*vww +336N[i][20]*2*u*v*v +337N[i][21]*2*u*w*w +338N[i][23]*v*v*w*w +339N[i][24]*2*u*v*w*w +340N[i][25]*2*u*v*v*w +341N[i][26]*2*u*v*v*w*w );342}343344return R;345}346/*******************************************************************************347*348* Name: elm_27node_brick_dndv_fvalue( double *,double,double,double )349*350* Purpose: return value of a first partial derivate in (v) of a351* quantity given on nodes at point (u,v,w).352* Use trough (element_type_t *) structure.353*354*355* Parameters:356*357* Input: (double *) quantity values at nodes358* (double u,double v,double w) point where values are evaluated359*360* Output: none361*362* Return value: quantity value363*364******************************************************************************/365static double elm_27node_brick_dndv_fvalue(double *F,double u,double v,double w)366{367double R=0.0,uw=u*w,v2=2*v,uu=u*u,uv2=u*v2,v2w=v2*w,ww=w*w,uuw=uu*w,uv2w=uw*v2,uww=u*ww;368int i;369370for( i=0; i<27; i++ )371{372R += F[i]*( N[i][2] +373N[i][4]*u +374N[i][6]*w +375N[i][7]*uw +376N[i][9]*v2 +377N[i][11]*uu +378N[i][13]*uv2 +379N[i][15]*v2w +380N[i][16]*ww +381N[i][17]*uuw +382N[i][18]*uv2w +383N[i][19]*uww +384N[i][20]*u*u*2*v +385N[i][22]*2*v*w*w +386N[i][23]*u*2*v*w*w +387N[i][24]*u*u*w*w +388N[i][25]*u*u*2*v*w +389N[i][26]*u*u*2*v*w*w );390}391392return R;393}394395/*******************************************************************************396*397* Name: elm_27node_brick_dndw_fvalue( double *,double,double,double )398*399* Purpose: return value of a first partial derivate in (w) of a400* quantity given on nodes at point (u,v,w)401* Use trough (element_type_t *) structure.402*403*404* Parameters:405*406* Input: (double *) quantity values at nodes407* (double u,double v,double w) point where values are evaluated408*409* Output: none410*411* Return value: quantity value412*413******************************************************************************/414static double elm_27node_brick_dndw_fvalue(double *F,double u,double v,double w)415{416double R=0.0,uv=u*v,w2=2*w,uu=u*u,uw2=u*w2,vv=v*v,vw2=v*w2,uuv=uu*v,uvv=u*vv,uvw2=uv*w2;417int i;418419for( i=0; i<27; i++ )420{421R += F[i]*( N[i][3] +422N[i][5]*u +423N[i][6]*v +424N[i][7]*uv +425N[i][10]*w2 +426N[i][12]*uu +427N[i][14]*uw2 +428N[i][15]*vv +429N[i][16]*vw2 +430N[i][17]*uuv +431N[i][18]*uvv +432N[i][19]*uvw2 +433N[i][21]*u*u*2*w +434N[i][22]*v*v*2*w +435N[i][23]*u*v*v*2*w +436N[i][24]*u*u*v*2*w +437N[i][25]*u*u*v*v +438N[i][26]*u*u*v*v*2*w );439}440441return R;442}443444445/*******************************************************************************446*447* Name: elm_27node_brick_point_inside(448* double *nx,double *ny,double *nz,449* double px, double py, double pz,450* double *u,double *v,double *w )451*452* Purpose: Find if point (px,py,pz) is inside the element, and return453* element coordinates of the point.454*455* Parameters:456*457* Input: (double *) nx,ny,nz node coordinates458* (double) px,py,pz point to consider459*460* Output: (double *) u,v,w point in element coordinates if inside461*462* Return value: in/out status463*464* NOTES: TODO: FIX THIS465* trivial for this one...466*467******************************************************************************/468int elm_27node_brick_point_inside469(470double *nx, double *ny, double *nz,471double px, double py, double pz, double *u,double *v,double *w472)473{474int elm_8node_brick_point_inside();475return elm_8node_brick_point_inside( nx,ny,nz,px,py,pz,u,v,w );476}477478/*******************************************************************************479*480* Name: elm_27node_brick_isoline481*482* Purpose: Extract a iso line from triangle with given threshold483*484* Parameters:485*486* Input: (double) K, contour threshold487* (double *) F, contour quantity488* (double *) C, color quantity489* (double *) X,Y,Z vertex coords.490*491* Output: (line_t *) place to store the line492*493* Return value: number of lines generated (0,...,144)494*495******************************************************************************/496static int elm_27node_brick_isoline497(498double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line499)500{501double f[8],c[8],x[8],y[8],z[8];502503int i, j, k, n=0, above=0;504int elm_8node_quad_isoline();505506for( i=0; i<27; i++ ) above += F[i]>K;507if ( above == 0 || above == 27 ) return 0;508509for( i=0; i<6; i++ )510{511for( j=0; j<8; j++ )512{513k = ElmBrickFace[i][j];514f[j] = F[k];515c[j] = C[k];516x[j] = X[k];517y[j] = Y[k];518z[j] = Z[k];519}520n += elm_8node_quad_isoline( K,f,c,x,y,z,&Line[n] );521}522523return n;524}525526527/*******************************************************************************528*529* Name: elm_27node_brick_isosurface(530* double *nx,double *ny,double *nz,531* double px, double py, double pz,532* double *u,double *v,double *w )533*534* Purpose: Find if point (px,py,pz) is inside the element, and return535* element coordinates of the point.536*537* Parameters:538*539* Input: (double *) nx,ny,nz node coordinates540* (double) px,py,pz point to consider541*542* Output: (double *) u,v,w point in element coordinates if inside543*544* Return value: in/out status545*546* NOTES: TODO: FIX THIS547*548******************************************************************************/549int elm_27node_brick_isosurface550(551double K,double *F,double *C,552double *X,double *Y,double *Z,553double *U,double *V,double *W,554polygon_t *Polygon555)556{557double f[8],c[8],x[8],y[8],z[8],u[8],v[8],w[8];558int i,j,k, n=0, above = 0;559int elm_8node_brick_isosurface();560561for( i=0; i<27; i++ ) above += F[i]>K;562if ( above == 0 || above == 27 ) return 0;563564n += elm_8node_brick_isosurface( K,F,C,X,Y,Z,U,V,W,Polygon );565return n;566}567568569/******************************************************************************570*571* Name: elm_27node_brick_initialize( )572*573* Purpose: Register the element type574*575* Parameters:576*577* Input: (char *) description of the element578* (int) numeric code for the element579*580* Output: Global list of element types is modified581*582* Return value: malloc() success583*584******************************************************************************/585int elm_27node_brick_initialize()586{587static char *Name = "ELM_27NODE_BRICK";588589element_type_t ElementDef;590591int elm_add_element_type();592593elm_27node_brick_shape_functions();594595ElementDef.ElementName = Name;596ElementDef.ElementCode = 827;597598ElementDef.NumberOfNodes = 27;599600ElementDef.NodeU = NodeU;601ElementDef.NodeV = NodeV;602ElementDef.NodeW = NodeW;603604ElementDef.PartialU = (double (*)())elm_27node_brick_dndu_fvalue;605ElementDef.PartialV = (double (*)())elm_27node_brick_dndv_fvalue;606ElementDef.PartialW = (double (*)())elm_27node_brick_dndw_fvalue;607608ElementDef.FunctionValue = (double (*)())elm_27node_brick_fvalue;609ElementDef.Triangulate = (int (*)())elm_27node_brick_triangulate;610ElementDef.PointInside = (int (*)())elm_27node_brick_point_inside;611ElementDef.IsoLine = (int (*)())elm_27node_brick_isoline;612ElementDef.IsoSurface = (int (*)())elm_27node_brick_isosurface;613614return elm_add_element_type( &ElementDef ) ;615}616617618