1
#include "fdebug_adapt.h"
3
!#define LIPNIKOV_FUNCTIONAL
4
#ifdef LIPNIKOV_FUNCTIONAL
5
function elmfnc(biglst, nodlst, ielm, nod1, nod2, nod3, nod4,
6
& undlen) result(functional)
13
integer :: ielm, nod1, nod2, nod3, nod4
18
real, parameter :: m=2.0*huge(0)-3.0, c= -1.0*huge(0)+2.0 ! mapping between reals and ints for the cache
19
real, dimension(9) :: metric
20
real, dimension(3) :: tmppos
21
real, dimension(3, 3) :: positions
22
real :: volume ! volume with respect to the metric
23
real :: metric_determinant ! determinant of the metric
24
real :: tetvol ! volume of the tet in physical space
25
real :: edgelens ! 2-norm of vector of edge lengths in metric space
26
real :: F ! from Agouzal et al, 1999
28
real, parameter :: factor = 6.0**(2.5) * sqrt(2.0)
30
integer, dimension(4) :: nods
32
real, parameter :: bst = 12.0 / sqrt(2.0) ! inverse of ideal tet volume
33
integer :: intval ! undlen cast to an integer
36
C - Sort the nodes into ascending order
45
IF( K .GT. NODS(2) ) THEN
52
IF( K .GT. NODS(3) ) THEN
59
IF( K .GT. NODS(4) ) THEN
65
IF( K .GT. NODS(2) ) THEN
72
IF( K .GT. NODS(3) ) THEN
78
IF( K .GT. NODS(2) ) THEN
85
cache = biglst(7, ielm)
86
ielm2 = biglst(nxtbig, ielm)
92
! if we have no cached information, then we need to compute it, na ja?
94
! first things first, let us fetch the metric and positions
95
tmppos = nodlst(1:3, nods(1))
96
metric = nodlst(7:15, nods(1))
98
positions(:, 1) = nodlst(1:3, nods(2)) - tmppos
99
metric = metric + nodlst(7:15, nods(2))
101
positions(:, 2) = nodlst(1:3, nods(3)) - tmppos
102
metric = metric + nodlst(7:15, nods(3))
104
positions(:, 3) = nodlst(1:3, nods(4)) - tmppos
105
metric = metric + nodlst(7:15, nods(4))
107
metric = metric / 4.0
110
& metric(1) * (metric(5) * metric(9) - metric(6) * metric(8))
111
&- metric(2) * (metric(4) * metric(9) - metric(6) * metric(7))
112
&+ metric(3) * (metric(4) * metric(8) - metric(5) * metric(7))
115
& positions(1,1) * (positions(2,2) * positions(3,3) - positions(2,3) * positions(3,2))
116
&- positions(1,2) * (positions(2,1) * positions(3,3) - positions(2,3) * positions(3,1))
117
&+ positions(1,3) * (positions(2,1) * positions(3,2) - positions(2,2) * positions(3,1))
118
tetvol = tetvol / 6.0
120
undlen = sqrt(metric_determinant) * tetvol
121
! if(negate) undlen = - undlen
123
undlen = undlen * bst
125
!write(0,*) "computed undlen: ", undlen
126
tmppos = positions(:, 1)
128
& tmppos(1) * (metric(1) * tmppos(1) + metric(2) * tmppos(2) + metric(3) * tmppos(3))
129
&+ tmppos(2) * (metric(4) * tmppos(1) + metric(5) * tmppos(2) + metric(6) * tmppos(3))
130
&+ tmppos(3) * (metric(7) * tmppos(1) + metric(8) * tmppos(2) + metric(9) * tmppos(3))
132
tmppos = positions(:, 2)
133
edgelens = edgelens +
134
& tmppos(1) * (metric(1) * tmppos(1) + metric(2) * tmppos(2) + metric(3) * tmppos(3))
135
&+ tmppos(2) * (metric(4) * tmppos(1) + metric(5) * tmppos(2) + metric(6) * tmppos(3))
136
&+ tmppos(3) * (metric(7) * tmppos(1) + metric(8) * tmppos(2) + metric(9) * tmppos(3))
138
tmppos = positions(:, 3)
139
edgelens = edgelens +
140
& tmppos(1) * (metric(1) * tmppos(1) + metric(2) * tmppos(2) + metric(3) * tmppos(3))
141
&+ tmppos(2) * (metric(4) * tmppos(1) + metric(5) * tmppos(2) + metric(6) * tmppos(3))
142
&+ tmppos(3) * (metric(7) * tmppos(1) + metric(8) * tmppos(2) + metric(9) * tmppos(3))
144
tmppos = positions(:, 1) - positions(:, 2)
145
edgelens = edgelens +
146
& tmppos(1) * (metric(1) * tmppos(1) + metric(2) * tmppos(2) + metric(3) * tmppos(3))
147
&+ tmppos(2) * (metric(4) * tmppos(1) + metric(5) * tmppos(2) + metric(6) * tmppos(3))
148
&+ tmppos(3) * (metric(7) * tmppos(1) + metric(8) * tmppos(2) + metric(9) * tmppos(3))
150
tmppos = positions(:, 1) - positions(:, 3)
151
edgelens = edgelens +
152
& tmppos(1) * (metric(1) * tmppos(1) + metric(2) * tmppos(2) + metric(3) * tmppos(3))
153
&+ tmppos(2) * (metric(4) * tmppos(1) + metric(5) * tmppos(2) + metric(6) * tmppos(3))
154
&+ tmppos(3) * (metric(7) * tmppos(1) + metric(8) * tmppos(2) + metric(9) * tmppos(3))
156
tmppos = positions(:, 2) - positions(:, 3)
157
edgelens = edgelens +
158
& tmppos(1) * (metric(1) * tmppos(1) + metric(2) * tmppos(2) + metric(3) * tmppos(3))
159
&+ tmppos(2) * (metric(4) * tmppos(1) + metric(5) * tmppos(2) + metric(6) * tmppos(3))
160
&+ tmppos(3) * (metric(7) * tmppos(1) + metric(8) * tmppos(2) + metric(9) * tmppos(3))
162
edgelens = sqrt(edgelens)
164
x = edgelens / sqrt(6.0); x = min(x, 1.0/x)
166
functional = factor * (volume / edgelens**3) * F
168
undlen = min(max(undlen, -2.01E+3), 2.01E+3)
169
intval = int(undlen * 1000000)
170
undlen = float(intval) / 1000000
172
biglst(7, ielm) = intval
173
biglst(7, ielm2) = int(m * functional + c)
176
undlen = float(cache) / 1000000
177
functional = (biglst(7, ielm2) - c) / m
180
if (negate) undlen = -undlen
181
!write(0,*) "negate: ", negate, "; returning undlen: ", undlen
182
assert(functional >= 0.0)
183
assert(functional <= 1.0)
185
! And swap for adaptivity's convention
186
functional = 5.0/max(functional, 5.0e-30) - 5.0
190
C Copyright (C) 2006 Imperial College London and others.
192
C Please see the AUTHORS file in the main source directory for a full list
193
C of copyright holders.
196
C Applied Modelling and Computation Group
197
C Department of Earth Science and Engineering
198
C Imperial College London
200
C adrian@Imperial.ac.uk
202
C This library is free software; you can redistribute it and/or
203
C modify it under the terms of the GNU Lesser General Public
204
C License as published by the Free Software Foundation; either
205
C version 2.1 of the License.
207
C This library is distributed in the hope that it will be useful,
208
C but WITHOUT ANY WARRANTY; without even the implied warranty of
209
C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
210
C Lesser General Public License for more details.
212
C You should have received a copy of the GNU Lesser General Public
213
C License along with this library; if not, write to the Free Software
214
C Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
217
REAL FUNCTION ELMFNC( BIGLST, NODLST, IELM,
218
: NOD1, NOD2, NOD3, NOD4, UNDLEN )
219
C-----------------------------------------------------------------------
221
C - This subroutine calculates the element functional.
222
C - The functional is calculated from the four node pointers (NOD1-NOD4)
223
C - which have to be first arranged in ascending order (this makes sure
224
C - that the element will have the same functional every time it is
225
C - calculated, by removing round-off errors because the order of nodes
226
C - is the same each time).
227
C - If IELM>0 and element IELM has not already had its functional worked
228
C - out then xeveral critical values (sum of edge functionals etc) are
229
C - worked out and stored for use next time the functional is required
230
C - for this element. This reduces the amount of calculation required.
232
C-----------------------------------------------------------------------
236
REAL, PARAMETER :: BST = 4.898979486 ! sqrt(24)
245
COMMON / BLKTMP / ANGLEFACT
247
INTEGER IELM, NOD1, NOD2, NOD3, NOD4
251
integer i, j, k, nods(4), intval, nxt1, s
253
REAL X(4), Y(4), Z(4), V1(3), V2(3), V3(3), D1, D2, D3, D, Q,
254
: M(9), AREAS(4), VOL, EDGFNC, a, b, c,xx(4),yy(4),zz(4),
255
: L(6), det, getdtm, angfnc
257
logical negate, tstdts
266
IF( IERR .NE. 0 ) RETURN
268
C - Sort the nodes into ascending order
276
IF( K .GT. NODS(2) ) THEN
279
NEGATE = .NOT. NEGATE
283
IF( K .GT. NODS(3) ) THEN
286
NEGATE = .NOT. NEGATE
290
IF( K .GT. NODS(4) ) THEN
293
NEGATE = .NOT. NEGATE
296
IF( K .GT. NODS(2) ) THEN
299
NEGATE = .NOT. NEGATE
303
IF( K .GT. NODS(3) ) THEN
306
NEGATE = .NOT. NEGATE
309
IF( K .GT. NODS(2) ) THEN
312
NEGATE = .NOT. NEGATE
315
cc if( debug ) print*,' sorted: ',nods
317
C - Read the in-sphere radius stored in BIGLST
321
IF( IELM .GT. 0 ) THEN
322
INTVAL = BIGLST(7,IELM)
323
NXT1 = BIGLST(NXTBIG,IELM)
326
C - If there is no stored in-sphere info, then calculate it
328
IF( INTVAL .EQ. 0 ) THEN
335
if( tstdts .or. debug ) then
336
det = getdtm( nodlst(7,nods(i)) )
337
if( det .lt. 1e-20 ) then
338
print*,'+++ ELMFNC: Warning, small det:', det,nods(i)
339
print*,(nodlst(j,nods(i)),j=7,9)
340
print*,(nodlst(j,nods(i)),j=10,12)
341
print*,(nodlst(j,nods(i)),j=13,15)
344
X(I) = NODLST(1,NODS(I))
345
Y(I) = NODLST(2,NODS(I))
346
Z(I) = NODLST(3,NODS(I))
348
M(J) = M(J) + NODLST(J+6,NODS(I))*0.25
352
C - get all the element info with respect to metric M
353
C - (Volume, Face areas, Edge lengths, In-sphere, Quality)
355
CALL MTETIN( X, Y, Z, M, VOL, AREAS, L, UNDLEN, Q )
357
cc if( debug ) print*,' vol,rad,qly: ',vol,undlen,q
359
C - If we are using the quality of the element (instead of the in-sphere)...
361
if( useqly ) undlen = 1.0/q/bst
365
C - Don't worry about the maximum in-sphere radius, since such large
366
C - sizes will not contribute anything significant to the functional
368
D = MIN(MAX(D,-2.01E+3),2.01E+3)
370
INTVAL = INT(D*1000000)
371
IF( ABS(INTVAL) .LE. 1 ) THEN
372
IF( INTVAL .EQ. 0 .AND. IELM .LE. 0 ) THEN
374
IF( NEGATE ) UNDLEN = -UNDLEN
377
IF( D .GT. 0.0 ) THEN
379
ELSE IF( D .LT. 0.0 ) THEN
383
: '*** ELMFNC: GOT ZERO IN-SPHERE!',IELM
384
IF( IELM .LE. 0 ) write(0,*)
385
: ' Nodes: ',NOD1,NOD2,NOD3,NOD4
387
IF( IELM .GT. 0 .AND. INTVAL .EQ. 0 ) THEN
389
: '+++ Existing elem with zero in-sphere:',ielm
391
: ' d,v,r,q:',d,vol,undlen,q
393
: ' node 1: ',(nodlst(j,nod1),j=1,3)
395
: ' node 2: ',(nodlst(j,nod2),j=1,3)
397
: ' node 3: ',(nodlst(j,nod3),j=1,3)
399
: ' node 4: ',(nodlst(j,nod4),j=1,3)
402
write(0,*)(m(i),i=1,3)
403
write(0,*)(m(i),i=4,6)
404
write(0,*)(m(i),i=7,9)
412
: ' Calculating values in flat space...'
413
call mtetin( x, y, z, m, vol, areas, l, undlen, q )
415
: ' r,v,q: ',undlen,vol,q
420
IF( IELM .GT. 0 ) BIGLST(7,IELM) = INTVAL
421
D = FLOAT(INTVAL)/1000000
425
D = FLOAT(INTVAL)/1000000
429
C - work out the *signed* in-sphere radius (or quality) to be returned
430
C - (this is based on the node numbering originally sent into the call
431
C - and is relative to the value calculated when the nodes are in ascending
432
C - order in the calculation).
435
IF( NEGATE ) UNDLEN = -UNDLEN
437
C - Calculate the in-sphere contribution to the element functional.
438
C - This is 'fiddled' so it gets large extremely quickly once the
439
C - in-sphere becomes very small. Note that the value is continuous,
440
C - even though different equations are used for different ranges of
441
C - the in-sphere radius.
444
IF( D .GT. 9.9E-6 ) THEN
447
ELSE IF( D .GT. 9.9E-7 ) THEN
462
C - retreive the edge functional info (if NXT1>0)
464
IF( NXT1 .GT. 0 ) INTVAL = BIGLST(7,NXT1)
466
IF( INTVAL .EQ. 0 ) THEN
468
C - calculate (and store, if NXT1>0) half the sum of edge functionals
476
c D1 = L(1)*L(1) + L(2)*L(2) + L(3)*L(3)
477
c : + L(4)*L(4) + L(5)*L(5) + L(6)*L(6)
479
D1 = 0.5 * ( EDGFNC( BIGLST, NODLST, NOD1, NOD2, D2 )
480
: + EDGFNC( BIGLST, NODLST, NOD1, NOD3, D3 )
481
: + EDGFNC( BIGLST, NODLST, NOD1, NOD4, D2 )
482
: + EDGFNC( BIGLST, NODLST, NOD2, NOD3, D3 )
483
: + EDGFNC( BIGLST, NODLST, NOD2, NOD4, D2 )
484
: + EDGFNC( BIGLST, NODLST, NOD3, NOD4, D3 ) )
486
IF( ANGLEFACT .GT. 0.0 )
487
: D1 = D1 + ANGFNC( BIGLST, NODLST, NODS )*ANGLEFACT
489
C - large edges will be close to the functional bound, so we can cap them
492
INTVAL = INT(D1*1000)
493
IF( INTVAL .EQ. 0 ) INTVAL = 1
494
IF( NXT1 .GT. 0 ) BIGLST(7,NXT1) = INTVAL
495
D1 = FLOAT(INTVAL)/1000
498
D1 = FLOAT(INTVAL)/1000
507
C - This is an attempt to fix a problem where the in-sphere radius
508
C - contributes too much to the functional for elements which have
509
C - some kind of constraint to their edges (probably through the
510
C - geometry), meaning the edges end up becoming far too large (as it
511
C - tries to increase the in-sphere radius by any means possible).
512
C - The basic strategy to combat this is to increase the contribution
513
C - from the edges as they become too large.
514
C - It's worth remembering that having long edges is actually far worse
515
C - for interpolation errors than having small/thin elements!
516
C - Note that the value of the functional contribution is continuous,
517
C - even though different equations are used for ranges of d1...
519
if( d1 .gt. 2E+6 ) then
522
c else if( d1 .gt. 10 ) then
523
c d1 = d1 + d1*d1*d1*d1*d1 - 91102.0
524
else if( d1 .gt. 6 ) then
525
d1 = d1 + d1*d1*d1*d1 - 1102.0
526
else if( d1 .gt. 3 ) then
527
d1 = d1 + d1*d1*d1 - 22.0
528
else if( d1 .gt. 2 ) then
529
d1 = d1 + d1*d1 - 4.0
532
C - Work out the entire element functional from half the sum of the edge
533
C - functionals plus the in-sphere functional.
542
REAL FUNCTION ANGFNC( BIGLST, NODLST, NODS )
552
REAL NX1, NY1, NZ1, NX2, NY2, NZ2, NX3, NY3, NZ3, NX4, NY4, NZ4,
553
: X(6), Y(6), Z(6), V, D
559
NX1 = NODLST(1,NODS(1))
560
NY1 = NODLST(2,NODS(1))
561
NZ1 = NODLST(3,NODS(1))
564
X(I) = NODLST(1,NODS(I+1)) - NX1
565
Y(I) = NODLST(2,NODS(I+1)) - NY1
566
Z(I) = NODLST(3,NODS(I+1)) - NZ1
569
NX1 = NODLST(1,NODS(2))
570
NY1 = NODLST(2,NODS(2))
571
NZ1 = NODLST(3,NODS(2))
574
X(I) = NODLST(1,NODS(I-1)) - NX1
575
Y(I) = NODLST(2,NODS(I-1)) - NY1
576
Z(I) = NODLST(3,NODS(I-1)) - NZ1
579
X(6) = NODLST(1,NODS(4)) - NODLST(1,NODS(3))
580
Y(6) = NODLST(2,NODS(4)) - NODLST(2,NODS(3))
581
Z(6) = NODLST(3,NODS(4)) - NODLST(3,NODS(3))
583
C - work out normals to faces
585
NX1 = Y(2)*Z(4) - Y(4)*Z(2)
586
NY1 = Z(2)*X(4) - Z(4)*X(2)
587
NZ1 = X(2)*Y(4) - X(4)*Y(2)
589
V = NX1*NX1 + NY1*NY1 + NZ1*NZ1
590
if( v .lt. 1e-23 ) then
592
print*,'got small normal 1: ',v
602
NX2 = Y(3)*Z(1) - Y(1)*Z(3)
603
NY2 = Z(3)*X(1) - Z(1)*X(3)
604
NZ2 = X(3)*Y(1) - X(1)*Y(3)
606
V = NX2*NX2 + NY2*NY2 + NZ2*NZ2
607
if( v .lt. 1e-23 ) then
609
print*,'got small normal 2: ',v
619
NX3 = Y(5)*Z(4) - Y(4)*Z(5)
620
NY3 = Z(5)*X(4) - Z(4)*X(5)
621
NZ3 = X(5)*Y(4) - X(4)*Y(5)
623
V = NX3*NX3 + NY3*NY3 + NZ3*NZ3
624
if( v .lt. 1e-23 ) then
626
print*,'got small normal 3: ',v
636
NX4 = Y(3)*Z(6) - Y(6)*Z(3)
637
NY4 = Z(3)*X(6) - Z(6)*X(3)
638
NZ4 = X(3)*Y(6) - X(6)*Y(3)
640
V = NX4*NX4 + NY4*NY4 + NZ4*NZ4
641
if( v .lt. 1e-23 ) then
643
print*,'got small normal 4: ',v
653
C - work out the functionals for the angle between each pair of faces
655
D = NX1*NX2 + NY1*NY2 + NZ1*NZ2 + 1.0
656
IF( D .GT. 1E-15 ) THEN
660
print*,'got d = ',d,' for normals 1+2...'
671
D = NX1*NX3 + NY1*NY3 + NZ1*NZ3 + 1.0
672
IF( D .GT. 1E-15 ) THEN
676
print*,'got d = ',d,' for normals 1+3...'
687
D = NX1*NX4 + NY1*NY4 + NZ1*NZ4 + 1.0
688
IF( D .GT. 1E-15 ) THEN
692
print*,'got d = ',d,' for normals 1+4...'
703
D = NX2*NX3 + NY2*NY3 + NZ2*NZ3 + 1.0
704
IF( D .GT. 1E-15 ) THEN
708
print*,'got d = ',d,' for normals 2+3...'
719
D = NX2*NX4 + NY2*NY4 + NZ2*NZ4 + 1.0
720
IF( D .GT. 1E-15 ) THEN
724
print*,'got d = ',d,' for normals 2+4...'
735
D = NX3*NX4 + NY3*NY4 + NZ3*NZ4 + 1.0
736
IF( D .GT. 1E-15 ) THEN
740
print*,'got d = ',d,' for normals 3+4...'