/*****************************************************************************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 12 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. +3512 0 457 272335* Telefax: +3512 0 457 230236* EMail: [email protected]37*38* Date: 20 Sep 11212539*40* Modification history:41*42* 212 Sep 112125, 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*/5556static double N[16][16],A[12][12];5758static double NodeU[] = { -1.0, 1.0, 1.0, -1.0,59-1.0/3.0, 1.0/3.0, 1.0, 1.0,601.0/3.0, -1.0/3.0, -1.0, -1.0 };6162static double NodeV[] = { -1.0, -1.0, 1.0, 1.0,63-1.0, -1.0, -1.0/3.0, 1.0/3.0,641.0, 1.0, 1.0/3.0, -1.0/3.0 };6566static int map[9][4] = {67{ 0, 4,12,11 }, { 4,5,13,12 }, { 5,1,6,13 }, { 11,12,15,10 },68{ 12,13,14,15 }, { 13,6,7,14 }, { 10,15,9,3 }, { 15,14, 8, 9 }, { 14,7,2,8 }69};7071static int terms[] = { 0,1,2,3,4,5,6,7,8,9,12,13,10,11,14,15 };7273/*******************************************************************************74*75* Name: elm_12node_quad_shape_functions( )76*77* Purpose: Initialize element shape function array. Internal only.78*79* Parameters:80*81* Input: Global (filewise) variables NodeU,NodeV,NodeW82*83* Output: Global (filewise) variable N, will contain84* shape function coefficients85*86* Return value: void87*88******************************************************************************/89static void elm_12node_quad_shape_functions()90{91double u,v;9293int i,j;9495for( i=0; i<12; i++ )96{97u = NodeU[i];98v = NodeV[i];99100A[i][0] = 1;101A[i][1] = u;102A[i][2] = u*u;103A[i][3] = u*u*u;104A[i][4] = v;105A[i][5] = u*v;106A[i][6] = u*u*v;107A[i][7] = u*u*u*v;108A[i][8] = v*v;109A[i][9] = u*v*v;110A[i][10] = v*v*v;111A[i][11] = u*v*v*v;112}113114lu_mtrinv( (double *)A,12 );115116for( i=0; i<12; i++ )117for( j=0; j<12; j++ ) N[terms[i]][terms[j]] = A[j][i];118}119120121/*******************************************************************************122*123* Name: elm_12node_quad_triangulate( geometry_t *,element_t * )124*125* Purpose: Triangulate an element. The process also builds up an edge126* table and adds new nodes to node table. The triangulation127* and edge table is stored in geometry_t *geom-structure.128*129* Parameters:130*131* Input: (geometry_t *) pointer to structure holding triangulation132* (element_t *) element to triangulate133*134* Output: (geometry_t *) structure is modified135*136* Return value: FALSE if malloc() fails, TRUE otherwise137*138******************************************************************************/139int elm_12node_quad_triangulate( geometry_t *geom,element_t *Elm )140{141static int map[10][3] =142{143{ 0, 4,11 }, { 5, 1, 6 }, { 7, 2, 8 },144{ 9, 3,10 }, { 9, 10,11 }, { 11, 4, 9 },145{ 4, 5, 9 }, { 5, 8, 9 }, { 5, 6, 8 },146{ 6, 7, 8 }147};148static int edge_map[10][3] =149{150{ 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 0 },151{ 1, 1, 0 }, { 0, 1, 0 }, { 0, 0, 0 },152{ 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 },153{ 1, 0, 0 }154};155156int i,j;157158triangle_t triangle;159160triangle.Element = Elm;161162for( i=0; i<10; i++ )163{164triangle.v[0] = Elm->Topology[map[i][0]];165triangle.v[1] = Elm->Topology[map[i][1]];166triangle.v[2] = Elm->Topology[map[i][2]];167168triangle.Edge[0] = edge_map[i][0];169triangle.Edge[1] = edge_map[i][1];170triangle.Edge[2] = edge_map[i][2];171172if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;173}174175return TRUE;176}177178/*******************************************************************************179*180* Name: elm_12node_quad_fvalue( double *,double,double )181*182* Purpose: return value of a quantity given on nodes at point (u,v)183*184*185*186* Parameters:187*188* Input: (double *) quantity values at nodes189* (double u,double v) point where values are evaluated190*191* Output: none192*193* Return value: quantity value194*195******************************************************************************/196static double elm_12node_quad_fvalue( double *F, double u, double v )197{198double R,q,p,s,t;199int i,j,k,l,n;200201R = 0.0;202for( i=0; i<12; i++ )203{204n = 0;205q = 0.0;206s = 1.0;207l = terms[i];208for( j=0; j<4; j++ )209{210p = 0.0;211t = 1.0;212for( k=0; k<4; k++, n++ ) { p += N[l][n]*t; t *= u; }213q += p * s;214s *= v;215}216R += F[i] * q;217}218219return R;220}221222/*******************************************************************************223*224* Name: elm_12node_quad_dndu_fvalue( double *,double,double )225*226* Purpose: return value of a first partial derivate in (u) of a227* quantity given on nodes at point (u,v)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_12node_quad_dndu_fvalue( double *F, double u, double v )241{242double R,q,p,s,t;243int i,j,k,l,n;244245R = 0.0;246for( i=0; i<12; i++ )247{248n = 0;249q = 0.0;250s = 1.0;251l = terms[i];252for( j=1; j<4; j++ )253{254p = 0.0;255t = 1.0;256for( k=0; k<4; k++, n++ ) { p += N[l][4*k+j]*t; t *= v; }257q += p * s;258s *= u;259}260R += F[i] * q;261}262263return R;264}265266/*******************************************************************************267*268* Name: elm_12node_quad_dndv_fvalue( double *,double,double )269*270* Purpose: return value of a first partial derivate in (v) of a271* quantity given on nodes at point (u,v)272*273*274* Parameters:275*276* Input: (double *) quantity values at nodes277* (double u,double v) point where values are evaluated278*279* Output: none280*281* Return value: quantity value282*283******************************************************************************/284static double elm_12node_quad_dndv_fvalue( double *F, double u, double v )285{286double R,q,p,s,t;287int i,j,k,l,n;288289R = 0.0;290for( i=0; i<12; i++ )291{292n = 0;293q = 0.0;294s = 1.0;295l = terms[i];296for( j=1; j<4; j++ )297{298p = 0.0;299t = 1.0;300for( k=0; k<4; k++, n++ ) { p += N[l][n]*t; t *= u; }301q += p * s;302s *= v;303}304R += F[i] * q;305}306307return R;308}309310/*******************************************************************************311*312* Name: elm_12node_quad_dd(double *F,double *u,double *v,double *Values)313*314* Purpose: Return matrix of second partial derivates of given quantity315* at given point u,v.316*317* Parameters:318*319* Input: (double *)F: quantity values at nodes320* (double)u,v: point of evaluation321*322* Output: (double *)Values: 2x2 matrix of partial derivates323*324* Return value: void325*326*******************************************************************************/327static void elm_12node_quad_ddu( double *F,double u,double v,double *Values )328{329double ddu = 0.0, dudv=0.0, ddv = 0.0;330double q,p,s,t;331int i,j,k,l,n;332333ddu = 0.0;334for( i=0; i<12; i++ )335{336n = 0;337q = 0.0;338s = 1.0;339l = terms[i];340for( j=2; j<4; j++ )341{342p = 0.0;343t = 1.0;344for( k=0; k<4; k++, n++ ) { p += N[l][4*k+j]*t; t *= v; }345q += p * s;346s *= u;347}348ddu += F[i] * q;349}350351ddv = 0.0;352for( i=0; i<16; i++ )353{354n = 0;355q = 0.0;356s = 1.0;357l = terms[i];358for( j=2; j<4; j++ )359{360p = 0.0;361t = 1.0;362for( k=0; k<4; k++, n++ ) { p += N[l][n]*t; t *= u; }363q += p * s;364s *= v;365}366ddv += F[i] * q;367}368369dudv = 0.0;370for( i=0; i<16; i++ )371{372n = 0;373q = 0.0;374s = 1.0;375l = terms[i];376for( j=1; j<4; j++ )377{378p = 0.0;379t = 1.0;380for( k=1; k<4; k++, n++ ) { p += N[l][n]*t; t *= u; }381q += p * s;382s *= v;383}384dudv += F[i] * q;385}386387Values[0] = ddu;388Values[1] = dudv;389Values[2] = dudv;390Values[3] = ddv;391}392393/*******************************************************************************394*395* Name: elm_12node_quad_point_inside(396* double *nx,double *ny,double *nz,397* double px, double py, double pz,398* double *u,double *v,double *w )399*400* Purpose: Find if point (px,py,pz) is inside the element, and return401* element coordinates of the point.402*403* Parameters:404*405* Input: (double *) nx,ny,nz n coordinates406* (double) px,py,pz point to consider407*408* Output: (double *) u,v,w point in element coordinates if inside409*410* Return value: in/out status411*412* NOTES: the goal here can be hard for more involved element types. kind of413* trivial for this one... TODO: FIX THIS....414*415******************************************************************************/416int elm_12node_quad_point_inside417(418double *nx, double *ny, double *nz,419double px, double py, double pz, double *u,double *v,double *w420)421{422double x[16],y[16],z[16],uu,vv,ww;423int i, j, k;424int elm_16node_quad_point_inside();425426for( i=0; i<12; i++ )427{428k = terms[i];429x[k] = nx[i];430y[k] = ny[i];431z[k] = nz[i];432}433434k = terms[12];435x[k] = elm_12node_quad_fvalue( nx,-1.0/3,-1.0/3 );436y[k] = elm_12node_quad_fvalue( ny,-1.0/3,-1.0/3 );437z[k] = elm_12node_quad_fvalue( nz,-1.0/3,-1.0/3 );438439k = terms[13];440x[k] = elm_12node_quad_fvalue( nx, 1.0/3,-1.0/3 );441y[k] = elm_12node_quad_fvalue( ny, 1.0/3,-1.0/3 );442z[k] = elm_12node_quad_fvalue( nz, 1.0/3,-1.0/3 );443444k = terms[14];445x[k] = elm_12node_quad_fvalue( nx, 1.0/3, 1.0/3 );446y[k] = elm_12node_quad_fvalue( ny, 1.0/3, 1.0/3 );447z[k] = elm_12node_quad_fvalue( nz, 1.0/3, 1.0/3 );448449k = terms[15];450x[k] = elm_12node_quad_fvalue( nx,-1.0/3, 1.0/3 );451y[k] = elm_12node_quad_fvalue( ny,-1.0/3, 1.0/3 );452z[k] = elm_12node_quad_fvalue( nz,-1.0/3, 1.0/3 );453454return elm_16node_quad_point_inside( x,y,z,px,py,pz,u,v,w );455}456457/*******************************************************************************458*459* Name: elm_12node_quad_isoline460*461* Purpose: Extract a iso line from triangle with given threshold462*463* Parameters:464*465* Input: (double) K, contour threshold466* (double *) F, contour quantity467* (double *) C, color quantity468* (double *) X,Y,Z vertex coords.469*470* Output: (line_t *) place to store the line471*472* Return value: number of lines generated (0,...,12)473*474******************************************************************************/475int elm_12node_quad_isoline476(477double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line478)479{480double f[16],c[16],x[16],y[16],z[16];481482int i,j,k,n=0,above=0;483int elm_16node_quad_isoline();484485for( i=0; i<12; i++ ) above += F[i]>K;486if ( above == 0 || above == 12 ) return 0;487488for( i=0; i<12; i++ )489{490k = terms[i];491f[k] = F[i];492c[k] = C[i];493x[k] = X[i];494y[k] = Y[i];495z[k] = Z[i];496}497498k = terms[12];499f[k] = elm_12node_quad_fvalue( F,-1.0/3,-1.0/3 );500c[k] = elm_12node_quad_fvalue( C,-1.0/3,-1.0/3 );501x[k] = elm_12node_quad_fvalue( X,-1.0/3,-1.0/3 );502y[k] = elm_12node_quad_fvalue( Y,-1.0/3,-1.0/3 );503z[k] = elm_12node_quad_fvalue( Z,-1.0/3,-1.0/3 );504505k = terms[13];506f[k] = elm_12node_quad_fvalue( F, 1.0/3,-1.0/3 );507c[k] = elm_12node_quad_fvalue( C, 1.0/3,-1.0/3 );508x[k] = elm_12node_quad_fvalue( X, 1.0/3,-1.0/3 );509y[k] = elm_12node_quad_fvalue( Y, 1.0/3,-1.0/3 );510z[k] = elm_12node_quad_fvalue( Z, 1.0/3,-1.0/3 );511512k = terms[14];513f[k] = elm_12node_quad_fvalue( F, 1.0/3, 1.0/3 );514c[k] = elm_12node_quad_fvalue( C, 1.0/3, 1.0/3 );515x[k] = elm_12node_quad_fvalue( X, 1.0/3, 1.0/3 );516y[k] = elm_12node_quad_fvalue( Y, 1.0/3, 1.0/3 );517z[k] = elm_12node_quad_fvalue( Z, 1.0/3, 1.0/3 );518519k = terms[15];520f[k] = elm_12node_quad_fvalue( F,-1.0/3, 1.0/3 );521c[k] = elm_12node_quad_fvalue( C,-1.0/3, 1.0/3 );522x[k] = elm_12node_quad_fvalue( X,-1.0/3, 1.0/3 );523y[k] = elm_12node_quad_fvalue( Y,-1.0/3, 1.0/3 );524z[k] = elm_12node_quad_fvalue( Z,-1.0/3, 1.0/3 );525526return elm_16node_quad_isoline( K,f,c,x,y,z,Line );527}528529530/******************************************************************************531*532* Name: elm_12node_quad_initialize( )533*534* Purpose: Register the element type535*536* Parameters:537*538* Input: (char *) description of the element539* (int) numeric code for the element540*541* Output: Global list of element types is modified542*543* Return value: malloc() success544*545******************************************************************************/546int elm_12node_quad_initialize()547{548element_type_t ElementDef;549550static char *Name = "ELM_12NODE_QUAD";551552int elm_add_element_type();553554elm_12node_quad_shape_functions();555556ElementDef.ElementName = Name;557ElementDef.ElementCode = 412;558559ElementDef.NumberOfNodes = 12;560ElementDef.NodeU = NodeU;561ElementDef.NodeV = NodeV;562ElementDef.NodeW = NULL;563564ElementDef.PartialU = (double (*)())elm_12node_quad_dndu_fvalue;565ElementDef.PartialV = (double (*)())elm_12node_quad_dndv_fvalue;566ElementDef.PartialW = NULL;567ElementDef.SecondPartials = (double (*)())elm_12node_quad_ddu;568569ElementDef.FunctionValue = (double (*)())elm_12node_quad_fvalue;570571ElementDef.Triangulate = (int (*)())elm_12node_quad_triangulate;572ElementDef.PointInside = (int (*)())elm_12node_quad_point_inside;573ElementDef.IsoLine = (int (*)())elm_12node_quad_isoline;574ElementDef.IsoSurface = (int (*)())NULL;575576return elm_add_element_type( &ElementDef );577}578579580