/*****************************************************************************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 4 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* Four node quadrilater surface element54*55* 3----------256* | |57* | |58* v | |59* 0----------160* u61*/6263static double N[4][4] =64{65{ 1.0/4.0, -1.0/4.0, -1.0/4.0, 1.0/4.0 }, /* 1 - u - v + uv */66{ 1.0/4.0, 1.0/4.0, -1.0/4.0, -1.0/4.0 },67{ 1.0/4.0, 1.0/4.0, 1.0/4.0, 1.0/4.0 },68{ 1.0/4.0, -1.0/4.0, 1.0/4.0, -1.0/4.0 }69};7071static double NodeU[] = { -1.0, 1.0, 1.0, -1.0, 0.0 };72static double NodeV[] = { -1.0, -1.0, 1.0, 1.0, 0.0 };7374/*******************************************************************************75*76* Name: elm_4node_quad_triangulate( geometry_t *,element_t * )77*78* Purpose: Triangulate an element. The process also builds up an edge79* table and adds new nodes to node table. The triangulation80* and edge table is stored in geometry_t *geom-structure.81*82* Parameters:83*84* Input: (geometry_t *) pointer to structure holding triangulation85* (element_t *) element to triangulate86*87* Output: (geometry_t *) structure is modified88*89* Return value: FALSE if malloc() fails, TRUE otherwise90*91******************************************************************************/92int elm_4node_quad_triangulate( geometry_t *geom,element_t *Elm,element_t *Parent )93{94double x[4],y[4],z[4],f[4][4],elm_4node_quad_fvalue();9596triangle_t triangle;97vertex_t vertex;9899int i,j,n;100101#if 0102for( i=0; i<4; i++ )103{104x[i] = geom->Vertices[Elm->Topology[i]].x[0];105y[i] = geom->Vertices[Elm->Topology[i]].x[1];106z[i] = geom->Vertices[Elm->Topology[i]].x[2];107108for( j=0; j<4; j++ )109{110f[j][i] = FuncArray[j][Elm->Topology[i]];111}112}113114vertex.x[0] = elm_4node_quad_fvalue(x,0.0,0.0);115vertex.x[1] = elm_4node_quad_fvalue(y,0.0,0.0);116vertex.x[2] = elm_4node_quad_fvalue(z,0.0,0.0);117vertex.ElementModelNode = FALSE;118119if ( (n=geo_add_vertex( geom,&vertex )) < 0 ) return FALSE;120121for( j=0; j<4; j++ )122{123FuncArray[j][n] = elm_4node_quad_fvalue(f[j],0.0,0.0);124}125126triangle.Element = Elm;127for( i=0; i<4; i++ )128{129triangle.v[0] = Elm->Topology[i];130if ( i==3 )131triangle.v[1] = Elm->Topology[0];132else133triangle.v[1] = Elm->Topology[i+1];134triangle.v[2] = n;135136geo_triangle_normal( geom,&triangle );137138triangle.Edge[0] = TRUE;139triangle.Edge[1] = FALSE;140triangle.Edge[2] = FALSE;141142if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;143}144#else145triangle.Element = Parent;146147triangle.v[0] = Elm->Topology[0];148triangle.v[1] = Elm->Topology[1];149triangle.v[2] = Elm->Topology[2];150151triangle.Edge[0] = TRUE;152triangle.Edge[1] = TRUE;153triangle.Edge[2] = FALSE;154155if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;156157triangle.v[0] = Elm->Topology[0];158triangle.v[1] = Elm->Topology[2];159triangle.v[2] = Elm->Topology[3];160161triangle.Edge[0] = FALSE;162triangle.Edge[1] = TRUE;163triangle.Edge[2] = TRUE;164165if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;166#endif167168return TRUE;169}170171/*******************************************************************************172*173* Name: elm_4node_quad_nvalue( double *,double,double )174*175* Purpose: return shape function values at given point (u,v)176*177*178*179* Parameters:180*181* Input: (double u,double v) point where values are evaluated182*183* Output: (double *) storage for values184*185* Return value: void186*187******************************************************************************/188static void elm_4node_quad_nvalue( double *R, double u, double v )189{190int i;191192for( i=0; i<4; i++ )193{194R[i] = N[i][0] + N[i][1]*u + N[i][2]*v + N[i][3]*u*v;195}196}197198/*******************************************************************************199*200* Name: elm_4node_quad_fvalue( double *,double,double )201*202* Purpose: return value of a quantity given on nodes at point (u,v)203*204*205*206* Parameters:207*208* Input: (double *) quantity values at nodes209* (double u,double v) point where values are evaluated210*211* Output: none212*213* Return value: quantity value214*215******************************************************************************/216double elm_4node_quad_fvalue( double *F, double u, double v )217{218double R=0.0,uv=u*v;219int i;220221for( i=0; i<4; i++ )222{223R += F[i]*( N[i][0] + N[i][1]*u + N[i][2]*v + N[i][3]*uv );224}225226return R;227}228229/*******************************************************************************230*231* Name: elm_4node_quad_dndu_fvalue( double *,double,double )232*233* Purpose: return value of a first partial derivate in (u) of a234* quantity given on nodes at point (u,v)235*236*237* Parameters:238*239* Input: (double *) quantity values at nodes240* (double u,double v) point where values are evaluated241*242* Output: none243*244* Return value: quantity value245*246******************************************************************************/247static double elm_4node_quad_dndu_fvalue( double *F, double u, double v )248{249double R=0.0;250int i;251252for( i=0; i<4; i++ ) R += F[i]*(N[i][1] + N[i][3]*v);253254return R;255}256257/*******************************************************************************258*259* Name: elm_4node_quad_dndv_fvalue( double *,double,double )260*261* Purpose: return value of a first partial derivate in (v) of a262* quantity given on nodes at point (u,v)263*264*265* Parameters:266*267* Input: (double *) quantity values at nodes268* (double u,double v) point where values are evaluated269*270* Output: none271*272* Return value: quantity value273*274******************************************************************************/275static double elm_4node_quad_dndv_fvalue( double *F, double u, double v )276{277double R=0.0;278int i;279280for( i=0; i<4; i++ ) R += F[i]*(N[i][2] + N[i][3]*u);281282return R;283}284285/*******************************************************************************286*287* Name: elm_4node_quad_point_inside(288* double *nx,double *ny,double *nz,289* double px, double py, double pz,290* double *u,double *v,double *w )291*292* Purpose: Find if point (px,py,pz) is inside the element, and return293* element coordinates of the point.294*295* Parameters:296*297* Input: (double *) nx,ny,nz node coordinates298* (double) px,py,pz point to consider299*300* Output: (double *) u,v,w point in element coordinates if inside301*302* Return value: in/out status303*304* NOTES: the goal here can be hard for more involved element types. kind of305* trivial for this one...306*307******************************************************************************/308int elm_4node_quad_point_inside309(310double *nx, double *ny, double *nz,311double px, double py, double pz, double *u,double *v,double *w312)313{314double ax,bx,cx,dx,ay,by,cy,dy,a,b,c,d,r;315316*u = *v = *w = 0.0;317318if ( px > MAX(MAX(MAX( nx[0],nx[1] ),nx[2] ),nx[3] ) ) return FALSE;319if ( px < MIN(MIN(MIN( nx[0],nx[1] ),nx[2] ),nx[3] ) ) return FALSE;320321if ( py > MAX(MAX(MAX( ny[0],ny[1] ),ny[2] ),ny[3] ) ) return FALSE;322if ( py < MIN(MIN(MIN( ny[0],ny[1] ),ny[2] ),ny[3] ) ) return FALSE;323#if 0324if ( pz > MAX(MAX(MAX( nz[0],nz[1] ),nz[2] ),nz[3] ) ) return FALSE;325if ( pz < MIN(MIN(MIN( nz[0],nz[1] ),nz[2] ),nz[3] ) ) return FALSE;326#endif327328ax = 0.25*( nx[0] + nx[1] + nx[2] + nx[3] );329bx = 0.25*( -nx[0] + nx[1] + nx[2] - nx[3] );330cx = 0.25*( -nx[0] - nx[1] + nx[2] + nx[3] );331dx = 0.25*( nx[0] - nx[1] + nx[2] - nx[3] );332333ay = 0.25*( ny[0] + ny[1] + ny[2] + ny[3] );334by = 0.25*( -ny[0] + ny[1] + ny[2] - ny[3] );335cy = 0.25*( -ny[0] - ny[1] + ny[2] + ny[3] );336dy = 0.25*( ny[0] - ny[1] + ny[2] - ny[3] );337338px -= ax;339py -= ay;340341a = cy*dx - cx*dy;342b = bx*cy - by*cx + dy*px - dx*py;343c = by*px - bx*py;344345*u = *v = *w = 0.0;346347if ( ABS(a) < AEPS )348{349r = -c/b;350if ( r < -1.0 || r > 1.0 ) return FALSE;351352*v = r;353if ( ABS(bx + dx*r) < AEPS )354*u = (py - cy*r)/(by + dy*r);355else356*u = (px - cx*r)/(bx + dx*r);357358return (*u >= -1.0 && *u <= 1.0);359}360361if ( (d=b*b - 4*a*c) < 0.0 ) return FALSE;362363r = 1.0/(2*a);364b = r*b;365d = r*sqrt(d);366367r = -b + d;368if ( r >= -1.0 && r <= 1.0 )369{370*v = r;371if ( ABS(bx + dx*r) < AEPS )372*u = (py - cy*r)/(by + dy*r);373else374*u = (px - cx*r)/(bx + dx*r);375if ( *u >= -1.0 && *u <= 1.0 ) return TRUE;376}377378r = -b - d;379if ( r >= -1.0 && r <= 1.0 )380{381*v = r;382if ( ABS(bx + dx*r) < AEPS )383*u = (py - cy*r)/(by + dy*r);384else385*u = (px - cx*r)/(bx + dx*r);386return (*u >= -1.0 && *u <= 1.0 );387}388389return FALSE;390}391392/*******************************************************************************393*394* Name: elm_4node_quad_isoline395*396* Purpose: Extract a iso line from triangle with given threshold397*398* Parameters:399*400* Input: (double) K, contour threshold401* (double *) F, contour quantity402* (double *) C, color quantity403* (double *) X,Y,Z vertex coords.404*405* Output: (line_t *) place to store the line406*407* Return value: number of lines generated (0,...,4)408*409******************************************************************************/410int elm_4node_quad_isoline411(412double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line413)414{415double f[3],c[3],x[3],y[3],z[3];416417int i, n=0, above=0;418int elm_3node_triangle_isoline();419420for( i=0; i<4; i++ ) above += F[i]>K;421if ( above == 0 || above == 4 ) return 0;422423f[0] = elm_4node_quad_fvalue( F,0.0,0.0 );424c[0] = elm_4node_quad_fvalue( C,0.0,0.0 );425x[0] = elm_4node_quad_fvalue( X,0.0,0.0 );426y[0] = elm_4node_quad_fvalue( Y,0.0,0.0 );427z[0] = elm_4node_quad_fvalue( Z,0.0,0.0 );428429f[1] = F[3];430c[1] = C[3];431x[1] = X[3];432y[1] = Y[3];433z[1] = Z[3];434for( i=0; i<4; i++ )435{436f[2] = F[i];437c[2] = C[i];438x[2] = X[i];439y[2] = Y[i];440z[2] = Z[i];441442n += elm_3node_triangle_isoline( K,f,c,x,y,z,&Line[n] );443444f[1] = F[i];445c[1] = C[i];446x[1] = X[i];447y[1] = Y[i];448z[1] = Z[i];449}450451return n;452}453454455/******************************************************************************456*457* Name: elm_4node_quad_initialize( )458*459* Purpose: Register the element type460*461* Parameters:462*463* Input: (char *) description of the element464* (int) numeric code for the element465*466* Output: Global list of element types is modified467*468* Return value: malloc() success469*470******************************************************************************/471int elm_4node_quad_initialize()472{473element_type_t ElementDef;474475static char *Name = "ELM_4NODE_QUAD";476int elm_add_element_type();477478ElementDef.ElementName = Name;479ElementDef.ElementCode = 404;480481ElementDef.NumberOfNodes = 4;482ElementDef.NodeU = NodeU;483ElementDef.NodeV = NodeV;484ElementDef.NodeW = NULL;485486ElementDef.PartialU = (double (*)())elm_4node_quad_dndu_fvalue;487ElementDef.PartialV = (double (*)())elm_4node_quad_dndv_fvalue;488ElementDef.PartialW = NULL;489490ElementDef.FunctionValue = (double (*)())elm_4node_quad_fvalue;491ElementDef.Triangulate = (int (*)())elm_4node_quad_triangulate;492ElementDef.PointInside = (int (*)())elm_4node_quad_point_inside;493ElementDef.IsoLine = (int (*)())elm_4node_quad_isoline;494ElementDef.IsoSurface = (int (*)())NULL;495496return elm_add_element_type( &ElementDef );497}498499500