1 /*****************************************************************************
2  *
3  *  Elmer, A Finite Element Software for Multiphysical Problems
4  *
5  *  Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6  *
7  *  This program is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU General Public License
9  *  as published by the Free Software Foundation; either version 2
10  *  of the License, or (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program (in file fem/GPL-2); if not, write to the
19  *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  *****************************************************************************/
23 
24 /*******************************************************************************
25  *
26  * Definition of three node triangle element.
27  *
28  *******************************************************************************
29  *
30  *                     Author:       Juha Ruokolainen
31  *
32  *                    Address: CSC - IT Center for Science Ltd.
33  *                                Keilaranta 14, P.O. BOX 405
34  *                                  02101 Espoo, Finland
35  *                                  Tel. +358 0 457 2723
36  *                                Telefax: +358 0 457 2302
37  *                              EMail: Juha.Ruokolainen@csc.fi
38  *
39  *                       Date: 20 Sep 1995
40  *
41  *
42  * Modification history:
43  *
44  * 28 Sep 1995, changed call to elm_triangle_normal to geo_triangle normal
45  *              routine elm_... doesn't exist anymore
46  *
47  ******************************************************************************/
48 
49 #include "../elmerpost.h"
50 #include <elements.h>
51 
52 /*
53  * Three node triangular surface element
54  *
55  *         2 v=1
56  *        / \
57  *       /   \
58  *      /     \
59  *     0-------1 u=1
60  *
61  */
62 static double N[3][3] =
63 {
64     { 1.0,-1.0,-1.0 },
65     { 0.0, 1.0, 0.0 },
66     { 0.0, 0.0, 1.0 }
67 };
68 
69 static double NodeU[3] = { 0.0, 1.0, 0.0 };
70 static double NodeV[3] = { 0.0, 0.0, 1.0 };
71 
72 /*******************************************************************************
73  *
74  *     Name:        elm_4node_triangle_triangulate( geometry_t *,element_t * )
75  *
76  *     Purpose:     Triangulate an element. The process also builds up an edge
77  *                  table and adds new nodes to node table. The triangulation
78  *                  and edge table is stored in geometry_t *geom-structure.
79  *
80  *     Parameters:
81  *
82  *         Input:   (geometry_t *) pointer to structure holding triangulation
83  *                  (element_t  *) element to triangulate
84  *
85  *         Output:  (geometry_t *) structure is modified
86  *
87  *   Return value:  FALSE if malloc() fails, TRUE otherwise
88  *
89  ******************************************************************************/
elm_4node_triangle_triangulate(geometry_t * geom,element_t * Elm,element_t * Parent)90 int elm_4node_triangle_triangulate( geometry_t *geom, element_t *Elm, element_t *Parent)
91 {
92     double u,v,w,s;
93 
94     int i,j;
95 
96     triangle_t triangle;
97 
98     triangle.Element = Parent;
99     for( i=0; i<3; i++ )
100     {
101         triangle.v[i] = Elm->Topology[i];
102         triangle.Edge[i] = TRUE;
103     }
104     geo_triangle_normal( geom,&triangle );
105 
106     return geo_add_triangle( geom, &triangle );
107 }
108 
109 /*******************************************************************************
110  *
111  *     Name:        elm_4node_triangle_point_inside(
112  *                         double *nx,double *ny,double *nz,
113  *                         double px, double py, double pz,
114  *                         double *u,double *v,double *w )
115  *
116  *     Purpose:     Find if point (px,py,pz) is inside the element, and return
117  *                  element coordinates of the point.
118  *
119  *     Parameters:
120  *
121  *         Input:   (double *) nx,ny,nz node coordinates
122  *                  (double) px,py,pz point to consider
123  *
124  *         Output:  (double *) u,v,w point in element coordinates if inside
125  *
126  *   Return value:  in/out status
127  *
128  * NOTES: the goal here can be hard for more involved element types. kind of
129  *        trivial for this one... (TODO: this is for xy-plane tri only)
130  *
131  ******************************************************************************/
elm_4node_triangle_point_inside(double * nx,double * ny,double * nz,double px,double py,double pz,double * u,double * v,double * w)132 int elm_4node_triangle_point_inside
133    (
134                    double *nx, double *ny, double *nz,
135          double px, double py, double pz, double *u,double *v,double *w
136    )
137 {
138     double A00,A01,A10,A11,B00,B01,B10,B11,detA;
139 
140     if ( px > MAX(MAX( nx[0],nx[1] ),nx[2] ) ) return FALSE;
141     if ( px < MIN(MIN( nx[0],nx[1] ),nx[2] ) ) return FALSE;
142 
143     if ( py > MAX(MAX( ny[0],ny[1] ),ny[2] ) ) return FALSE;
144     if ( py < MIN(MIN( ny[0],ny[1] ),ny[2] ) ) return FALSE;
145 
146 #if 0
147     if ( pz > MAX(MAX( nz[0],nz[1] ),nz[2] ) ) return FALSE;
148     if ( pz < MIN(MIN( nz[0],nz[1] ),nz[2] ) ) return FALSE;
149 #endif
150 
151     A00 = nx[1] - nx[0];
152     A01 = nx[2] - nx[0];
153     A10 = ny[1] - ny[0];
154     A11 = ny[2] - ny[0];
155 
156     detA = A00*A11 - A01*A10;
157     if ( ABS(detA) < AEPS )
158     {
159         fprintf( stderr, "4node_triangle_inside: SINGULAR, HUH? \n" );
160         return FALSE;
161     }
162 
163     detA = 1/detA;
164 
165     B00 =  A11*detA;
166     B10 = -A10*detA;
167     B01 = -A01*detA;
168     B11 =  A00*detA;
169 
170     px -= nx[0];
171     py -= ny[0];
172     *u = *v = *w = 0.0;
173 
174     *u = B00*px + B01*py;
175     if ( *u < 0.0 || *u > 1.0 ) return FALSE;
176 
177     *v = B10*px + B11*py;
178     if ( *v < 0.0 || *v > 1.0 ) return FALSE;
179 
180     return (*u + *v) <= 1.0;
181 }
182 
183 /*******************************************************************************
184  *
185  *     Name:        elm_4node_triangle_fvalue( double *,double,double )
186  *
187  *     Purpose:     return value of a quantity given on nodes at point (u,v)
188  *
189  *
190  *     Parameters:
191  *
192  *         Input:  (double *) quantity values at nodes
193  *                 (double u,double v) point where value is evaluated
194  *
195  *         Output:  none
196  *
197  *   Return value:  quantity value
198  *
199  ******************************************************************************/
elm_4node_triangle_fvalue(double * F,double u,double v)200 static double elm_4node_triangle_fvalue(double *F,double u,double v)
201 {
202     return F[0]*(1-u-v) + F[1]*u  + F[2]*v;
203 }
204 
205 /*******************************************************************************
206  *
207  *     Name:        elm_4node_triangle_dndu_fvalue( double *,double,double )
208  *
209  *     Purpose:     return value of a first partial derivate in (u) of a
210  *                  quantity given on nodes at point (u,v)
211  *
212  *
213  *     Parameters:
214  *
215  *         Input:  (double *) quantity values at nodes
216  *                 (double u,double v) point where value is evaluated
217  *
218  *         Output:  none
219  *
220  *   Return value:  quantity value
221  *
222  ******************************************************************************/
elm_4node_triangle_dndu_fvalue(double * F,double u,double v)223 static double elm_4node_triangle_dndu_fvalue(double *F,double u,double v)
224 {
225     return -F[0] + F[1];
226 }
227 
228 /*******************************************************************************
229  *
230  *     Name:        elm_4node_triangle_dndv_fvalue( double *,double,double )
231  *
232  *     Purpose:     return value of a first partial derivate in (v) of a
233  *                  quantity given on nodes at point (u,v)
234  *
235  *
236  *     Parameters:
237  *
238  *         Input:  (double *) quantity values at nodes
239  *                 (double u,double v) point where value is evaluated
240  *
241  *         Output:  none
242  *
243  *   Return value:  quantity value
244  *
245  ******************************************************************************/
elm_4node_triangle_dndv_fvalue(double * F,double u,double v)246 static double elm_4node_triangle_dndv_fvalue(double *F,double u,double v)
247 {
248      return -F[0] + F[2];
249 }
250 
251 #define FEPS 1.0E-9
252 
253 /*******************************************************************************
254  *
255  *     Name:        elm_4node_triangle_isoline
256  *
257  *     Purpose:     Extract a iso line from triangle with given threshold
258  *
259  *     Parameters:
260  *
261  *         Input:   (double) K, contour threshold
262  *                  (double *) F, contour quantity
263  *                  (double *) C, color quantity
264  *                  (double *) X,Y,Z vertex coords.
265  *
266  *         Output:  (line_t *)  place to store the line
267  *
268  *   Return value:  number of lines generated (0 or 1)
269  *
270 *******************************************************************************/
elm_4node_triangle_isoline(double K,double * F,double * C,double * X,double * Y,double * Z,line_t * Line)271 int elm_4node_triangle_isoline
272   (
273      double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line
274   )
275 {
276     double F0=F[0],F1=F[1],F2=F[2],t;
277     int i,n=0;
278 
279     int S0 = (F0 > K);
280     int S1 = (F1 > K);
281     int S2 = (F2 > K);
282     int S = S0 + S1 + S2;
283 
284     if ( S==0 || S==3 ) return 0;
285 
286     if (S0 ^ S1)
287     {
288         if ( ABS(F1-F0) < FEPS ) return 0;
289         t = (K-F0)/(F1-F0);
290 
291         Line->x[n] = t*(X[1] - X[0]) + X[0];
292         Line->y[n] = t*(Y[1] - Y[0]) + Y[0];
293         Line->z[n] = t*(Z[1] - Z[0]) + Z[0];
294         Line->f[n] = K;
295         if ( C ) Line->c[n] = t*(C[1] - C[0]) + C[0];
296         n++;
297     }
298 
299     if (S0 ^ S2)
300     {
301         if ( ABS(F2-F0) < FEPS ) return 0;
302         t = (K-F0)/(F2-F0);
303 
304         Line->x[n] = t*(X[2] - X[0]) + X[0];
305         Line->y[n] = t*(Y[2] - Y[0]) + Y[0];
306         Line->z[n] = t*(Z[2] - Z[0]) + Z[0];
307         Line->f[n] = K;
308         if ( C ) Line->c[n] = t*(C[2] - C[0]) + C[0];
309         n++;
310     }
311 
312     if (S1 ^ S2)
313     {
314         if ( ABS(F2-F1) < FEPS ) return 0;
315         t = (K-F1)/(F2-F1);
316 
317         Line->x[n] = t*(X[2] - X[1]) + X[1];
318         Line->y[n] = t*(Y[2] - Y[1]) + Y[1];
319         Line->z[n] = t*(Z[2] - Z[1]) + Z[1];
320         Line->f[n] = K;
321         if ( C ) Line->c[n] = t*(C[2] - C[1]) + C[1];
322         n++;
323     }
324 
325     return (n>=2);
326 }
327 
328 
329 /*******************************************************************************
330  *
331  *     Name:        elm_4node_triangle_initialize()
332  *
333  *     Purpose:     Register the element type
334  *
335  *     Parameters:
336  *
337  *         Input:  (char *) description of the element
338  *                 (int)    numeric code for the element
339  *
340  *         Output:  Global list of element types is modified
341  *
342  *   Return value:  malloc() success
343  *
344  ******************************************************************************/
elm_4node_triangle_initialize()345 int elm_4node_triangle_initialize()
346 {
347      static char *Name = "ELM_4NODE_TRIANGLE";
348 
349      element_type_t ElementDef;
350 
351      ElementDef.ElementName = Name;
352      ElementDef.ElementCode = 304;
353 
354      ElementDef.NumberOfNodes = 4;
355 
356      ElementDef.NodeU = NodeU;
357      ElementDef.NodeV = NodeV;
358      ElementDef.NodeW = NULL;
359 
360      ElementDef.PartialU = (double (*)())elm_4node_triangle_dndu_fvalue;
361      ElementDef.PartialV = (double (*)())elm_4node_triangle_dndv_fvalue;
362      ElementDef.PartialW = (double (*)())NULL;
363 
364      ElementDef.FunctionValue = (double (*)())elm_4node_triangle_fvalue;
365      ElementDef.Triangulate   = (int (*)())elm_4node_triangle_triangulate;
366      ElementDef.IsoLine       = (int (*)())elm_4node_triangle_isoline;
367      ElementDef.PointInside   = (int (*)())elm_4node_triangle_point_inside;
368      ElementDef.IsoSurface    = (int (*)())NULL;
369 
370      return elm_add_element_type( &ElementDef ) ;
371 }
372