/*****************************************************************************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 8 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* Eight node brick volume element.51*52* 7---------653* /| /|54* 4---------5 |55* | | | |56* | | | |57* | 3-------|-2 w v58* w|/v |/ |/59* 0---------1 ---u60* u61*/6263static double A[8][8],N[8][8];6465static double NodeU[] = { -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0 };66static double NodeV[] = { -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0 };67static double NodeW[] = { -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 };686970/*******************************************************************************71*72* Name: elm_8node_brick_triangulate( geometry_t *,element_t * )73*74* Purpose: Triangulate an element. The process also builds up an edge75* table and adds new nodes to node table. The triangulation76* and edge table is stored in geometry_t *geom-structure.77*78* Parameters:79*80* Input: (geometry_t *) pointer to structure holding triangulation81* (element_t *) element to triangulate82*83* Output: (geometry_t *) structure is modified84*85* Return value: FALSE if malloc() fails, TRUE otherwise86*87******************************************************************************/88static int elm_8node_brick_triangulate( geometry_t *geom,element_t *brick )89{90element_t quad;91int i,j;92int geo_add_edge();93int elm_4node_quad_triangulate();9495if ( GlobalOptions.VolumeSides )96{97int topo[4];9899quad.DisplayFlag = TRUE;100quad.Topology = topo;101for( i=0; i<MAX_GROUP_IDS; i++ ) quad.GroupIds[i] = brick->GroupIds[i];102103for( i=0; i<6; i++ )104{105for( j=0; j<4; j++ ) quad.Topology[j] = brick->Topology[ElmBrickFace[i][j]];106if ( !elm_4node_quad_triangulate( geom, &quad, brick ) ) return FALSE;107}108} else {109if ( !geo_add_edge( geom, brick->Topology[0], brick->Topology[1],brick ) ) return FALSE;110if ( !geo_add_edge( geom, brick->Topology[0], brick->Topology[3],brick ) ) return FALSE;111if ( !geo_add_edge( geom, brick->Topology[0], brick->Topology[4],brick ) ) return FALSE;112if ( !geo_add_edge( geom, brick->Topology[1], brick->Topology[2],brick ) ) return FALSE;113if ( !geo_add_edge( geom, brick->Topology[1], brick->Topology[5],brick ) ) return FALSE;114if ( !geo_add_edge( geom, brick->Topology[2], brick->Topology[3],brick ) ) return FALSE;115if ( !geo_add_edge( geom, brick->Topology[2], brick->Topology[6],brick ) ) return FALSE;116if ( !geo_add_edge( geom, brick->Topology[3], brick->Topology[7],brick ) ) return FALSE;117if ( !geo_add_edge( geom, brick->Topology[4], brick->Topology[5],brick ) ) return FALSE;118if ( !geo_add_edge( geom, brick->Topology[4], brick->Topology[7],brick ) ) return FALSE;119if ( !geo_add_edge( geom, brick->Topology[5], brick->Topology[6],brick ) ) return FALSE;120if ( !geo_add_edge( geom, brick->Topology[6], brick->Topology[7],brick ) ) return FALSE;121}122123return TRUE;124}125126127128129/*******************************************************************************130*131* Name: elm_8node_brick_shape_functions( )132*133* Purpose: Initialize element shape function array. Internal only.134*135* Parameters:136*137* Input: Global (filewise) variables NodeU,NodeV,NodeW138*139* Output: Global (filewise) variable N[8][8], will contain140* shape function coefficients141*142* Return value: void143*144******************************************************************************/145static void elm_8node_brick_shape_functions()146{147double u,v,w;148149int i,j;150151for( i=0; i<8; i++ )152{153u = NodeU[i];154v = NodeV[i];155w = NodeW[i];156157A[i][0] = 1;158A[i][1] = u;159A[i][2] = v;160A[i][3] = w;161A[i][4] = u*v;162A[i][5] = u*w;163A[i][6] = v*w;164A[i][7] = u*v*w;165}166167lu_mtrinv( (double *)A,8 );168169for( i=0; i<8; i++ )170for( j=0; j<8; j++ ) N[i][j] = A[j][i];171}172173/*******************************************************************************174*175* Name: elm_8node_brick_fvalue( double *,double,double,double )176*177* Purpose: return value of a quantity given on nodes at point (u,v,w)178* Use trough (element_type_t *) structure.179*180* Parameters:181*182* Input: (double *) quantity values at nodes183* (double,double,double) point where values are evaluated184*185* Output: none186*187* Return value: quantity value188*189******************************************************************************/190static double elm_8node_brick_fvalue(double *F,double u,double v,double w)191{192double R=0.0,uv=u*v,uw=u*w,vw=v*w,uvw=u*v*w;193int i;194195for( i=0; i<8; i++ )196{197R += F[i]*(N[i][0]+198N[i][1]*u+199N[i][2]*v+200N[i][3]*w+201N[i][4]*uv+202N[i][5]*uw+203N[i][6]*vw+204N[i][7]*uvw );205}206207return R;208}209210/*******************************************************************************211*212* Name: elm_8node_brick_dndu_fvalue( double *,double,double,double )213*214* Purpose: return value of a first partial derivate in (v) of a215* quantity given on nodes at point (u,v).216* Use trough (element_type_t *) structure.217*218*219* Parameters:220*221* Input: (double *) quantity values at nodes222* (double u,double v,double w) point where values are evaluated223*224* Output: none225*226* Return value: quantity value227*228******************************************************************************/229static double elm_8node_brick_dndu_fvalue(double *F,double u,double v,double w)230{231double R=0.0,vw=v*w;232int i;233234for( i=0; i<8; i++ )235{236R += F[i]*(N[i][1] + N[i][4]*v + N[i][5]*w + N[i][7]*vw);237}238239return R;240}241242/*******************************************************************************243*244* Name: elm_8node_brick_dndv_fvalue( double *,double,double,double )245*246* Purpose: return value of a first partial derivate in (v) of a247* quantity given on nodes at point (u,v,w).248* Use trough (element_type_t *) structure.249*250*251* Parameters:252*253* Input: (double *) quantity values at nodes254* (double u,double v,double w) point where values are evaluated255*256* Output: none257*258* Return value: quantity value259*260******************************************************************************/261static double elm_8node_brick_dndv_fvalue(double *F,double u,double v,double w)262{263double R=0.0,uw=u*w;264int i;265266for( i=0; i<8; i++ )267{268R += F[i]*(N[i][2] + N[i][4]*u + N[i][6]*w + N[i][7]*uw);269}270271return R;272}273274/*******************************************************************************275*276* Name: elm_8node_brick_dndw_fvalue( double *,double,double,double )277*278* Purpose: return value of a first partial derivate in (w) of a279* quantity given on nodes at point (u,v,w)280* Use trough (element_type_t *) structure.281*282*283* Parameters:284*285* Input: (double *) quantity values at nodes286* (double u,double v,double w) point where values are evaluated287*288* Output: none289*290* Return value: quantity value291*292******************************************************************************/293static double elm_8node_brick_dndw_fvalue(double *F,double u,double v,double w)294{295double R=0.0,uv=u*v;296int i;297298for( i=0; i<8; i++ )299{300R += F[i]*(N[i][3] + N[i][5]*u + N[i][6]*v + N[i][7]*uv);301}302303return R;304}305306/*******************************************************************************307*308* Name: elm_8node_brick_point_inside(309* double *nx,double *ny,double *nz,310* double px, double py, double pz,311* double *u,double *v,double *w )312*313* Purpose: Find if point (px,py,pz) is inside the element, and return314* element coordinates of the point.315*316* Parameters:317*318* Input: (double *) nx,ny,nz node coordinates319* (double) px,py,pz point to consider320*321* Output: (double *) u,v,w point in element coordinates if inside322*323* Return value: in/out status324*325* NOTES: the goal here can be hard for more involved element types. kind of326* trivial for this one...327*328******************************************************************************/329int elm_8node_brick_point_inside330(331double *nx, double *ny, double *nz,332double px, double py, double pz, double *u,double *v,double *w333)334{335double x[4],y[4],z[4],r,s,t,maxx,minx,maxy,miny,maxz,minz;336int i,j;337338static int map[12][3] =339{340{ 0,1,2 }, { 0,2,3 }, { 4,5,6 }, { 4,6,7 }, { 3,2,6 }, { 3,6,7 },341{ 1,5,6 }, { 1,6,2 }, { 0,4,7 }, { 0,7,3 }, { 0,1,5 }, { 0,5,4 },342};343int elm_4node_tetra_point_inside();344345maxx = minx = nx[0];346maxy = miny = ny[0];347maxz = minz = nz[0];348349for( i=1; i<8; i++ )350{351maxx = MAX( nx[i],maxx );352maxy = MAX( ny[i],maxy );353maxz = MAX( nz[i],maxz );354355minx = MIN( nx[i],minx );356miny = MIN( ny[i],miny );357minz = MIN( nz[i],minz );358}359360if ( px > maxx || px < minx ) return FALSE;361if ( py > maxy || py < miny ) return FALSE;362if ( pz > maxz || pz < minz ) return FALSE;363364x[0] = 0.125*(nx[0]+nx[1]+nx[2]+nx[3]+nx[4]+nx[5]+nx[6]+nx[7]);365y[0] = 0.125*(ny[0]+ny[1]+ny[2]+ny[3]+ny[4]+ny[5]+ny[6]+ny[7]);366z[0] = 0.125*(nz[0]+nz[1]+nz[2]+nz[3]+nz[4]+nz[5]+nz[6]+nz[7]);367368for( i=0; i<12; i++ )369{370for( j=0; j<3; j++ )371{372x[j+1] = nx[map[i][j]];373y[j+1] = ny[map[i][j]];374z[j+1] = nz[map[i][j]];375}376377if ( elm_4node_tetra_point_inside( x,y,z,px,py,pz,&r,&s,&t ) )378{379*u = NodeU[map[i][0]]*r + NodeU[map[i][1]]*s + NodeU[map[i][2]]*t;380*v = NodeV[map[i][0]]*r + NodeV[map[i][1]]*s + NodeV[map[i][2]]*t;381*w = NodeW[map[i][0]]*r + NodeW[map[i][1]]*s + NodeW[map[i][2]]*t;382return TRUE;383}384}385386return FALSE;387}388389/*******************************************************************************390*391* Name: elm_8node_brick_isoline392*393* Purpose: Extract a iso line from triangle with given threshold394*395* Parameters:396*397* Input: (double) K, contour threshold398* (double *) F, contour quantity399* (double *) C, color quantity400* (double *) X,Y,Z vertex coords.401*402* Output: (line_t *) place to store the line403*404* Return value: number of lines generated (0,...,24)405*406******************************************************************************/407int elm_8node_brick_isoline408(409double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line410)411{412double f[4],c[4],x[4],y[4],z[4];413414int i, j, k, n=0, above=0;415int elm_4node_quad_isoline();416417for( i=0; i<8; i++ ) above += F[i]>K;418if ( above == 0 || above == 8 ) return 0;419420for( i=0; i<6; i++ )421{422for( j=0; j<4; j++ )423{424k = ElmBrickFace[i][j];425f[j] = F[k];426c[j] = C[k];427x[j] = X[k];428y[j] = Y[k];429z[j] = Z[k];430}431n += elm_4node_quad_isoline( K,f,c,x,y,z,&Line[n] );432}433434return n;435}436437/*******************************************************************************438*439* Name: elm_8node_brick_isosurface440*441* Purpose: Extract isosurfaces for brick element.442*443* Parameters:444*445* Input: (double ) K: contour threshold446* (double *) F: contour quantity values at nodes447* (double *) C: color quantity values at nodes448* (double *) X,Y,Z: node coordinates449* (double *) U,V,W: normal vector at nodes450*451* Output: (polygon_t *)Polygon: output triangles.452*453* Return value: How many triangles we've got (possible values are 0-48)...454*455******************************************************************************/456int elm_8node_brick_isosurface457(458double K,double *F,double *C, double *X,double *Y,double *Z,459double *U,double *V,double *W, polygon_t *Polygon460)461{462double tx[4],ty[4],tz[4],tu[4],tv[4],tw[4],tf[4],tc[4];463int i,j,n;464465int above = 0, below = 0;466467int elm_4node_tetra_isosurface();468469for( i=0; i<8; i++ ) above += F[i]>K;470for( i=0; i<8; i++ ) below += F[i]<K;471if ( below == 8 || above == 8 ) return 0;472473tx[0] = 0.125 * ( X[0] + X[1] + X[2] + X[3] + X[4] + X[5] + X[6] + X[7] );474ty[0] = 0.125 * ( Y[0] + Y[1] + Y[2] + Y[3] + Y[4] + Y[5] + Y[6] + Y[7] );475tz[0] = 0.125 * ( Z[0] + Z[1] + Z[2] + Z[3] + Z[4] + Z[5] + Z[6] + Z[7] );476tu[0] = 0.125 * ( U[0] + U[1] + U[2] + U[3] + U[4] + U[5] + U[6] + U[7] );477tv[0] = 0.125 * ( V[0] + V[1] + V[2] + V[3] + V[4] + V[5] + V[6] + V[7] );478tw[0] = 0.125 * ( W[0] + W[1] + W[2] + W[3] + W[4] + W[5] + W[6] + W[7] );479tf[0] = 0.125 * ( F[0] + F[1] + F[2] + F[3] + F[4] + F[5] + F[6] + F[7] );480tc[0] = 0.125 * ( C[0] + C[1] + C[2] + C[3] + C[4] + C[5] + C[6] + C[7] );481482n = 0;483for( i=0; i<6; i++ )484{485tx[1] = 0.0;486ty[1] = 0.0;487tz[1] = 0.0;488tu[1] = 0.0;489tv[1] = 0.0;490tw[1] = 0.0;491tf[1] = 0.0;492tc[1] = 0.0;493for( j=0; j<4; j++ )494{495tx[1] += X[ElmBrickFace[i][j]];496ty[1] += Y[ElmBrickFace[i][j]];497tz[1] += Z[ElmBrickFace[i][j]];498tu[1] += U[ElmBrickFace[i][j]];499tv[1] += V[ElmBrickFace[i][j]];500tw[1] += W[ElmBrickFace[i][j]];501tf[1] += F[ElmBrickFace[i][j]];502tc[1] += C[ElmBrickFace[i][j]];503}504tx[1] /= 4.0;505ty[1] /= 4.0;506tz[1] /= 4.0;507tu[1] /= 4.0;508tv[1] /= 4.0;509tw[1] /= 4.0;510tf[1] /= 4.0;511tc[1] /= 4.0;512513for( j=0; j<3; j++ )514{515tx[2] = X[ElmBrickFace[i][j]];516ty[2] = Y[ElmBrickFace[i][j]];517tz[2] = Z[ElmBrickFace[i][j]];518tu[2] = U[ElmBrickFace[i][j]];519tv[2] = V[ElmBrickFace[i][j]];520tw[2] = W[ElmBrickFace[i][j]];521tf[2] = F[ElmBrickFace[i][j]];522tc[2] = C[ElmBrickFace[i][j]];523524tx[3] = X[ElmBrickFace[i][j+1]];525ty[3] = Y[ElmBrickFace[i][j+1]];526tz[3] = Z[ElmBrickFace[i][j+1]];527tu[3] = U[ElmBrickFace[i][j+1]];528tv[3] = V[ElmBrickFace[i][j+1]];529tw[3] = W[ElmBrickFace[i][j+1]];530tf[3] = F[ElmBrickFace[i][j+1]];531tc[3] = C[ElmBrickFace[i][j+1]];532n += elm_4node_tetra_isosurface( K,tf,tc,tx,ty,tz,tu,tv,tw,&Polygon[n] );533}534535tx[2] = X[ElmBrickFace[i][3]];536ty[2] = Y[ElmBrickFace[i][3]];537tz[2] = Z[ElmBrickFace[i][3]];538tu[2] = U[ElmBrickFace[i][3]];539tv[2] = V[ElmBrickFace[i][3]];540tw[2] = W[ElmBrickFace[i][3]];541tf[2] = F[ElmBrickFace[i][3]];542tc[2] = C[ElmBrickFace[i][3]];543544tx[3] = X[ElmBrickFace[i][0]];545ty[3] = Y[ElmBrickFace[i][0]];546tz[3] = Z[ElmBrickFace[i][0]];547tu[3] = U[ElmBrickFace[i][0]];548tv[3] = V[ElmBrickFace[i][0]];549tw[3] = W[ElmBrickFace[i][0]];550tf[3] = F[ElmBrickFace[i][0]];551tc[3] = C[ElmBrickFace[i][0]];552n += elm_4node_tetra_isosurface( K,tf,tc,tx,ty,tz,tu,tv,tw,&Polygon[n] );553}554return n;555}556557/*******************************************************************************558*559* Name: elm_8node_brick_isosurface1560*561* Purpose: Extract isosurfaces for brick element.562*563* Parameters:564*565* Input: (double ) K: contour threshold566* (double *) F: contour quantity values at nodes567* (double *) C: color quantity values at nodes568* (double *) X,Y,Z: node coordinates569* (double *) U,V,W: normal vector at nodes570*571* Output: (polygon_t *)Polygon: output triangles.572*573* Return value: How many triangles we've got (possible values are 0-48)...574*575******************************************************************************/576int elm_8node_brick_isosurface1577(578double K,double *F,double *C, double *X,double *Y,double *Z,579double *U,double *V,double *W, polygon_t *Polygon580)581{582double tx[4],ty[4],tz[4],tu[4],tv[4],tw[4],tf[4],tc[4];583int i,j,l,n;584585static int map[12][3] =586{587{ 0,1,2 }, { 0,2,3 }, { 4,5,6 }, { 4,6,7 }, { 3,2,6 }, { 3,6,7 },588{ 1,5,6 }, { 1,6,2 }, { 0,4,7 }, { 0,7,3 }, { 0,1,5 }, { 0,5,4 },589};590591int above = 0, below = 0;592593int elm_4node_tetra_isosurface();594595for( i=0; i<8; i++ ) above += F[i]>K;596for( i=0; i<8; i++ ) below += F[i]<K;597if ( below == 8 || above == 8 ) return 0;598599tx[0] = 0.125 * ( X[0] + X[1] + X[2] + X[3] + X[4] + X[5] + X[6] + X[7] );600ty[0] = 0.125 * ( Y[0] + Y[1] + Y[2] + Y[3] + Y[4] + Y[5] + Y[6] + Y[7] );601tz[0] = 0.125 * ( Z[0] + Z[1] + Z[2] + Z[3] + Z[4] + Z[5] + Z[6] + Z[7] );602tu[0] = 0.125 * ( U[0] + U[1] + U[2] + U[3] + U[4] + U[5] + U[6] + U[7] );603tv[0] = 0.125 * ( V[0] + V[1] + V[2] + V[3] + V[4] + V[5] + V[6] + V[7] );604tw[0] = 0.125 * ( W[0] + W[1] + W[2] + W[3] + W[4] + W[5] + W[6] + W[7] );605tf[0] = 0.125 * ( F[0] + F[1] + F[2] + F[3] + F[4] + F[5] + F[6] + F[7] );606tc[0] = 0.125 * ( C[0] + C[1] + C[2] + C[3] + C[4] + C[5] + C[6] + C[7] );607608n = 0;609for( i=0; i<12; i++ )610{611for( j=1; j<4; j++ )612{613l = map[i][j-1];614tx[j] = X[l];615ty[j] = Y[l];616tz[j] = Z[l];617tu[j] = U[l];618tv[j] = V[l];619tw[j] = W[l];620tf[j] = F[l];621tc[j] = C[l];622}623n += elm_4node_tetra_isosurface( K,tf,tc,tx,ty,tz,tu,tv,tw,&Polygon[n] );624}625return n;626}627628629/******************************************************************************630*631* Name: elm_8node_brick_initialize( )632*633* Purpose: Register the element type634*635* Parameters:636*637* Input: (char *) description of the element638* (int) numeric code for the element639*640* Output: Global list of element types is modified641*642* Return value: malloc() success643*644******************************************************************************/645int elm_8node_brick_initialize()646{647static char *Name = "ELM_8NODE_BRICK";648649element_type_t ElementDef;650651int elm_add_element_type();652653elm_8node_brick_shape_functions();654655ElementDef.ElementName = Name;656ElementDef.ElementCode = 808;657658ElementDef.NumberOfNodes = 8;659660ElementDef.NodeU = NodeU;661ElementDef.NodeV = NodeV;662ElementDef.NodeW = NodeW;663664ElementDef.PartialU = (double (*)())elm_8node_brick_dndu_fvalue;665ElementDef.PartialV = (double (*)())elm_8node_brick_dndv_fvalue;666ElementDef.PartialW = (double (*)())elm_8node_brick_dndw_fvalue;667668ElementDef.FunctionValue = (double (*)())elm_8node_brick_fvalue;669ElementDef.Triangulate = (int (*)())elm_8node_brick_triangulate;670ElementDef.PointInside = (int (*)())elm_8node_brick_point_inside;671ElementDef.IsoLine = (int (*)())elm_8node_brick_isoline;672ElementDef.IsoSurface = (int (*)())elm_8node_brick_isosurface1;673674return elm_add_element_type( &ElementDef ) ;675}676677678679