/*****************************************************************************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* Isoparametric 20 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[20][20],N[20][20];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.090};9192static double NodeV[] = {93-1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.0,941.0, 0.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.095};9697static double NodeW[] = {98-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0,99-1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0100};101102103/*******************************************************************************104*105* Name: elm_20node_brick_triangulate( geometry_t *,element_t * )106*107* Purpose: Triangulate an element. The process also builds up an edge108* table and adds new nodes to node table. The triangulation109* and edge table is stored in geometry_t *geom-structure.110*111* Parameters:112*113* Input: (geometry_t *) pointer to structure holding triangulation114* (element_t *) element to triangulate115*116* Output: (geometry_t *) structure is modified117*118* Return value: FALSE if malloc() fails, TRUE otherwise119*120******************************************************************************/121static int elm_20node_brick_triangulate( geometry_t *geom,element_t *brick )122{123element_t quad;124int i,j;125int geo_add_edge();126int elm_4node_quad_triangulate();127128if ( GlobalOptions.VolumeSides )129{130int topo[4];131132quad.DisplayFlag = TRUE;133quad.Topology = topo;134for( i=0; i<MAX_GROUP_IDS; i++ ) quad.GroupIds[i] = brick->GroupIds[i];135136for( i=0; i<6; i++ )137{138for( j=0; j<4; j++ )139{140quad.Topology[j] = brick->Topology[ElmBrickFace[i][j]];141}142if ( !elm_4node_quad_triangulate( geom, &quad, brick ) ) return FALSE;143}144} else {145if ( !geo_add_edge( geom, brick->Topology[0], brick->Topology[8], brick ) ) return FALSE;146if ( !geo_add_edge( geom, brick->Topology[8], brick->Topology[1], brick ) ) return FALSE;147if ( !geo_add_edge( geom, brick->Topology[1], brick->Topology[9], brick ) ) return FALSE;148if ( !geo_add_edge( geom, brick->Topology[9], brick->Topology[2], brick ) ) return FALSE;149if ( !geo_add_edge( geom, brick->Topology[2], brick->Topology[10], brick ) ) return FALSE;150if ( !geo_add_edge( geom, brick->Topology[10], brick->Topology[3], brick ) ) return FALSE;151if ( !geo_add_edge( geom, brick->Topology[3], brick->Topology[11], brick ) ) return FALSE;152if ( !geo_add_edge( geom, brick->Topology[11], brick->Topology[0], brick ) ) return FALSE;153if ( !geo_add_edge( geom, brick->Topology[0], brick->Topology[12], brick ) ) return FALSE;154if ( !geo_add_edge( geom, brick->Topology[12], brick->Topology[4], brick ) ) return FALSE;155if ( !geo_add_edge( geom, brick->Topology[1], brick->Topology[13], brick ) ) return FALSE;156if ( !geo_add_edge( geom, brick->Topology[13], brick->Topology[5], brick ) ) return FALSE;157if ( !geo_add_edge( geom, brick->Topology[2], brick->Topology[14], brick ) ) return FALSE;158if ( !geo_add_edge( geom, brick->Topology[14], brick->Topology[6], brick ) ) return FALSE;159if ( !geo_add_edge( geom, brick->Topology[3], brick->Topology[15], brick ) ) return FALSE;160if ( !geo_add_edge( geom, brick->Topology[15], brick->Topology[7], brick ) ) return FALSE;161if ( !geo_add_edge( geom, brick->Topology[15], brick->Topology[7], brick ) ) return FALSE;162if ( !geo_add_edge( geom, brick->Topology[4], brick->Topology[16], brick ) ) return FALSE;163if ( !geo_add_edge( geom, brick->Topology[16], brick->Topology[5], brick ) ) return FALSE;164if ( !geo_add_edge( geom, brick->Topology[5], brick->Topology[17], brick ) ) return FALSE;165if ( !geo_add_edge( geom, brick->Topology[17], brick->Topology[6], brick ) ) return FALSE;166if ( !geo_add_edge( geom, brick->Topology[6], brick->Topology[18], brick ) ) return FALSE;167if ( !geo_add_edge( geom, brick->Topology[18], brick->Topology[7], brick ) ) return FALSE;168if ( !geo_add_edge( geom, brick->Topology[7], brick->Topology[19], brick ) ) return FALSE;169if ( !geo_add_edge( geom, brick->Topology[19], brick->Topology[4], brick ) ) return FALSE;170}171172return TRUE;173}174175/*******************************************************************************176*177* Name: elm_20node_brick_shape_functions( )178*179* Purpose: Initialize element shape function array. Internal only.180*181* Parameters:182*183* Input: Global (filewise) variables NodeU,NodeV,NodeW184*185* Output: Global (filewise) variable N[8][8], will contain186* shape function coefficients187*188* Return value: void189*190******************************************************************************/191static void elm_20node_brick_shape_functions()192{193double u,v,w;194int i,j;195196for( i=0; i<20; i++ )197{198u = NodeU[i];199v = NodeV[i];200w = NodeW[i];201202A[i][0] = 1;203A[i][1] = u;204A[i][2] = v;205A[i][3] = w;206A[i][4] = u*v;207A[i][5] = u*w;208A[i][6] = v*w;209A[i][7] = u*v*w;210A[i][8] = u*u;211A[i][9] = v*v;212A[i][10] = w*w;213A[i][11] = u*u*v;214A[i][12] = u*u*w;215A[i][13] = u*v*v;216A[i][14] = u*w*w;217A[i][15] = v*v*w;218A[i][16] = v*w*w;219A[i][17] = u*u*v*w;220A[i][18] = u*v*v*w;221A[i][19] = u*v*w*w;222}223224lu_mtrinv( (double *)A,20 );225226for( i=0; i<20; i++ )227for( j=0; j<20; j++ ) N[i][j] = A[j][i];228}229230/*******************************************************************************231*232* Name: elm_20node_brick_fvalue( double *,double,double,double )233*234* Purpose: return value of a quantity given on nodes at point (u,v,w)235* Use trough (element_type_t *) structure.236*237* Parameters:238*239* Input: (double *) quantity values at nodes240* (double,double,double) point where values are evaluated241*242* Output: none243*244* Return value: quantity value245*246******************************************************************************/247static double elm_20node_brick_fvalue(double *F,double u,double v,double w)248{249double 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,250uuv=uu*v,uuw=uu*w,uvv=u*vv,uww=u*ww,vvw=vv*w,vww=v*ww,251uuvw=uu*vw,uvvw=vv*uw,uvww=uv*ww;252int i;253254for( i=0; i<20; i++ )255{256R += F[i]*( N[i][0] +257N[i][1]*u +258N[i][2]*v +259N[i][3]*w +260N[i][4]*uv +261N[i][5]*uw +262N[i][6]*vw +263N[i][7]*uvw +264N[i][8]*uu +265N[i][9]*vv +266N[i][10]*ww +267N[i][11]*uuv +268N[i][12]*uuw +269N[i][13]*uvv +270N[i][14]*uww +271N[i][15]*vvw +272N[i][16]*vww +273N[i][17]*uuvw +274N[i][18]*uvvw +275N[i][19]*uvww );276}277278return R;279}280281/*******************************************************************************282*283* Name: elm_20node_brick_dndu_fvalue( double *,double,double,double )284*285* Purpose: return value of a first partial derivate in (v) of a286* quantity given on nodes at point (u,v).287* Use trough (element_type_t *) structure.288*289*290* Parameters:291*292* Input: (double *) quantity values at nodes293* (double u,double v,double w) point where values are evaluated294*295* Output: none296*297* Return value: quantity value298*299******************************************************************************/300static double elm_20node_brick_dndu_fvalue(double *F,double u,double v,double w)301{302double 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;303int i;304305for( i=0; i<20; i++ )306{307R += F[i]*( N[i][1] +308N[i][4]*v +309N[i][5]*w +310N[i][7]*vw +311N[i][8]*u2 +312N[i][11]*u2v +313N[i][12]*u2w +314N[i][13]*vv +315N[i][14]*ww +316N[i][17]*u2vw +317N[i][18]*vvw +318N[i][19]*vww );319}320321return R;322}323/*******************************************************************************324*325* Name: elm_20node_brick_dndv_fvalue( double *,double,double,double )326*327* Purpose: return value of a first partial derivate in (v) of a328* quantity given on nodes at point (u,v,w).329* Use trough (element_type_t *) structure.330*331*332* Parameters:333*334* Input: (double *) quantity values at nodes335* (double u,double v,double w) point where values are evaluated336*337* Output: none338*339* Return value: quantity value340*341******************************************************************************/342static double elm_20node_brick_dndv_fvalue(double *F,double u,double v,double w)343{344double 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;345int i;346347for( i=0; i<20; i++ )348{349R += F[i]*( N[i][2] +350N[i][4]*u +351N[i][6]*w +352N[i][7]*uw +353N[i][9]*v2 +354N[i][11]*uu +355N[i][13]*uv2 +356N[i][15]*v2w +357N[i][16]*ww +358N[i][17]*uuw +359N[i][18]*uv2w +360N[i][19]*uww );361}362363return R;364}365366/*******************************************************************************367*368* Name: elm_20node_brick_dndw_fvalue( double *,double,double,double )369*370* Purpose: return value of a first partial derivate in (w) of a371* quantity given on nodes at point (u,v,w)372* Use trough (element_type_t *) structure.373*374*375* Parameters:376*377* Input: (double *) quantity values at nodes378* (double u,double v,double w) point where values are evaluated379*380* Output: none381*382* Return value: quantity value383*384******************************************************************************/385static double elm_20node_brick_dndw_fvalue(double *F,double u,double v,double w)386{387double 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;388int i;389390for( i=0; i<20; i++ )391{392R += F[i]*( N[i][3] +393N[i][5]*u +394N[i][6]*v +395N[i][7]*uv +396N[i][10]*w2 +397N[i][12]*uu +398N[i][14]*uw2 +399N[i][15]*vv +400N[i][16]*vw2 +401N[i][17]*uuv +402N[i][18]*uvv +403N[i][19]*uvw2 );404}405406return R;407}408409410/*******************************************************************************411*412* Name: elm_20node_brick_point_inside(413* double *nx,double *ny,double *nz,414* double px, double py, double pz,415* double *u,double *v,double *w )416*417* Purpose: Find if point (px,py,pz) is inside the element, and return418* element coordinates of the point.419*420* Parameters:421*422* Input: (double *) nx,ny,nz node coordinates423* (double) px,py,pz point to consider424*425* Output: (double *) u,v,w point in element coordinates if inside426*427* Return value: in/out status428*429* NOTES: TODO: FIX THIS430* trivial for this one...431*432******************************************************************************/433int elm_20node_brick_point_inside434(435double *nx, double *ny, double *nz,436double px, double py, double pz, double *u,double *v,double *w437)438{439int elm_8node_brick_point_inside();440return elm_8node_brick_point_inside( nx,ny,nz,px,py,pz,u,v,w );441}442443/*******************************************************************************444*445* Name: elm_20node_brick_isoline446*447* Purpose: Extract a iso line from triangle with given threshold448*449* Parameters:450*451* Input: (double) K, contour threshold452* (double *) F, contour quantity453* (double *) C, color quantity454* (double *) X,Y,Z vertex coords.455*456* Output: (line_t *) place to store the line457*458* Return value: number of lines generated (0,...,144)459*460******************************************************************************/461static int elm_20node_brick_isoline462(463double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line464)465{466double f[8],c[8],x[8],y[8],z[8];467468int i, j, k, n=0, above=0;469int elm_8node_quad_isoline();470471for( i=0; i<20; i++ ) above += F[i]>K;472if ( above == 0 || above == 20 ) return 0;473474for( i=0; i<6; i++ )475{476for( j=0; j<8; j++ )477{478k = ElmBrickFace[i][j];479f[j] = F[k];480c[j] = C[k];481x[j] = X[k];482y[j] = Y[k];483z[j] = Z[k];484}485n += elm_8node_quad_isoline( K,f,c,x,y,z,&Line[n] );486}487488return n;489}490491492/*******************************************************************************493*494* Name: elm_20node_brick_isosurface(495* double *nx,double *ny,double *nz,496* double px, double py, double pz,497* double *u,double *v,double *w )498*499* Purpose: Find if point (px,py,pz) is inside the element, and return500* element coordinates of the point.501*502* Parameters:503*504* Input: (double *) nx,ny,nz node coordinates505* (double) px,py,pz point to consider506*507* Output: (double *) u,v,w point in element coordinates if inside508*509* Return value: in/out status510*511* NOTES: TODO: FIX THIS512*513******************************************************************************/514int elm_20node_brick_isosurface515(516double K,double *F,double *C,517double *X,double *Y,double *Z,518double *U,double *V,double *W,519polygon_t *Polygon520)521{522double f[8],c[8],x[8],y[8],z[8],u[8],v[8],w[8];523int i,j,k, n=0, above = 0;524int elm_8node_brick_isosurface();525526for( i=0; i<20; i++ ) above += F[i]>K;527if ( above == 0 || above == 20 ) return 0;528529n += elm_8node_brick_isosurface( K,F,C,X,Y,Z,U,V,W,Polygon );530return n;531}532533534/******************************************************************************535*536* Name: elm_20node_brick_initialize( )537*538* Purpose: Register the element type539*540* Parameters:541*542* Input: (char *) description of the element543* (int) numeric code for the element544*545* Output: Global list of element types is modified546*547* Return value: malloc() success548*549******************************************************************************/550int elm_20node_brick_initialize()551{552static char *Name = "ELM_20NODE_BRICK";553554element_type_t ElementDef;555int elm_add_element_type();556557elm_20node_brick_shape_functions();558559ElementDef.ElementName = Name;560ElementDef.ElementCode = 820;561562ElementDef.NumberOfNodes = 20;563564ElementDef.NodeU = NodeU;565ElementDef.NodeV = NodeV;566ElementDef.NodeW = NodeW;567568ElementDef.PartialU = (double (*)())elm_20node_brick_dndu_fvalue;569ElementDef.PartialV = (double (*)())elm_20node_brick_dndv_fvalue;570ElementDef.PartialW = (double (*)())elm_20node_brick_dndw_fvalue;571572ElementDef.FunctionValue = (double (*)())elm_20node_brick_fvalue;573ElementDef.Triangulate = (int (*)())elm_20node_brick_triangulate;574ElementDef.PointInside = (int (*)())elm_20node_brick_point_inside;575ElementDef.IsoLine = (int (*)())elm_20node_brick_isoline;576ElementDef.IsoSurface = (int (*)())elm_20node_brick_isosurface;577578return elm_add_element_type( &ElementDef ) ;579}580581582