Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/GeneralUtils.F90
5156 views
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 library is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU Lesser General Public
9
! * License as published by the Free Software Foundation; either
10
! * version 2.1 of the License, or (at your option) any later version.
11
! *
12
! * This library 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 GNU
15
! * Lesser General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU Lesser General Public
18
! * License along with this library (in file ../LGPL-2.1); if not, write
19
! * to the Free Software Foundation, Inc., 51 Franklin Street,
20
! * Fifth Floor, Boston, MA 02110-1301 USA
21
! *
22
! *****************************************************************************/
23
!
24
!/******************************************************************************
25
! *
26
! * Authors: Juha Ruokolainen
27
! * Email: [email protected]
28
! * Web: http://www.csc.fi/elmer
29
! * Address: CSC - IT Center for Science Ltd.
30
! * Keilaranta 14
31
! * 02101 Espoo, Finland
32
! *
33
! * Original Date: 01 Oct 1996
34
! *
35
! *****************************************************************************/
36
37
#include "../config.h"
38
39
!> \ingroup ElmerLib
40
!> \}
41
42
!-----------------------------------------------------------------------------
43
!> Miscellaneous utilities.
44
!-----------------------------------------------------------------------------
45
MODULE GeneralUtils
46
47
USE LoadMod
48
49
#ifdef HAVE_LUA
50
USE, INTRINSIC :: ISO_C_BINDING
51
#endif
52
53
IMPLICIT NONE
54
55
INTERFACE AllocateVector
56
MODULE PROCEDURE AllocateRealVector, AllocateIntegerVector, &
57
AllocateComplexVector, AllocateLogicalVector, &
58
AllocateElementVector
59
END INTERFACE
60
61
INTERFACE AllocateArray
62
MODULE PROCEDURE AllocateRealArray, AllocateIntegerArray, &
63
AllocateComplexArray, AllocateLogicalArray
64
END INTERFACE
65
66
INTERFACE ComponentName
67
MODULE PROCEDURE ComponentNameStr, ComponentNameVar
68
END INTERFACE
69
70
REAL(KIND=dp), PRIVATE :: AdvanceTime1, AdvanceTime2
71
72
CONTAINS
73
74
!------------------------------------------------------------------------------
75
SUBROUTINE StartAdvanceOutput( SolverName, OutputType )
76
!------------------------------------------------------------------------------
77
CHARACTER(LEN=*) :: SolverName, OutputType
78
!------------------------------------------------------------------------------
79
AdvanceTime1 = RealTime()
80
AdvanceTime2 = RealTime()
81
CALL Info( SolverName, OutputType, Level=5 )
82
!------------------------------------------------------------------------------
83
END SUBROUTINE StartAdvanceOutput
84
!------------------------------------------------------------------------------
85
86
87
!------------------------------------------------------------------------------
88
SUBROUTINE AdvanceOutput(t,n,dot_t,percent_t)
89
!------------------------------------------------------------------------------
90
IMPLICIT NONE
91
INTEGER :: t,n
92
REAL(KIND=dp), OPTIONAL :: dot_t,percent_t
93
!------------------------------------------------------------------------------
94
INTEGER :: i
95
REAL(KIND=dp) :: d_t, p_t
96
!------------------------------------------------------------------------------
97
d_t = 1._dp
98
p_t = 20._dp
99
IF ( PRESENT(dot_t) ) d_t = dot_t
100
IF ( PRESENT(percent_t) ) p_t = percent_t
101
102
IF ( RealTime() - AdvanceTime1 > d_t ) THEN
103
CALL Info( '', '.', Level=5, noAdvance=.TRUE. )
104
105
IF ( RealTime() - AdvanceTime2 > p_t ) THEN
106
i = NINT(t*100.0/n)
107
WRITE(Message, '(i3,a)' ) i, '%'
108
CALL Info( '', Message, Level=5 )
109
AdvanceTime2 = RealTime()
110
END IF
111
AdvanceTime1 = RealTime()
112
END IF
113
!------------------------------------------------------------------------------
114
END SUBROUTINE AdvanceOutput
115
!------------------------------------------------------------------------------
116
117
118
!------------------------------------------------------------------------------
119
PURE FUNCTION lentrim(str) RESULT(n)
120
!------------------------------------------------------------------------------
121
CHARACTER(LEN=*), INTENT(IN) :: str
122
INTEGER :: n
123
DO n=LEN(str),1,-1
124
IF ( str(n:n) /= ' ' ) EXIT
125
END DO
126
!------------------------------------------------------------------------------
127
END FUNCTION lentrim
128
!------------------------------------------------------------------------------
129
130
131
!------------------------------------------------------------------------------
132
!> Compare equality of start of s1 to (in most uses string literal) s2.
133
!------------------------------------------------------------------------------
134
!------------------------------------------------------------------------------
135
PURE FUNCTION SEQL(s1,s2) RESULT(L)
136
!------------------------------------------------------------------------------
137
LOGICAL :: L
138
CHARACTER(LEN=*), INTENT(IN) :: s1,s2
139
!------------------------------------------------------------------------------
140
INTEGER :: n
141
!------------------------------------------------------------------------------
142
L = .FALSE.
143
n = LEN(s2)
144
IF(LEN(s1) < n) RETURN
145
IF (s1(1:n)==s2) L=.TRUE.
146
!------------------------------------------------------------------------------
147
END FUNCTION SEQL
148
!------------------------------------------------------------------------------
149
150
151
!------------------------------------------------------------------------------
152
!> Converts integer to string. Handy when writing output with integer data.
153
!------------------------------------------------------------------------------
154
PURE FUNCTION i2s(ival) RESULT(s)
155
!------------------------------------------------------------------------------
156
INTEGER, INTENT(in) :: ival
157
CHARACTER(:), ALLOCATABLE :: s
158
!------------------------------------------------------------------------------
159
INTEGER :: i,j,n,t,v,len
160
INTEGER(8) :: m
161
CHARACTER, PARAMETER :: DIGITS(0:9)=['0','1','2','3','4','5','6','7','8','9']
162
!------------------------------------------------------------------------------
163
164
IF(ival>=0) THEN
165
v = ival
166
IF (v<10) THEN
167
s = DIGITS(v)
168
ELSE IF (ival<100) THEN
169
i = v/10
170
s = DIGITS(i)//DIGITS(v-10*i)
171
ELSE
172
n=3
173
m=100
174
DO WHILE(10*m<=v)
175
n=n+1
176
m=m*10
177
END DO
178
179
ALLOCATE(CHARACTER(n)::s)
180
DO i=1,n
181
t = v / m
182
s(i:i) = DIGITS(t)
183
v = v - t*m
184
m = m / 10
185
END DO
186
END IF
187
ELSE
188
v = -ival
189
IF (v<10) THEN
190
s = '-'//DIGITS(v)
191
ELSE IF (v<100) THEN
192
i = v/10
193
s = '-'//DIGITS(i)//DIGITS(v-10*i)
194
ELSE
195
n=3
196
m=100
197
DO WHILE(10*m<=v)
198
n=n+1
199
m=m*10
200
END DO
201
202
ALLOCATE(CHARACTER(n+1)::s)
203
s(1:1) = '-'
204
DO i=2,n+1
205
t = v / m
206
s(i:i) = DIGITS(t)
207
v = v - t*m
208
m = m / 10
209
END DO
210
END IF
211
END IF
212
!------------------------------------------------------------------------------
213
END FUNCTION i2s
214
!------------------------------------------------------------------------------
215
216
217
218
!------------------------------------------------------------------------------
219
!> Converts string of length n to an integer number.
220
!------------------------------------------------------------------------------
221
PURE FUNCTION s2i(str,n) RESULT(ival)
222
!------------------------------------------------------------------------------
223
INTEGER, INTENT(IN) :: n
224
INTEGER :: ival
225
CHARACTER(LEN=n), INTENT(IN) :: str
226
!------------------------------------------------------------------------------
227
LOGICAL :: neg
228
INTEGER :: j,k
229
INTEGER, PARAMETER :: ic0 = ICHAR('0')
230
231
neg = str(1:1)=='-'
232
k=1
233
IF ( neg ) k=2
234
235
ival = 0
236
DO j=k,n
237
ival = 10*ival + ICHAR(str(j:j)) - ic0
238
END DO
239
IF(neg) ival=-ival
240
END FUNCTION s2i
241
!------------------------------------------------------------------------------
242
243
244
!------------------------------------------------------------------------------
245
!> Converts a string into a number of integer numbers
246
!> It is assumed that the integers may also be separated by
247
!> the given separator.
248
!------------------------------------------------------------------------------
249
FUNCTION str2ints(str,ints,sep) RESULT(n)
250
!------------------------------------------------------------------------------
251
INTEGER, INTENT(out) :: ints(:)
252
CHARACTER(LEN=*), INTENT(in) :: str
253
CHARACTER, OPTIONAL, INTENT(in) :: sep
254
255
INTEGER :: i,k,l,m,n,ic, icsep
256
INTEGER, PARAMETER :: ic0 = ICHAR('0'), ic9 = ICHAR('9'), icm = ICHAR('-'), &
257
ics = ICHAR(' ')
258
259
IF( PRESENT( sep ) ) THEN
260
icsep = ICHAR(sep)
261
ELSE
262
icsep = ics
263
END IF
264
265
266
k = LEN_TRIM(str)
267
l = 1
268
n = 0
269
DO WHILE(l<=k.AND.n<SIZE(ints))
270
DO WHILE(l<=k)
271
ic = ICHAR(str(l:l))
272
IF( ic == ics .OR. ic == icsep ) THEN
273
CONTINUE
274
ELSE
275
EXIT
276
END IF
277
l=l+1
278
END DO
279
IF(l>k) EXIT
280
IF(.NOT.(ic==icm .OR. ic>=ic0 .AND. ic<=ic9)) EXIT
281
282
m = l+1
283
DO WHILE(m<=k)
284
ic = ICHAR(str(m:m))
285
IF(ic<ic0 .OR. ic>ic9) EXIT
286
m=m+1
287
END DO
288
289
n = n + 1
290
ints(n) = s2i(str(l:m-1),m-l)
291
l = m
292
END DO
293
END FUNCTION str2ints
294
!------------------------------------------------------------------------------
295
296
SUBROUTINE WaitSec(t)
297
REAL(KIND=dp) :: t,t0,t1
298
299
t0 = RealTime()
300
DO WHILE(.TRUE.)
301
t1 = RealTime()
302
IF(t1-t0 > t) EXIT
303
END DO
304
305
END SUBROUTINE WaitSec
306
307
!------------------------------------------------------------------------------
308
SUBROUTINE SystemCommand( cmd )
309
!------------------------------------------------------------------------------
310
CHARACTER(LEN=*) :: cmd
311
CALL SystemC( TRIM(cmd) // CHAR(0) )
312
!------------------------------------------------------------------------------
313
END SUBROUTINE SystemCommand
314
!------------------------------------------------------------------------------
315
316
317
!------------------------------------------------------------------------------
318
SUBROUTINE RenameF(old,new)
319
!------------------------------------------------------------------------------
320
CHARACTER(LEN=*) :: old,new
321
!------------------------------------------------------------------------------
322
INTERFACE
323
SUBROUTINE rename_c(old,new) bind(c,name="rename_c")
324
USE, INTRINSIC :: iso_c_binding
325
CHARACTER(KIND=C_CHAR) :: old(*), new(*)
326
END SUBROUTINE rename_c
327
END INTERFACE
328
329
CALL rename_c(TRIM(old)//CHAR(0), TRIM(new)//CHAR(0))
330
!------------------------------------------------------------------------------
331
END SUBROUTINE RenameF
332
!------------------------------------------------------------------------------
333
334
335
!------------------------------------------------------------------------------
336
PURE FUNCTION FileNameQualified(file) RESULT(L)
337
!------------------------------------------------------------------------------
338
LOGICAL :: L
339
CHARACTER(*), INTENT(IN) :: file
340
!------------------------------------------------------------------------------
341
L = INDEX(file,':')>0 .OR. file(1:1)=='/' .OR. file(1:1)==Backslash
342
!------------------------------------------------------------------------------
343
END FUNCTION FileNameQualified
344
!------------------------------------------------------------------------------
345
346
!------------------------------------------------------------------------------
347
PURE FUNCTION LittleEndian() RESULT(L)
348
!------------------------------------------------------------------------------
349
LOGICAL :: L
350
!------------------------------------------------------------------------------
351
INTEGER(1) :: s(2)
352
INTEGER(2), PARAMETER :: t = 256*7+8
353
!------------------------------------------------------------------------------
354
s = TRANSFER(t,s)
355
L=s(1)==8
356
!------------------------------------------------------------------------------
357
END FUNCTION LittleEndian
358
!------------------------------------------------------------------------------
359
360
!------------------------------------------------------------------------------
361
FUNCTION FormatDate() RESULT( date )
362
!------------------------------------------------------------------------------
363
CHARACTER(20) :: date
364
INTEGER :: dates(8)
365
366
CALL DATE_AND_TIME( VALUES=dates )
367
WRITE( date, &
368
'(I4,"/",I2.2,"/",I2.2," ",I2.2,":",I2.2,":",I2.2)' ) &
369
dates(1),dates(2),dates(3),dates(5),dates(6),dates(7)
370
!------------------------------------------------------------------------------
371
END FUNCTION FormatDate
372
!------------------------------------------------------------------------------
373
374
375
!------------------------------------------------------------------------------
376
!> Sort an array of integer values.
377
!------------------------------------------------------------------------------
378
PURE SUBROUTINE Sort( n,a )
379
!------------------------------------------------------------------------------
380
INTEGER, INTENT(in) :: n
381
INTEGER, INTENT(inout) :: a(:)
382
!------------------------------------------------------------------------------
383
384
INTEGER :: i,j,l,ir,ra
385
!------------------------------------------------------------------------------
386
387
IF ( n <= 1 ) RETURN
388
389
l = n / 2 + 1
390
ir = n
391
DO WHILE( .TRUE. )
392
IF ( l > 1 ) THEN
393
l = l - 1
394
ra = a(l)
395
ELSE
396
ra = a(ir)
397
a(ir) = a(1)
398
ir = ir - 1
399
IF ( ir == 1 ) THEN
400
a(1) = ra
401
RETURN
402
END IF
403
END IF
404
i = l
405
j = l + l
406
DO WHILE( j <= ir )
407
IF ( j<ir ) THEN
408
IF ( a(j)<a(j+1) ) j = j+1
409
END IF
410
411
IF ( ra<a(j) ) THEN
412
a(i) = a(j)
413
i = j
414
j = j + i
415
ELSE
416
j = ir + 1
417
END IF
418
a(i) = ra
419
END DO
420
END DO
421
422
!------------------------------------------------------------------------------
423
END SUBROUTINE Sort
424
!------------------------------------------------------------------------------
425
426
!------------------------------------------------------------------------------
427
!> Sort an integer array a, together with an another integer array.
428
!------------------------------------------------------------------------------
429
PURE SUBROUTINE SortI( n,a,b )
430
!------------------------------------------------------------------------------
431
INTEGER, INTENT(in) :: n
432
INTEGER, INTENT(inout) :: a(:),b(:)
433
!------------------------------------------------------------------------------
434
435
INTEGER :: i,j,l,ir,ra,rb
436
!------------------------------------------------------------------------------
437
438
IF ( n <= 1 ) RETURN
439
440
l = n / 2 + 1
441
ir = n
442
DO WHILE( .TRUE. )
443
IF ( l > 1 ) THEN
444
l = l - 1
445
ra = a(l)
446
rb = b(l)
447
ELSE
448
ra = a(ir)
449
rb = b(ir)
450
a(ir) = a(1)
451
b(ir) = b(1)
452
ir = ir - 1
453
IF ( ir == 1 ) THEN
454
a(1) = ra
455
b(1) = rb
456
RETURN
457
END IF
458
END IF
459
i = l
460
j = l + l
461
DO WHILE( j <= ir )
462
IF ( j<ir ) THEN
463
IF ( a(j)<a(j+1) ) j = j+1
464
END IF
465
IF ( ra<a(j) ) THEN
466
a(i) = a(j)
467
b(i) = b(j)
468
i = j
469
j = j + i
470
ELSE
471
j = ir + 1
472
END IF
473
a(i) = ra
474
b(i) = rb
475
END DO
476
END DO
477
478
!------------------------------------------------------------------------------
479
END SUBROUTINE SortI
480
!------------------------------------------------------------------------------
481
482
483
!------------------------------------------------------------------------------
484
!> Sort an index array, and change the order of an real array accordingly.
485
!------------------------------------------------------------------------------
486
PURE SUBROUTINE SortF( n,a,b )
487
!------------------------------------------------------------------------------
488
INTEGER, INTENT(in) :: n
489
INTEGER, INTENT(inout) :: a(:)
490
REAL(KIND=dp), INTENT(inout) :: b(:)
491
!------------------------------------------------------------------------------
492
493
INTEGER :: i,j,l,ir,ra
494
REAL(KIND=dp) :: rb
495
!------------------------------------------------------------------------------
496
497
IF ( n <= 1 ) RETURN
498
499
l = n / 2 + 1
500
ir = n
501
DO WHILE( .TRUE. )
502
503
IF ( l > 1 ) THEN
504
l = l - 1
505
ra = a(l)
506
rb = b(l)
507
ELSE
508
ra = a(ir)
509
rb = b(ir)
510
a(ir) = a(1)
511
b(ir) = b(1)
512
ir = ir - 1
513
IF ( ir == 1 ) THEN
514
a(1) = ra
515
b(1) = rb
516
RETURN
517
END IF
518
END IF
519
i = l
520
j = l + l
521
DO WHILE( j <= ir )
522
IF ( j<ir ) THEN
523
IF ( a(j)<a(j+1) ) j = j+1
524
END IF
525
IF ( ra<a(j) ) THEN
526
a(i) = a(j)
527
b(i) = b(j)
528
i = j
529
j = j + i
530
ELSE
531
j = ir + 1
532
END IF
533
a(i) = ra
534
b(i) = rb
535
END DO
536
END DO
537
538
!------------------------------------------------------------------------------
539
END SUBROUTINE SortF
540
!------------------------------------------------------------------------------
541
542
543
!------------------------------------------------------------------------------
544
!> Sort an real array, and change the order of an index array accordingly.
545
!------------------------------------------------------------------------------
546
PURE SUBROUTINE SortD( n,a,b )
547
!------------------------------------------------------------------------------
548
INTEGER, INTENT(in) :: n
549
INTEGER, INTENT(inout) :: b(:)
550
REAL(KIND=dp), INTENT(inout) :: a(:)
551
!------------------------------------------------------------------------------
552
553
INTEGER :: i,j,l,ir,rb
554
REAL(KIND=dp) :: ra
555
!------------------------------------------------------------------------------
556
557
IF ( n <= 1 ) RETURN
558
559
l = n / 2 + 1
560
ir = n
561
DO WHILE( .TRUE. )
562
563
IF ( l > 1 ) THEN
564
l = l - 1
565
ra = a(l)
566
rb = b(l)
567
ELSE
568
ra = a(ir)
569
rb = b(ir)
570
a(ir) = a(1)
571
b(ir) = b(1)
572
ir = ir - 1
573
IF ( ir == 1 ) THEN
574
a(1) = ra
575
b(1) = rb
576
RETURN
577
END IF
578
END IF
579
i = l
580
j = l + l
581
DO WHILE( j <= ir )
582
IF ( j<ir ) THEN
583
IF ( a(j)<a(j+1) ) j = j+1
584
END IF
585
IF ( ra<a(j) ) THEN
586
a(i) = a(j)
587
b(i) = b(j)
588
i = j
589
j = j + i
590
ELSE
591
j = ir + 1
592
END IF
593
a(i) = ra
594
b(i) = rb
595
END DO
596
END DO
597
598
!------------------------------------------------------------------------------
599
END SUBROUTINE SortD
600
!------------------------------------------------------------------------------
601
602
603
!------------------------------------------------------------------------------
604
!> Sort an complex array, and organize an index table accordingly.
605
!------------------------------------------------------------------------------
606
PURE SUBROUTINE SortC( n,a,b )
607
!------------------------------------------------------------------------------
608
INTEGER, INTENT(in) :: n
609
INTEGER, INTENT(inout) :: b(:)
610
COMPLEX(KIND=dp), INTENT(inout) :: a(:)
611
!------------------------------------------------------------------------------
612
613
INTEGER :: i,j,l,ir,rb
614
COMPLEX(KIND=dp) :: ra
615
!------------------------------------------------------------------------------
616
617
IF ( n <= 1 ) RETURN
618
619
l = n / 2 + 1
620
ir = n
621
DO WHILE( .TRUE. )
622
IF ( l > 1 ) THEN
623
l = l - 1
624
ra = a(l)
625
rb = b(l)
626
ELSE
627
ra = a(ir)
628
rb = b(ir)
629
a(ir) = a(1)
630
b(ir) = b(1)
631
ir = ir - 1
632
IF ( ir == 1 ) THEN
633
a(1) = ra
634
b(1) = rb
635
RETURN
636
END IF
637
END IF
638
i = l
639
j = l + l
640
DO WHILE( j <= ir )
641
IF ( j<ir ) THEN
642
IF ( ABS(a(j))<ABS(a(j+1)) ) j = j+1
643
END IF
644
IF ( ABS(ra)<ABS(a(j)) ) THEN
645
a(i) = a(j)
646
b(i) = b(j)
647
i = j
648
j = j + i
649
ELSE
650
j = ir + 1
651
END IF
652
a(i) = ra
653
b(i) = rb
654
END DO
655
END DO
656
657
!------------------------------------------------------------------------------
658
END SUBROUTINE SortC
659
!------------------------------------------------------------------------------
660
661
662
!------------------------------------------------------------------------------
663
!> Order real components in b in a decreasing order and return the new order
664
!> of indexes in a.
665
!------------------------------------------------------------------------------
666
PURE SUBROUTINE SortR( n,a,b )
667
!------------------------------------------------------------------------------
668
INTEGER, INTENT(in) :: n
669
INTEGER, INTENT(inout) :: a(:)
670
REAL(KIND=dp), INTENT(inout) :: b(:)
671
!------------------------------------------------------------------------------
672
673
INTEGER :: i,j,l,ir,ra
674
REAL(KIND=dp) :: rb
675
!------------------------------------------------------------------------------
676
677
IF ( n <= 1 ) RETURN
678
679
l = n / 2 + 1
680
ir = n
681
DO WHILE( .TRUE. )
682
683
IF ( l > 1 ) THEN
684
l = l - 1
685
ra = a(l)
686
rb = b(l)
687
ELSE
688
ra = a(ir)
689
rb = b(ir)
690
a(ir) = a(1)
691
b(ir) = b(1)
692
ir = ir - 1
693
IF ( ir == 1 ) THEN
694
a(1) = ra
695
b(1) = rb
696
RETURN
697
END IF
698
END IF
699
i = l
700
j = l + l
701
DO WHILE( j <= ir )
702
IF ( j<ir ) THEN
703
IF ( b(j) > b(j+1) ) j = j+1
704
END IF
705
IF ( rb > b(j) ) THEN
706
a(i) = a(j)
707
b(i) = b(j)
708
i = j
709
j = j + i
710
ELSE
711
j = ir + 1
712
END IF
713
a(i) = ra
714
b(i) = rb
715
END DO
716
END DO
717
718
!------------------------------------------------------------------------------
719
END SUBROUTINE SortR
720
!------------------------------------------------------------------------------
721
722
!------------------------------------------------------------------------------
723
!> Search an integer value in an ordered array.
724
!------------------------------------------------------------------------------
725
PURE FUNCTION SearchI( N,Array,Val ) RESULT ( Idx )
726
!------------------------------------------------------------------------------
727
INTEGER, INTENT(in) :: N,Val,Array(:)
728
!------------------------------------------------------------------------------
729
INTEGER :: Lower, Upper,Lou,Idx
730
!------------------------------------------------------------------------------
731
732
Idx = 0
733
Upper = N
734
Lower = 1
735
736
! Handle the special case
737
738
IF ( Upper == 0 ) RETURN
739
740
DO WHILE( .TRUE. )
741
IF ( Array(Lower) == Val) THEN
742
Idx = Lower
743
EXIT
744
ELSE IF ( Array(Upper) == Val ) THEN
745
Idx = Upper
746
EXIT
747
END IF
748
749
IF ( (Upper-Lower)>1 ) THEN
750
Lou = ISHFT((Upper + Lower), -1)
751
IF ( Array(Lou) < Val ) THEN
752
Lower = Lou
753
ELSE
754
Upper = Lou
755
END IF
756
ELSE
757
EXIT
758
END IF
759
END DO
760
761
RETURN
762
763
!------------------------------------------------------------------------------
764
END FUNCTION SearchI
765
!------------------------------------------------------------------------------
766
767
768
769
!------------------------------------------------------------------------------
770
!> Search a real value in an ordered array.
771
!------------------------------------------------------------------------------
772
PURE FUNCTION SearchR( N,Array,Val ) RESULT ( Idx )
773
!------------------------------------------------------------------------------
774
775
INTEGER, INTENT(in) :: N
776
INTEGER :: Idx
777
REAL(KIND=dP), INTENT(in) :: Val,Array(:)
778
!------------------------------------------------------------------------------
779
INTEGER :: Lower, Upper,Lou
780
!------------------------------------------------------------------------------
781
782
Idx = 0
783
Upper = N
784
Lower = 1
785
786
! Handle the special case
787
IF ( Upper == 0 ) RETURN
788
789
DO WHILE( .TRUE. )
790
IF ( ABS( Array(Lower) - Val) < TINY(Val) ) THEN
791
Idx = Lower
792
EXIT
793
ELSE IF ( ABS( Array(Upper) - Val ) < TINY(Val) ) THEN
794
Idx = Upper
795
EXIT
796
END IF
797
798
IF ( (Upper-Lower) > 1 ) THEN
799
Lou = ISHFT((Upper + Lower), -1)
800
IF ( Array(Lou) < Val ) THEN
801
Lower = Lou
802
ELSE
803
Upper = Lou
804
END IF
805
ELSE
806
EXIT
807
END IF
808
END DO
809
810
RETURN
811
812
!------------------------------------------------------------------------------
813
END FUNCTION SearchR
814
!------------------------------------------------------------------------------
815
816
817
!------------------------------------------------------------------------------
818
SUBROUTINE OpenIncludeFile( Unit, FileName, IncludePath )
819
!------------------------------------------------------------------------------
820
INTEGER :: Unit
821
CHARACTER(LEN=*) :: FileName, IncludePath
822
!------------------------------------------------------------------------------
823
INTEGER :: i,j,k,k0,k1,l,iostat
824
CHARACTER(LEN=1024) :: name, TmpName
825
!------------------------------------------------------------------------------
826
827
i = 1
828
name = FileName
829
DO WHILE( name(i:i) == ' ' .OR. name(i:i)=='"')
830
i = i + 1
831
END DO
832
j = LEN_TRIM(name)
833
IF ( name(j:j) == '"' ) j=j-1
834
name = TRIM(name(i:j))
835
836
IF ( INDEX(name,':') == 0 .AND. name(1:1) /= '/' .AND. &
837
name(1:1) /= Backslash ) THEN
838
k0 = 1
839
DO WHILE( IncludePath(k0:k0) == '"' )
840
k0 = k0+1
841
END DO
842
k1 = INDEX( IncludePath, ';' )
843
844
DO WHILE( k1 >= k0 )
845
DO k = k1-1,k0,-1
846
IF ( IncludePath(k:k) /= ' ' .AND. IncludePath(k:k)/='"' ) EXIT
847
END DO
848
IF ( IncludePath(k:k) == '"' ) k=k-1
849
IF ( k >= k0 ) THEN
850
WRITE( tmpName,'(a,a,a)' ) IncludePath(k0:k), '/', TRIM(name)
851
OPEN( Unit, FILE=TRIM(tmpName), STATUS='OLD',ERR=10 )
852
RETURN
853
END IF
854
10 CONTINUE
855
k0 = k1+1
856
k1 = INDEX( IncludePath(k0:), ';' ) + k0 - 1
857
END DO
858
859
IF ( LEN_TRIM(IncludePath(k0:))>0 ) THEN
860
k1 = INDEX( IncludePath(k0:), '"' ) + k0 - 2
861
IF ( k1 < k0 ) k1=LEN_TRIM(IncludePath)
862
tmpName = TRIM(IncludePath(k0:k1)) // '/' // TRIM(name)
863
OPEN( Unit, FILE=TRIM(TmpName), STATUS='OLD',ERR=20 )
864
RETURN
865
END IF
866
867
20 CONTINUE
868
OPEN( Unit, FILE=TRIM(name), STATUS='OLD',IOSTAT=iostat )
869
ELSE
870
OPEN( Unit, FILE=TRIM(name), STATUS='OLD',IOSTAT=iostat )
871
END IF
872
873
IF( iostat /= 0 ) THEN
874
CALL Fatal('OpenIncludeFile','Cannot open include file: '//TRIM(Name))
875
END IF
876
877
878
!------------------------------------------------------------------------------
879
END SUBROUTINE OpenIncludeFile
880
!------------------------------------------------------------------------------
881
882
883
!------------------------------------------------------------------------------
884
!> Read a (logical) line from FORTRAN device Unit and remove leading, trailing,
885
!> and multiple blanks between words. Also convert uppercase characters to
886
!> lowercase.The logical line can continue the several physical lines by adding
887
!> the backslash (\) mark at the end of a physical line.
888
!------------------------------------------------------------------------------
889
RECURSIVE FUNCTION ReadAndTrim( Unit,str,echo,literal,noeval ) RESULT(l)
890
!------------------------------------------------------------------------------
891
INTEGER :: Unit !< Fortran unit number to read from
892
CHARACTER(LEN=:), ALLOCATABLE :: str !< The string read from the file
893
LOGICAL, OPTIONAL :: Echo
894
LOGICAL, OPTIONAL :: literal
895
LOGICAL, OPTIONAL :: noeval
896
LOGICAL :: l !< Success of the read operation
897
!------------------------------------------------------------------------------
898
INTEGER, PARAMETER :: MAXLEN = 163840
899
900
CHARACTER(LEN=:), ALLOCATABLE :: temp
901
CHARACTER(LEN=12) :: tmpstr
902
CHARACTER(LEN=MAXLEN) :: readstr = ' ', copystr = ' ', matcstr=' ' , IncludePath=' '
903
904
LOGICAL :: InsideQuotes, OpenSection=.FALSE., DoEval
905
INTEGER :: i,j,k,m,ValueStarts=0,inlen,ninlen,outlen,IncludeUnit=28,IncludeUnitBase=28
906
907
CHARACTER(LEN=MAX_NAME_LEN) :: Prefix = ' '
908
909
INTEGER, PARAMETER :: A=ICHAR('A'),Z=ICHAR('Z'),U2L=ICHAR('a')-ICHAR('A'),Tab=9
910
CHARACTER(LEN=MAXLEN) :: tmatcstr, tcmdstr
911
INTEGER :: tninlen
912
913
SAVE ReadStr, ValueStarts, Prefix, OpenSection
914
915
IF ( PRESENT(literal) ) literal=.FALSE.
916
l = .TRUE.
917
918
! Optionally do not expand the MATC and LUA expressions.
919
DoEval = .TRUE.
920
IF( PRESENT( NoEval ) ) THEN
921
DoEval = .NOT. NoEval
922
END IF
923
924
IF(.NOT.ALLOCATED(str)) ALLOCATE(CHARACTER(512)::str)
925
outlen = LEN(str)
926
927
IF ( ValueStarts==0 .AND. OpenSection ) THEN
928
str = 'end'
929
ValueStarts = 0
930
OpenSection = .FALSE.
931
RETURN
932
END IF
933
934
IF ( ValueStarts == 0 ) THEN
935
tmpstr = ' '
936
DO WHILE( .TRUE. )
937
IF ( IncludeUnit < IncludeUnitBase ) THEN
938
READ( IncludeUnit,'(A)',END=1,ERR=1 ) readstr
939
GO TO 2
940
1 CLOSE(IncludeUnit)
941
IncludeUnit = IncludeUnit+1
942
READ( IncludeUnit,'(A)',END=10,ERR=10 ) readstr
943
2 CONTINUE
944
ELSE
945
READ( Unit,'(A)',END=10,ERR=10 ) readstr
946
END IF
947
948
readstr = ADJUSTL(readstr)
949
950
DO k=1,12
951
j = ICHAR(readstr(k:k))
952
IF ( j >= A .AND. j<= Z ) THEN
953
Tmpstr(k:k) = CHAR(j+U2L)
954
ELSE
955
tmpstr(k:k) = readstr(k:k)
956
END IF
957
END DO
958
959
IF ( SEQL(Tmpstr, 'include path') ) THEN
960
k = LEN_TRIM(readstr)
961
IncludePath(1:k-13) = readstr(14:k)
962
Tmpstr = ''
963
ELSE
964
EXIT
965
END IF
966
END DO
967
968
IF ( SEQL(tmpstr, 'include ') ) THEN
969
IncludeUnit = IncludeUnit-1
970
971
CALL Info('OpenIncludeFile','Trying to include file: '//TRIM(readstr(9:)),Level=10)
972
973
inlen = LEN_TRIM(readstr)
974
975
i = INDEX( readstr(1:inlen), '$' )
976
IF ( i>0 .AND. i<inlen ) THEN
977
CALL TrimMatcExpression()
978
CALL Info('ReadAndTrim','Include file after MATC trimming: '&
979
//TRIM(readstr(9:)),Level=6)
980
END IF
981
982
i = INDEX( readstr(1:inlen),'#')
983
IF( i>0 .AND. i<inlen ) THEN
984
#ifdef HAVE_LUA
985
CALL TrimLuaExpression()
986
CALL Info('ReadAndTrim','Include file after LUA trimming: '&
987
//TRIM(readstr(9:)),Level=6)
988
#else
989
CALL Fatal('ReadAndTrim','LUA not included, cannot continue')
990
#endif
991
END IF
992
993
CALL OpenIncludeFile( IncludeUnit, TRIM(readstr(9:)), IncludePath )
994
995
READ( IncludeUnit,'(A)',END=3,ERR=3 ) readstr
996
GO TO 4
997
3 CLOSE(IncludeUnit)
998
IncludeUnit = IncludeUnit+1
999
READ( Unit,'(A)',END=10,ERR=10 ) readstr
1000
4 CONTINUE
1001
END IF
1002
ninlen = LEN_TRIM(readstr)
1003
ELSE
1004
inlen = LEN_TRIM(readstr)
1005
ninlen = inlen-ValueStarts+1
1006
IF ( Prefix == ' ' ) THEN
1007
readstr = readstr(ValueStarts:inlen)
1008
ELSE IF ( Prefix == '::' ) THEN
1009
readstr = readstr(ValueStarts:inlen)
1010
OpenSection = .TRUE.
1011
Prefix = ' '
1012
ELSE
1013
DO i=ValueStarts,inlen
1014
IF ( readstr(i:i) == ')' ) THEN
1015
readstr(i:i) = ' '
1016
EXIT
1017
ELSE IF ( readstr(i:i) == ',' ) THEN
1018
readstr(i:i) = ' '
1019
END IF
1020
END DO
1021
ninlen = ninlen + LEN_TRIM(Prefix) + 1
1022
readstr = TRIM(Prefix) // ' ' // readstr(ValueStarts:inlen)
1023
END IF
1024
END IF
1025
1026
ValueStarts = 0
1027
InsideQuotes = .FALSE.
1028
1029
i = INDEX( readstr(1:ninlen), '!' )
1030
IF ( i>0 ) ninlen=i-1
1031
1032
i = 1
1033
inlen = ninlen
1034
DO WHILE( i <= inlen )
1035
IF ( readstr(i:i) == '"' ) InsideQuotes = .NOT.InsideQuotes
1036
IF ( .NOT. InsideQuotes .AND. readstr(i:i) == CHAR(92) .AND. i==inlen ) THEN
1037
readstr(i:i) = ' '
1038
IF ( IncludeUnit < IncludeUnitBase ) THEN
1039
READ( IncludeUnit,'(A)',END=10,ERR=10 ) readstr(i+1:MAXLEN)
1040
ELSE
1041
READ( Unit,'(A)',END=10,ERR=10 ) readstr(i+1:MAXLEN)
1042
END IF
1043
DO j=LEN(readstr),i+1,-1
1044
IF ( readstr(j:j) /= ' ' ) EXIT
1045
END DO
1046
inlen = inlen + j-i
1047
END IF
1048
i = i + 1
1049
END DO
1050
1051
i = INDEX( readstr(1:inlen), '#' )
1052
IF ( i>0 .AND. i<inlen .AND. DoEval ) THEN
1053
#ifdef HAVE_LUA
1054
CALL TrimLuaExpression()
1055
#else
1056
CALL Fatal('ReadAndTrim','LUA not included, cannot continue')
1057
#endif
1058
END IF
1059
1060
i = INDEX( readstr(1:inlen), '$' )
1061
IF ( i>0 .AND. i<inlen .AND. DoEval ) THEN
1062
CALL TrimMatcExpression()
1063
END IF
1064
1065
IF ( PRESENT( Echo ) ) THEN
1066
IF ( Echo .AND. inlen > 0 ) WRITE( 6, '(a)' ) readstr(1:inlen)
1067
END IF
1068
1069
i = 1
1070
DO WHILE(i <= inlen )
1071
IF (readstr(i:i) /= ' ' .AND. ICHAR(readstr(i:i))/=Tab ) EXIT
1072
i = i + 1
1073
END DO
1074
1075
InsideQuotes = .FALSE.
1076
1077
IF ( PRESENT(literal) ) THEN
1078
IF ( readstr(i:i) == '"' ) literal=.TRUE.
1079
END IF
1080
1081
k = 1
1082
DO WHILE( i<=inlen )
1083
IF ( readstr(i:i) == '"' ) THEN
1084
InsideQuotes = .NOT.InsideQuotes
1085
i=i+1
1086
IF ( i>inlen ) EXIT
1087
END IF
1088
1089
IF ( .NOT.InsideQuotes ) THEN
1090
IF ( readstr(i:i) == '!' .OR. readstr(i:i) == '#' .OR. &
1091
readstr(i:i) == '=' .OR. readstr(i:i) == '(' .OR. &
1092
readstr(i:i) == ';' .OR. readstr(i:i+1) == '::' ) EXIT
1093
IF (ICHAR( readstr(i:i))<32.AND.ICHAR(readstr(i:i))/=Tab) EXIT
1094
END IF
1095
1096
DO WHILE( i <= inlen )
1097
IF ( readstr(i:i) == '"' ) THEN
1098
InsideQuotes = .NOT.InsideQuotes
1099
i=i+1
1100
IF ( i>inlen ) EXIT
1101
END IF
1102
1103
IF ( .NOT.InsideQuotes ) THEN
1104
IF ( readstr(i:i) == ' ' .OR. readstr(i:i) == '=' .OR. &
1105
readstr(i:i) == ';' .OR. readstr(i:i) == '(' .OR. &
1106
readstr(i:i+1) == '::' ) EXIT
1107
IF ( ICHAR( readstr(i:i))<32 ) EXIT
1108
END IF
1109
1110
IF ( k>outlen ) THEN
1111
temp = str
1112
DEALLOCATE(str)
1113
outlen=LEN(temp)+512
1114
ALLOCATE(CHARACTER(outlen)::str)
1115
str(1:LEN(temp))=temp; str(LEN(temp)+1:)=''
1116
DEALLOCATE(temp)
1117
END IF
1118
1119
j = ICHAR( readstr(i:i) )
1120
IF ( .NOT.InsideQuotes .AND. j>=A .AND. j<=Z ) THEN
1121
str(k:k) = CHAR(j+U2L)
1122
ELSE IF ( .NOT.InsideQuotes .AND. j==Tab ) THEN
1123
str(k:k) = ' '
1124
ELSE
1125
str(k:k) = readstr(i:i)
1126
ENDIF
1127
1128
i = i + 1
1129
k = k + 1
1130
END DO
1131
1132
IF ( k <= outlen ) str(k:k) = ' '
1133
k = k + 1
1134
1135
DO WHILE( i<=inlen )
1136
IF ( readstr(i:i) /= ' ' .AND. ICHAR(readstr(i:i))/=Tab ) EXIT
1137
i = i + 1
1138
END DO
1139
END DO
1140
str(k:)=' '
1141
1142
IF ( i <= inlen ) THEN
1143
Prefix = ' '
1144
IF ( ReadStr(i:i) == '=' ) THEN
1145
ValueStarts = i + 1
1146
ELSE IF ( ReadStr(i:i) == ';' ) THEN
1147
ValueStarts = i + 1
1148
ELSE IF ( ReadStr(i:i) == '(' ) THEN
1149
ValueStarts = i + 1
1150
Prefix = 'Size'
1151
ELSE IF ( ReadStr(i:i+1) == '::' ) THEN
1152
ValueStarts = i + 2
1153
Prefix = '::'
1154
ELSE IF ( ICHAR(readstr(i:i)) < 32 ) THEN
1155
DO WHILE( i <= inlen )
1156
IF ( ICHAR(readstr(i:i)) >= 32 ) EXIT
1157
i = i + 1
1158
END DO
1159
IF ( i <= inlen ) ValueStarts = i
1160
END IF
1161
END IF
1162
RETURN
1163
10 CONTINUE
1164
l = .FALSE.
1165
!------------------------------------------------------------------------------
1166
1167
CONTAINS
1168
1169
SUBROUTINE TrimMatcExpression()
1170
1171
i = INDEX( readstr(1:inlen), '$' )
1172
IF ( i>0 .AND. i<inlen ) THEN
1173
m = i
1174
copystr(i:inlen) = readstr(i:inlen)
1175
DO WHILE(i<=inlen)
1176
IF ( copystr(i:i) == '$' ) THEN
1177
DO j=i+1,inlen-1
1178
IF ( copystr(j:j) == '$' ) EXIT
1179
END DO
1180
ninlen = j - i
1181
! Initialize variables for each copy of MATC separately
1182
1183
!$OMP PARALLEL DEFAULT(NONE) &
1184
!$OMP SHARED(copystr, i, matcstr, ninlen, inlen) &
1185
!$OMP PRIVATE(tcmdstr, tmatcstr, tninlen)
1186
1187
tninlen = ninlen
1188
tcmdstr = copystr(i+1:inlen)
1189
tninlen = MATC(tcmdstr, tmatcstr, tninlen)
1190
!$OMP BARRIER
1191
1192
!$OMP SINGLE
1193
matcstr(1:tninlen) = tmatcstr(1:tninlen)
1194
ninlen = tninlen
1195
!$OMP END SINGLE
1196
1197
!$OMP END PARALLEL
1198
1199
DO k=1,ninlen
1200
readstr(m:m) = matcstr(k:k)
1201
m = m + 1
1202
END DO
1203
i = j+1
1204
ELSE
1205
readstr(m:m) = copystr(i:i)
1206
i = i + 1
1207
m = m + 1
1208
END IF
1209
END DO
1210
inlen = m-1
1211
readstr(inlen+1:) = ' '
1212
END IF
1213
1214
END SUBROUTINE TrimMatcExpression
1215
1216
#ifdef HAVE_LUA
1217
SUBROUTINE TrimLuaExpression()
1218
1219
INTEGER :: lstat
1220
character(kind=c_char, len=:), pointer :: lua_result
1221
integer :: result_len
1222
logical :: closed_region, first_bang
1223
closed_region = .false.
1224
first_bang = .true.
1225
m = i
1226
copystr(i:inlen) = readstr(i:inlen)
1227
DO WHILE(i<=inlen)
1228
IF ( copystr(i:i) == '#' ) THEN
1229
DO j=i+1,inlen-1
1230
IF ( copystr(j:j) == '#' ) EXIT
1231
END DO
1232
ninlen = j - i
1233
1234
! Initialize variables for each copy of Lua interpreter separately
1235
1236
tninlen = ninlen
1237
tcmdstr = copystr(i+1:inlen)
1238
1239
IF(tcmdstr(tninlen:tninlen) == '#') then
1240
closed_region = .TRUE.
1241
ELSE
1242
closed_region = .FALSE.
1243
END IF
1244
1245
!$OMP PARALLEL DEFAULT(NONE) &
1246
!$OMP FIRSTPRIVATE(tcmdstr, tninlen, lstat) &
1247
!$OMP SHARED(lua_result, result_len, closed_region, i, j, inlen, first_bang)
1248
IF(closed_region) THEN
1249
lstat = lua_dostring( LuaState, &
1250
'return tostring('// tcmdstr(1:tninlen-1) // ')'//c_null_char, 1)
1251
ELSE
1252
IF (i == 1 .and. first_bang .and. j == inlen) THEN ! ' # <luacode>' case, do not do 'return tostring(..)'.
1253
! Instead, just execute the line in the lua interpreter
1254
1255
lstat = lua_dostring( LuaState, tcmdstr(1:tninlen) // c_null_char, 1)
1256
1257
ELSE ! 'abc = # <luacode>' case, oneliners only
1258
1259
lstat = lua_dostring( LuaState, &
1260
'return tostring('// tcmdstr(1:tninlen) // ')'//c_null_char, 1)
1261
END IF
1262
END IF
1263
!$OMP CRITICAL
1264
lua_result => lua_popstring(LuaState, result_len)
1265
!$OMP END CRITICAL
1266
!$OMP END PARALLEL
1267
1268
matcstr(1:result_len) = lua_result(1:result_len)
1269
ninlen = result_len
1270
1271
DO k=1,ninlen
1272
readstr(m:m) = matcstr(k:k)
1273
m = m + 1
1274
END DO
1275
i = j+1
1276
ELSE
1277
readstr(m:m) = copystr(i:i)
1278
i = i + 1
1279
m = m + 1
1280
END IF
1281
first_bang = .false.
1282
END DO
1283
inlen = m-1
1284
readstr(inlen+1:) = ' '
1285
END SUBROUTINE TrimLuaExpression
1286
#endif
1287
1288
END FUNCTION ReadAndTrim
1289
!------------------------------------------------------------------------------
1290
1291
1292
!------------------------------------------------------------------------------
1293
PURE FUNCTION GetVarName(Var) RESULT(str)
1294
!------------------------------------------------------------------------------
1295
TYPE(Variable_t), INTENT(in) :: Var
1296
CHARACTER(LEN=Var % NameLen) :: str
1297
!------------------------------------------------------------------------------
1298
str = Var % Name(1:Var % NameLen)
1299
!------------------------------------------------------------------------------
1300
END FUNCTION GetVarName
1301
!------------------------------------------------------------------------------
1302
1303
1304
!------------------------------------------------------------------------------
1305
FUNCTION ComponentNameVar( Var, Component ) RESULT(str)
1306
!------------------------------------------------------------------------------
1307
TYPE(Variable_t),INTENT(in) :: Var
1308
INTEGER, OPTIONAL,INTENT(in) :: Component
1309
!------------------------------------------------------------------------------
1310
CHARACTER(:), ALLOCATABLE :: str
1311
!------------------------------------------------------------------------------
1312
IF ( Var % Name(1:Var % NameLen) == 'flow solution' ) THEN
1313
str='flow solution'
1314
IF ( .NOT. PRESENT(Component) ) RETURN
1315
IF ( Component == Var % DOFs ) THEN
1316
str = 'pressure'
1317
RETURN
1318
ELSE
1319
str = 'velocity ' // i2s(Component)
1320
END IF
1321
ELSE
1322
str = ComponentName(Var % Name, Component)
1323
END IF
1324
!------------------------------------------------------------------------------
1325
END FUNCTION ComponentNameVar
1326
!------------------------------------------------------------------------------
1327
1328
1329
!------------------------------------------------------------------------------
1330
FUNCTION ComponentNameStr( BaseName, Component_arg ) RESULT(str)
1331
!------------------------------------------------------------------------------
1332
INTEGER, OPTIONAL, INTENT(in) :: Component_arg
1333
CHARACTER(:), ALLOCATABLE :: str
1334
CHARACTER(LEN=*), INTENT(in) :: BaseName
1335
!------------------------------------------------------------------------------
1336
INTEGER :: ind, ind1, DOFsTot, DOFs, Component
1337
!------------------------------------------------------------------------------
1338
ind = INDEX( BaseName,'[' )
1339
1340
Component = 0
1341
IF ( PRESENT(Component_arg) ) Component=Component_arg
1342
1343
IF ( ind<=0 ) THEN
1344
str = TRIM(BaseName)
1345
IF ( Component > 0 ) THEN
1346
str = str // ' ' // i2s(Component)
1347
END IF
1348
ELSE IF( Component == 0 ) THEN
1349
str = BaseName(1:ind-1)
1350
ELSE
1351
DOFsTot = 0
1352
DO WHILE( .TRUE. )
1353
ind1 = INDEX( BaseName(ind+1:),':' )+ind
1354
IF ( ind1 <= ind ) THEN
1355
CALL Fatal( 'ComponentName', 'Syntax error in variable definition.' )
1356
END IF
1357
READ(BaseName(ind1+1:),'(i1)') DOFs
1358
DOFsTot = DOFsTot+DOFs
1359
IF ( DOFsTot>=Component ) EXIT
1360
ind = ind1+2
1361
END DO
1362
str = BaseName(ind+1:ind1-1)
1363
IF ( DOFs>1 ) THEN
1364
DOFs = Component - DOFsTot + DOFs
1365
str = str // ' ' //i2s(DOFs)
1366
END IF
1367
END IF
1368
!------------------------------------------------------------------------------
1369
END FUNCTION ComponentNameStr
1370
!------------------------------------------------------------------------------
1371
1372
1373
!------------------------------------------------------------------------------
1374
!> Solves a tridiagonal linear system.
1375
!------------------------------------------------------------------------------
1376
PURE SUBROUTINE SolveTriDiag( n, y, h, r )
1377
!------------------------------------------------------------------------------
1378
INTEGER, INTENT(in) :: n
1379
REAL(KIND=dp), INTENT(out) :: r(:)
1380
REAL(KIND=dp), INTENT(in) :: y(:), h(:)
1381
1382
REAL(KIND=dp) :: s,b(n)
1383
INTEGER :: i
1384
1385
DO i=2,n-1
1386
b(i) = 2 * ( h(i-1) + h(i) )
1387
r(i) = 3 * ( h(i) * ( y(i)-y(i-1) ) / h(i-1) + &
1388
h(i-1) * ( y(i+1)-y(i) ) / h(i) )
1389
END DO
1390
1391
r(2) = r(2) - h(2) * r(1)
1392
DO i=2,n-2
1393
s = -h(i+1) / b(i)
1394
r(i+1) = r(i+1) + s * r(i)
1395
b(i+1) = b(i+1) + s * h(i-1)
1396
END DO
1397
1398
DO i=n-1,2,-1
1399
r(i) = (r(i) - h(i-1) * r(i+1)) / b(i)
1400
END DO
1401
!------------------------------------------------------------------------------
1402
END SUBROUTINE SolveTriDiag
1403
!------------------------------------------------------------------------------
1404
1405
1406
FUNCTION CheckMonotone(n,x) RESULT ( Monotone )
1407
REAL(KIND=dp), INTENT(in) :: x(:)
1408
INTEGER, INTENT(in) :: n
1409
LOGICAL :: Monotone
1410
1411
INTEGER :: i
1412
1413
Monotone = .TRUE.
1414
DO i=1,n-1
1415
IF( x(i+1) <= x(i) ) THEN
1416
Monotone = .FALSE.
1417
WRITE (Message,'(E14.7,A,E14.7)') x(i),'>=',x(i+1)
1418
CALL WARN('CheckMonotone', Message)
1419
EXIT
1420
END IF
1421
END DO
1422
1423
END FUNCTION CheckMonotone
1424
1425
!------------------------------------------------------------------------------
1426
!> Solver for the coefficients of a cubic spline.
1427
!------------------------------------------------------------------------------
1428
PURE SUBROUTINE CubicSpline( n,x,y,r, monotone )
1429
!------------------------------------------------------------------------------
1430
REAL(KIND=dp), INTENT(in) :: x(:),y(:)
1431
REAL(KIND=dp), INTENT(out) :: r(:)
1432
INTEGER, INTENT(in) :: n
1433
LOGICAL, OPTIONAL, INTENT(in) :: monotone
1434
1435
REAL(KIND=dp) :: t,h(n),tau, alpha, beta
1436
INTEGER :: i
1437
LOGICAL :: mono
1438
1439
DO i=1,n-1
1440
h(i) = x(i+1) - x(i)
1441
END DO
1442
1443
r(1) = (y(2) - y(1) ) / h(1)
1444
r(n) = (y(n) - y(n-1) ) / h(n-1)
1445
1446
mono = .FALSE.
1447
IF(PRESENT(monotone)) mono = Monotone
1448
1449
IF (mono) THEN
1450
DO i=1,n-1
1451
h(i) = (y(i+1) - y(i) ) / h(i)
1452
END DO
1453
1454
DO i=2,n-1
1455
r(i) = (h(i-1) + h(i))/2
1456
END DO
1457
1458
DO i=1,n-1
1459
IF(ABS(h(i))<10*AEPS) THEN
1460
r(i) = 0._dp; r(i+1) = 0._dp
1461
CYCLE
1462
END IF
1463
1464
alpha = r(i) / h(i); beta = r(i+1) / h(i)
1465
IF ( alpha < 0._dp .OR. beta < 0._dp ) THEN
1466
r(i) = 0._dp;
1467
CYCLE
1468
END IF
1469
1470
tau = SQRT(alpha**2 + beta**2)
1471
IF(tau > 3) THEN
1472
tau = 3._dp / tau
1473
r(i) = alpha*tau*h(i); r(i+1)=beta*tau*h(i)
1474
END IF
1475
END DO
1476
ELSE
1477
CALL SolveTriDiag( n,y,h,r )
1478
END IF
1479
!------------------------------------------------------------------------------
1480
END SUBROUTINE CubicSpline
1481
!------------------------------------------------------------------------------
1482
1483
!------------------------------------------------------------------------------
1484
!> Evaluate a cubic spline.
1485
!------------------------------------------------------------------------------
1486
PURE FUNCTION CubicSplineVal(x,y,r,t) RESULT(s)
1487
!------------------------------------------------------------------------------
1488
REAL(KIND=dp) :: s
1489
REAL(KIND=dp), INTENT(in) :: x(:),y(:),r(:),t
1490
!------------------------------------------------------------------------------
1491
REAL(KIND=dp) :: a,b,c,d,h,lt
1492
1493
h = x(2)-x(1)
1494
a = -2 * ( y(2) - y(1) ) + ( r(1) + r(2) ) * h
1495
b = 3 * ( y(2) - y(1) ) - ( 2*r(1) + r(2) ) * h
1496
c = r(1) * h
1497
d = y(1)
1498
1499
lt = (t - x(1)) / h
1500
s = ((a*lt + b) * lt + c) * lt + d
1501
!------------------------------------------------------------------------------
1502
END FUNCTION CubicSplineVal
1503
!------------------------------------------------------------------------------
1504
1505
1506
!------------------------------------------------------------------------------
1507
!> Evaluate derivative of cubic spline.
1508
!------------------------------------------------------------------------------
1509
PURE FUNCTION CubicSplinedVal(x,y,r,t) RESULT(s)
1510
!------------------------------------------------------------------------------
1511
REAL(KIND=dp) :: s
1512
REAL(KIND=dp), INTENT(in) :: x(:),y(:),r(:),t
1513
!------------------------------------------------------------------------------
1514
REAL(KIND=dp) :: a,b,c,h,lt
1515
1516
h = x(2)-x(1)
1517
a = -2 * ( y(2) - y(1) ) + ( r(1) + r(2) ) * h
1518
b = 3 * ( y(2) - y(1) ) - ( 2*r(1) + r(2) ) * h
1519
c = r(1) * h
1520
1521
lt = (t - x(1)) / h
1522
s = ((3*a*lt + 2*b) * lt + c)/h
1523
!------------------------------------------------------------------------------
1524
END FUNCTION CubicSplinedVal
1525
!------------------------------------------------------------------------------
1526
1527
1528
!------------------------------------------------------------------------------
1529
!> Search array index such that tval(i) <= t < tval(i+1)
1530
!------------------------------------------------------------------------------
1531
PURE FUNCTION SearchInterval( tval, t ) RESULT(i)
1532
!------------------------------------------------------------------------------
1533
INTEGER :: i
1534
REAL(KIND=dp), INTENT(in) :: tval(:), t
1535
!------------------------------------------------------------------------------
1536
INTEGER :: n,n0,n1
1537
!------------------------------------------------------------------------------
1538
1539
n = SIZE(tval)
1540
1541
IF (t < tval(2)) THEN
1542
i = 1
1543
ELSE IF (t>=tval(n-1)) THEN
1544
i = n-1
1545
ELSE
1546
n0 = 1
1547
n1 = n
1548
i = (n0+n1)/2
1549
DO WHILE(.TRUE.)
1550
IF ( tval(i) <= t .AND. tval(i+1)>t ) EXIT
1551
1552
IF ( tval(i) > t ) THEN
1553
n1 = i-1
1554
ELSE
1555
n0 = i+1
1556
END IF
1557
i = (n0+n1)/2
1558
END DO
1559
END IF
1560
IF(i>n-1) i=n-1
1561
1562
!------------------------------------------------------------------------------
1563
END FUNCTION SearchInterval
1564
!------------------------------------------------------------------------------
1565
1566
!------------------------------------------------------------------------------
1567
!> As SearchInterval, but doesn't assume we'll find the value in the interval
1568
!------------------------------------------------------------------------------
1569
PURE FUNCTION SearchIntPosition( tval, t ) RESULT(i)
1570
!------------------------------------------------------------------------------
1571
INTEGER :: i
1572
INTEGER, INTENT(in) :: tval(:), t
1573
!------------------------------------------------------------------------------
1574
INTEGER :: n,n0,n1
1575
!------------------------------------------------------------------------------
1576
1577
n = SIZE(tval)
1578
1579
IF (t < tval(1)) THEN
1580
i = 0
1581
ELSE IF (t>=tval(n)) THEN
1582
i = n
1583
ELSE
1584
n0 = 1
1585
n1 = n
1586
i = (n0+n1)/2
1587
DO WHILE(.TRUE.)
1588
IF ( tval(i) <= t .AND. tval(i+1)>t ) EXIT
1589
1590
IF ( tval(i) > t ) THEN
1591
n1 = i-1
1592
ELSE
1593
n0 = i+1
1594
END IF
1595
i = (n0+n1)/2
1596
END DO
1597
END IF
1598
IF(i>n) i=n
1599
1600
!------------------------------------------------------------------------------
1601
END FUNCTION SearchIntPosition
1602
!------------------------------------------------------------------------------
1603
1604
1605
!------------------------------------------------------------------------------
1606
!> Interpolate values in a curve given by linear table or splines.
1607
!------------------------------------------------------------------------------
1608
PURE FUNCTION InterpolateCurve( TValues,FValues,T, CubicCoeff) RESULT( F )
1609
!------------------------------------------------------------------------------
1610
REAL(KIND=dp) :: F
1611
REAL(KIND=dp), INTENT(iN) :: TValues(:),FValues(:),T
1612
REAL(KIND=dp), OPTIONAL, POINTER, INTENT(in) :: CubicCoeff(:)
1613
!------------------------------------------------------------------------------
1614
INTEGER :: i,n
1615
LOGICAL :: Cubic
1616
!------------------------------------------------------------------------------
1617
1618
n = SIZE(TValues)
1619
1620
! This is a misuse of the interpolation in case of standard dependency
1621
! of type y=a*x.
1622
IF( n == 1 ) THEN
1623
F = FValues(1) * T
1624
RETURN
1625
END IF
1626
1627
i = SearchInterval( Tvalues, t )
1628
1629
Cubic = PRESENT(CubicCoeff)
1630
Cubic = Cubic .AND. T>=Tvalues(1) .AND. T<=Tvalues(n)
1631
IF ( Cubic ) Cubic = Cubic.AND.ASSOCIATED(CubicCoeff)
1632
1633
IF ( Cubic ) THEN
1634
F = CubicSplineVal(Tvalues(i:i+1),FValues(i:i+1),CubicCoeff(i:i+1),T)
1635
ELSE
1636
F = (T-TValues(i)) / (TValues(i+1)-TValues(i))
1637
F = (1-F)*FValues(i) + F*FValues(i+1)
1638
END IF
1639
END FUNCTION InterpolateCurve
1640
!------------------------------------------------------------------------------
1641
1642
1643
!------------------------------------------------------------------------------
1644
!> Derivate a curve given by linear table or splines.
1645
!------------------------------------------------------------------------------
1646
PURE FUNCTION DerivateCurve( TValues,FValues,T,CubicCoeff ) RESULT( F )
1647
!------------------------------------------------------------------------------
1648
REAL(KIND=dp) :: F
1649
REAL(KIND=dp), INTENT(in) :: TValues(:),FValues(:),T
1650
REAL(KIND=dp), OPTIONAL, POINTER, INTENT(in) :: CubicCoeff(:)
1651
!------------------------------------------------------------------------------
1652
INTEGER :: i,n
1653
LOGICAL :: Cubic
1654
!------------------------------------------------------------------------------
1655
n = SIZE(TValues)
1656
1657
i = SearchInterval( Tvalues, t )
1658
1659
Cubic = PRESENT(CubicCoeff)
1660
Cubic = Cubic .AND. T>=Tvalues(1) .AND. T<=Tvalues(n)
1661
IF ( Cubic ) Cubic = Cubic.AND.ASSOCIATED(CubicCoeff)
1662
1663
IF (Cubic) THEN
1664
F = CubicSplinedVal(Tvalues(i:i+1),FValues(i:i+1),CubicCoeff(i:i+1),T)
1665
ELSE
1666
F = (FValues(i+1)-FValues(i)) / (TValues(i+1)-TValues(i))
1667
END IF
1668
!------------------------------------------------------------------------------
1669
END FUNCTION DerivateCurve
1670
!------------------------------------------------------------------------------
1671
1672
1673
!------------------------------------------------------------------------------
1674
!> Integrate a curve given by linear table or splines.
1675
!------------------------------------------------------------------------------
1676
PURE SUBROUTINE CumulativeIntegral(TValues,FValues,CubicCoeff,Cumulative)
1677
!------------------------------------------------------------------------------
1678
REAL(KIND=dp), INTENT(in) :: TValues(:),FValues(:)
1679
REAL(KIND=dp), INTENT(out) :: Cumulative(:)
1680
REAL(KIND=dp), OPTIONAL, POINTER, INTENT(in) :: CubicCoeff(:)
1681
!------------------------------------------------------------------------------
1682
INTEGER :: i,n
1683
LOGICAL :: Cubic
1684
REAL(KIND=dp) :: t(2), y(2), r(2), h, a, b, c, d
1685
!------------------------------------------------------------------------------
1686
n = SIZE(TValues)
1687
1688
Cubic = PRESENT(CubicCoeff)
1689
IF ( Cubic ) Cubic = Cubic.AND.ASSOCIATED(CubicCoeff)
1690
1691
! here only complete intervals:
1692
! -----------------------------
1693
Cumulative(1) = 0._dp
1694
IF ( Cubic ) THEN
1695
DO i=1,n-1
1696
t(1) = Tvalues(i)
1697
t(2) = Tvalues(i+1)
1698
1699
y(1) = FValues(i)
1700
y(2) = FValues(i+1)
1701
1702
r(1) = CubicCoeff(i)
1703
r(2) = CubicCoeff(i+1)
1704
1705
h = t(2) - t(1)
1706
1707
a = (-2 * (y(2) - y(1)) + ( r(1) + r(2)) * h)/4
1708
b = ( 3 * (y(2) - y(1)) - (2*r(1) + r(2)) * h)/3
1709
c = (r(1) * h)/2
1710
d = y(1)
1711
Cumulative(i+1) = Cumulative(i) + h*(a+b+c+d)
1712
END DO
1713
ELSE
1714
DO i=1,n-1
1715
t(1) = Tvalues(i)
1716
t(2) = Tvalues(i+1)
1717
1718
y(1) = FValues(i)
1719
y(2) = FValues(i+1)
1720
1721
h = t(2) - t(1)
1722
c = (y(2)-y(1))/2
1723
d = y(1)
1724
Cumulative(i+1) = Cumulative(i) + h*(c+d)
1725
END DO
1726
END IF
1727
!------------------------------------------------------------------------------
1728
END SUBROUTINE CumulativeIntegral
1729
!------------------------------------------------------------------------------
1730
1731
!------------------------------------------------------------------------------
1732
!> Integrate a curve given by linear table or splines.
1733
!------------------------------------------------------------------------------
1734
FUNCTION IntegrateCurve(TValues,FValues,CubicCoeff,T0,T1,Cumulative,Found) RESULT(sumf)
1735
!------------------------------------------------------------------------------
1736
REAL(KIND=dp) :: sumf
1737
1738
REAL(KIND=dp), INTENT(in) :: TValues(:),FValues(:)
1739
REAL(KIND=dp), OPTIONAL, INTENT(in) :: T0, T1
1740
REAL(KIND=dp), OPTIONAL, INTENT(in) :: Cumulative(:)
1741
REAL(KIND=dp), OPTIONAL, POINTER, INTENT(in) :: CubicCoeff(:)
1742
LOGICAL, OPTIONAL :: Found
1743
!------------------------------------------------------------------------------
1744
INTEGER :: i,n,i0,i1
1745
LOGICAL :: Cubic
1746
REAL(KIND=dp) :: t(2), y(2), r(2), h, a, b, c, d, s0, s1, tt0, tt1
1747
!------------------------------------------------------------------------------
1748
1749
sumf = 0.0_dp
1750
IF(PRESENT(Found)) Found = .FALSE.
1751
1752
n = SIZE(TValues)
1753
IF(n<2) RETURN
1754
1755
IF(SIZE(FValues) /= n ) THEN
1756
CALL Warn('IntegrateCurve','TValues and Fvalues should be of same size!')
1757
RETURN
1758
END IF
1759
1760
tt0 = TValues(1)
1761
IF(PRESENT(t0)) tt0=t0
1762
1763
tt1 = TValues(n)
1764
IF(PRESENT(t1)) tt1=t1
1765
1766
IF(tt0>=tt1) RETURN
1767
1768
IF(PRESENT(Found)) Found = .TRUE.
1769
1770
1771
! t0 < first, t1 <= first
1772
IF(tt1<=Tvalues(1)) THEN
1773
t(1) = Tvalues(1)
1774
t(2) = Tvalues(2)
1775
1776
y(1) = FValues(1)
1777
y(2) = FValues(2)
1778
1779
h = t(2) - t(1)
1780
s0 = (tt0 - t(1)) / h
1781
s1 = (tt1 - t(1)) / h
1782
c = (y(2) - y(1)) / 2
1783
d = y(1)
1784
sumf = sumf + h * ((c*s1 + d)*s1 - (c*s0 + d)*s0)
1785
RETURN
1786
END IF
1787
1788
! t0 >= last, t1 > last
1789
IF(tt0>=Tvalues(n)) THEN
1790
t(1) = Tvalues(n-1)
1791
t(2) = Tvalues(n)
1792
1793
y(1) = FValues(n-1)
1794
y(2) = FValues(n)
1795
1796
h = t(2) - t(1)
1797
s0 = (tt0 - t(1)) / h
1798
s1 = (tt1 - t(1)) / h
1799
c = (y(2) - y(1)) / 2
1800
d = y(1)
1801
sumf = sumf + h * ((c*s1 + d)*s1 - (c*s0 + d)*s0)
1802
RETURN
1803
END IF
1804
1805
! first interval outside
1806
IF(tt0<Tvalues(1)) THEN
1807
t(1) = Tvalues(1)
1808
t(2) = Tvalues(2)
1809
1810
y(1) = FValues(1)
1811
y(2) = FValues(2)
1812
1813
h = t(2) - t(1)
1814
s0 = (tt0 - t(1)) / h
1815
c = (y(2) - y(1)) / 2
1816
d = y(1)
1817
sumf = sumf - h * (c*s0 + d)*s0
1818
tt0 = Tvalues(1)
1819
END IF
1820
1821
! last interval outside
1822
IF(tt1>Tvalues(n)) THEN
1823
t(1) = Tvalues(n-1)
1824
t(2) = Tvalues(n)
1825
1826
y(1) = FValues(n-1)
1827
y(2) = FValues(n)
1828
1829
h = t(2) - t(1)
1830
s1 = (tt1 - t(1)) / h
1831
c = (y(2) - y(1)) / 2
1832
d = y(1)
1833
sumf = sumf + h * ( (c*s1 + d)*s1 - (c+d) )
1834
tt1 = Tvalues(n)
1835
END IF
1836
1837
IF(tt0 >= tt1) RETURN
1838
1839
Cubic = PRESENT(CubicCoeff)
1840
IF ( Cubic ) Cubic = Cubic.AND.ASSOCIATED(CubicCoeff)
1841
1842
i0 = SearchInterval( Tvalues, tt0 )
1843
1844
! first (possibly partial) interval:
1845
! -------------------------------------
1846
t(1) = Tvalues(i0)
1847
t(2) = Tvalues(i0+1)
1848
1849
h = t(2) - t(1)
1850
s0 = (tt0-t(1))/h
1851
s1 = MIN((tt1-t(1))/h,1._dp)
1852
1853
IF(s0>0 .OR. s1<1) THEN
1854
y(1) = FValues(i0)
1855
y(2) = FValues(i0+1)
1856
1857
IF(Cubic) THEN
1858
r(1) = CubicCoeff(i0)
1859
r(2) = CubicCoeff(i0+1)
1860
1861
a = (-2 * (y(2) - y(1)) + ( r(1) + r(2)) * h)/4
1862
b = ( 3 * (y(2) - y(1)) - (2*r(1) + r(2)) * h)/3
1863
c = (r(1) * h)/2
1864
d = y(1)
1865
sumf = sumf + h * ( (((a*s1 + b)*s1 + c)*s1 + d)*s1 - &
1866
(((a*s0 + b)*s0 + c)*s0 + d)*s0 )
1867
1868
ELSE
1869
c = (y(2)-y(1))/2
1870
d = y(1)
1871
sumf = sumf + h * ( (c*s1 + d)*s1 - (c*s0 + d)*s0 )
1872
END IF
1873
i0 = i0 + 1
1874
tt0 = Tvalues(i0)
1875
IF(tt0 >= tt1) RETURN
1876
END IF
1877
1878
i1 = SearchInterval( Tvalues, tt1 )
1879
1880
! last (possibly partial) interval:
1881
! ------------------------------------
1882
t(1) = Tvalues(i1)
1883
t(2) = Tvalues(i1+1)
1884
1885
h = t(2) - t(1)
1886
1887
s0 = MAX((tt0-t(1))/h, 0.0_dp)
1888
s1 = (tt1-t(1))/h
1889
1890
IF(s0>0 .OR. s1<1) THEN
1891
y(1) = FValues(i1)
1892
y(2) = FValues(i1+1)
1893
1894
IF(Cubic) THEN
1895
r(1) = CubicCoeff(i1)
1896
r(2) = CubicCoeff(i1+1)
1897
1898
a = (-2 * (y(2) - y(1)) + ( r(1) + r(2)) * h)/4
1899
b = ( 3 * (y(2) - y(1)) - (2*r(1) + r(2)) * h)/3
1900
c = (r(1) * h)/2
1901
d = y(1)
1902
sumf = sumf + h * ( (((a*s1 + b)*s1 + c)*s1 + d)*s1 - &
1903
(((a*s0 + b)*s0 + c)*s0 + d)*s0 )
1904
ELSE
1905
c = (y(2)-y(1))/2
1906
d = y(1)
1907
sumf = sumf + h * ( (c*s1 + d)*s1 - (c*s0 + d)*s0 )
1908
END IF
1909
i1 = i1 - 1
1910
tt1 = Tvalues(i1+1)
1911
IF(tt0 >= tt1) RETURN
1912
END IF
1913
1914
! here only complete intervals:
1915
! -----------------------------
1916
1917
IF(PRESENT(Cumulative)) THEN
1918
sumf = sumf + Cumulative(i1+1) - Cumulative(i0)
1919
RETURN
1920
END IF
1921
1922
IF ( Cubic ) THEN
1923
DO i=i0,i1
1924
t(1) = Tvalues(i)
1925
t(2) = Tvalues(i+1)
1926
1927
y(1) = FValues(i)
1928
y(2) = FValues(i+1)
1929
1930
r(1) = CubicCoeff(i)
1931
r(2) = CubicCoeff(i+1)
1932
1933
h = t(2) - t(1)
1934
1935
a = (-2 * (y(2) - y(1)) + ( r(1) + r(2)) * h)/4
1936
b = ( 3 * (y(2) - y(1)) - (2*r(1) + r(2)) * h)/3
1937
c = (r(1) * h)/2
1938
d = y(1)
1939
sumf = sumf + h * (a+b+c+d)
1940
END DO
1941
ELSE
1942
DO i=i0,i1
1943
t(1) = Tvalues(i)
1944
t(2) = Tvalues(i+1)
1945
1946
y(1) = FValues(i)
1947
y(2) = FValues(i+1)
1948
1949
h = t(2) - t(1)
1950
c = (y(2)-y(1))/2
1951
d = y(1)
1952
sumf = sumf + h * (c+d)
1953
END DO
1954
END IF
1955
!------------------------------------------------------------------------------
1956
END FUNCTION IntegrateCurve
1957
!------------------------------------------------------------------------------
1958
1959
1960
!------------------------------------------------------------------------------
1961
SUBROUTINE ClearMatrix( Matrix )
1962
#if defined(ELMER_HAVE_MPI_MODULE)
1963
USE mpi
1964
#endif
1965
TYPE(Matrix_t), POINTER, INTENT(in) :: Matrix
1966
#if defined(ELMER_HAVE_MPIF_HEADER)
1967
INCLUDE "mpif.h"
1968
#endif
1969
1970
Matrix % FORMAT = MATRIX_CRS
1971
1972
NULLIFY( Matrix % Child )
1973
NULLIFY( Matrix % Parent )
1974
NULLIFY( Matrix % EMatrix )
1975
NULLIFY( Matrix % ConstraintMatrix )
1976
1977
NULLIFY( Matrix % Perm )
1978
NULLIFY( Matrix % InvPerm )
1979
1980
NULLIFY( Matrix % Cols )
1981
NULLIFY( Matrix % Rows )
1982
NULLIFY( Matrix % Diag )
1983
1984
NULLIFY( Matrix % RHS )
1985
NULLIFY( Matrix % Force )
1986
NULLIFY( Matrix % RHS_im )
1987
1988
NULLIFY( Matrix % Values )
1989
NULLIFY( Matrix % ILUValues )
1990
NULLIFY( Matrix % MassValues )
1991
NULLIFY( Matrix % DampValues )
1992
1993
NULLIFY( Matrix % BulkRHS )
1994
NULLIFY( Matrix % BulkValues )
1995
1996
NULLIFY( Matrix % BulkResidual )
1997
1998
NULLIFY( Matrix % ILUCols )
1999
NULLIFY( Matrix % ILURows )
2000
NULLIFY( Matrix % ILUDiag )
2001
2002
NULLIFY( Matrix % CRHS )
2003
NULLIFY( Matrix % CForce )
2004
2005
NULLIFY( Matrix % ParMatrix )
2006
2007
NULLIFY( Matrix % CValues )
2008
NULLIFY( Matrix % CILUValues )
2009
NULLIFY( Matrix % CMassValues )
2010
NULLIFY( Matrix % CDampValues )
2011
2012
! NULLIFY( Matrix % GRows )
2013
! NULLIFY( Matrix % RowOwner )
2014
NULLIFY( Matrix % GOrder )
2015
NULLIFY( Matrix % EPerm )
2016
2017
NULLIFY( Matrix % ParMatrix )
2018
2019
NULLIFY( Matrix % ParallelInfo )
2020
#ifdef HAVE_UMFPACK
2021
Matrix % UMFPack_Numeric = 0
2022
#endif
2023
2024
Matrix % Cholesky = .FALSE.
2025
Matrix % Lumped = .FALSE.
2026
Matrix % Ordered = .FALSE.
2027
Matrix % COMPLEX = .FALSE.
2028
Matrix % Symmetric = .FALSE.
2029
Matrix % SolveCount = 0
2030
Matrix % NumberOfRows = 0
2031
Matrix % Ndeg = -1
2032
Matrix % ProjectorBC = 0
2033
Matrix % ProjectorType = PROJECTOR_TYPE_DEFAULT
2034
2035
Matrix % Solver => NULL()
2036
2037
Matrix % DGMatrix = .FALSE.
2038
Matrix % Comm = ELMER_COMM_WORLD
2039
2040
END SUBROUTINE ClearMatrix
2041
2042
2043
!------------------------------------------------------------------------------
2044
FUNCTION AllocateMatrix() RESULT(Matrix)
2045
!------------------------------------------------------------------------------
2046
TYPE(Matrix_t), POINTER :: Matrix
2047
!------------------------------------------------------------------------------
2048
ALLOCATE( Matrix )
2049
CALL ClearMatrix( Matrix )
2050
!------------------------------------------------------------------------------
2051
END FUNCTION AllocateMatrix
2052
!------------------------------------------------------------------------------
2053
2054
2055
!------------------------------------------------------------------------------
2056
RECURSIVE SUBROUTINE FreeQuadrantTree( Root )
2057
!------------------------------------------------------------------------------
2058
TYPE(Quadrant_t), POINTER :: Root
2059
2060
INTEGER :: i
2061
2062
IF ( .NOT. ASSOCIATED( Root ) ) RETURN
2063
2064
IF ( ASSOCIATED(Root % Elements) ) DEALLOCATE( Root % Elements )
2065
2066
IF ( ASSOCIATED( Root % ChildQuadrants ) ) THEN
2067
DO i=1,SIZE(Root % ChildQuadrants)
2068
CALL FreeQuadrantTree( Root % ChildQuadrants(i) % Quadrant )
2069
END DO
2070
DEALLOCATE( Root % ChildQuadrants )
2071
NULLIFY( Root % ChildQuadrants )
2072
END IF
2073
2074
DEALLOCATE( Root )
2075
!------------------------------------------------------------------------------
2076
END SUBROUTINE FreeQuadrantTree
2077
!------------------------------------------------------------------------------
2078
2079
2080
!------------------------------------------------------------------------------
2081
SUBROUTINE AllocateRealVector( F, n, From, FailureMessage )
2082
!------------------------------------------------------------------------------
2083
REAL(KIND=dp), POINTER :: F(:)
2084
INTEGER :: n
2085
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2086
!------------------------------------------------------------------------------
2087
INTEGER :: istat
2088
!------------------------------------------------------------------------------
2089
2090
ALLOCATE( F(n), STAT=istat )
2091
IF ( istat /= 0 ) THEN
2092
WRITE( Message, * )'Unable to allocate ', n, ' element real array.'
2093
CALL Error( 'AllocateRealVector', Message )
2094
IF ( PRESENT( From ) ) THEN
2095
WRITE( Message, * )'Requested From: ', TRIM(From)
2096
CALL Error( 'AllocateRealVector', Message )
2097
END IF
2098
IF ( PRESENT( FailureMessage ) ) THEN
2099
CALL Fatal( 'AllocateRealVector', FailureMessage )
2100
END IF
2101
END IF
2102
!------------------------------------------------------------------------------
2103
END SUBROUTINE AllocateRealVector
2104
!------------------------------------------------------------------------------
2105
2106
2107
!------------------------------------------------------------------------------
2108
SUBROUTINE AllocateComplexVector( f, n, From, FailureMessage )
2109
!------------------------------------------------------------------------------
2110
COMPLEX(KIND=dp), POINTER :: f(:)
2111
INTEGER :: n
2112
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2113
!------------------------------------------------------------------------------
2114
INTEGER :: istat
2115
!------------------------------------------------------------------------------
2116
2117
ALLOCATE( f(n), STAT=istat )
2118
IF ( istat /= 0 ) THEN
2119
WRITE( Message, * )'Unable to allocate ', n, ' element complex array.'
2120
CALL Error( 'AllocateComplexVector', Message )
2121
IF ( PRESENT( From ) ) THEN
2122
WRITE( Message, * )'Requested From: ', TRIM(From)
2123
CALL Error( 'AllocateComplexVector', Message )
2124
END IF
2125
IF ( PRESENT( FailureMessage ) ) THEN
2126
CALL Fatal( 'AllocateComplexVector', FailureMessage )
2127
END IF
2128
END IF
2129
!------------------------------------------------------------------------------
2130
END SUBROUTINE AllocateComplexVector
2131
!------------------------------------------------------------------------------
2132
2133
2134
!------------------------------------------------------------------------------
2135
SUBROUTINE AllocateIntegerVector( f, n, From, FailureMessage )
2136
!------------------------------------------------------------------------------
2137
INTEGER, POINTER :: f(:)
2138
INTEGER :: n
2139
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2140
!------------------------------------------------------------------------------
2141
INTEGER :: istat
2142
!------------------------------------------------------------------------------
2143
2144
ALLOCATE( f(n), STAT=istat )
2145
IF ( istat /= 0 ) THEN
2146
WRITE( Message, * )'Unable to allocate ', n, ' element integer array.'
2147
CALL Error( 'AllocateIntegerVector', Message )
2148
IF ( PRESENT( From ) ) THEN
2149
WRITE( Message, * )'Requested From: ', TRIM(From)
2150
CALL Error( 'AllocateIntegerVector', Message )
2151
END IF
2152
IF ( PRESENT( FailureMessage ) ) THEN
2153
CALL Fatal( 'AllocateIntegerVector', FailureMessage )
2154
END IF
2155
END IF
2156
!------------------------------------------------------------------------------
2157
END SUBROUTINE AllocateIntegerVector
2158
!------------------------------------------------------------------------------
2159
2160
2161
!------------------------------------------------------------------------------
2162
SUBROUTINE AllocateLogicalVector( f, n, From, FailureMessage )
2163
!------------------------------------------------------------------------------
2164
LOGICAL, POINTER :: f(:)
2165
INTEGER :: n
2166
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2167
!------------------------------------------------------------------------------
2168
INTEGER :: istat
2169
!------------------------------------------------------------------------------
2170
2171
ALLOCATE( f(n), STAT=istat )
2172
IF ( istat /= 0 ) THEN
2173
WRITE( Message, * )'Unable to allocate ', n, ' element logical array.'
2174
CALL Error( 'AllocateLogicalVector', Message )
2175
IF ( PRESENT( From ) ) THEN
2176
WRITE( Message, * )'Requested From: ', TRIM(From)
2177
CALL Error( 'AllocateLogicalVector', Message )
2178
END IF
2179
IF ( PRESENT( FailureMessage ) ) THEN
2180
CALL Fatal( 'AllocateLogicalVector', FailureMessage )
2181
END IF
2182
END IF
2183
!------------------------------------------------------------------------------
2184
END SUBROUTINE AllocateLogicalVector
2185
!------------------------------------------------------------------------------
2186
2187
2188
!------------------------------------------------------------------------------
2189
SUBROUTINE AllocateElementVector( f, n, From, FailureMessage )
2190
!------------------------------------------------------------------------------
2191
TYPE(Element_t), POINTER :: f(:)
2192
INTEGER :: n
2193
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2194
!------------------------------------------------------------------------------
2195
INTEGER :: istat
2196
!------------------------------------------------------------------------------
2197
2198
ALLOCATE( f(n), STAT=istat )
2199
IF ( istat /= 0 ) THEN
2200
WRITE( Message, * )'Unable to allocate structured ', n, ' element array.'
2201
CALL Error( 'AllocateElementVector', Message )
2202
IF ( PRESENT( From ) ) THEN
2203
WRITE( Message, * )'Requested From: ', TRIM(From)
2204
CALL Error( 'AllocateElementVector', Message )
2205
END IF
2206
IF ( PRESENT( FailureMessage ) ) THEN
2207
CALL Fatal( 'AllocateElementVector', FailureMessage )
2208
END IF
2209
END IF
2210
!------------------------------------------------------------------------------
2211
END SUBROUTINE AllocateElementVector
2212
!------------------------------------------------------------------------------
2213
2214
2215
!------------------------------------------------------------------------------
2216
SUBROUTINE AllocateRealArray( f, n1, n2, From, FailureMessage )
2217
!------------------------------------------------------------------------------
2218
REAL(KIND=dp), POINTER :: f(:,:)
2219
INTEGER :: n1,n2
2220
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2221
!------------------------------------------------------------------------------
2222
INTEGER :: istat
2223
!------------------------------------------------------------------------------
2224
2225
ALLOCATE( f(n1,n2), STAT=istat )
2226
IF ( istat /= 0 ) THEN
2227
WRITE( Message, * )'Unable to allocate ', n1, ' by ', n2, ' element real matrix.'
2228
CALL Error( 'AllocateRealArray', Message )
2229
IF ( PRESENT( From ) ) THEN
2230
WRITE( Message, * )'Requested From: ', TRIM(From)
2231
CALL Error( 'AllocateRealArray', Message )
2232
END IF
2233
IF ( PRESENT( FailureMessage ) ) THEN
2234
CALL Fatal( 'AllocateRealArray', FailureMessage )
2235
END IF
2236
END IF
2237
!------------------------------------------------------------------------------
2238
END SUBROUTINE AllocateRealArray
2239
!------------------------------------------------------------------------------
2240
2241
!------------------------------------------------------------------------------
2242
SUBROUTINE AllocateComplexArray( f, n1, n2, From, FailureMessage )
2243
!------------------------------------------------------------------------------
2244
COMPLEX(KIND=dp), POINTER :: f(:,:)
2245
INTEGER :: n1,n2
2246
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2247
!------------------------------------------------------------------------------
2248
INTEGER :: istat
2249
!------------------------------------------------------------------------------
2250
2251
ALLOCATE( f(n1,n2), STAT=istat )
2252
IF ( istat /= 0 ) THEN
2253
WRITE( Message, * )'Unable to allocate ', n1, ' by ', n2, ' element complex matrix.'
2254
CALL Error( 'AllocateComplexArray', Message )
2255
IF ( PRESENT( From ) ) THEN
2256
WRITE( Message, * )'Requested From: ', TRIM(From)
2257
CALL Error( 'AllocateComplexArray', Message )
2258
END IF
2259
IF ( PRESENT( FailureMessage ) ) THEN
2260
CALL Fatal( 'AllocateComplexArray', FailureMessage )
2261
END IF
2262
END IF
2263
!------------------------------------------------------------------------------
2264
END SUBROUTINE AllocateComplexArray
2265
!------------------------------------------------------------------------------
2266
2267
2268
!------------------------------------------------------------------------------
2269
SUBROUTINE AllocateIntegerArray( f, n1, n2, From, FailureMessage )
2270
!------------------------------------------------------------------------------
2271
INTEGER, POINTER :: f(:,:)
2272
INTEGER :: n1,n2
2273
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2274
!------------------------------------------------------------------------------
2275
INTEGER :: istat
2276
!------------------------------------------------------------------------------
2277
2278
istat = -1
2279
IF ( n1 > 0 .AND. n2 > 0 ) THEN
2280
ALLOCATE( f(n1,n2), STAT=istat )
2281
END IF
2282
IF ( istat /= 0 ) THEN
2283
WRITE( Message, * )'Unable to allocate ', n1, ' by ', n2, ' element integer matrix.'
2284
CALL Error( 'AllocateIntegerArray', Message )
2285
IF ( PRESENT( From ) ) THEN
2286
WRITE( Message, * )'Requested From: ', TRIM(From)
2287
CALL Error( 'AllocateIntegerArray', Message )
2288
END IF
2289
IF ( PRESENT( FailureMessage ) ) THEN
2290
CALL Fatal( 'AllocateIntegerArray', FailureMessage )
2291
END IF
2292
END IF
2293
!------------------------------------------------------------------------------
2294
END SUBROUTINE AllocateIntegerArray
2295
!------------------------------------------------------------------------------
2296
2297
2298
2299
!------------------------------------------------------------------------------
2300
SUBROUTINE AllocateLogicalArray( f, n1, n2, From, FailureMessage )
2301
!------------------------------------------------------------------------------
2302
LOGICAL, POINTER :: f(:,:)
2303
INTEGER :: n1,n2
2304
CHARACTER(LEN=*), OPTIONAL :: From, FailureMessage
2305
!------------------------------------------------------------------------------
2306
INTEGER :: istat
2307
!------------------------------------------------------------------------------
2308
2309
istat = -1
2310
IF ( n1 > 0 .AND. n2 > 0 ) THEN
2311
ALLOCATE( f(n1,n2), STAT=istat )
2312
END IF
2313
IF ( istat /= 0 ) THEN
2314
WRITE( Message, * )'Unable to allocate ', n1, ' by ', n2, ' element logical matrix.'
2315
CALL Error( 'AllocateLogicalArray', Message )
2316
IF ( PRESENT( From ) ) THEN
2317
WRITE( Message, * )'Requested From: ', TRIM(From)
2318
CALL Error( 'AllocateLogicalArray', Message )
2319
END IF
2320
IF ( PRESENT( FailureMessage ) ) THEN
2321
CALL Fatal( 'AllocateLogicalArray', FailureMessage )
2322
END IF
2323
END IF
2324
!------------------------------------------------------------------------------
2325
END SUBROUTINE AllocateLogicalArray
2326
!------------------------------------------------------------------------------
2327
2328
! Pad given integer value to be the next largest multiple of nbyte
2329
FUNCTION IntegerNBytePad(val, nbyte) RESULT(padval)
2330
IMPLICIT NONE
2331
2332
INTEGER, INTENT(IN) :: val, nbyte
2333
INTEGER :: padval
2334
! Parameters and variables
2335
INTEGER, PARAMETER :: bytesinint = KIND(val)
2336
INTEGER :: nbytesinint
2337
2338
! Compute number of nbytes in int
2339
nbytesinint = nbyte/bytesinint
2340
! Compute value padded to multiples of n-byte
2341
padval=((val-1)/nbytesinint)*nbytesinint+nbytesinint
2342
END FUNCTION IntegerNBytePad
2343
2344
! Pad given value to be the next largest multiple of nbyte
2345
FUNCTION NBytePad(val, bytesinelem, nbyte) RESULT(padval)
2346
IMPLICIT NONE
2347
2348
INTEGER, INTENT(IN) :: val, bytesinelem, nbyte
2349
INTEGER :: padval
2350
! Variables
2351
INTEGER :: nbytesinelem
2352
2353
! Compute number of nbytes in a single element
2354
nbytesinelem = nbyte/bytesinelem
2355
! Compute value padded to multiples of n-byte
2356
padval=((val-1)/nbytesinelem)*nbytesinelem+nbytesinelem
2357
END FUNCTION NBytePad
2358
2359
!------------------------------------------------------------------------------
2360
!> Given the filename0 (and suffix0) find the 1st free filename
2361
!> that does not exist in the current working directory
2362
!------------------------------------------------------------------------------
2363
2364
FUNCTION NextFreeFilename(Filename0,Suffix0,LastExisting) RESULT (Filename)
2365
2366
CHARACTER(LEN=*) :: Filename0
2367
CHARACTER(LEN=*), OPTIONAL :: Suffix0
2368
LOGICAL, OPTIONAL :: LastExisting
2369
CHARACTER(:), ALLOCATABLE :: Filename,Prefix,Suffix,PrevFilename
2370
LOGICAL :: FileIs
2371
INTEGER :: No, ind, len
2372
2373
ind = INDEX( FileName0,'.',.TRUE. )
2374
len = LEN_TRIM(Filename0)
2375
IF(ind > 0) THEN
2376
Prefix = Filename0(1:ind-1)
2377
Suffix = Filename0(ind:len)
2378
ELSE
2379
Prefix = Filename0(1:len)
2380
IF(PRESENT(Suffix0)) THEN
2381
Suffix = '.'//TRIM(Suffix0)
2382
ELSE
2383
Suffix = '.dat'
2384
END IF
2385
END IF
2386
2387
DO No = 1,9999
2388
IF( No > 0 ) PrevFilename = Filename
2389
FileName = TRIM(Prefix)//I2S(No)//TRIM(Suffix)
2390
2391
INQUIRE( FILE=Filename, EXIST=FileIs )
2392
IF(.NOT. FileIs) EXIT
2393
END DO
2394
2395
IF( PRESENT(LastExisting)) THEN
2396
IF( LastExisting ) Filename = PrevFilename
2397
END IF
2398
2399
CALL Info('NextFreeFilename','Next Free filename is: '//TRIM(Filename),Level=12)
2400
2401
!------------------------------------------------------------------------------
2402
END FUNCTION NextFreeFilename
2403
!------------------------------------------------------------------------------
2404
2405
!------------------------------------------------------------------------------
2406
!> Given the filename0 add a string related to the partitioning.
2407
!------------------------------------------------------------------------------
2408
2409
FUNCTION AddFilenameParSuffix(Filename0,Suffix0,Parallel,MyPe,NumWidth,PeMax,PeSeparator) RESULT (Filename)
2410
2411
CHARACTER(LEN=*) :: Filename0
2412
CHARACTER(LEN=*), OPTIONAL :: Suffix0
2413
CHARACTER(LEN=*), OPTIONAL :: PeSeparator
2414
LOGICAL :: Parallel
2415
INTEGER :: MyPe
2416
INTEGER, OPTIONAL :: NumWidth
2417
INTEGER, OPTIONAL :: PeMax
2418
CHARACTER(LEN=MAX_NAME_LEN) :: Filename
2419
!------------------------------------------------------------------------------
2420
CHARACTER(LEN=MAX_NAME_LEN) :: OutStyle
2421
CHARACTER(:), ALLOCATABLE :: Prefix, Suffix
2422
INTEGER :: No, ind, len, NumW, NoLim
2423
2424
ind = INDEX( FileName0,'.',.TRUE. )
2425
len = LEN_TRIM(Filename0)
2426
2427
! If the only dot is the first one it only related to the current working directory.
2428
IF(ind > 1) THEN
2429
Prefix = Filename0(1:ind-1)
2430
Suffix = Filename0(ind:len)
2431
ELSE
2432
Prefix = Filename0(1:len)
2433
IF(PRESENT(Suffix0)) THEN
2434
Suffix = '.'//TRIM(Suffix0)
2435
ELSE
2436
Suffix = '.dat'
2437
END IF
2438
END IF
2439
2440
IF( Parallel ) THEN
2441
No = MyPe + 1
2442
2443
IF( PRESENT(NumWidth) ) THEN
2444
NumW = NumWidth
2445
ELSE IF( PRESENT( PeMax ) ) THEN
2446
NumW = CEILING( LOG10( 1.0_dp * PeMax ) )
2447
ELSE
2448
NumW = 4
2449
END IF
2450
NoLim = 10**NumW
2451
2452
IF( PRESENT( PeSeparator ) ) THEN
2453
Prefix = TRIM(Prefix)//TRIM(PeSeparator)
2454
END IF
2455
2456
IF( No >= NoLim ) THEN
2457
FileName = TRIM(Prefix)//I2S(No)//TRIM(Suffix)
2458
ELSE
2459
WRITE( OutStyle,'(A,I1,A,I1,A)') '(A,I',NumW,'.',NumW,',A)'
2460
WRITE( FileName,OutStyle) TRIM(Prefix),No,TRIM(Suffix)
2461
END IF
2462
ELSE
2463
FileName = TRIM(Prefix)//TRIM(Suffix)
2464
END IF
2465
2466
!------------------------------------------------------------------------------
2467
END FUNCTION AddFilenameParSuffix
2468
!------------------------------------------------------------------------------
2469
2470
2471
! This takes union of two integer vectors
2472
! and returns the number of common values.
2473
!---------------------------------------------
2474
FUNCTION CountSameIntegers(v1,v2,vsame) RESULT ( n )
2475
INTEGER, POINTER :: v1(:), v2(:)
2476
INTEGER, POINTER, OPTIONAL :: vsame(:)
2477
INTEGER :: n
2478
2479
INTEGER :: i1,i2
2480
2481
n = 0
2482
IF(.NOT. ASSOCIATED(v1)) RETURN
2483
IF(.NOT. ASSOCIATED(v2)) RETURN
2484
2485
DO i1=1,SIZE(v1)
2486
DO i2=1,SIZE(v2)
2487
IF( v1(i1) == v2(i2) ) n = n+1
2488
END DO
2489
END DO
2490
2491
IF(n==0) RETURN
2492
2493
IF( PRESENT(vsame) ) THEN
2494
IF(.NOT. ASSOCIATED(vsame) ) THEN
2495
ALLOCATE(vsame(n) )
2496
END IF
2497
vsame = 0
2498
n = 0
2499
2500
DO i1=1,SIZE(v1)
2501
DO i2=1,SIZE(v2)
2502
IF( v1(i1) == v2(i2) ) THEN
2503
n = n+1
2504
vsame(n) = v1(i1)
2505
END IF
2506
END DO
2507
END DO
2508
END IF
2509
2510
END FUNCTION CountSameIntegers
2511
2512
2513
2514
!---------------------------------------------------------<
2515
!> Returns values from a normal distribution to be used in
2516
!> thermal velocity distribution, for example.
2517
!---------------------------------------------------------
2518
FUNCTION NormalRandom() RESULT ( normalrand )
2519
2520
REAL(KIND=dp) :: normalrand,mean
2521
INTEGER :: flag = 0
2522
REAL(KIND=dp) :: fac,gsave,rsq,r1,r2
2523
2524
SAVE flag,gsave
2525
2526
IF (flag == 0) THEN
2527
rsq=2.0_dp
2528
2529
DO WHILE(rsq >= 1.0_dp .OR. rsq == 0.0_dp )
2530
CALL RANDOM_NUMBER(r1)
2531
CALL RANDOM_NUMBER(r2)
2532
r1 = 2.0_dp * r1 - 1.0_dp
2533
r2 = 2.0_dp * r2 - 1.0_dp
2534
rsq = r1*r1 + r2*r2
2535
ENDDO
2536
2537
fac = SQRT(-2.0_dp * LOG(rsq) / rsq)
2538
gsave = r1 * fac
2539
normalrand = r2 * fac
2540
flag = 1
2541
ELSE
2542
normalrand = gsave
2543
flag = 0
2544
ENDIF
2545
2546
END FUNCTION NormalRandom
2547
2548
2549
!---------------------------------------------------------
2550
!> Returns values from a even distribution [0,1]
2551
!---------------------------------------------------------
2552
FUNCTION EvenRandom() RESULT ( rand )
2553
REAL(KIND=dp) :: rand
2554
CALL RANDOM_NUMBER(rand)
2555
END FUNCTION EvenRandom
2556
2557
2558
!-----------------------------------------------------
2559
! Convert to effective BH-curve for harmonic analysis
2560
!-----------------------------------------------------
2561
SUBROUTINE ConvertTableToHarmonic(n,bVal,hVal)
2562
INTEGER :: n
2563
REAL(KIND=dp) :: bval(:), hval(:)
2564
2565
INTEGER :: i,j,n_int = 200
2566
REAL(KIND=dp) :: alpha,b,h,nu_eff, hOrig(n)
2567
2568
hOrig = hVal(1:n)
2569
DO i=1,n
2570
nu_eff = 0._dp
2571
DO j=1,n_int
2572
alpha = PI/2._dp*j/(1._dp*N_int)
2573
b = sin(alpha)*bVal(i)
2574
h = linterpolate(n,b,bVal,hOrig)
2575
IF(b>0.0_dp) nu_eff = nu_eff + h/b
2576
END DO
2577
hVal(i) = nu_eff * bVal(i) / N_int
2578
END DO
2579
2580
CONTAINS
2581
2582
! Evaluates y=f(x) for a piecewise linear function f defined by x_points and y_points
2583
FUNCTION linterpolate(n, x, xp, yp) RESULT(y)
2584
INTEGER :: n
2585
REAL(KIND=dp) :: x, y, xp(:), yp(:)
2586
2587
INTEGER :: i
2588
REAL(KIND=dp) :: x0,x1,y0,y1,t
2589
2590
y = 0._dp
2591
DO i=2,n
2592
x0=xp(i-1); x1=xp(i)
2593
IF((x >= x0) .AND. (x <= x1)) THEN
2594
y0=yp(i-1); y1=yp(i)
2595
t=(x-x0)/(x1-x0);
2596
y=(1-t)*y0 + t*y1;
2597
EXIT
2598
END IF
2599
END DO
2600
END FUNCTION linterpolate
2601
END SUBROUTINE ConvertTableToHarmonic
2602
2603
2604
SUBROUTINE ForceLoad
2605
CALL MPI_SEND()
2606
END SUBROUTINE ForceLoad
2607
2608
END MODULE GeneralUtils
2609
2610
2611
!---------------------------------------------------------
2612
!> Module mainly for writing xml based vtk files.
2613
!> The idea is that same routines save both the ascii
2614
!> and binary format.
2615
!---------------------------------------------------------
2616
MODULE AscBinOutputUtils
2617
2618
2619
USE Types
2620
IMPLICIT NONE
2621
2622
LOGICAL, PRIVATE :: AsciiOutput, SinglePrec, CalcSum = .FALSE.
2623
INTEGER, PRIVATE :: VtuUnit = 0, BufferSize = 0
2624
REAL, POINTER, PRIVATE :: FVals(:)
2625
REAL(KIND=dp), POINTER, PRIVATE :: DVals(:)
2626
INTEGER, POINTER, PRIVATE :: IVals(:)
2627
INTEGER, PRIVATE :: INoVals, NoVals
2628
REAL(KIND=dp) :: RSum = 0.0_dp, Isum = 0.0_dp
2629
INTEGER :: Rcount = 0, Icount = 0, Scount = 0, Ssum = 0
2630
2631
SAVE :: AsciiOutput, SinglePrec, VtuUnit, BufferSize, &
2632
FVals, DVals, IVals, CalcSum, Rsum, Isum, Ssum, RCount, Icount, Scount
2633
2634
2635
2636
CONTAINS
2637
2638
2639
! Initialize the buffer for writing, choose mode etc.
2640
!-----------------------------------------------------------------
2641
SUBROUTINE AscBinWriteInit( IsAscii, IsSingle, UnitNo, BufSize )
2642
2643
LOGICAL :: IsAscii, IsSingle
2644
INTEGER :: UnitNo, BufSize
2645
2646
AsciiOutput = IsAscii
2647
SinglePrec = IsSingle
2648
VtuUnit = UnitNo
2649
BufferSize = BufSize
2650
2651
CALL Info('AscBinWriteInit','Initializing buffered ascii/binary writing',Level=8)
2652
IF( AsciiOutput ) THEN
2653
CALL Info('AscBinWriteInit','Writing in ascii',Level=10)
2654
ELSE
2655
CALL Info('AscBinWriteInit','Writing in binary',Level=10)
2656
END IF
2657
2658
IF( SinglePrec ) THEN
2659
CALL Info('AscBinWriteInit','Writing in single precision',Level=10)
2660
ELSE
2661
CALL Info('AscBinWriteInit','Writing in double precision',Level=10)
2662
END IF
2663
2664
WRITE(Message,'(A,I0)') 'Writing to unit number: ',VtuUnit
2665
CALL Info('AscBinWriteInit',Message,Level=10)
2666
2667
IF(.NOT. AsciiOutput ) THEN
2668
WRITE(Message,'(A,I0)') 'Size of buffer is: ',BufferSize
2669
CALL Info('AscBinWriteInit',Message,Level=10)
2670
2671
ALLOCATE( Ivals( BufferSize ) )
2672
IF( SinglePrec ) THEN
2673
ALLOCATE( FVals( BufferSize ) )
2674
ELSE
2675
ALLOCATE( Dvals( BufferSize ) )
2676
END IF
2677
2678
INoVals = 0
2679
NoVals = 0
2680
END IF
2681
2682
END SUBROUTINE AscBinWriteInit
2683
2684
2685
! Free the buffer, next buffer can be different in size and type
2686
!---------------------------------------------------------------
2687
SUBROUTINE AscBinWriteFree()
2688
2689
CALL Info('AscBinWriteFree','Terminating buffered ascii/binary writing',Level=10)
2690
2691
IF( AsciiOutput ) RETURN
2692
2693
IF( SinglePrec ) THEN
2694
DEALLOCATE( FVals )
2695
ELSE
2696
DEALLOCATE( DVals )
2697
END IF
2698
DEALLOCATE( IVals )
2699
2700
BufferSize = 0
2701
VtuUnit = 0
2702
2703
END SUBROUTINE AscBinWriteFree
2704
2705
2706
2707
! The writing of xml strings is done here to allow easier modification
2708
! of output strategies.
2709
!-------------------------------------------------------------------------
2710
SUBROUTINE AscBinStrWrite( Str )
2711
2712
CHARACTER(LEN=1024) :: Str
2713
INTEGER, PARAMETER :: VtuUnit = 58
2714
2715
WRITE( VtuUnit ) TRIM(Str)
2716
IF( CalcSum ) THEN
2717
Scount = Scount + 1
2718
Ssum = Ssum + len_trim( Str )
2719
END IF
2720
2721
2722
END SUBROUTINE AscBinStrWrite
2723
2724
2725
! Write a binary value, either in single or double precision
2726
!------------------------------------------------------------------------
2727
SUBROUTINE AscBinRealWrite( val, EmptyBuffer )
2728
2729
INTEGER, PARAMETER :: VtuUnit = 58
2730
REAL(KIND=dp) :: val
2731
LOGICAL, OPTIONAL :: EmptyBuffer
2732
LOGICAL :: Empty
2733
CHARACTER(LEN=1024) :: Str
2734
2735
IF( VtuUnit == 0 ) THEN
2736
CALL Fatal('AscBinRealWrite','Buffer not initialized for writing')
2737
END IF
2738
2739
IF( PRESENT( EmptyBuffer ) ) THEN
2740
Empty = EmptyBuffer
2741
ELSE
2742
Empty = .FALSE.
2743
END IF
2744
2745
! Ascii output is not buffered
2746
IF( AsciiOutput ) THEN
2747
IF( Empty ) RETURN
2748
IF( ABS( val ) <= TINY ( val ) ) THEN
2749
WRITE(Str,'(A)') " 0.0"
2750
ELSE IF( SinglePrec ) THEN
2751
WRITE( Str,'(ES12.3E3)') val
2752
ELSE
2753
WRITE( Str,'(ES16.7E3)') val
2754
END IF
2755
WRITE( VtuUnit ) TRIM(Str)
2756
IF( CalcSum ) THEN
2757
Rcount = Rcount + 1
2758
Rsum = Rsum + val
2759
END IF
2760
RETURN
2761
END IF
2762
2763
! Buffered binary output
2764
IF( Empty .OR. NoVals == BufferSize ) THEN
2765
IF( NoVals == 0 ) THEN
2766
RETURN
2767
ELSE IF( SinglePrec ) THEN
2768
WRITE( VtuUnit ) Fvals(1:NoVals)
2769
ELSE
2770
WRITE( VtuUnit ) DVals(1:NoVals)
2771
END IF
2772
2773
IF( CalcSum ) THEN
2774
Rcount = Rcount + NoVals
2775
IF( SinglePrec ) THEN
2776
Rsum = 1.0_dp * SUM( Fvals(1:NoVals) )
2777
ELSE
2778
Rsum = SUM( DVals(1:NoVals) )
2779
END IF
2780
END IF
2781
2782
NoVals = 0
2783
IF( Empty ) RETURN
2784
END IF
2785
2786
! Save values in the buffer (either single or double prec.)
2787
NoVals = NoVals + 1
2788
IF( SinglePrec ) THEN
2789
Fvals(NoVals) = val
2790
ELSE
2791
DVals(NoVals) = val
2792
END IF
2793
2794
2795
END SUBROUTINE AscBinRealWrite
2796
2797
2798
! Write an integer value
2799
!-------------------------------------------------
2800
SUBROUTINE AscBinIntegerWrite( ival, EmptyBuffer )
2801
2802
INTEGER, PARAMETER :: VtuUnit = 58
2803
INTEGER :: ival
2804
LOGICAL, OPTIONAL :: EmptyBuffer
2805
LOGICAL :: Empty
2806
CHARACTER(LEN=1024) :: Str
2807
2808
IF( VtuUnit == 0 ) THEN
2809
CALL Fatal('AscBinIntegerWrite','Buffer not initialized for writing')
2810
END IF
2811
2812
IF( PRESENT( EmptyBuffer ) ) THEN
2813
Empty = EmptyBuffer
2814
ELSE
2815
Empty = .FALSE.
2816
END IF
2817
2818
IF( AsciiOutput ) THEN
2819
IF( Empty ) RETURN
2820
WRITE( Str, '(" ",I0)') ival
2821
WRITE( VtuUnit ) TRIM(Str)
2822
IF( CalcSum ) Isum = Isum + ival
2823
RETURN
2824
END IF
2825
2826
IF( Empty .OR. INoVals == BufferSize ) THEN
2827
IF( INoVals == 0 ) THEN
2828
RETURN
2829
ELSE
2830
WRITE( VtuUnit ) Ivals(1:INoVals)
2831
IF( CalcSum ) THEN
2832
Icount = Icount + 1
2833
Isum = Isum + SUM( Ivals(1:INoVals) )
2834
END IF
2835
END IF
2836
INoVals = 0
2837
IF( Empty ) RETURN
2838
END IF
2839
2840
INoVals = INoVals + 1
2841
Ivals(INoVals) = ival
2842
2843
END SUBROUTINE AscBinIntegerWrite
2844
2845
2846
SUBROUTINE AscBinInitNorm(CalcNorm)
2847
LOGICAL :: CalcNorm
2848
2849
CalcSum = CalcNorm
2850
RSum = 0.0_dp
2851
ISum = 0.0_dp
2852
Ssum = 0
2853
Rcount = 0
2854
Icount = 0
2855
Scount = 0
2856
2857
END SUBROUTINE AscBinInitNorm
2858
2859
2860
FUNCTION AscBinCompareNorm(RefResults,ExtResults) RESULT ( RelativeNorm )
2861
REAL(KIND=dp), DIMENSION(*) :: RefResults
2862
REAL(KIND=dp), DIMENSION(*), OPTIONAL :: ExtResults
2863
REAL(KIND=dp) :: RelativeNorm
2864
REAL(KIND=dp), POINTER :: ThisResults(:)
2865
REAL(KIND=dp) :: c
2866
INTEGER :: i, n
2867
2868
n = 6 !SIZE(RefResults)
2869
ALLOCATE(ThisResults(n))
2870
2871
IF( PRESENT( ExtResults ) ) THEN
2872
ThisResults(1:n) = ExtResults(1:n)
2873
ELSE
2874
ThisResults(1) = scount
2875
ThisResults(2) = icount
2876
ThisResults(3) = rcount
2877
ThisResults(4) = ssum
2878
ThisResults(5) = isum ! we use real for isum since it could be huge too!
2879
ThisResults(6) = rsum
2880
END IF
2881
2882
PRINT *,'Checksums for file output:'
2883
PRINT *,'RefResults:',RefResults(1:n)
2884
PRINT *,'ThisResults:',ThisResults(1:n)
2885
2886
! We have a special relative pseunonorm that should be one!
2887
RelativeNorm = 0.0
2888
DO i=1,n
2889
IF( ABS(RefResults(i) ) > EPSILON(c) ) THEN
2890
c = ThisResults(i)/RefResults(i)
2891
IF( ABS(ThisResults(i) ) > EPSILON(c) ) THEN
2892
c = MAX( c, 1.0_dp /c )
2893
END IF
2894
ELSE
2895
c = 1.0_dp + ABS(ThisResults(i))
2896
END IF
2897
RelativeNorm = RelativeNorm + c
2898
END DO
2899
RelativeNorm = RelativeNorm / n
2900
2901
END FUNCTION AscBinCompareNorm
2902
2903
2904
END MODULE AscBinOutputUtils
2905
2906
2907
!> \}
2908
2909
2910