/*****************************************************************************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 9 node quad 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: 20 Sep 199539*40* Modification history:41*42* 28 Sep 1995, changed call to elm_triangle_normal to geo_triangle normal43* routine elm_... doesn't exist anymore44* Juha R45*46*47******************************************************************************/4849#include "../elmerpost.h"50#include <elements.h>5152/*53*54* shape functions: N0 = ( uv(1-u-v)+u^2+v^2-1)/455* N1 = (-uv(1+u-v)+u^2+v^2-1)/456* N2 = ( uv(1+u+v)+u^2+v^2-1)/4 3---6---257* N3 = (-uv(1-u+v)+u^2+v^2-1)/4 | |58* N4 = ((1-v)(1-u^2)/2 7 559* N5 = ((1+u)(1-v^2)/2 v | |60* N6 = ((1+v)(1-u^2)/2 0---4---161* N7 = ((1-u)(1-v^2)/2 u62*63*/6465static double N[9][9],A[9][9];6667static double NodeU[] = { -1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0 };68static double NodeV[] = { -1.0, -1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0 };6970/*******************************************************************************71*72* Name: elm_9node_quad_shape_functions( )73*74* Purpose: Initialize element shape function array. Internal only.75*76* Parameters:77*78* Input: Global (filewise) variables NodeU,NodeV,NodeW79*80* Output: Global (filewise) variable N[6][6], will contain81* shape function coefficients82*83* Return value: void84*85******************************************************************************/86static void elm_9node_quad_shape_functions()87{88double u,v;8990int i,j;9192for( i=0; i<9; i++ )93{94u = NodeU[i];95v = NodeV[i];9697A[i][0] = 1;98A[i][1] = u;99A[i][2] = v;100A[i][3] = u*v;101A[i][4] = u*u;102A[i][5] = v*v;103A[i][6] = u*u*v;104A[i][7] = u*v*v;105A[i][8] = u*u*v*v;106}107108lu_mtrinv( (double *)A,9 );109110for( i=0; i<9; i++ )111for( j=0; j<9; j++ ) N[i][j] = A[j][i];112}113114115/*******************************************************************************116*117* Name: elm_9node_quad_triangulate( geometry_t *,element_t * )118*119* Purpose: Triangulate an element. The process also builds up an edge120* table and adds new nodes to node table. The triangulation121* and edge table is stored in geometry_t *geom-structure.122*123* Parameters:124*125* Input: (geometry_t *) pointer to structure holding triangulation126* (element_t *) element to triangulate127*128* Output: (geometry_t *) structure is modified129*130* Return value: FALSE if malloc() fails, TRUE otherwise131*132******************************************************************************/133int elm_9node_quad_triangulate( geometry_t *geom,element_t *Elm )134{135triangle_t triangle;136137triangle.Element = Elm;138139triangle.v[0] = Elm->Topology[0];140triangle.v[1] = Elm->Topology[4];141triangle.v[2] = Elm->Topology[8];142143triangle.Edge[0] = TRUE;144triangle.Edge[1] = FALSE;145triangle.Edge[2] = FALSE;146147if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;148149triangle.v[0] = Elm->Topology[4];150triangle.v[1] = Elm->Topology[1];151triangle.v[2] = Elm->Topology[8];152153triangle.Edge[0] = TRUE;154triangle.Edge[1] = FALSE;155triangle.Edge[2] = FALSE;156157if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;158159triangle.v[0] = Elm->Topology[1];160triangle.v[1] = Elm->Topology[5];161triangle.v[2] = Elm->Topology[8];162163triangle.Edge[0] = TRUE;164triangle.Edge[1] = FALSE;165triangle.Edge[2] = FALSE;166167if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;168169triangle.v[0] = Elm->Topology[5];170triangle.v[1] = Elm->Topology[2];171triangle.v[2] = Elm->Topology[8];172173triangle.Edge[0] = TRUE;174triangle.Edge[1] = FALSE;175triangle.Edge[2] = FALSE;176177if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;178179triangle.v[0] = Elm->Topology[2];180triangle.v[1] = Elm->Topology[6];181triangle.v[2] = Elm->Topology[8];182183triangle.Edge[0] = TRUE;184triangle.Edge[1] = FALSE;185triangle.Edge[2] = FALSE;186187if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;188189triangle.v[0] = Elm->Topology[6];190triangle.v[1] = Elm->Topology[3];191triangle.v[2] = Elm->Topology[8];192193triangle.Edge[0] = TRUE;194triangle.Edge[1] = FALSE;195triangle.Edge[2] = FALSE;196197if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;198199triangle.v[0] = Elm->Topology[3];200triangle.v[1] = Elm->Topology[7];201triangle.v[2] = Elm->Topology[8];202203triangle.Edge[0] = TRUE;204triangle.Edge[1] = FALSE;205triangle.Edge[2] = FALSE;206207if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;208209triangle.v[0] = Elm->Topology[7];210triangle.v[1] = Elm->Topology[0];211triangle.v[2] = Elm->Topology[8];212213triangle.Edge[0] = TRUE;214triangle.Edge[1] = FALSE;215triangle.Edge[2] = FALSE;216217if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;218219return TRUE;220}221222/*******************************************************************************223*224* Name: elm_9node_quad_fvalue( double *,double,double )225*226* Purpose: return value of a quantity given on nodes at point (u,v)227*228*229*230* Parameters:231*232* Input: (double *) quantity values at nodes233* (double u,double v) point where values are evaluated234*235* Output: none236*237* Return value: quantity value238*239******************************************************************************/240static double elm_9node_quad_fvalue( double *F, double u, double v )241{242double R,uv=u*v,uu=u*u,vv=v*v,uuv=uu*v,uvv=u*vv;243int i;244245R = 0.0;246for( i=0; i<9; i++ )247{248R += F[i]*(N[i][0] +249N[i][1]*u +250N[i][2]*v +251N[i][3]*uv +252N[i][4]*uu +253N[i][5]*vv +254N[i][6]*uuv +255N[i][7]*uvv +256N[i][8]*uu*vv);257}258259return R;260}261262/*******************************************************************************263*264* Name: elm_9node_quad_dndu_fvalue( double *,double,double )265*266* Purpose: return value of a first partial derivate in (u) of a267* quantity given on nodes at point (u,v)268*269*270* Parameters:271*272* Input: (double *) quantity values at nodes273* (double u,double v) point where values are evaluated274*275* Output: none276*277* Return value: quantity value278*279******************************************************************************/280static double elm_9node_quad_dndu_fvalue( double *F, double u, double v )281{282double R=0.0,uv=u*v,vv=v*v;283int i;284285for( i=0; i<9; i++ )286{287R += F[i]*(N[i][1]+N[i][3]*v+2*N[i][4]*u+2*N[i][6]*uv+N[i][7]*vv+2*N[i][8]*u*vv);288}289290return R;291}292293/*******************************************************************************294*295* Name: elm_9node_quad_dndv_fvalue( double *,double,double )296*297* Purpose: return value of a first partial derivate in (v) of a298* quantity given on nodes at point (u,v)299*300*301* Parameters:302*303* Input: (double *) quantity values at nodes304* (double u,double v) point where values are evaluated305*306* Output: none307*308* Return value: quantity value309*310******************************************************************************/311static double elm_9node_quad_dndv_fvalue( double *F, double u, double v )312{313double R=0.0,uu=u*u,uv=u*v;314315int i;316317for( i=0; i<9; i++ )318{319R += F[i]*(N[i][2]+N[i][3]*u+2*N[i][5]*v+N[i][6]*uu+2*N[i][7]*uv+2*N[i][8]*uu*v);320}321322return R;323}324325/*******************************************************************************326*327* Name: elm_9node_quad_dd(double *F,double *u,double *v,double *Values)328*329* Purpose: Return matrix of second partial derivates of given quantity330* at given point u,v.331*332* Parameters:333*334* Input: (double *)F: quantity values at nodes335* (double)u,v: point of evaluation336*337* Output: (double *)Values: 2x2 matrix of partial derivates338*339* Return value: void340*341*******************************************************************************/342static void elm_9node_quad_ddu( double *F,double u,double v,double *Values )343{344double ddu = 0.0, dudv=0.0, ddv = 0.0;345346int i;347348for( i=0; i<9; i++ )349{350ddu += F[i]*( 2*N[i][4] + 2*v*N[i][6] + 2*v*v*N[i][8] );351ddv += F[i]*( 2*N[i][5] + 2*v*N[i][7] + 2*u*u*N[i][8] );352dudv += F[i]*( N[i][3] + 2*u*N[i][6] + 2*v*N[i][7] + 4*u*v*N[i][8] );353}354355Values[0] = ddu;356Values[1] = dudv;357Values[2] = dudv;358Values[3] = ddv;359}360361/*******************************************************************************362*363* Name: elm_9node_quad_point_inside(364* double *nx,double *ny,double *nz,365* double px, double py, double pz,366* double *u,double *v,double *w )367*368* Purpose: Find if point (px,py,pz) is inside the element, and return369* element coordinates of the point.370*371* Parameters:372*373* Input: (double *) nx,ny,nz n coordinates374* (double) px,py,pz point to consider375*376* Output: (double *) u,v,w point in element coordinates if inside377*378* Return value: in/out status379*380* NOTES: the goal here can be hard for more involved element types. kind of381* trivial for this one... TODO: FIX THIS....382*383******************************************************************************/384int elm_9node_quad_point_inside385(386double *nx, double *ny, double *nz,387double px, double py, double pz, double *u,double *v,double *w388)389{390double lx[4],ly[4],lz[4],cx,cy,cz;391392int i,j,k;393394static int map[4][3] =395{396{ 7,0,4 }, { 4,1,5 }, { 5,2,6 }, { 6,3,7 }397};398399int elm_4node_quad_point_inside();400401cx = elm_9node_quad_fvalue( nx,0.0,0.0 );402cy = elm_9node_quad_fvalue( ny,0.0,0.0 );403cz = elm_9node_quad_fvalue( nz,0.0,0.0 );404405for( i=0; i<4; i++ )406{407408switch( i )409{410case 0:411lx[0] = nx[0]; ly[0] = ny[0]; lz[0] = nz[0];412lx[1] = nx[4]; ly[1] = ny[4]; lz[1] = nz[4];413lx[2] = cx; ly[2] = cy; lz[2] = cz;414lx[3] = nx[7]; ly[3] = ny[7]; lz[3] = nz[7];415break;416case 1:417lx[0] = nx[4]; ly[0] = ny[4]; lz[0] = nz[4];418lx[1] = nx[1]; ly[1] = ny[1]; lz[1] = nz[1];419lx[2] = nx[5]; ly[2] = ny[5]; lz[2] = nz[5];420lx[3] = cx; ly[3] = cy; lz[3] = cz;421break;422case 2:423lx[0] = cx; ly[0] = cy; lz[0] = cz;424lx[1] = nx[5]; ly[1] = ny[5]; lz[1] = nz[5];425lx[2] = nx[2]; ly[2] = ny[2]; lz[2] = nz[2];426lx[3] = nx[6]; ly[3] = ny[6]; lz[3] = nz[6];427break;428case 3:429lx[0] = nx[7]; ly[0] = ny[7]; lz[0] = nz[7];430lx[1] = cx; ly[1] = cy; lz[1] = cz;431lx[2] = nx[6]; ly[2] = ny[6]; lz[2] = nz[6];432lx[3] = nx[3]; ly[3] = ny[3]; lz[3] = nz[3];433break;434}435436if ( elm_4node_quad_point_inside( lx,ly,lz,px,py,pz,u,v,w ) )437{438switch( i )439{440case 0:441*u = *u/2 - 0.5;442*v = *v/2 - 0.5;443break;444445case 1:446*u = *u/2 + 0.5;447*v = *v/2 - 0.5;448break;449450case 2:451*u = *u/2 + 0.5;452*v = *v/2 + 0.5;453break;454455case 3:456*u = *u/2 - 0.5;457*v = *v/2 + 0.5;458break;459}460461return TRUE;462}463}464465return FALSE;466}467468/*******************************************************************************469*470* Name: elm_9node_quad_isoline471*472* Purpose: Extract a iso line from triangle with given threshold473*474* Parameters:475*476* Input: (double) K, contour threshold477* (double *) F, contour quantity478* (double *) C, color quantity479* (double *) X,Y,Z vertex coords.480*481* Output: (line_t *) place to store the line482*483* Return value: number of lines generated (0,...,16)484*485******************************************************************************/486int elm_9node_quad_isoline487(488double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line489)490{491double f[4],c[4],x[4],y[4],z[4];492493int i, j, k, n=0, above=0;494495static int map[4][3] =496{497{ 7,0,4 }, { 4,1,5 }, { 5,2,6 }, { 6,3,7 }498};499500int elm_4node_quad_isoline();501502for( i=0; i<9; i++ ) above += F[i]>K;503if ( above == 0 || above == 9 ) return 0;504505f[0] = elm_9node_quad_fvalue( F,0.0,0.0 );506c[0] = elm_9node_quad_fvalue( C,0.0,0.0 );507x[0] = elm_9node_quad_fvalue( X,0.0,0.0 );508y[0] = elm_9node_quad_fvalue( Y,0.0,0.0 );509z[0] = elm_9node_quad_fvalue( Z,0.0,0.0 );510511for( i=0; i<4; i++ )512{513for( j=1; j<4; j++ )514{515k = map[i][j-1];516f[j] = F[k];517c[j] = C[k];518x[j] = X[k];519y[j] = Y[k];520z[j] = Z[k];521}522n += elm_4node_quad_isoline( K,f,c,x,y,z,&Line[n] );523}524525return n;526}527528529/******************************************************************************530*531* Name: elm_9node_quad_initialize( )532*533* Purpose: Register the element type534*535* Parameters:536*537* Input: (char *) description of the element538* (int) numeric code for the element539*540* Output: Global list of element types is modified541*542* Return value: malloc() success543*544******************************************************************************/545int elm_9node_quad_initialize()546{547element_type_t ElementDef;548549static char *Name = "ELM_9NODE_QUAD";550551int elm_add_element_type();552553elm_9node_quad_shape_functions();554555ElementDef.ElementName = Name;556ElementDef.ElementCode = 409;557558ElementDef.NumberOfNodes = 9;559ElementDef.NodeU = NodeU;560ElementDef.NodeV = NodeV;561ElementDef.NodeW = NULL;562563ElementDef.PartialU = (double (*)())elm_9node_quad_dndu_fvalue;564ElementDef.PartialV = (double (*)())elm_9node_quad_dndv_fvalue;565ElementDef.PartialW = NULL;566ElementDef.SecondPartials = (double (*)())elm_9node_quad_ddu;567568ElementDef.FunctionValue = (double (*)())elm_9node_quad_fvalue;569570ElementDef.Triangulate = (int (*)())elm_9node_quad_triangulate;571ElementDef.PointInside = (int (*)())elm_9node_quad_point_inside;572ElementDef.IsoLine = (int (*)())elm_9node_quad_isoline;573ElementDef.IsoSurface = (int (*)())NULL;574575return elm_add_element_type( &ElementDef );576}577578579