scalefree 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3323 @@
1
+ PROGRAM FLATPOWER
2
+ C
3
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
4
+ C
5
+ C Scale-free dynamical modeling software as discussed in the file README.
6
+ C
7
+ C All routines are written in double precision. Note that this requires
8
+ C the statement IMPLICIT REAL*8 (a-h,o-z) at the beginning of each
9
+ C program part. Don't mix single and real precision ! This generally leads
10
+ C to disaster.
11
+ C
12
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
13
+ C
14
+ IMPLICIT REAL*8 (a-h,o-z)
15
+ C
16
+ CCCCCCCCCCCCCCCCCCCC
17
+ C
18
+ PARAMETER (pi=3.14159265358979D0)
19
+ C
20
+ CCCCCCCCCCCCCCCCCCCC
21
+ C
22
+ DIMENSION xmom(0:100),darr(0:100),harr(0:100),
23
+ & velar(101),vpval(101)
24
+ CHARACTER*256 outpath
25
+ INTEGER iout
26
+ C
27
+ CCCCCCCCCCCCCCCCCCCC
28
+ C
29
+ COMMON /potent/ ipot
30
+ C
31
+ C ipot=1 for Kepler potential and ipot=2 for logarithmic potential
32
+ C
33
+ COMMON /DFcase/ icase
34
+ C
35
+ C icase=1 for the case I DFs, icase=2 for the case II DFs.
36
+ C
37
+ COMMON /param/ gamma, beta, q, alpha, eta
38
+ C
39
+ C Model parameters
40
+ C
41
+ COMMON /viewing/ xinc
42
+ C
43
+ C The inclination angle in radians
44
+ C
45
+ COMMON /howint/ iint
46
+ C
47
+ C Determines how the line of sight integration is done
48
+ C
49
+ COMMON /romoeps/ eps
50
+ C
51
+ C fractional accuracy for Romberg integration
52
+ C
53
+ COMMON /gleg/ qx(300),qw(300),nGL
54
+ C
55
+ C Common block with Gauss-Legendre coefficients for integration along the
56
+ C line of sight.
57
+ C
58
+ COMMON /reg/ xlam
59
+ C
60
+ C Common block with the regularization parameter used in calculating VPs
61
+ C
62
+ COMMON /smoo/ epsmoo
63
+ C
64
+ C Parameter that determines the requested smoothness, as fraction of
65
+ C the VP maximum.
66
+ C
67
+ COMMON /verbose/ iverb
68
+ C
69
+ COMMON /projcase/ iproj
70
+ C
71
+ C iproj=1 (LOS), 2 (POSR), 3 (POST)
72
+ C
73
+ C
74
+ C Determines whether verbose output should be generated for VP calculations
75
+ C
76
+ CCCCCCCCCCCCCCCCCCCC
77
+ C
78
+ C Get the model parameters
79
+ C
80
+ CCCCCCCCCCCCCCCCCCCC
81
+ C
82
+ WRITE (*,*) 'Please answer the following questions about'
83
+ WRITE (*,*) 'the parameters of the model:'
84
+ WRITE (*,*) ' '
85
+ C
86
+ WRITE (*,*) 'Kepler (1) or Logarithmic (2) Potential ?'
87
+ READ (*,*) ipot
88
+ WRITE (*,*) ' '
89
+ C
90
+ WRITE (*,*) 'Power-law slope gamma of the mass density'
91
+ READ (*,*) gamma
92
+ WRITE (*,*) ' '
93
+ C
94
+ WRITE (*,*) 'Intrinsic axial ratio q of the mass density'
95
+ READ (*,*) q
96
+ WRITE (*,*) ' '
97
+ C
98
+ WRITE (*,*) 'Case I (1) or Case II (2) DF ?'
99
+ READ (*,*) icase
100
+ WRITE (*,*) ' '
101
+ C
102
+ WRITE (*,*) 'Anisotropy parameter beta of the DF'
103
+ READ (*,*) beta
104
+ WRITE (*,*) ' '
105
+ C
106
+ C The parameters s and t of the odd part of the DF are called
107
+ C eta and alpha in the coding convention of this program.
108
+ C
109
+ WRITE (*,*) 'Odd part parameters s and t for the DF'
110
+ READ (*,*) eta, alpha
111
+ WRITE (*,*) ' '
112
+ C
113
+ WRITE (*,*) 'Viewing inclination i in degrees (90=edge-on)'
114
+ READ (*,*) xinc
115
+ WRITE (*,*) ' '
116
+ C
117
+ C Transform the inclination to radians
118
+ C
119
+ xinc = (xinc/180.0D0)*pi
120
+ C
121
+ CCCCCCCCCCCCCCCCCCCC
122
+ C
123
+ C Get information on numerical details
124
+ C
125
+ CCCCCCCCCCCCCCCCCCCC
126
+ C
127
+ WRITE (*,*) 'Please answer the following questions about'
128
+ WRITE (*,*) 'the numerical details of the calculations:'
129
+ WRITE (*,*) ' '
130
+ C
131
+ WRITE (*,*) 'Use Romberg (0) or Gauss-Legendre (1) integration'
132
+ WRITE (*,*) 'for line-of-sight projection and integration over'
133
+ WRITE (*,*) 'the meridional or sky plane? (default=1)'
134
+ READ (*,*) iint
135
+ WRITE (*,*) ' '
136
+ C
137
+ IF (iint.EQ.0) THEN
138
+ WRITE (*,*) 'Give the fractional accuracy epsilon (0.0=default)'
139
+ READ (*,*) eps
140
+ WRITE (*,*) ' '
141
+ IF (eps.EQ.0.0D0) eps = 1.0D-7
142
+ ELSE
143
+ WRITE (*,*) 'Give number of quadrature points (0=default)'
144
+ READ (*,*) nGL
145
+ WRITE (*,*) ' '
146
+ IF (nGL.EQ.0) nGL = 100
147
+ CALL GAULEG (0.0D0,1.0D0,qx,qw,nGL)
148
+ END IF
149
+ C
150
+ WRITE (*,*) 'Algorithm to calculate VPs and Gauss-Hermite moments'
151
+ WRITE (*,*) ' 1: Solve VanderMonde matrix directly without'
152
+ WRITE (*,*) ' regularization. Resulting VP will be nonsense'
153
+ WRITE (*,*) ' but the GH moments are generally well'
154
+ WRITE (*,*) ' determined.'
155
+ WRITE (*,*) ' 2: Use regularization with a fixed regularization'
156
+ WRITE (*,*) ' parameter.'
157
+ WRITE (*,*) ' 3: Use regularization. Increase regularization'
158
+ WRITE (*,*) ' parameter until the VP has no more than 3'
159
+ WRITE (*,*) ' significant local maxima. A local maximum is'
160
+ WRITE (*,*) ' significant if it exceeds the value of its'
161
+ WRITE (*,*) ' neighbors on the grid by eps times the'
162
+ WRITE (*,*) ' absolute VP maximum.'
163
+ WRITE (*,*) 'Choose 1 for default.'
164
+ READ (*,*) iVPfit
165
+ WRITE (*,*) ' '
166
+ C
167
+ IF (iVPfit.EQ.1) THEN
168
+ C
169
+ xlam = -1.0
170
+ C
171
+ WRITE (*,*) 'Give the maximum number of projected moments'
172
+ WRITE (*,*) 'to use (should be an even number)'
173
+ WRITE (*,*) '(0 yields default)'
174
+ READ (*,*) maxord
175
+ WRITE (*,*) ' '
176
+ C
177
+ ELSE IF (iVPfit.EQ.2) THEN
178
+ C
179
+ WRITE (*,*) 'Give the regularization parameter (> 0)'
180
+ READ (*,*) xlam
181
+ WRITE (*,*) ' '
182
+ C
183
+ WRITE (*,*) 'Give the number of projected moments'
184
+ WRITE (*,*) 'to use (should be an even number)'
185
+ WRITE (*,*) '(0 yields default)'
186
+ READ (*,*) maxord
187
+ WRITE (*,*) ' '
188
+ C
189
+ ELSE IF (iVPfit.EQ.3) THEN
190
+ C
191
+ xlam = 0.0
192
+ C
193
+ WRITE (*,*) 'Give smoothness factor eps (0.0 yields default)'
194
+ READ (*,*) epsmoo
195
+ WRITE (*,*) ' '
196
+ C
197
+ IF (epsmoo.EQ.0.0) epsmoo = 1.0D-3
198
+
199
+ WRITE (*,*) 'Give the number of projected moments'
200
+ WRITE (*,*) 'to use (should be an even number)'
201
+ WRITE (*,*) '(0 yields default)'
202
+ READ (*,*) maxord
203
+ WRITE (*,*) ' '
204
+ C
205
+ ELSE
206
+ C
207
+ STOP 'Wrong answer'
208
+ C
209
+ END IF
210
+ C
211
+ IF (maxord.EQ.0) maxord = 30
212
+ C
213
+ CCCCCCCCCCCCCCCCCCCC
214
+ C
215
+ C Fill the arrays with the coefficients of the power series that yield
216
+ C the intrinsic velocity moments.
217
+ C
218
+ CCCCCCCCCCCCCCCCCCCC
219
+ C
220
+ WRITE (*,*) 'Calculating all series coefficients up to'
221
+ WRITE (*,*) 'the selected (maximum) order ........'
222
+ CALL FILLARRAYS(maxord)
223
+ WRITE (*,*) ' '
224
+ C
225
+ CCCCCCCCCCCCCCCCCCCC
226
+ C
227
+ C Now calculate anything that the user may be interested in
228
+ C
229
+ CCCCCCCCCCCCCCCCCCCC
230
+ C
231
+ C
232
+ CCCCCCCCCCCCCCCCCCCC
233
+ C
234
+ C Select where to write numerical results (table output)
235
+ C
236
+ iproj = 1
237
+ WRITE (*,*) 'Output file for results (blank = STDOUT)'
238
+ READ (*,'(A)') outpath
239
+ lout = LENSTR(outpath)
240
+ IF (lout.GT.0) THEN
241
+ iout = 20
242
+ OPEN(unit=iout,file=outpath(1:lout),status='unknown')
243
+ ELSE
244
+ iout = 6
245
+ END IF
246
+ WRITE (*,*) ' '
247
+ C
248
+ 51 WRITE (*,*) 'Calculate intrinsic (0) or projected (1)'
249
+ WRITE (*,*) 'kinematical quantities ?'
250
+ WRITE (*,*) 'This gives results for a fixed angle in the'
251
+ WRITE (*,*) 'meridional or projected plane.'
252
+ WRITE (*,*) 'Instead, add 2 to get results mass-weighted'
253
+ WRITE (*,*) 'over angles between 0 and pi/2'
254
+ READ (*,*) iwhat
255
+ WRITE (*,*) ' '
256
+ C
257
+ WRITE (*,*) 'Note: all results are at an'
258
+ WRITE (*,*) '(intrinsic or projected) radius of 1 in'
259
+ WRITE (*,*) 'dimensionless units. Results can be scaled to other'
260
+ WRITE (*,*) 'radii using the scale-free nature of the models.'
261
+ WRITE (*,*) ' '
262
+ C
263
+ IF (iwhat.EQ.0) THEN
264
+ C
265
+ WRITE (*,*) 'Give angle theta in the meridional plane'
266
+ WRITE (*,*) '(in degrees) (0 = symmetry axis)'
267
+ READ (*,*) theta
268
+ WRITE (*,*) ' '
269
+ C
270
+ C Transform to radians
271
+ C
272
+ theta = (theta/180.0D0)*pi
273
+ rho = RHOVELMOM(theta,0,0,0)
274
+ C
275
+ WRITE (*,*) 'Intrinsic velocity moments:'
276
+ WRITE (*,'(5A12)') 'rho','<v_ph>','<v_r^2>','<v_th^2>',
277
+ & '<v_ph^2>'
278
+ WRITE (*,'(6F12.8)') rho,RHOVELMOM(theta,0,0,1)/rho,
279
+ & RHOVELMOM(theta,2,0,0)/rho,
280
+ & RHOVELMOM(theta,0,2,0)/rho,
281
+ & RHOVELMOM(theta,0,0,2)/rho
282
+ WRITE (*,*) ' '
283
+ C
284
+ ELSE IF (iwhat.EQ.2) THEN
285
+ C
286
+ rho = RHOVELMOMTHAV(0,0,0)
287
+ rhop1 = RHOVELMOMTHAV(0,0,1)
288
+ rhor2 = RHOVELMOMTHAV(2,0,0)
289
+ rhot2 = RHOVELMOMTHAV(0,2,0)
290
+ rhop2 = RHOVELMOMTHAV(0,0,2)
291
+ betav = 1.0D0 - ((rhot2+rhop2)/(2.0D0*rhor2))
292
+ C
293
+ WRITE (*,*) 'Intrinsic velocity moments:'
294
+ WRITE (*,*) 'Mass-weighted average spherical shell:'
295
+ WRITE (*,'(6A12)') 'rho','<v_ph>','<v_r^2>','<v_th^2>',
296
+ & '<v_ph^2>','beta'
297
+ WRITE (*,'(6F12.8)') rho, rhop1/rho,
298
+ & rhor2/rho, rhot2/rho, rhop2/rho, betav
299
+ WRITE (*,*) ' '
300
+ C
301
+ ELSE IF (iwhat.EQ.1) THEN
302
+ C
303
+ WRITE (*,*) 'Give angle on the projected plane'
304
+ WRITE (*,*) '(in degrees) (0 = major axis)'
305
+ READ (*,*) xi
306
+ WRITE (*,*) ' '
307
+ C
308
+ C Transform to radians
309
+ C
310
+ xi = (xi/180.0D0)*pi
311
+ C
312
+ rhop = RHOPROJ(xi)
313
+ WRITE (iout,'(A)') '# kind=projected_point'
314
+ WRITE (iout,'(A,F16.8)') '# xi_deg ', (xi*180.0D0/pi)
315
+ WRITE (iout,'(A)') '# columns: iproj rho_p v1 v2 v3 v4'
316
+ DO iproj=1,3
317
+ v1 = PROJMOM(xi,1)
318
+ v2 = PROJMOM(xi,2)
319
+ v3 = PROJMOM(xi,3)
320
+ v4 = PROJMOM(xi,4)
321
+ WRITE (iout,'(I3,1X,5E24.16)') iproj, rhop, v1, v2, v3, v4
322
+ END DO
323
+ WRITE (iout,*) ' '
324
+ C
325
+ ELSE IF (iwhat.EQ.3) THEN
326
+ C
327
+ rhop0 = RHOPROJMOMAV(0)
328
+ rhop1 = RHOPROJMOMAV(1)
329
+ rhop2 = RHOPROJMOMAV(2)
330
+ rhop3 = RHOPROJMOMAV(3)
331
+ rhop4 = RHOPROJMOMAV(4)
332
+ C
333
+ WRITE (iout,'(A)') '# kind=projected_circle_average'
334
+ WRITE (iout,'(A)') '# columns: iproj rho_p v1 v2 v3 v4'
335
+ DO iproj=1,3
336
+ rhop0 = RHOPROJMOMAV(0)
337
+ rhop1 = RHOPROJMOMAV(1)
338
+ rhop2 = RHOPROJMOMAV(2)
339
+ rhop3 = RHOPROJMOMAV(3)
340
+ rhop4 = RHOPROJMOMAV(4)
341
+ WRITE (iout,'(I3,1X,5E24.16)') iproj, rhop0, rhop1/rhop0,
342
+ & rhop2/rhop0, rhop3/rhop0, rhop4/rhop0
343
+ END DO
344
+ WRITE (iout,*) ' '
345
+ C
346
+ ELSE
347
+ C
348
+ STOP 'Wrong answer'
349
+ C
350
+ END IF
351
+ C
352
+ CCCCCCCCCCCCCCCCCCCC
353
+ C
354
+ C If iwhat=1 or 3, then calculate and write also VP information
355
+ C
356
+ CCCCCCCCCCCCCCCCCCCC
357
+ C
358
+ IF ((iwhat.EQ.1).OR.(iwhat.EQ.3)) THEN
359
+ C
360
+ C Set the number of GH moments to calculate
361
+ C
362
+ nord = 6
363
+ C
364
+ C Verbose ?
365
+ C
366
+ WRITE (*,*) 'Give verbose output of intermediate steps'
367
+ WRITE (*,*) 'for VP calculation ? (0/1)'
368
+ READ (*,*) iverb
369
+ WRITE (*,*) ' '
370
+ C
371
+ C Calculate the VP and VP coefficients for all projected components
372
+ C
373
+ WRITE (iout,'(A)') '# kind=vp'
374
+ WRITE (iout,'(A)') '# columns: iproj true_gam true_V true_sig'
375
+ WRITE (iout,'(A)') '# gauss_gam gauss_V gauss_sig'
376
+ WRITE (iout,'(A)') '# h0 h1 h2 h3 h4 h5 h6'
377
+
378
+ DO iproj=1,3
379
+ IF (xlam.LT.0.0) THEN
380
+ CALL VPANALYSE_CONV (iwhat,xi,nord,xmom,gam0,V0,sig0,darr,
381
+ & velar,vpval,nvel,gam,Vgau,sig,harr)
382
+ ELSE
383
+ CALL VPANALYSE_FIX (iwhat,xi,maxord,xmom,gam0,V0,sig0,darr,
384
+ & velar,vpval,nvel,gam,Vgau,sig,harr)
385
+ END IF
386
+ C
387
+ WRITE (iout,'(I3,1X,6E24.16,1X,7F10.5)') iproj, gam0, V0, sig0,
388
+ & gam, Vgau, sig, harr(0), harr(1), harr(2), harr(3),
389
+ & harr(4), harr(5), harr(6)
390
+ C
391
+ C Write the VP solution as a table block (v, VP)
392
+ C
393
+ WRITE (iout,'(A,I3)') '# vp_table iproj ', iproj
394
+ WRITE (iout,'(A)') '# columns: v vp'
395
+ DO j=1,nvel
396
+ WRITE (iout,'(2E24.16)') velar(j), vpval(j)
397
+ END DO
398
+ WRITE (iout,*) ' '
399
+ END DO
400
+ C
401
+ END IF
402
+ C
403
+ CCCCCCCCCCCCCCCCCCCC
404
+ C
405
+ C Continue ?
406
+ C
407
+ CCCCCCCCCCCCCCCCCCCC
408
+ C
409
+ WRITE (*,*) 'Calculate something else for this model ? (0/1)'
410
+ READ (*,*) imore
411
+ WRITE (*,*) ' '
412
+ C
413
+ IF (imore.EQ.1) GOTO 51
414
+ C
415
+ CCCCCCCCCCCCCCCCCCCC
416
+ C
417
+ C End of program
418
+ C
419
+ CCCCCCCCCCCCCCCCCCCC
420
+ C
421
+ END
422
+
423
+
424
+ SUBROUTINE FILLARRAYS (maxxord)
425
+ C
426
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
427
+ C
428
+ C Fill the arrays with the coefficients of the power series that yield
429
+ C the intrinsic velocity moments. It is assumed that moments up to order
430
+ C maxxord are required. After this subroutine has been called,
431
+ C the subroutines COFARR and KMAXARR can be used to recover the coefficients,
432
+ C without having to calculate them again.
433
+ C
434
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
435
+ C
436
+ IMPLICIT REAL*8 (a-h,o-z)
437
+ C
438
+ PARAMETER (maxlength = 2000000 ,
439
+ & mord = 200 ,
440
+ & mev = mord/2 )
441
+ C
442
+ COMMON /all/ allcofs(1:maxlength),
443
+ & icstart(0:mev,0:mev,0:mord),
444
+ & kmaxall(0:mev,0:mev,0:mord), maxord
445
+ C
446
+ DIMENSION cofs(0:1000)
447
+ C
448
+ CCCCCCCCCCCCCCCCCCCC
449
+ C
450
+ maxord = maxxord
451
+ C
452
+ IF (2*(maxord/2).NE.maxord) STOP 'maxord should be even'
453
+ IF (maxord.GT.mord) STOP 'maxord is too large for array'
454
+ C
455
+ C Fill the array which holds all the coefficients of the power series
456
+ C in e^2 SIN^2(theta), required to calculate the intrinsic velocity
457
+ C moments up to order maxord.
458
+ C
459
+ C WRITE (*,*)
460
+ C & 'Calculating series coefficients for the velocity moments ...'
461
+ C
462
+ ic = 1
463
+ DO ir=0,maxord,2
464
+ DO ith=0,maxord,2
465
+ DO iph=0,maxord
466
+ icstart(ir/2,ith/2,iph) = ic
467
+ CALL CALCCOEFFLN(cofs,kmax,ir,ith,iph)
468
+ kmaxall(ir/2,ith/2,iph) = kmax
469
+ DO k=0,kmax
470
+ allcofs(ic) = cofs(k)
471
+ ic = ic+1
472
+ END DO
473
+ IF (ic.GE.maxlength) STOP 'ic too large for array'
474
+ END DO
475
+ END DO
476
+ C WRITE (*,'(2I5,I10)') ir,maxord,ic-1
477
+ END DO
478
+ C WRITE (*,*) ' '
479
+ C
480
+ END
481
+
482
+
483
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
484
+ C
485
+ C The function SPHPROJMOM calculatates the results for spherical non-rotating
486
+ C models using the results of van der Marel & Franx, for the purpose of testing
487
+ C only.
488
+ C
489
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
490
+
491
+ REAL*8 FUNCTION SPHPROJMOM(nord)
492
+ C
493
+ C Calculate the projected moment of order nord at projected radius 1
494
+ C (in dimensionless units), using equation (B6a) or (B8a) of van der Marel
495
+ C & Franx (modified to correspond to the units used here).
496
+ C Useful for the purpose of testing.
497
+ C
498
+ IMPLICIT REAL*8 (a-h,o-z)
499
+ C
500
+ COMMON /potent/ ipot
501
+ C
502
+ C ipot=1 for Kepler potential and ipot=2 for logarithmic potential
503
+ C
504
+ COMMON /param/ gamma, beta, q, alpha, eta
505
+ C
506
+ IF (2*(nord/2).NE.nord) STOP 'No vdM & F result for odd order'
507
+ C
508
+ no2 = nord/2
509
+ dnord = DBLE(nord)
510
+ dno2 = DBLE(no2)
511
+ C
512
+ sum = 0.0D0
513
+ DO k=0,no2
514
+ dk = DBLE(k)
515
+ facln = binomln(nord,2*k) +
516
+ & betaln(dno2-dk+0.5D0,0.5D0) - betaln(0.5D0,0.5D0) +
517
+ & betaln(dk+0.5D0,dno2-dk+1.0D0-beta) -
518
+ & betaln(0.5D0,1.0D0-beta) +
519
+ & gammaln(dno2+1.5D0-beta) - gammaln(1.5D0-beta)
520
+ IF (ipot.EQ.1) THEN
521
+ facln = facln +
522
+ & betaln(0.5D0*(gamma-1.0D0+dno2+dnord-(2.0D0*dk)),
523
+ & dk+0.5D0) - betaln(0.5D0*(gamma-1.0D0),0.5D0) +
524
+ & gammaln(gamma-(2.0D0*beta)+1.0D0) -
525
+ & gammaln(gamma+dno2-(2.0D0*beta)+1.0D0)
526
+ ELSE IF (ipot.EQ.2) THEN
527
+ facln = facln +
528
+ & betaln(0.5D0*(gamma-1.0D0+dnord-(2.0D0*dk)),
529
+ & dk+0.5D0) - betaln(0.5D0*(gamma-1.0D0),0.5D0) -
530
+ & (dno2*LOG(gamma-(2.0D0*beta)))
531
+ ELSE
532
+ STOP 'ipot wrong value'
533
+ END IF
534
+ sum = sum + EXPP(facln)
535
+ END DO
536
+ C
537
+ SPHPROJMOM = sum
538
+ C
539
+ END
540
+
541
+
542
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
543
+ C
544
+ C The subroutines VPANALYSE_* calculate properties of the VPs on the sky.
545
+ C They call FINDVP, which calculates the VP by solution of a
546
+ C (regularized) VanderMonde matrix, calculates the best fitting Gaussian by
547
+ C means of FITGAUSS and CHI2H, and calculates the Gauss-Hermite coefficients
548
+ C by means of GAUHERM. The routine GRAMCHARCOF calculates the
549
+ C coefficients of the Gram-Charlier series.
550
+ C
551
+ C VPANALYSE_FIX : uses a fixed number of projected moments.
552
+ C Can be used if the regularization is sufficient.
553
+ C VPANALYSE_CONV : Adds more or less projected momemnts until some
554
+ C sort of convergence is achieved. Works reasonable
555
+ C without regularization. The returned VP is nonsense,
556
+ C but the GH coefficients are reasonably OK.
557
+ C
558
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
559
+
560
+
561
+ SUBROUTINE VPANALYSE_FIX (iwhat,xi,nord,xmom,gam0,V0,sig0,darr,
562
+ & velar,vpval,nvel,gam,Vgau,sig,harr)
563
+ C
564
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
565
+ C
566
+ C If iwhat=1, then do calculations at a given an angle xi from the major axis.
567
+ C If iwhat=3, then integrated over all angles in the first sky quadrant.
568
+ C In either case, calculate at projected radius 1
569
+ C (in dimensionless units), given an integer nord:
570
+ C - the first nord projected moments, returned in xmom
571
+ C - the lowest order true moments (gam0,V0,sig0)
572
+ C - the first nord Gram-Charlier coefficients, returned in darr
573
+ C - the velocity profile, approximated at nord discrete velocities velar,
574
+ C returned in vpval
575
+ C - the parameters (gam,Vgau,sig) of the best fitting Gaussian
576
+ C - the first nord Gauss-Hermite moments, returned in harr.
577
+ C
578
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
579
+ C
580
+ IMPLICIT REAL*8 (a-h,o-z)
581
+ C
582
+ PARAMETER (maxlength = 2000000 ,
583
+ & mord = 200 ,
584
+ & mev = mord/2 )
585
+ C
586
+ DIMENSION xmom(0:100),darr(0:100),velar(101),vpval(101),
587
+ & harr(0:100)
588
+ C
589
+ COMMON /all/ allcofs(1:maxlength),
590
+ & icstart(0:mev,0:mev,0:mord),
591
+ & kmaxall(0:mev,0:mev,0:mord), maxord
592
+ C
593
+ COMMON /potent/ ipot
594
+ C
595
+ C ipot=1 for Kepler potential and ipot=2 for logarithmic potential
596
+ C
597
+ COMMON /verbose/ iverb
598
+ C
599
+ C Determines whether verbose output should be generated for VP calculations
600
+ C
601
+ CCCCCCCCC
602
+ C
603
+ C Set nord to the nearest even integer
604
+ C
605
+ nordin = nord
606
+ IF (2*(nord/2).NE.nord) nord=nord-1
607
+ C
608
+ C Calculate the projected velocity moments
609
+ C
610
+ IF (iverb.EQ.1) THEN
611
+ WRITE (*,*) 'Calculating first', nord,
612
+ & ' projected velocity moments ...'
613
+ WRITE (*,*) ' '
614
+ END IF
615
+ C
616
+ rhopr0 = RHOPROJMOMAV(0)
617
+ DO i=0,nord
618
+ IF (iwhat.EQ.1) THEN
619
+ xmom(i) = PROJMOM(xi,i)
620
+ ELSE IF (iwhat.EQ.3) THEN
621
+ xmom(i) = RHOPROJMOMAV(i) / rhopr0
622
+ END IF
623
+ END DO
624
+ C
625
+ C Calculate the normalization, mean and dispersion
626
+ C
627
+ gam0 = xmom(0)
628
+ V0 = xmom(1)
629
+ sig0 = SQRT(xmom(2)-(xmom(1)**2.0D0))
630
+ C
631
+ C Set initial values for the best fitting Gaussian
632
+ C
633
+ gam = gam0 - (gam0*darr(4)*SQRT(24.0D0)/32.0D0)
634
+ Vgau = V0 - (sig0*darr(3)*SQRT(6.0D0)/4.0D0)
635
+ sig = sig0 - (sig0*darr(4)*SQRT(24.0D0)/8.0D0)
636
+ C
637
+ C Calculate the VP, best fitting Gaussian, and Gauss-Hermite coefficients.
638
+ C
639
+ CALL FINDVP (nord,xmom,velar,vpval,nvel,gam,Vgau,sig,harr)
640
+ C
641
+ C Write the resulting VP to the screen
642
+ C
643
+ IF (iverb.EQ.1) THEN
644
+ C WRITE (*,'(A31,I3,A9)')
645
+ C & 'VP reconstructed from the first',nord,'moments:'
646
+ C DO i=1,nvel
647
+ C WRITE (*,'(I5,2F20.8)') i,velar(i),vpval(i)
648
+ C END DO
649
+ C WRITE (*,*) ' '
650
+ END IF
651
+ C
652
+ C Calculate the Gram-Charlier coefficients
653
+ C
654
+ CALL GRAMCHARCOF (xmom,nord,V0,sig0,darr)
655
+ C
656
+ C Reset nord to its input value
657
+ C
658
+ nord = nordin
659
+ C
660
+ END
661
+
662
+
663
+ SUBROUTINE VPANALYSE_CONV (iwhat,xi,nord,xmom,gam0,V0,sig0,darr,
664
+ & velar,vpval,nvel,gam,Vgau,sig,harr)
665
+ C
666
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
667
+ C
668
+ C If iwhat=1, then do calculations at a given an angle xi from the major axis.
669
+ C If iwhat=3, then integrated over all angles in the first sky quadrant.
670
+ C In either case, calculate at projected radius 1
671
+ C (in dimensionless units), given an integer nord:
672
+ C - the first nord or more projected moments, returned in xmom
673
+ C - the lowest order true moments (gam0,V0,sig0)
674
+ C - the first nord or more Gram-Charlier coefficients, returned in darr
675
+ C - the velocity profile, approximated at nvel discrete velocities velar,
676
+ C returned in vpval
677
+ C - the parameters (gam,Vgau,sig) of the best fitting Gaussian
678
+ C - the first nord Gauss-Hermite moments, returned in harr.
679
+ C
680
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
681
+ C
682
+ IMPLICIT REAL*8 (a-h,o-z)
683
+ C
684
+ PARAMETER (maxlength = 2000000 ,
685
+ & mord = 200 ,
686
+ & mev = mord/2 )
687
+ C
688
+ DIMENSION xmom(0:100),darr(0:100),velar(101),vpval(101),
689
+ & harr(0:100),hold(0:100)
690
+ C
691
+ COMMON /all/ allcofs(1:maxlength),
692
+ & icstart(0:mev,0:mev,0:mord),
693
+ & kmaxall(0:mev,0:mev,0:mord), maxord
694
+ C
695
+ COMMON /potent/ ipot
696
+ C
697
+ C ipot=1 for Kepler potential and ipot=2 for logarithmic potential
698
+ C
699
+ COMMON /verbose/ iverb
700
+ C
701
+ C Determines whether verbose output should be generated for VP calculations
702
+ C
703
+ CCCCCCCCC
704
+ C
705
+ C Calculate the lowest order moments
706
+ C
707
+ rhopr0 = RHOPROJMOMAV(0)
708
+ DO i=0,2
709
+ IF (iwhat.EQ.1) THEN
710
+ xmom(i) = PROJMOM(xi,i)
711
+ ELSE IF (iwhat.EQ.3) THEN
712
+ xmom(i) = RHOPROJMOMAV(i) / rhopr0
713
+ END IF
714
+ END DO
715
+ C
716
+ C Calculate the normalization, mean and dispersion
717
+ C
718
+ gam0 = xmom(0)
719
+ V0 = xmom(1)
720
+ sig0 = SQRT(xmom(2)-(xmom(1)**2.0D0))
721
+ C
722
+ C Set initial values for the best fitting Gaussian
723
+ C
724
+ gam = gam0 - (gam0*darr(4)*SQRT(24.0D0)/32.0D0)
725
+ Vgau = V0 - (sig0*darr(3)*SQRT(6.0D0)/4.0D0)
726
+ sig = sig0 - (sig0*darr(4)*SQRT(24.0D0)/8.0D0)
727
+ C
728
+ C Now calculate all moments up to order minord. The choice
729
+ C for minord is based on the criterium that delv (see FINDVP below)
730
+ C should be approximately equal to sig. It is never chosen smaller
731
+ C than either nord or neversmaller.
732
+ C
733
+ IF (ipot.EQ.1) THEN
734
+ vmin = -1.0D0
735
+ vmax = 1.0D0
736
+ ELSE
737
+ vmin = -3.0D0
738
+ vmax = 3.0D0
739
+ END IF
740
+ C
741
+ neversmaller = 10
742
+ minord = INT(1.0D0+((vmax-vmin)/(0.5*sig)))
743
+ ncur = MIN(maxord,MAX(minord,MAX(neversmaller,nord)))
744
+ C
745
+ C Use only even values for ncur
746
+ C
747
+ IF (2*(ncur/2).NE.ncur) ncur=ncur-1
748
+ C
749
+ IF (iverb.EQ.1) THEN
750
+ WRITE (*,*) 'Calculating first', ncur,
751
+ & ' projected velocity moments ...'
752
+ WRITE (*,*) ' '
753
+ END IF
754
+ C
755
+ DO i=3,ncur
756
+ IF (iwhat.EQ.1) THEN
757
+ xmom(i) = PROJMOM(xi,i)
758
+ ELSE IF (iwhat.EQ.3) THEN
759
+ xmom(i) = RHOPROJMOMAV(i) / rhopr0
760
+ END IF
761
+ END DO
762
+ C
763
+ gamold = gam
764
+ Vold = Vgau
765
+ sigold = sig
766
+ DO i=0,nord
767
+ hold(i) = 0.0D0
768
+ END DO
769
+ delold = 1.0D10
770
+ C
771
+ istop = -1
772
+ C
773
+ C Calculate the VP, best fitting Gaussian, and Gauss-Hermite coefficients.
774
+ C Iterate until convergence is reached.
775
+ C
776
+ 71 CALL FINDVP (ncur,xmom,velar,vpval,nvel,gam,Vgau,sig,harr)
777
+ C
778
+ C Write the resulting VP to the screen
779
+ C
780
+ IF (iverb.EQ.1) THEN
781
+ C
782
+ C WRITE (*,'(A31,I3,A9)')
783
+ C & 'VP reconstructed from the first',ncur,'moments:'
784
+ C DO i=1,nvel
785
+ C WRITE (*,'(I5,2F20.8)') i,velar(i),vpval(i)
786
+ C END DO
787
+ C WRITE (*,*) ' '
788
+ C
789
+ WRITE (*,'(A44,I3,A9)')
790
+ & 'VP coefficients reconstructed from the first',ncur,'moments:'
791
+ WRITE (*,'(15F8.4)') gam,Vgau,sig,(harr(k),k=0,nord)
792
+ WRITE (*,*) ' '
793
+ C
794
+ END IF
795
+ C
796
+ C If this was the first try, check for large negative values in the VP,
797
+ C indicative of the fact that too many moments have been used.
798
+ C
799
+ IF (istop.EQ.-1) THEN
800
+ ineg = 0
801
+ DO i=1,nvel
802
+ IF (vpval(i).LE.-0.5D0) ineg=1
803
+ END DO
804
+ IF ((ineg.EQ.1).AND.(ncur.GE.10)) THEN
805
+ ncur = ncur-2
806
+ GOTO 71
807
+ END IF
808
+ END IF
809
+ C
810
+ IF (istop.NE.1) THEN
811
+ C
812
+ C Calculate how much the difference is from the previous estimate
813
+ C
814
+ del = (((gam-gamold)/gamold)**2.0D0) +
815
+ & (((Vgau-Vold)/sigold)**2.0D0) +
816
+ & (((sig-sigold)/sigold)**2.0D0)
817
+ DO i=0,nord
818
+ del = del + ((harr(i)-hold(i))**2.0D0)
819
+ END DO
820
+ del = SQRT(del/DBLE(nord+4))
821
+ C
822
+ IF (iverb.EQ.1) THEN
823
+ WRITE (*,'(A36,F12.8)')
824
+ & 'Change with respect to previous step',del
825
+ WRITE (*,*) ' '
826
+ END IF
827
+ C
828
+ IF (del.GT.delold) THEN
829
+ C
830
+ C Stop whenever things start diverging (the problem of recovering the VP
831
+ C from the moments is numerically unstable to round-off error if to many
832
+ C moments are used).
833
+ C
834
+ gam = gamold
835
+ Vgau = Vold
836
+ sig = sigold
837
+ IF (istop.EQ.-2) THEN
838
+ ncur = ncur-4
839
+ delold = 1.0D10
840
+ istop = -1
841
+ ELSE
842
+ ncur = ncur-2
843
+ istop = 1
844
+ END IF
845
+ GOTO 71
846
+ C
847
+ ELSE IF ((del.GE.1.0D-5).AND.(ncur+2.LE.maxord)) THEN
848
+ C
849
+ C Keep on going by including two more moments
850
+ C
851
+ gamold = gam
852
+ Vold = Vgau
853
+ sigold = sig
854
+ DO i=0,nord
855
+ hold(i) = harr(i)
856
+ END DO
857
+ delold = del
858
+ C
859
+ xmom(ncur+1) = PROJMOM(xi,ncur+1)
860
+ xmom(ncur+2) = PROJMOM(xi,ncur+2)
861
+ ncur = ncur+2
862
+ IF (istop.EQ.-1) THEN
863
+ istop = -2
864
+ ELSE
865
+ istop = 0
866
+ END IF
867
+ GOTO 71
868
+ C
869
+ END IF
870
+ C
871
+ END IF
872
+ C
873
+ C Calculate the Gram-Charlier coefficients
874
+ C
875
+ CALL GRAMCHARCOF (xmom,ncur,V0,sig0,darr)
876
+ C
877
+ END
878
+
879
+
880
+ SUBROUTINE FINDVP (nord,xmom,velar,vpval,nvel,
881
+ & gam,Vgau,sig,harr)
882
+ C
883
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
884
+ C
885
+ C Given nord projected moments xmom, calculate the VP as an array vpval
886
+ C at the nvel=nord+1 velocities velar, by solving the corresponding
887
+ C vanderMonde matrix. Calculate the parameters
888
+ C (gam,Vgau,sig) of the best fitting Gaussian (which must have been
889
+ C preset at appropriate initial guesses). The first nord Gauss-Hermite
890
+ C moments are returned in harr.
891
+ C
892
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
893
+ C
894
+ IMPLICIT REAL*8 (a-h,o-z)
895
+ C
896
+ DIMENSION xmom(0:100),velar(101),vpval(101),harr(0:100)
897
+ DIMENSION qmom(101),weight(101)
898
+ C
899
+ COMMON /potent/ ipot
900
+ C
901
+ C ipot=1 for Kepler potential and ipot=2 for logarithmic potential
902
+ C
903
+ COMMON /vpcur/ vvelar(101),vvpval(101),wweight(101),nvvel
904
+ C
905
+ C Common block in which the current velocity profile is stored, for use in
906
+ C REAL FUNCTION CHI2H.
907
+ C
908
+ COMMON /reg/ xlam
909
+ C
910
+ COMMON /verbose/ iverb
911
+ C
912
+ C Determines whether verbose output should be generated for VP calculations
913
+ C
914
+ CCCCCCCCCCCCCCCCC
915
+ C
916
+ C We will approximate integrals with quadrature formulae of the form:
917
+ C INT f(x) dx = SUM_{n=0}^{N} w_n f(x_n)
918
+ C where the {x_n} are a set of abscissa, and the w_n a set of weights.
919
+ C
920
+ C For the Kepler potential the terminal velocities are -1 and 1. We
921
+ C choose Eulerian integration between these limits.
922
+ C For the Logarithmic potential we also use Eulerian integration, now
923
+ C with limits -3 and 3. Gaussian quadratures were tried, but didn't work
924
+ C satisfactorily.
925
+ C
926
+ nvel = nord+1
927
+ C
928
+ IF (ipot.EQ.1) THEN
929
+ vmin = -1.0D0
930
+ vmax = 1.0D0
931
+ delv = (vmax-vmin)/DBLE(nvel)
932
+ DO i=1,nvel
933
+ velar(i) = vmin + ((DBLE(i)-0.5D0)*delv)
934
+ weight(i) = delv
935
+ END DO
936
+ ELSE
937
+ vmin = -3.0D0
938
+ vmax = 3.0D0
939
+ delv = (vmax-vmin)/DBLE(nvel)
940
+ DO i=1,nvel
941
+ velar(i) = vmin + ((DBLE(i)-0.5D0)*delv)
942
+ weight(i) = delv
943
+ END DO
944
+ END IF
945
+ C
946
+ C Define a vector with the moments that are to be reproduced
947
+ C
948
+ DO i=1,nvel
949
+ qmom(i) = xmom(i-1)
950
+ END DO
951
+ C
952
+ C Now solve the corresponding Van der Monde matrix (Numerical
953
+ C Recipes, eq. 2.8.2). If xlam<0, then do not use regularization.
954
+ C If xlam>0, then use regularization. If xlam=0, then the
955
+ C regularization parameter is determined iteratively, so as to yield
956
+ C an acceptably smooth VP.
957
+ C
958
+ IF (xlam.LT.0.0D0) THEN
959
+ CALL VANDER(velar,vpval,qmom,nvel)
960
+ ELSE IF (xlam.GT.0.0D0) THEN
961
+ CALL REG_VANDER(velar,vpval,qmom,nvel,xlam)
962
+ ELSE
963
+ xlamreg = 1.0D-30
964
+ 81 CALL REG_VANDER(velar,vpval,qmom,nvel,xlamreg)
965
+ CALL TESTSMOOTH(velar,vpval,nvel,iOK,Nmax)
966
+ IF (iverb.EQ.1) THEN
967
+ WRITE (*,'(A35,E15.7,I5)')
968
+ & 'Regularization, local maxima : ', xlamreg, Nmax
969
+ END IF
970
+ IF (iOK.EQ.0) THEN
971
+ xlamreg = xlamreg * 10.0D0
972
+ GOTO 81
973
+ END IF
974
+ IF (iverb.EQ.1) WRITE (*,*) ' '
975
+ END IF
976
+ C
977
+ C And divide by the weights to get the approximations to the VP
978
+ C
979
+ DO i=1,nvel
980
+ vpval(i) = vpval(i)/weight(i)
981
+ END DO
982
+ C
983
+ C Copy the results for use in FITGAUSS
984
+ C
985
+ nvvel = nvel
986
+ DO i=1,nvel
987
+ vvpval(i) = vpval(i)
988
+ vvelar(i) = velar(i)
989
+ wweight(i) = weight(i)
990
+ END DO
991
+ C
992
+ C Find the best fitting Gaussian (by searching for those values that
993
+ C come as closely as possible to generating h0=1, h1=h2=0).
994
+ C
995
+ CALL FITGAUSS (gam,Vgau,sig)
996
+ C
997
+ C Now get all the Gauss-Hermite coefficients up to order nord
998
+ C
999
+ CALL GAUHERM (velar,vpval,weight,nvel,gam,Vgau,sig,harr,nord)
1000
+ C
1001
+ END
1002
+
1003
+
1004
+ SUBROUTINE TESTSMOOTH(velar,vpval,nvel,iOK,Nmax)
1005
+ C
1006
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1007
+ C
1008
+ C Test whether a recoverd VP is acceptably smooth. The test crtiterion is
1009
+ C that there are no more than 3 `significant' local maxima in the VP.
1010
+ C
1011
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1012
+ C
1013
+ IMPLICIT REAL*8 (a-h,o-z)
1014
+ C
1015
+ DIMENSION velar(101),vpval(101)
1016
+ C
1017
+ COMMON /smoo/ epsmoo
1018
+ C
1019
+ C Parameter that determines the requested smoothness, as fraction of
1020
+ C the VP maximum.
1021
+ C
1022
+ CCCCCCCCCCCCCCCCCCCC
1023
+ C
1024
+ C Find the maximum of ABS(VP)
1025
+ C
1026
+ vpmax = -1.0D30
1027
+ DO i=1,nvel
1028
+ IF (ABS(vpval(i)).GT.vpmax) THEN
1029
+ vpmax = ABS(vpval(i))
1030
+ END IF
1031
+ END DO
1032
+ C
1033
+ C Find the number of local maxima
1034
+ C
1035
+ dmax = epsmoo * vpmax
1036
+ Nmax = 0
1037
+ iOK = 1
1038
+ C
1039
+ DO i=2,nvel-1
1040
+ dvm = vpval(i)-vpval(i-1)
1041
+ dvp = vpval(i)-vpval(i+1)
1042
+ IF ((dvm.GT.dmax).AND.(dvp.GT.dmax)) Nmax = Nmax + 1
1043
+ END DO
1044
+ C
1045
+ IF (Nmax.GE.4) iOK=0
1046
+ C
1047
+ END
1048
+
1049
+
1050
+ SUBROUTINE FITGAUSS (gam,Vgau,sig)
1051
+ C
1052
+ C Find the best fitting Gaussian parameters (gam,Vgau,sig) for
1053
+ C the VP in the common block /vpcur/. The parameters must be preset at
1054
+ C initial guesses. The function CHI2H below is minimized using the Numerical
1055
+ C Recipes routine amoeba.
1056
+ C
1057
+ IMPLICIT REAL*8 (a-h,o-z)
1058
+ C
1059
+ PARAMETER (eps = 1.0D-16)
1060
+ C
1061
+ DIMENSION P(4,3),Y(4),help(3)
1062
+ C
1063
+ C Starting simpleces for routine AMOEBA, and the function values
1064
+ C in the starting simpleces.
1065
+ C
1066
+ EXTERNAL CHI2H
1067
+ C
1068
+ C Initialize the fits
1069
+ C
1070
+ epsmal = 0.6D0
1071
+ epsmal = MIN(0.9D0,ABS(epsmal))
1072
+ pl1 = 1.0D0 + epsmal
1073
+ xmn1 = 1.0D0 - epsmal
1074
+ C
1075
+ C Determines the size of the starting simplex
1076
+ C
1077
+ P(1,1) = gam
1078
+ P(1,2) = Vgau
1079
+ P(1,3) = sig * pl1
1080
+ P(2,1) = gam * xmn1
1081
+ P(2,2) = Vgau - (sig*epsmal)
1082
+ P(2,3) = sig * xmn1
1083
+ P(3,1) = gam * pl1
1084
+ P(3,2) = Vgau - (sig*epsmal)
1085
+ P(3,3) = sig * xmn1
1086
+ P(4,1) = gam
1087
+ P(4,2) = Vgau + (sig*epsmal)
1088
+ P(4,3) = sig * xmn1
1089
+ C
1090
+ C Initialize
1091
+ C
1092
+ DO i=1,4
1093
+ DO j=1,3
1094
+ help(j) = P(i,j)
1095
+ END DO
1096
+ Y(i) = CHI2H(help)
1097
+ END DO
1098
+ C
1099
+ CALL AMOEBA(P,Y,4,3,3,eps,CHI2H,iter)
1100
+ C
1101
+ gam = (ABS(P(1,1))+ABS(P(2,1))+ABS(P(3,1))+
1102
+ & ABS(P(4,1)))/4.0D0
1103
+ Vgau = (P(1,2)+P(2,2)+P(3,2)+P(4,2))/4.0D0
1104
+ sig = (ABS(P(1,3))+ABS(P(2,3))+ABS(P(3,3))+
1105
+ & ABS(P(4,3)))/4.0D0
1106
+ C
1107
+ END
1108
+
1109
+
1110
+ REAL*8 FUNCTION CHI2H (y)
1111
+ C
1112
+ C Calculates the chih^2 = (h0-1)^2 + (h1^2) + (h2^2) for a Gaussian
1113
+ C with parameters gam = |y(1)|, Vgau = y(2), sig = |y(3)|,
1114
+ C for the VP in the common block /vpcur/
1115
+ C
1116
+ IMPLICIT REAL*8 (a-h,o-z)
1117
+ C
1118
+ DIMENSION y(3),harr(0:100)
1119
+ C
1120
+ COMMON /vpcur/ velar(101),vpval(101),weight(101),nvel
1121
+ C
1122
+ C Avoid values of gamma and sigma too close to zero.
1123
+ C
1124
+ gam = MAX(1.0D-3,ABS(y(1)))
1125
+ Vgau = y(2)
1126
+ sig = MAX(1.0D-3,ABS(y(3)))
1127
+ C
1128
+ CALL GAUHERM (velar,vpval,weight,nvel,gam,Vgau,sig,harr,2)
1129
+ C
1130
+ CHI2H = 1.0D0 + ((harr(0)-1.0D0)**2.0D0) +
1131
+ & (harr(1)**2.0D0) + (harr(2)**2.0D0)
1132
+ C
1133
+ END
1134
+
1135
+
1136
+ SUBROUTINE GAUHERM (velar,vpval,weight,nvel,
1137
+ & gam,Vgau,sig,harr,nhord)
1138
+ C
1139
+ C Given the VP as an array vpval, corrsponding to nvel velocities velar,
1140
+ C calculate the Gauss-Hermite coefficients harr up to order nhord that belong
1141
+ C to the given reference values gam,Vgau,sig.
1142
+ C
1143
+ IMPLICIT REAL*8 (a-h,o-z)
1144
+ C
1145
+ PARAMETER (pi=3.14159265358979D0)
1146
+ C
1147
+ DIMENSION velar(101),vpval(101),weight(101),harr(0:100)
1148
+ C
1149
+ DO l=0,nhord
1150
+ harr(l) = 0.0D0
1151
+ END DO
1152
+ C
1153
+ DO i=1,nvel
1154
+ w = (velar(i)-Vgau)/sig
1155
+ DO l=0,nhord
1156
+ harr(l) = harr(l) +
1157
+ & (vpval(i)*weight(i)*SDGAUSS(w)*H_POL(l,w))
1158
+ END DO
1159
+ END DO
1160
+ C
1161
+ DO l=0,nhord
1162
+ harr(l) = harr(l) * 2.0D0 * SQRT(pi) / gam
1163
+ END DO
1164
+ C
1165
+ END
1166
+
1167
+
1168
+ SUBROUTINE GRAMCHARCOF (xmom,nord,V0,sig0,darr)
1169
+ C
1170
+ C Calculate the Gram-Charlier coefficients of the velocity profile, given
1171
+ C the array xmom, containing the first nord moments.
1172
+ C The reference values (V0,sig0) of the series are required at
1173
+ C input separately. These need not necessarily correspond to the true
1174
+ C mean and dispersion of the VP. The Gram-Charlier coefficients are
1175
+ C calculated up to order nord, and are returned in darr.
1176
+ C
1177
+ IMPLICIT REAL*8 (a-h,o-z)
1178
+ C
1179
+ DIMENSION xmom(0:100),darr(0:100)
1180
+ C
1181
+ DO l=0,nord
1182
+ dl = DBLE(l)
1183
+ darr(l) = 0.0D0
1184
+ DO j=0,l
1185
+ dj = DBLE(j)
1186
+ IF (2*((j+l)/2).EQ.(j+l)) THEN
1187
+ pfacln = (0.5D0*gammaln(dl+1.0D0)) - gammaln(dj+1.0D0) -
1188
+ & gammaln(dl-dj+1.0D0) +
1189
+ & (gammaln(0.5D0*(dl-dj+1.0D0))) - gammaln(0.5D0) +
1190
+ & (0.5D0*(dl-dj)*LOG(2.0D0))
1191
+ pfac = ((-1.0D0)**((l-j)/2)) * EXPP(pfacln)
1192
+ DO i=0,j
1193
+ darr(l) = darr(l) +
1194
+ & ( ((-1.0D0)**(j-i)) * (V0**(j-i)) *
1195
+ & ((1.0/sig0)**j) * xmom(i) * pfac *
1196
+ & EXPP(binomln(j,i)) )
1197
+ END DO
1198
+ END IF
1199
+ END DO
1200
+ END DO
1201
+ C
1202
+ END
1203
+
1204
+
1205
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1206
+ C
1207
+ C The function SDGAUSS, HE_POL and H_POL calculate the standard
1208
+ C Gaussian and Hermite polynomials.
1209
+ C
1210
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1211
+
1212
+ REAL*8 FUNCTION SDGAUSS (x)
1213
+ C
1214
+ C Returns the standard Gaussian as function of x
1215
+ C
1216
+ IMPLICIT REAL*8 (a-h,o-z)
1217
+ PARAMETER (pi=3.14159265358979D0)
1218
+ SDGAUSS = (1.0D0/SQRT(2.0D0*pi)) * EXPP(-0.5D0*x*x)
1219
+ END
1220
+
1221
+
1222
+ REAL*8 FUNCTION HE_POL (l,x)
1223
+ C
1224
+ C Returns the value of the Hermite polynomial He_l(x) as defined
1225
+ C in Appendix A of van der Marel & Franx.
1226
+ C
1227
+ IMPLICIT REAL*8 (a-h,o-z)
1228
+ C
1229
+ HE_POL = 0.0D0
1230
+ dl = DBLE(l)
1231
+ DO j=l,0,-1
1232
+ IF (2*((j+l)/2).EQ.j+l) THEN
1233
+ dj = DBLE(j)
1234
+ pfacln = (0.5D0*gammaln(dl+1.0D0)) -
1235
+ & gammaln(dj+1.0D0) - gammaln(dl-dj+1.0D0) +
1236
+ & gammaln(0.5D0*(dl-dj+1.0D0)) -
1237
+ & gammaln(0.5D0) + (0.5D0*(dl-dj)*LOG(2.0D0))
1238
+ pfac = ((-1.0D0)**((l-j)/2)) * EXPP(pfacln)
1239
+ ELSE
1240
+ pfac = 0.0D0
1241
+ END IF
1242
+ HE_POL = pfac + (x*HE_POL)
1243
+ END DO
1244
+ C
1245
+ END
1246
+
1247
+
1248
+ REAL*8 FUNCTION H_POL (l,x)
1249
+ C
1250
+ C Returns the value of the Hermite polynomial H_l(x) as defined
1251
+ C in Appendix A of van der Marel & Franx.
1252
+ C
1253
+ IMPLICIT REAL*8 (a-h,o-z)
1254
+ H_POL = HE_POL(l,x*SQRT(2.0D0))
1255
+ END
1256
+
1257
+
1258
+ REAL*8 FUNCTION RHOPROJMOMAV (nord)
1259
+ C
1260
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1261
+ C
1262
+ C The function RHOPROJMOMAV calculates the
1263
+ C projected rho times velocity moment of a given order, integrated along
1264
+ C a circle in the first quadrant of the sky.
1265
+ C
1266
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1267
+ C
1268
+ IMPLICIT REAL*8 (a-h,o-z)
1269
+ C
1270
+ PARAMETER (pi=3.14159265358979D0)
1271
+ C
1272
+ COMMON /howint/ iint
1273
+ C
1274
+ COMMON /curprojorder/ nordcur
1275
+ C
1276
+ C Common block that holds copies of the order with which this
1277
+ C function is called.
1278
+ C
1279
+ EXTERNAL TOINTPROJ,MIDPNTB
1280
+ C
1281
+ CCCCCCCCCCCCCCCCCCCC
1282
+ C
1283
+ nordcur = nord
1284
+ C
1285
+ IF (iint.EQ.0) THEN
1286
+ CALL QROMOB (TOINTPROJ,0.0D0,0.5D0*pi,SS,MIDPNTB)
1287
+ ELSE
1288
+ CALL QGAUSLEGB (TOINTPROJ,0.0D0,0.5D0*pi,SS)
1289
+ END IF
1290
+ C
1291
+ RHOPROJMOMAV = SS / (0.5D0*pi)
1292
+ C
1293
+ END
1294
+
1295
+
1296
+ REAL*8 FUNCTION TOINTPROJ (xi)
1297
+ C
1298
+ C The function that must be integrated to get the first-quadrant integral
1299
+ C over a circle on the sky of rho times projected velocity moment for the
1300
+ C order given by /curprojorder/.
1301
+ C
1302
+ IMPLICIT REAL*8 (a-h,o-z)
1303
+ C
1304
+ COMMON /curprojorder/ nordcur
1305
+ C
1306
+ TOINTPROJ = RHOPROJ(xi) * PROJMOM(xi,nordcur)
1307
+ C
1308
+ END
1309
+
1310
+
1311
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1312
+ C
1313
+ C The function RHOPROJ calculates the projected mass density analytically.
1314
+ C The function PROJMOM calculates the projected velocity momemnts by
1315
+ C numerical 1D integration over the function TOINT. This uses
1316
+ C RHOVPROJMOM, rho times the n-th projected velocity moment (selected
1317
+ C point in the galaxy.
1318
+ C
1319
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1320
+
1321
+ REAL*8 FUNCTION RHOPROJ (xi)
1322
+ C
1323
+ C The projected mass density at scaled projected radius equal to 1,
1324
+ C and angle xi from the major axis. The expression is known
1325
+ C analytically, because the 3D mass density is simply a power law on
1326
+ C spheroids.
1327
+ C
1328
+ IMPLICIT REAL*8 (a-h,o-z)
1329
+ C
1330
+ COMMON /param/ gamma, beta, q, alpha, eta
1331
+ COMMON /viewing/ xinc
1332
+ C
1333
+ qp2 = (COS(xinc)**2.0D0) + ((q*q)*(SIN(xinc)**2.0D0))
1334
+ qp = SQRT(qp2)
1335
+ C
1336
+ xacc = COS(xi)
1337
+ yacc = SIN(xi)
1338
+ C
1339
+ RHOPROJ = (q/qp) * EXPP(betaln(0.5D0,0.5D0*(gamma-1.0D0))) *
1340
+ & ( ((xacc**2.0D0)+((yacc**2.0D0)/qp2))**
1341
+ & (0.5D0*(1.0D0-gamma)) )
1342
+ C
1343
+ END
1344
+
1345
+
1346
+ REAL*8 FUNCTION PROJMOM (xi,nord)
1347
+ C
1348
+ C Calculate the projected n-th order velocity moment on the sky,
1349
+ C at scaled projected radius equal to 1, and angle xi from the
1350
+ C major axis.
1351
+ C
1352
+ IMPLICIT REAL*8 (a-h,o-z)
1353
+ C
1354
+ PARAMETER (pi=3.14159265358979D0)
1355
+ C
1356
+ COMMON /losmom/ xxi,nnord
1357
+ C
1358
+ COMMON /projcase/ iproj
1359
+ C
1360
+ C
1361
+ COMMON /howint/ iint
1362
+ C
1363
+ EXTERNAL TOINT,MIDPNT
1364
+ C
1365
+ IF ( ((2*(nord/2)).NE.nord) .AND.
1366
+ & (ABS(COS(xi)).LE.1.0D-12) ) THEN
1367
+ PROJMOM = 0.0D0
1368
+ RETURN
1369
+ END IF
1370
+ C
1371
+ IF (nord.EQ.0) THEN
1372
+ PROJMOM = 1.0D0
1373
+ RETURN
1374
+ END IF
1375
+ C
1376
+ xxi = xi
1377
+ nnord = nord
1378
+ C
1379
+ IF (iint.EQ.0) THEN
1380
+ CALL QROMO (TOINT,-0.5D0*pi,0.5D0*pi,SS,MIDPNT)
1381
+ ELSE
1382
+ CALL QGAUSLEG (TOINT,-0.5D0*pi,0.5D0*pi,SS)
1383
+ END IF
1384
+ C
1385
+ PROJMOM = SS / RHOPROJ(xi)
1386
+ C
1387
+ END
1388
+
1389
+
1390
+ REAL*8 FUNCTION TOINT (tau)
1391
+ C
1392
+ C The function that must be integrated to get the n-th order velocity
1393
+ C moment on the sky.
1394
+ C
1395
+ IMPLICIT REAL*8 (a-h,o-z)
1396
+ C
1397
+ COMMON /losmom/ xi,nord
1398
+ C
1399
+ COMMON /projcase/ iproj
1400
+ C
1401
+ C
1402
+ COMMON /potent/ ipot
1403
+ C
1404
+ C ipot=1 for Kepler potential and ipot=2 for logarithmic potential
1405
+ C
1406
+ COMMON /param/ gamma, beta, q, alpha, eta
1407
+ COMMON /viewing/ xinc
1408
+ C
1409
+ xacc = COS(xi)
1410
+ yacc = SIN(xi)
1411
+ zacc = TAN(tau)
1412
+ C
1413
+ x = (-1.0D0*COS(xinc)*yacc) + (SIN(xinc)*zacc)
1414
+ y = xacc
1415
+ z = (SIN(xinc)*yacc) + (COS(xinc)*zacc)
1416
+ Rc = SQRT((x**2.0D0)+(y**2.0D0))
1417
+ r = SQRT((Rc**2.0D0)+(z**2.0D0))
1418
+ C
1419
+ theta = ACOS(z/r)
1420
+ phi = ACOS(x/Rc)
1421
+ C
1422
+ IF (ipot.EQ.1) THEN
1423
+ TOINT = (COS(tau)**(gamma-2.0D0+(0.5D0*DBLE(nord)))) *
1424
+ & RHOVPROJMOM(theta,phi,nord)
1425
+ ELSE IF (ipot.EQ.2) THEN
1426
+ TOINT = (COS(tau)**(gamma-2.0D0)) *
1427
+ & RHOVPROJMOM(theta,phi,nord)
1428
+ ELSE
1429
+ STOP 'ipot wrong value'
1430
+ END IF
1431
+ C
1432
+ END
1433
+
1434
+
1435
+ REAL*8 FUNCTION RHOVLOSMOM(theta,phi,nord)
1436
+ C
1437
+ C Returns rho times the nord-th line-of-sight velocity moment at the
1438
+ C point with polar coordinates (theta,phi) in radians, and radius 1
1439
+ C (in dimensionless units).
1440
+ C
1441
+ IMPLICIT REAL*8 (a-h,o-z)
1442
+ C
1443
+ COMMON /param/ gamma, beta, q, alpha, eta
1444
+ COMMON /viewing/ xinc
1445
+ C
1446
+ Afac = (COS(phi)*SIN(theta)*SIN(xinc)) + (COS(theta)*COS(xinc))
1447
+ Bfac = (COS(phi)*COS(theta)*SIN(xinc)) - (SIN(theta)*COS(xinc))
1448
+ Cfac = (-1.0D0*SIN(phi)*SIN(xinc))
1449
+ C
1450
+ IF (Afac.LT.0.0D0) THEN
1451
+ Asign = -1.0D0
1452
+ ELSE
1453
+ Asign = 1.0D0
1454
+ END IF
1455
+ Afac = MAX(1.0D-20,ABS(Afac))
1456
+ C
1457
+ IF (Bfac.LT.0.0D0) THEN
1458
+ Bsign = -1.0D0
1459
+ ELSE
1460
+ Bsign = 1.0D0
1461
+ END IF
1462
+ Bfac = MAX(1.0D-20,ABS(Bfac))
1463
+ C
1464
+ IF (Cfac.LT.0.0D0) THEN
1465
+ Csign = -1.0D0
1466
+ ELSE
1467
+ Csign = 1.0D0
1468
+ END IF
1469
+ Cfac = MAX(1.0D-20,ABS(Cfac))
1470
+ C
1471
+ RHOVLOSMOM = 0.0D0
1472
+ DO k=0,nord
1473
+ DO j=0,nord-k
1474
+ facln = binomln(nord,k) + binomln(nord-k,j) +
1475
+ & (DBLE(k)*LOG(Afac)) + (DBLE(j)*LOG(Bfac)) +
1476
+ & (DBLE(nord-k-j)*LOG(Cfac))
1477
+ RHOVLOSMOM = RHOVLOSMOM + ( EXPP(facln)*
1478
+ & (Asign**k)*(Bsign**j)*(Csign**(nord-k-j))*
1479
+ & RHOVELMOM(theta,k,j,nord-k-j) )
1480
+ END DO
1481
+ END DO
1482
+ C
1483
+ END
1484
+
1485
+
1486
+ REAL*8 FUNCTION RHOVPOSRMOM(theta,phi,nord)
1487
+ C
1488
+ C Returns rho times the nord-th line-of-sight velocity moment at the
1489
+ C point with polar coordinates (theta,phi) in radians, and radius 1
1490
+ C (in dimensionless units).
1491
+ C
1492
+ IMPLICIT REAL*8 (a-h,o-z)
1493
+ C
1494
+ COMMON /param/ gamma, beta, q, alpha, eta
1495
+ COMMON /viewing/ xinc
1496
+ C
1497
+ SP = SIN(phi)
1498
+ CP = COS(phi)
1499
+ ST = SIN(theta)
1500
+ CT = COS(theta)
1501
+ SX = SIN(xinc)
1502
+ CX = COS(xinc)
1503
+ CTT = COS(2.0D0*theta)
1504
+ C
1505
+ Afac = SQRT(ST*ST*SP*SP+(CT*SX - ST*CX*CP)**2.0D0)
1506
+ Bfac = (ST*CT*CX*CX*CP*CP + ST*CT*(SP*SP - SX*SX) -
1507
+ & CTT*SX*CX*CP)/Afac
1508
+ Cfac = SP*(ST*CP + ST*CX*CX*(-1.0D0*CP) +
1509
+ & CT*SX*CX)/Afac
1510
+ C
1511
+ IF (Afac.LT.0.0D0) THEN
1512
+ Asign = -1.0D0
1513
+ ELSE
1514
+ Asign = 1.0D0
1515
+ END IF
1516
+ Afac = MAX(1.0D-20,ABS(Afac))
1517
+ C
1518
+ IF (Bfac.LT.0.0D0) THEN
1519
+ Bsign = -1.0D0
1520
+ ELSE
1521
+ Bsign = 1.0D0
1522
+ END IF
1523
+ Bfac = MAX(1.0D-20,ABS(Bfac))
1524
+ C
1525
+ IF (Cfac.LT.0.0D0) THEN
1526
+ Csign = -1.0D0
1527
+ ELSE
1528
+ Csign = 1.0D0
1529
+ END IF
1530
+ Cfac = MAX(1.0D-20,ABS(Cfac))
1531
+ C
1532
+ RHOVPOSRMOM = 0.0D0
1533
+ DO k=0,nord
1534
+ DO j=0,nord-k
1535
+ facln = binomln(nord,k) + binomln(nord-k,j) +
1536
+ & (DBLE(k)*LOG(Afac)) + (DBLE(j)*LOG(Bfac)) +
1537
+ & (DBLE(nord-k-j)*LOG(Cfac))
1538
+ RHOVPOSRMOM = RHOVPOSRMOM + ( EXPP(facln)*
1539
+ & (Asign**k)*(Bsign**j)*(Csign**(nord-k-j))*
1540
+ & RHOVELMOM(theta,k,j,nord-k-j) )
1541
+ END DO
1542
+ END DO
1543
+ C
1544
+ END
1545
+
1546
+
1547
+
1548
+ REAL*8 FUNCTION RHOVPOSTMOM(theta,phi,nord)
1549
+ C
1550
+ C Returns rho times the nord-th line-of-sight velocity moment at the
1551
+ C point with polar coordinates (theta,phi) in radians, and radius 1
1552
+ C (in dimensionless units).
1553
+ C
1554
+ IMPLICIT REAL*8 (a-h,o-z)
1555
+ C
1556
+ COMMON /param/ gamma, beta, q, alpha, eta
1557
+ COMMON /viewing/ xinc
1558
+ C
1559
+ SP = SIN(phi)
1560
+ CP = COS(phi)
1561
+ ST = SIN(theta)
1562
+ CT = COS(theta)
1563
+ SX = SIN(xinc)
1564
+ CX = COS(xinc)
1565
+ DEN = SQRT(ST*ST*SP*SP+(CT*SX - ST*CX*CP)**2.0D0)
1566
+ C
1567
+ Bfac = SX*SP/DEN
1568
+ Cfac = (CT*SX*CP - ST*CX)/DEN
1569
+ C
1570
+ IF (Bfac.LT.0.0D0) THEN
1571
+ Bsign = -1.0D0
1572
+ ELSE
1573
+ Bsign = 1.0D0
1574
+ END IF
1575
+ Bfac = MAX(1.0D-20,ABS(Bfac))
1576
+ C
1577
+ IF (Cfac.LT.0.0D0) THEN
1578
+ Csign = -1.0D0
1579
+ ELSE
1580
+ Csign = 1.0D0
1581
+ END IF
1582
+ Cfac = MAX(1.0D-20,ABS(Cfac))
1583
+ C
1584
+ RHOVPOSTMOM = 0.0D0
1585
+ DO j=0,nord
1586
+ facln = binomln(nord,0) + binomln(nord,j) +
1587
+ & (DBLE(j)*LOG(Bfac)) +
1588
+ & (DBLE(nord-j)*LOG(Cfac))
1589
+ RHOVPOSTMOM = RHOVPOSTMOM + ( EXPP(facln)*
1590
+ & (Bsign**j)*(Csign**(nord-j))*
1591
+ & RHOVELMOM(theta,0,j,nord-j) )
1592
+ END DO
1593
+ C
1594
+ END
1595
+
1596
+
1597
+ REAL*8 FUNCTION RHOVPROJMOM(theta,phi,nord)
1598
+ C
1599
+ C Select the projected component (LOS=1, POSR=2, POST=3)
1600
+ C and return rho times the nord-th projected velocity moment at the
1601
+ C point with polar coordinates (theta,phi) in radians, and radius 1
1602
+ C (in dimensionless units).
1603
+ C
1604
+ IMPLICIT REAL*8 (a-h,o-z)
1605
+ C
1606
+ COMMON /projcase/ iproj
1607
+ C
1608
+ IF (iproj.EQ.1) THEN
1609
+ RHOVPROJMOM = RHOVLOSMOM(theta,phi,nord)
1610
+ ELSE IF (iproj.EQ.2) THEN
1611
+ RHOVPROJMOM = RHOVPOSRMOM(theta,phi,nord)
1612
+ ELSE IF (iproj.EQ.3) THEN
1613
+ RHOVPROJMOM = RHOVPOSTMOM(theta,phi,nord)
1614
+ ELSE
1615
+ STOP 'iproj wrong value'
1616
+ END IF
1617
+ C
1618
+ END
1619
+
1620
+
1621
+
1622
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1623
+ C
1624
+ C The subroutine VIRIALTENSORS calculates the virial tensors, using
1625
+ C the fact that the intrinsic moments are power series in e^2 SIN^2(theta).
1626
+ C
1627
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1628
+
1629
+ SUBROUTINE VIRIALTENSORS (potx,potz,xkinr,xkinth,xkinph,
1630
+ & xkinRc,xkinz,xkinx)
1631
+ C
1632
+ C Calculate the tensors for potential and kinemtic energy, and write
1633
+ C the results to the screen.
1634
+ C
1635
+ IMPLICIT REAL*8 (a-h,o-z)
1636
+ C
1637
+ COMMON /param/ gamma, beta, q, alpha, eta
1638
+ C
1639
+ e2 = 1.0D0 - (q*q)
1640
+ e2 = MAX(e2,1.0D-20)
1641
+ C
1642
+ potx = 0.0D0
1643
+ potz = 0.0D0
1644
+ prefln = PREFACLN(0,0,0)
1645
+ DO k=0,KMAXARR(0,0,0)
1646
+ dk = DBLE(k)
1647
+ addxln = prefln + COFARR(k,0,0,0) + (dk*LOG(e2)) +
1648
+ & betaln(2.0D0+dk,0.5D0)
1649
+ addzln = prefln + COFARR(k,0,0,0) + (dk*LOG(e2)) +
1650
+ & betaln(1.0D0+dk,1.5D0)
1651
+ potx = potx - (0.5D0*EXPP(addxln))
1652
+ potz = potz - EXPP(addzln)
1653
+ END DO
1654
+ C
1655
+ xkinr = 0.0D0
1656
+ xkinr1 = 0.0D0
1657
+ xkinr2 = 0.0D0
1658
+ prefln = PREFACLN(2,0,0)
1659
+ DO k=0,KMAXARR(2,0,0)
1660
+ dk = DBLE(k)
1661
+ addln = prefln + COFARR(k,2,0,0) + (dk*LOG(e2)) +
1662
+ & betaln(1.0D0+dk,0.5D0)
1663
+ addln1 = prefln + COFARR(k,2,0,0) + (dk*LOG(e2)) +
1664
+ & betaln(2.0D0+dk,0.5D0)
1665
+ addln2 = prefln + COFARR(k,2,0,0) + (dk*LOG(e2)) +
1666
+ & betaln(1.0D0+dk,1.5D0)
1667
+ xkinr = xkinr + EXPP(addln)
1668
+ xkinr1 = xkinr1 + EXPP(addln1)
1669
+ xkinr2 = xkinr2 + EXPP(addln2)
1670
+ END DO
1671
+ C
1672
+ xkinth = 0.0D0
1673
+ xkinth1 = 0.0D0
1674
+ xkinth2 = 0.0D0
1675
+ prefln = PREFACLN(0,2,0)
1676
+ DO k=0,KMAXARR(0,2,0)
1677
+ dk = DBLE(k)
1678
+ addln = prefln + COFARR(k,0,2,0) + (dk*LOG(e2)) +
1679
+ & betaln(1.0D0+dk,0.5D0)
1680
+ addln1 = prefln + COFARR(k,0,2,0) + (dk*LOG(e2)) +
1681
+ & betaln(2.0D0+dk,0.5D0)
1682
+ addln2 = prefln + COFARR(k,0,2,0) + (dk*LOG(e2)) +
1683
+ & betaln(1.0D0+dk,1.5D0)
1684
+ xkinth = xkinth + EXPP(addln)
1685
+ xkinth1 = xkinth1 + EXPP(addln1)
1686
+ xkinth2 = xkinth2 + EXPP(addln2)
1687
+ END DO
1688
+ C
1689
+ xkinph = 0.0D0
1690
+ prefln = PREFACLN(0,0,2)
1691
+ DO k=0,KMAXARR(0,0,2)
1692
+ dk = DBLE(k)
1693
+ addln = prefln + COFARR(k,0,0,2) + (dk*LOG(e2)) +
1694
+ & betaln(1.0D0+dk,0.5D0)
1695
+ xkinph = xkinph + EXPP(addln)
1696
+ END DO
1697
+ C
1698
+ xkinRc = xkinr1 + xkinth2
1699
+ xkinz = xkinr2 + xkinth1
1700
+ xkinx = 0.5D0 * (xkinRc+xkinph)
1701
+ C
1702
+ END
1703
+
1704
+
1705
+ REAL*8 FUNCTION RHOVELMOMTHAV(lr,lth,lph)
1706
+ C
1707
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1708
+ C
1709
+ C The function RHOVELMOMTHAV calculates rho times the
1710
+ C intrinsic velocity moment of a given order, integrated over
1711
+ C a spherical shell of unit radius.
1712
+ C
1713
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1714
+ C
1715
+ IMPLICIT REAL*8 (a-h,o-z)
1716
+ C
1717
+ PARAMETER (pi=3.14159265358979D0)
1718
+ C
1719
+ COMMON /howint/ iint
1720
+ C
1721
+ COMMON /curorders/ lrcur,lthcur,lphcur
1722
+ C
1723
+ C Common block that holds copies of the orders with which this
1724
+ C function is called.
1725
+ C
1726
+ EXTERNAL TOINTMER,MIDPNT
1727
+ C
1728
+ CCCCCCCCCCCCCCCCCCCC
1729
+ C
1730
+ lrcur = lr
1731
+ lthcur = lth
1732
+ lphcur = lph
1733
+ C
1734
+ IF (iint.EQ.0) THEN
1735
+ CALL QROMO (TOINTMER,0.0D0,0.5D0*pi,SS,MIDPNT)
1736
+ ELSE
1737
+ CALL QGAUSLEG (TOINTMER,0.0D0,0.5D0*pi,SS)
1738
+ END IF
1739
+ C
1740
+ RHOVELMOMTHAV = SS
1741
+ C
1742
+ END
1743
+
1744
+
1745
+ REAL*8 FUNCTION TOINTMER (theta)
1746
+ C
1747
+ C The function that must be integrated to get the integral over a spherical
1748
+ C shell of rho times the intrinsic velocity moment of the orders given by
1749
+ C /curorders/.
1750
+ C
1751
+ IMPLICIT REAL*8 (a-h,o-z)
1752
+ C
1753
+ COMMON /curorders/ lrcur,lthcur,lphcur
1754
+ C
1755
+ TOINTMER = SIN(theta) * RHOVELMOM(theta,lrcur,lthcur,lphcur)
1756
+ C
1757
+ END
1758
+
1759
+
1760
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1761
+ C
1762
+ C The function RHOVELMOM calculates rho times intrinsic velocity momemnt
1763
+ C of a given order. This is a prefactor times a power series in
1764
+ C e^2 SIN^2(theta). The (ln of the) prefactor is calculated by PREFACLN.
1765
+ C The subroutines COFARR and KMAXARR allow the power series
1766
+ C to be reconstructed, by reading values from the arrays allcofs and
1767
+ C kmaxall, in the common block /all/. These arrays must have been filled
1768
+ C previously in the main program, using the subroutine CALCCOEFFLN.
1769
+ C This subroutine calls the function COEFFLN for each term in the series.
1770
+ C
1771
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
1772
+
1773
+ REAL*8 FUNCTION RHOVELMOM(theta,lr,lth,lph)
1774
+ C
1775
+ C Calculates the rho times velocity moment of order (lr,lth,lph).
1776
+ C The fractional accuracy is eps. The polar angle theta must be given
1777
+ C in radians. The dimensionless radius is assumed to be unity.
1778
+ C
1779
+ IMPLICIT REAL*8 (a-h,o-z)
1780
+ C
1781
+ PARAMETER (eps = 1.0D-10)
1782
+ C
1783
+ COMMON /param/ gamma, beta, q, alpha, eta
1784
+ C
1785
+ DIMENSION cofs(0:1000)
1786
+ C
1787
+ IF ((2*(lr/2).NE.lr).OR.(2*(lth/2).NE.lth)) THEN
1788
+ RHOVELMOM = 0.0D0
1789
+ RETURN
1790
+ END IF
1791
+ C
1792
+ kmax = KMAXARR(lr,lth,lph)
1793
+ DO k=0,kmax
1794
+ cofs(k) = COFARR(k,lr,lth,lph)
1795
+ END DO
1796
+ C
1797
+ prefln = PREFACLN(lr,lth,lph)
1798
+ C
1799
+ e2 = 1.0D0 - (q*q)
1800
+ s2 = (SIN(theta))**2.0D0
1801
+ C
1802
+ k = 0
1803
+ xnewadd = EXPP(cofs(0))
1804
+ sum = xnewadd
1805
+ epsab = eps*EXPP(cofs(0))
1806
+ C
1807
+ IF ((e2*s2).GE.1.0D-12) THEN
1808
+ C
1809
+ 35 k = k+1
1810
+ oldadd = xnewadd
1811
+ xnewadd = EXPP(cofs(k)+(DBLE(k)*LOG(e2*s2)))
1812
+ sum = sum + xnewadd
1813
+ IF ( (.NOT.((ABS(xnewadd).LE.epsab).AND.
1814
+ & (ABS(oldadd).LE.epsab))) .AND.
1815
+ & (k.LE.kmax) ) THEN
1816
+ GOTO 35
1817
+ END IF
1818
+ C
1819
+ END IF
1820
+ C
1821
+ IF (2*(lph/2).EQ.lph) THEN
1822
+ RHOVELMOM = EXPP(prefln) * sum
1823
+ ELSE
1824
+ IF (s2.LE.1.0D-12) THEN
1825
+ RHOVELMOM = 0.0D0
1826
+ ELSE
1827
+ RHOVELMOM = EXPP(prefln) * sum * ((2.0D0*eta)-1.0D0) *
1828
+ & (s2**alpha)
1829
+ END IF
1830
+ END IF
1831
+ C
1832
+ END
1833
+
1834
+
1835
+ REAL*8 FUNCTION PREFACLN(lr,lth,lph)
1836
+ C
1837
+ C Calculates the logarithm of the pre-factor by which the relevant
1838
+ C series must be multiplied to get the velocity moment
1839
+ C of order (lr,lth,lph). This function does not take into account the factor
1840
+ C (2 eta - 1) * (sin^2(theta))^{alpha} that must be added for the odd
1841
+ C moments.
1842
+ C
1843
+ IMPLICIT REAL*8 (a-h,o-z)
1844
+ C
1845
+ COMMON /potent/ ipot
1846
+ C
1847
+ C ipot=1 for Kepler potential and ipot=2 for logarithmic potential
1848
+ C
1849
+ COMMON /param/ gamma, beta, q, alpha, eta
1850
+ C
1851
+ IF ((2*(lr/2).NE.lr).OR.(2*(lth/2).NE.lth)) THEN
1852
+ PREFACLN = -100.0D0
1853
+ RETURN
1854
+ END IF
1855
+ C
1856
+ IF (2*(lph/2).EQ.lph) THEN
1857
+ alp = 0.0D0
1858
+ ELSE
1859
+ alp = alpha
1860
+ END IF
1861
+ C
1862
+ dlr = DBLE(lr)
1863
+ dlth = DBLE(lth)
1864
+ dlph = DBLE(lph)
1865
+ C
1866
+ PREFACLN = (gamma*LOG(q)) +
1867
+ & betaln(1.0D0+alp-beta+(0.5D0*(dlth+dlph)),
1868
+ & (0.5D0*(dlr+1.0D0))) +
1869
+ & betaln(alp+(0.5D0*(dlph+1.0D0)),(0.5D0*(dlth+1.0D0))) -
1870
+ & betaln(1.0D0-beta,0.5D0) - betaln(0.5D0,0.5D0)
1871
+ C
1872
+ IF (ipot.EQ.1) THEN
1873
+ PREFACLN = PREFACLN + (alp*LOG(4.0D0)) +
1874
+ & betaln(1.5D0-beta+alp+(0.5D0*(dlr+dlth+dlph)),
1875
+ & gamma-beta-0.5D0+alp) -
1876
+ & betaln(1.5D0-beta,gamma-beta-0.5D0)
1877
+ ELSE IF (ipot.EQ.2) THEN
1878
+ PREFACLN = PREFACLN + (alp*(1.0D0+LOG(2.0D0))) +
1879
+ & gammaln(1.5D0-beta+alp+(0.5D0*(dlr+dlth+dlph))) -
1880
+ & gammaln(1.5D0-beta)
1881
+ ELSE
1882
+ STOP 'ipot wrong value'
1883
+ END IF
1884
+ C
1885
+ END
1886
+
1887
+
1888
+ REAL*8 FUNCTION COFARR(k,lr,lth,lph)
1889
+ C
1890
+ C Get a value from the array allcofs
1891
+ C
1892
+ IMPLICIT REAL*8 (a-h,o-z)
1893
+ C
1894
+ PARAMETER (maxlength = 2000000 ,
1895
+ & mord = 200 ,
1896
+ & mev = mord/2 )
1897
+ C
1898
+ COMMON /all/ allcofs(1:maxlength),
1899
+ & icstart(0:mev,0:mev,0:mord),
1900
+ & kmaxall(0:mev,0:mev,0:mord),maxord
1901
+ C
1902
+ IF ((lr.GT.maxord).OR.(lth.GT.maxord).OR.
1903
+ & (lph.GT.maxord)) THEN
1904
+ STOP 'order to large in cofarr'
1905
+ END IF
1906
+ C
1907
+ IF ((2*(lr/2).NE.lr).OR.(2*(lth/2).NE.lth)) THEN
1908
+ COFARR = -100.0D0
1909
+ ELSE
1910
+ COFARR = allcofs(k+icstart(lr/2,lth/2,lph))
1911
+ END IF
1912
+ C
1913
+ END
1914
+
1915
+
1916
+ INTEGER FUNCTION KMAXARR(lr,lth,lph)
1917
+ C
1918
+ C Get a value from the array kmaxall
1919
+ C
1920
+ IMPLICIT REAL*8 (a-h,o-z)
1921
+ C
1922
+ PARAMETER (maxlength = 2000000 ,
1923
+ & mord = 200 ,
1924
+ & mev = mord/2 )
1925
+ C
1926
+ COMMON /all/ allcofs(1:maxlength),
1927
+ & icstart(0:mev,0:mev,0:mord),
1928
+ & kmaxall(0:mev,0:mev,0:mord),maxord
1929
+ C
1930
+ IF ((lr.GT.maxord).OR.(lth.GT.maxord).OR.
1931
+ & (lph.GT.maxord)) THEN
1932
+ STOP 'order too large in kmaxarr'
1933
+ END IF
1934
+ C
1935
+ IF ((2*(lr/2).NE.lr).OR.(2*(lth/2).NE.lth)) THEN
1936
+ KMAXARR = 0
1937
+ ELSE
1938
+ KMAXARR = kmaxall(lr/2,lth/2,lph)
1939
+ END IF
1940
+ C
1941
+ END
1942
+
1943
+
1944
+ SUBROUTINE CALCCOEFFLN(cofs,kmax,lr,lth,lph)
1945
+ C
1946
+ C Calculates the logarithm of coefficients in the hypergeometric series
1947
+ C that occurs in the expression for the velocity moment
1948
+ C of order (lr,lth,lph). The array cofs is filled up to order kmax,
1949
+ C which is determined by this subroutine so as to allow the
1950
+ C power series to be evaluated to a fractional accuracy eps.
1951
+ C
1952
+ IMPLICIT REAL*8 (a-h,o-z)
1953
+ C
1954
+ PARAMETER (eps = 1.0D-10)
1955
+ C
1956
+ DIMENSION cofs(0:1000)
1957
+ C
1958
+ COMMON /param/ gamma, beta, q, alpha, eta
1959
+ COMMON /order/ llr,llth,llph
1960
+ C
1961
+ C Fill the common block order
1962
+ C
1963
+ llr = lr
1964
+ llth = lth
1965
+ llph = lph
1966
+ C
1967
+ e2 = 1.0D0 - (q*q)
1968
+ C
1969
+ k = 0
1970
+ cofs(0) = COEFFLN(0)
1971
+ xnewadd = EXPP(cofs(0))
1972
+ sum = xnewadd
1973
+ epsab = eps*EXPP(cofs(0))
1974
+ C
1975
+ IF (e2.GE.1.0D-20) THEN
1976
+ 15 k = k+1
1977
+ oldadd = xnewadd
1978
+ cofs(k) = COEFFLN(k)
1979
+ xnewadd = EXPP(cofs(k)+(DBLE(k)*LOG(e2)))
1980
+ sum = sum + xnewadd
1981
+ IF ( (.NOT.((ABS(xnewadd).LE.epsab).AND.
1982
+ & (ABS(oldadd).LE.epsab))) .AND.
1983
+ & (k.LE.1000) ) THEN
1984
+ GOTO 15
1985
+ ELSE
1986
+ kmax = k
1987
+ END IF
1988
+ ELSE
1989
+ kmax = 0
1990
+ END IF
1991
+ C
1992
+ END
1993
+
1994
+
1995
+ REAL*8 FUNCTION COEFFLN(k)
1996
+ C
1997
+ C The logarithm of the k-th coefficient in the hypergeometric series
1998
+ C that occurs in the expression for the velocity moment
1999
+ C of order (lr,lth,lph) (as contained in the common block /order/)
2000
+ C
2001
+ IMPLICIT REAL*8 (a-h,o-z)
2002
+ C
2003
+ COMMON /potent/ ipot
2004
+ C
2005
+ C ipot=1 for Kepler potential and ipot=2 for logarithmic potential
2006
+ C
2007
+ COMMON /DFcase/ icase
2008
+ C
2009
+ C icase=1 for the case I DFs, icase=2 for the case II DFs.
2010
+ C
2011
+ COMMON /param/ gamma, beta, q, alpha, eta
2012
+ COMMON /order/ lr,lth,lph
2013
+ C
2014
+ IF ((2*(lr/2).NE.lr).OR.(2*(lth/2).NE.lth)) THEN
2015
+ COEFFLN = 0.0D0
2016
+ RETURN
2017
+ END IF
2018
+ C
2019
+ IF (2*(lph/2).EQ.lph) THEN
2020
+ alp = 0.0D0
2021
+ ELSE
2022
+ alp = alpha
2023
+ END IF
2024
+ C
2025
+ dk = DBLE(k)
2026
+ dlr = DBLE(lr)
2027
+ dlth = DBLE(lth)
2028
+ dlph = DBLE(lph)
2029
+ C
2030
+ COEFFLN = pochln(0.5D0*gamma,k) - gammaln(dk+1.0D0) +
2031
+ & pochln(alp+(0.5D0*(dlph+1.0D0)),k) -
2032
+ & pochln(0.5D0,k) +
2033
+ & pochln(1.0D0,k) -
2034
+ & pochln(1.0D0+alp+(0.5D0*(dlth+dlph)),k)
2035
+ C
2036
+ IF (icase.EQ.1) THEN
2037
+ C
2038
+ IF (ipot.EQ.1) THEN
2039
+ COEFFLN = COEFFLN +
2040
+ & pochln(1.0D0-beta+alp+(0.5D0*(dlth+dlph)),k) -
2041
+ & pochln(1.0D0-beta,k) +
2042
+ & pochln(gamma-0.5D0-beta+alp,k) -
2043
+ & pochln(gamma-0.5D0-beta,k) +
2044
+ & pochln((0.5D0*(gamma+1.0D0))-beta,k) -
2045
+ & pochln((0.5D0*(gamma+1.0D0))-beta+alp+
2046
+ & (0.25D0*(dlr+dlth+dlph)),k) +
2047
+ & pochln(1.0D0-beta+(0.5D0*gamma),k) -
2048
+ & pochln(1.0D0-beta+(0.5D0*gamma)+alp+
2049
+ & (0.25D0*(dlr+dlth+dlph)),k)
2050
+ ELSE IF (ipot.EQ.2) THEN
2051
+ COEFFLN = COEFFLN +
2052
+ & pochln(1.0D0-beta+alp+(0.5D0*(dlth+dlph)),k) -
2053
+ & pochln(1.0D0-beta,k) +
2054
+ & ( (beta-1.5D0-dk-alp-(0.5D0*(dlr+dlth+dlph)))*
2055
+ & LOG(gamma-(2.0D0*beta)+(2.0D0*dk)+(2.0D0*alp)) ) -
2056
+ & ( (beta-1.5D0-dk)*
2057
+ & LOG(gamma-(2.0D0*beta)+(2.0D0*dk)) )
2058
+ ELSE
2059
+ STOP 'ipot wrong value'
2060
+ END IF
2061
+ C
2062
+ ELSE IF (icase.EQ.2) THEN
2063
+ C
2064
+ IF (ipot.EQ.1) THEN
2065
+ C
2066
+ C In this case the prefactor is the entire value of coeffln
2067
+ C
2068
+ ELSE IF (ipot.EQ.2) THEN
2069
+ C
2070
+ C Note that this factor could also be put in the prefactor PREFACLN because
2071
+ C it is independent of k (or dk=DOUBLE(k))
2072
+ C
2073
+ COEFFLN = COEFFLN +
2074
+ & ( (beta-1.5D0-alp-(0.5D0*(dlr+dlth+dlph)))*
2075
+ & LOG(gamma-(2.0D0*beta)+(2.0D0*alp)) ) -
2076
+ & ( (beta-1.5D0)*
2077
+ & LOG(gamma-(2.0D0*beta)) )
2078
+ C
2079
+ ELSE
2080
+ STOP 'ipot wrong value'
2081
+ END IF
2082
+ C
2083
+ ELSE
2084
+ C
2085
+ STOP 'icase wrong value'
2086
+ C
2087
+ END IF
2088
+ C
2089
+ END
2090
+
2091
+
2092
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2093
+ C
2094
+ C The functions gammaln, betaln, pochln and binomln calculate (the ln of)
2095
+ C mathematical expressions that are often needed. They are all based
2096
+ C indirectly on the function gammln in Numerical recipes which is accurate
2097
+ C approximately to 1.0D-10.
2098
+ C
2099
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2100
+
2101
+
2102
+ REAL*8 FUNCTION gammaln(x)
2103
+ C
2104
+ C The logarithm of the gamma function
2105
+ C
2106
+ IMPLICIT REAL*8 (a-h,o-z)
2107
+ PARAMETER (pi=3.14159265358979D0)
2108
+ IF (x.GE.1.0D0) THEN
2109
+ gammaln = gammln(x)
2110
+ ELSE IF (x.GE.0.0D0) THEN
2111
+ z = 1.0D0 - x
2112
+ gammaln = (LOG((pi*z)/SIN(pi*z))) - gammln(2.0D0-x)
2113
+ ELSE
2114
+ STOP 'x < 0 in gammaln'
2115
+ END IF
2116
+ END
2117
+
2118
+
2119
+ REAL*8 FUNCTION betaln(x,y)
2120
+ C
2121
+ C The logarithm of the beta function
2122
+ C
2123
+ IMPLICIT REAL*8 (a-h,o-z)
2124
+ betaln = gammaln(x) + gammaln(y) - gammaln(x+y)
2125
+ END
2126
+
2127
+
2128
+ REAL*8 FUNCTION pochln(x,k)
2129
+ C
2130
+ C The logarithm of Pochhammer's symbol
2131
+ C
2132
+ IMPLICIT REAL*8 (a-h,o-z)
2133
+ pochln = gammaln(x+DBLE(k)) - gammaln(x)
2134
+ END
2135
+
2136
+
2137
+ REAL*8 FUNCTION binomln(j,k)
2138
+ C
2139
+ C The logarithm of the binomial coefficient (j over k)
2140
+ C
2141
+ IMPLICIT REAL*8 (a-h,o-z)
2142
+ dj = DBLE(j)
2143
+ dk = DBLE(k)
2144
+ binomln = gammaln(dj+1.0D0) - gammaln(dk+1.0D0) -
2145
+ & gammaln(dj-dk+1.0D0)
2146
+ END
2147
+
2148
+
2149
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2150
+ C
2151
+ C The function EXPP is used throughout rather than the normal function
2152
+ C EXP, to avoid underflow.
2153
+ C
2154
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2155
+
2156
+ REAL*8 FUNCTION EXPP(x)
2157
+ C
2158
+ C Modified exponential function that will not underflow
2159
+ C
2160
+ IMPLICIT REAL*8 (a-h,o-z)
2161
+ IF (x.GE.-500D0) THEN
2162
+ EXPP = EXP(x)
2163
+ ELSE
2164
+ EXPP = 0.0D0
2165
+ END IF
2166
+ END
2167
+
2168
+
2169
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2170
+ C
2171
+ C A regularized vanderMonde matrix solver
2172
+ C
2173
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2174
+
2175
+
2176
+ SUBROUTINE REG_VANDER (x,w,q,n,xlam)
2177
+ C
2178
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2179
+ C
2180
+ C Solves a VanderMonde matrix with regularization.
2181
+ C Arguments are as in de subroutine VANDER from Numerical Recipes.
2182
+ C The input variable xlam is the regularization parameter.
2183
+ C
2184
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2185
+ C
2186
+ IMPLICIT REAL*8 (a-h,o-z)
2187
+ C
2188
+ INTEGER n,NMAX
2189
+ DIMENSION q(n),w(n),x(n)
2190
+ C
2191
+ PARAMETER (NMAX=101)
2192
+ C
2193
+ DIMENSION A(NMAX,NMAX), Anorm(NMAX,NMAX), H(NMAX,NMAX),
2194
+ & Areg(NMAX,NMAX), bnorm(NMAX), indx(NMAX)
2195
+ C
2196
+ CCCCCCCCCCCCCCCCCCCC
2197
+ C
2198
+ C Set up the matrix that occurs in the matrix equation that is to be solved.
2199
+ C
2200
+ DO i=1,n
2201
+ DO j=1,n
2202
+ A(i,j) = x(j)**(i-1)
2203
+ END DO
2204
+ END DO
2205
+ C
2206
+ C Calculate the matrix Atr*A that occurs in the normal equations.
2207
+ C
2208
+ DO i=1,n
2209
+ DO j=1,n
2210
+ Anorm(i,j) = 0.0D0
2211
+ DO k=1,n
2212
+ Anorm(i,j) = Anorm(i,j) + (A(k,i)*A(k,j))
2213
+ END DO
2214
+ END DO
2215
+ END DO
2216
+ C
2217
+ C Calculate the right-hand side vector Atr*q that occurs in the normal
2218
+ C equations.
2219
+ C
2220
+ DO i=1,n
2221
+ bnorm(i) = 0.0D0
2222
+ DO k=1,n
2223
+ bnorm(i) = bnorm(i) + (A(k,i)*q(k))
2224
+ END DO
2225
+ END DO
2226
+ C
2227
+ C Set up the desired regularization matrix H
2228
+ C
2229
+ CALL REGMAT2 (H,n,NMAX)
2230
+ C
2231
+ C Calculate the equipartition xlambda
2232
+ C
2233
+ Anormtr = 0.0D0
2234
+ Htr = 0.0D0
2235
+ DO i=1,n
2236
+ Anormtr = Anormtr + Anorm(i,i)
2237
+ Htr = Htr + H(i,i)
2238
+ END DO
2239
+ C
2240
+ xlameq = Anormtr / Htr
2241
+ C
2242
+ C Construct the regularized matrix
2243
+ C
2244
+ DO i=1,n
2245
+ DO j=1,n
2246
+ Areg(i,j) = Anorm(i,j) + (xlam*xlameq*H(i,j))
2247
+ END DO
2248
+ END DO
2249
+ C
2250
+ C The system to be solved is now: Areg*w = bnorm. The solution is found
2251
+ C with LU decomposition.
2252
+ C
2253
+ CALL LUDCMP (Areg,n,NMAX,indx,d)
2254
+ CALL LUBKSB (Areg,n,NMAX,indx,bnorm)
2255
+ C
2256
+ C The answer returned in bnorm is assigned to the vector w
2257
+ C
2258
+ DO i=1,n
2259
+ w(i) = bnorm(i)
2260
+ END DO
2261
+ C
2262
+ END
2263
+
2264
+
2265
+ SUBROUTINE REGMAT0 (H,n,np)
2266
+ C
2267
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2268
+ C
2269
+ C Set up a zeroth order regularization matrix
2270
+ C
2271
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2272
+ C
2273
+ IMPLICIT REAL*8 (a-h,o-z)
2274
+ C
2275
+ DIMENSION H(np,np)
2276
+ C
2277
+ IF (n.LE.2) STOP 'Matrix too small in REGMAT0'
2278
+ C
2279
+ DO i=1,n
2280
+ DO j=1,n
2281
+ H(i,j) = 0.0D0
2282
+ END DO
2283
+ END DO
2284
+ C
2285
+ H(1,1) = 1.0D0
2286
+ H(1,2) = -1.0D0
2287
+ C
2288
+ DO i=2,n-1
2289
+ H(i,i-1) = -1.0D0
2290
+ H(i,i) = 2.0D0
2291
+ H(i,i+1) = -1.0D0
2292
+ END DO
2293
+ C
2294
+ H(n,n-1) = -1.0D0
2295
+ H(n,n) = 1.0D0
2296
+ C
2297
+ END
2298
+
2299
+
2300
+ SUBROUTINE REGMAT1 (H,n,np)
2301
+ C
2302
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2303
+ C
2304
+ C Set up a first order regularization matrix
2305
+ C
2306
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2307
+ C
2308
+ IMPLICIT REAL*8 (a-h,o-z)
2309
+ C
2310
+ DIMENSION H(np,np)
2311
+ C
2312
+ IF (n.LE.4) STOP 'Matrix too small in REGMAT1'
2313
+ C
2314
+ DO i=1,n
2315
+ DO j=1,n
2316
+ H(i,j) = 0.0D0
2317
+ END DO
2318
+ END DO
2319
+ C
2320
+ H(1,1) = 1.0D0
2321
+ H(1,2) = -2.0D0
2322
+ H(1,3) = 1.0D0
2323
+ C
2324
+ H(2,1) = -2.0D0
2325
+ H(2,2) = 5.0D0
2326
+ H(2,3) = -4.0D0
2327
+ H(2,4) = 1.0D0
2328
+ C
2329
+ DO i=3,n-2
2330
+ H(i,i-2) = 1.0D0
2331
+ H(i,i-1) = -4.0D0
2332
+ H(i,i) = 6.0D0
2333
+ H(i,i+1) = -4.0D0
2334
+ H(i,i+2) = 1.0D0
2335
+ END DO
2336
+ C
2337
+ H(n-1,n-3) = 1.0D0
2338
+ H(n-1,n-2) = -4.0D0
2339
+ H(n-1,n-1) = 5.0D0
2340
+ H(n-1,n) = -2.0D0
2341
+ C
2342
+ H(n,n-2) = 1.0D0
2343
+ H(n,n-1) = -2.0D0
2344
+ H(n,n) = 1.0D0
2345
+ C
2346
+ END
2347
+
2348
+
2349
+ SUBROUTINE REGMAT2 (H,n,np)
2350
+ C
2351
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2352
+ C
2353
+ C Set up a second order regularization matrix
2354
+ C
2355
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2356
+ C
2357
+ IMPLICIT REAL*8 (a-h,o-z)
2358
+ C
2359
+ DIMENSION H(np,np)
2360
+ C
2361
+ IF (n.LE.6) STOP 'Matrix too small in REGMAT2'
2362
+ C
2363
+ DO i=1,n
2364
+ DO j=1,n
2365
+ H(i,j) = 0.0D0
2366
+ END DO
2367
+ END DO
2368
+ C
2369
+ H(1,1) = 1.0D0
2370
+ H(1,2) = -3.0D0
2371
+ H(1,3) = 3.0D0
2372
+ H(1,4) = -1.0D0
2373
+ C
2374
+ H(2,1) = -3.0D0
2375
+ H(2,2) = 10.0D0
2376
+ H(2,3) = -12.0D0
2377
+ H(2,4) = 6.0D0
2378
+ H(2,5) = -1.0D0
2379
+ C
2380
+ H(3,1) = 3.0D0
2381
+ H(3,2) = -12.0D0
2382
+ H(3,3) = 19.0D0
2383
+ H(3,4) = -15.0D0
2384
+ H(3,5) = 6.0D0
2385
+ H(3,6) = -1.0D0
2386
+ C
2387
+ DO i=4,n-3
2388
+ H(i,i-3) = -1.0D0
2389
+ H(i,i-2) = 6.0D0
2390
+ H(i,i-1) = -15.0D0
2391
+ H(i,i) = 20.0D0
2392
+ H(i,i+1) = -15.0D0
2393
+ H(i,i+2) = 6.0D0
2394
+ H(i,i+3) = -1.0D0
2395
+ END DO
2396
+ C
2397
+ H(n-2,n-5) = -1.0D0
2398
+ H(n-2,n-4) = 6.0D0
2399
+ H(n-2,n-3) = -15.0D0
2400
+ H(n-2,n-2) = 19.0D0
2401
+ H(n-2,n-1) = -12.0D0
2402
+ H(n-2,n) = 3.0D0
2403
+ C
2404
+ H(n-1,n-4) = -1.0D0
2405
+ H(n-1,n-3) = 6.0D0
2406
+ H(n-1,n-2) = -12.0D0
2407
+ H(n-1,n-1) = 10.0D0
2408
+ H(n-1,n) = -3.0D0
2409
+ C
2410
+ H(n,n-3) = -1.0D0
2411
+ H(n,n-2) = 3.0D0
2412
+ H(n,n-1) = -3.0D0
2413
+ H(n,n) = 1.0D0
2414
+ C
2415
+ END
2416
+
2417
+
2418
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2419
+ C
2420
+ C Required routines from Numerical recipes. All were modified to
2421
+ C be double precision. The parameter eps in QROMO determines the
2422
+ C speed of the program in calculating the VP parameters. Best results
2423
+ C are obtained with eps=1.0D-8, but this leads to a slow program.
2424
+ C
2425
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2426
+
2427
+
2428
+ REAL*8 FUNCTION gammln(x)
2429
+ C
2430
+ C Modified to be double precision
2431
+ C
2432
+ IMPLICIT REAL*8 (a-h,o-z)
2433
+ INTEGER j
2434
+ DIMENSION cof(6)
2435
+ SAVE cof,stp
2436
+ DATA cof,stp/76.18009172947146d0,-86.50532032941677d0,
2437
+ *24.01409824083091d0,-1.231739572450155d0,.1208650973866179d-2,
2438
+ *-.5395239384953d-5,2.5066282746310005d0/
2439
+ y=x
2440
+ tmp=x+5.5d0
2441
+ tmp=(x+0.5d0)*log(tmp)-tmp
2442
+ ser=1.000000000190015d0
2443
+ do 11 j=1,6
2444
+ y=y+1.d0
2445
+ ser=ser+cof(j)/y
2446
+ 11 continue
2447
+ gammln=tmp+log(stp*ser/x)
2448
+ return
2449
+ END
2450
+
2451
+
2452
+ SUBROUTINE qgausleg(func,a,b,ss)
2453
+ C
2454
+ C Modified version of qgaus. Common block /gleg/ must have been
2455
+ C filled previously
2456
+ C
2457
+ IMPLICIT REAL*8 (a-h,o-z)
2458
+ REAL*8 a,b,ss,func
2459
+ EXTERNAL func
2460
+ COMMON /gleg/ qx(300),qw(300),nGL
2461
+ ss = 0.0D0
2462
+ DO i=1,nGL
2463
+ ss = ss + (qw(i)*func(a+(qx(i)*(b-a))))
2464
+ END DO
2465
+ ss = ss*(b-a)
2466
+ END
2467
+
2468
+
2469
+ SUBROUTINE gauleg(x1,x2,x,w,n)
2470
+ C
2471
+ C Modified to be double precision
2472
+ C
2473
+ IMPLICIT REAL*8 (a-h,o-z)
2474
+ INTEGER n
2475
+ REAL*8 x1,x2,x(n),w(n)
2476
+ PARAMETER (EPS=3.0D-14)
2477
+ INTEGER i,j,m
2478
+ m=(n+1)/2
2479
+ xm=0.5d0*(x2+x1)
2480
+ xl=0.5d0*(x2-x1)
2481
+ do 12 i=1,m
2482
+ z=cos(3.141592654d0*(i-.25d0)/(n+.5d0))
2483
+ 1 continue
2484
+ p1=1.d0
2485
+ p2=0.d0
2486
+ do 11 j=1,n
2487
+ p3=p2
2488
+ p2=p1
2489
+ p1=((2.d0*j-1.d0)*z*p2-(j-1.d0)*p3)/j
2490
+ 11 continue
2491
+ pp=n*(z*p1-p2)/(z*z-1.d0)
2492
+ z1=z
2493
+ z=z1-p1/pp
2494
+ if(abs(z-z1).gt.EPS)goto 1
2495
+ x(i)=xm-xl*z
2496
+ x(n+1-i)=xm+xl*z
2497
+ w(i)=2.d0*xl/((1.d0-z*z)*pp*pp)
2498
+ w(n+1-i)=w(i)
2499
+ 12 continue
2500
+ return
2501
+ END
2502
+
2503
+
2504
+ SUBROUTINE qromo(func,a,b,ss,choose)
2505
+ C
2506
+ C Modified to be double precision, and to receive eps from common block
2507
+ C
2508
+ IMPLICIT REAL*8 (a-h,o-z)
2509
+ INTEGER JMAX,JMAXP,K,KM
2510
+ REAL*8 a,b,func,ss,EPS
2511
+ COMMON /romoeps/ eps
2512
+ EXTERNAL func,choose
2513
+ PARAMETER (JMAX=14, JMAXP=JMAX+1, K=5, KM=K-1)
2514
+ CU USES polint
2515
+ INTEGER j
2516
+ REAL*8 dss,h(JMAXP),s(JMAXP)
2517
+ h(1)=1.0D0
2518
+ do 11 j=1,JMAX
2519
+ call choose(func,a,b,s(j),j)
2520
+ if (j.ge.K) then
2521
+ call polint(h(j-KM),s(j-KM),K,0.0D0,ss,dss)
2522
+ if (abs(dss).le.EPS*abs(ss)) return
2523
+ endif
2524
+ s(j+1)=s(j)
2525
+ h(j+1)=h(j)/9.0D0
2526
+ 11 continue
2527
+ STOP 'too many steps in qromo'
2528
+ END
2529
+
2530
+
2531
+ SUBROUTINE trapzd(func,a,b,s,n)
2532
+ C
2533
+ C Modified to be double precision
2534
+ C
2535
+ IMPLICIT REAL*8 (a-h,o-z)
2536
+ INTEGER n
2537
+ REAL*8 a,b,s,func
2538
+ EXTERNAL func
2539
+ INTEGER it,j
2540
+ REAL*8 del,sum,tnm,x
2541
+ if (n.eq.1) then
2542
+ s=0.5D0*(b-a)*(func(a)+func(b))
2543
+ else
2544
+ it=2**(n-2)
2545
+ tnm=it
2546
+ del=(b-a)/tnm
2547
+ x=a+0.5D0*del
2548
+ sum=0.0D0
2549
+ do 11 j=1,it
2550
+ sum=sum+func(x)
2551
+ x=x+del
2552
+ 11 continue
2553
+ s=0.5D0*(s+(b-a)*sum/tnm)
2554
+ endif
2555
+ return
2556
+ END
2557
+
2558
+
2559
+ SUBROUTINE polint(xa,ya,n,x,y,dy)
2560
+ C
2561
+ C Modified to be double precision
2562
+ C
2563
+ IMPLICIT REAL*8 (a-h,o-z)
2564
+ INTEGER n,NMAX
2565
+ REAL*8 dy,x,y,xa(n),ya(n)
2566
+ PARAMETER (NMAX=10)
2567
+ INTEGER i,m,ns
2568
+ REAL*8 den,dif,dift,ho,hp,w,c(NMAX),d(NMAX)
2569
+ ns=1
2570
+ dif=abs(x-xa(1))
2571
+ do 11 i=1,n
2572
+ dift=abs(x-xa(i))
2573
+ if (dift.lt.dif) then
2574
+ ns=i
2575
+ dif=dift
2576
+ endif
2577
+ c(i)=ya(i)
2578
+ d(i)=ya(i)
2579
+ 11 continue
2580
+ y=ya(ns)
2581
+ ns=ns-1
2582
+ do 13 m=1,n-1
2583
+ do 12 i=1,n-m
2584
+ ho=xa(i)-x
2585
+ hp=xa(i+m)-x
2586
+ w=c(i+1)-d(i)
2587
+ den=ho-hp
2588
+ if(den.eq.0.0D0)STOP 'failure in polint'
2589
+ den=w/den
2590
+ d(i)=hp*den
2591
+ c(i)=ho*den
2592
+ 12 continue
2593
+ if (2*ns.lt.n-m)then
2594
+ dy=c(ns+1)
2595
+ else
2596
+ dy=d(ns)
2597
+ ns=ns-1
2598
+ endif
2599
+ y=y+dy
2600
+ 13 continue
2601
+ return
2602
+ END
2603
+
2604
+
2605
+ SUBROUTINE midpnt(func,a,b,s,n)
2606
+ C
2607
+ C Modified to be double precision
2608
+ C
2609
+ IMPLICIT REAL*8 (a-h,o-z)
2610
+ INTEGER n
2611
+ REAL*8 a,b,s,func
2612
+ EXTERNAL func
2613
+ INTEGER it,j
2614
+ REAL*8 ddel,del,sum,tnm,x
2615
+ if (n.eq.1) then
2616
+ s=(b-a)*func(0.5D0*(a+b))
2617
+ else
2618
+ it=3**(n-2)
2619
+ tnm=it
2620
+ del=(b-a)/(3.0D0*tnm)
2621
+ ddel=del+del
2622
+ x=a+0.5D0*del
2623
+ sum=0.0D0
2624
+ do 11 j=1,it
2625
+ sum=sum+func(x)
2626
+ x=x+ddel
2627
+ sum=sum+func(x)
2628
+ x=x+del
2629
+ 11 continue
2630
+ s=(s+(b-a)*sum/tnm)/3.0D0
2631
+ endif
2632
+ return
2633
+ END
2634
+
2635
+
2636
+ SUBROUTINE vander(x,w,q,n)
2637
+ C
2638
+ C Modified to be double precision
2639
+ C
2640
+ IMPLICIT REAL*8 (a-h,o-z)
2641
+ INTEGER n,NMAX
2642
+ DIMENSION q(n),w(n),x(n)
2643
+ PARAMETER (NMAX=101)
2644
+ INTEGER i,j,k,k1
2645
+ DOUBLE PRECISION b,s,t,xx,c(NMAX)
2646
+ if(n.eq.1)then
2647
+ w(1)=q(1)
2648
+ else
2649
+ do 11 i=1,n
2650
+ c(i)=0.d0
2651
+ 11 continue
2652
+ c(n)=-x(1)
2653
+ do 13 i=2,n
2654
+ xx=-x(i)
2655
+ do 12 j=n+1-i,n-1
2656
+ c(j)=c(j)+xx*c(j+1)
2657
+ 12 continue
2658
+ c(n)=c(n)+xx
2659
+ 13 continue
2660
+ do 15 i=1,n
2661
+ xx=x(i)
2662
+ t=1.d0
2663
+ b=1.d0
2664
+ s=q(n)
2665
+ k=n
2666
+ do 14 j=2,n
2667
+ k1=k-1
2668
+ b=c(k)+xx*b
2669
+ s=s+q(k1)*b
2670
+ t=xx*t+b
2671
+ k=k1
2672
+ 14 continue
2673
+ w(i)=s/t
2674
+ 15 continue
2675
+ endif
2676
+ return
2677
+ END
2678
+
2679
+
2680
+ SUBROUTINE amoeba(p,y,mp,np,ndim,ftol,funk,iter)
2681
+ C
2682
+ C Modified to be double precision
2683
+ C
2684
+ IMPLICIT REAL*8 (a-h,o-z)
2685
+ INTEGER iter,mp,ndim,np,NMAX,ITMAX
2686
+ REAL*8 ftol,p(mp,np),y(mp),funk
2687
+ PARAMETER (NMAX=20,ITMAX=5000)
2688
+ EXTERNAL funk
2689
+ CU USES amotry,funk
2690
+ INTEGER i,ihi,ilo,inhi,j,m,n
2691
+ REAL*8 rtol,sum,swap,ysave,ytry,psum(NMAX),amotry
2692
+ iter=0
2693
+ 1 do 12 n=1,ndim
2694
+ sum=0.0D0
2695
+ do 11 m=1,ndim+1
2696
+ sum=sum+p(m,n)
2697
+ 11 continue
2698
+ psum(n)=sum
2699
+ 12 continue
2700
+ 2 ilo=1
2701
+ if (y(1).gt.y(2)) then
2702
+ ihi=1
2703
+ inhi=2
2704
+ else
2705
+ ihi=2
2706
+ inhi=1
2707
+ endif
2708
+ do 13 i=1,ndim+1
2709
+ if(y(i).le.y(ilo)) ilo=i
2710
+ if(y(i).gt.y(ihi)) then
2711
+ inhi=ihi
2712
+ ihi=i
2713
+ else if(y(i).gt.y(inhi)) then
2714
+ if(i.ne.ihi) inhi=i
2715
+ endif
2716
+ 13 continue
2717
+ rtol=2.0D0*abs(y(ihi)-y(ilo))/(abs(y(ihi))+abs(y(ilo)))
2718
+ if (rtol.lt.ftol) then
2719
+ swap=y(1)
2720
+ y(1)=y(ilo)
2721
+ y(ilo)=swap
2722
+ do 14 n=1,ndim
2723
+ swap=p(1,n)
2724
+ p(1,n)=p(ilo,n)
2725
+ p(ilo,n)=swap
2726
+ 14 continue
2727
+ return
2728
+ endif
2729
+ C
2730
+ C Possibility to write intermediate results
2731
+ C
2732
+ C WRITE (*,'(I5,4F15.8)') iter,(p(ilo,j),j=1,3),y(ilo)
2733
+ C
2734
+ if (iter.ge.ITMAX) then
2735
+ write (*,*) 'ITMAX exceeded in amoeba'
2736
+ return
2737
+ endif
2738
+ iter=iter+2
2739
+ ytry=amotry(p,y,psum,mp,np,ndim,funk,ihi,-1.0D0)
2740
+ if (ytry.le.y(ilo)) then
2741
+ ytry=amotry(p,y,psum,mp,np,ndim,funk,ihi,2.0D0)
2742
+ else if (ytry.ge.y(inhi)) then
2743
+ ysave=y(ihi)
2744
+ ytry=amotry(p,y,psum,mp,np,ndim,funk,ihi,0.5D0)
2745
+ if (ytry.ge.ysave) then
2746
+ do 16 i=1,ndim+1
2747
+ if(i.ne.ilo)then
2748
+ do 15 j=1,ndim
2749
+ psum(j)=0.5D0*(p(i,j)+p(ilo,j))
2750
+ p(i,j)=psum(j)
2751
+ 15 continue
2752
+ y(i)=funk(psum)
2753
+ endif
2754
+ 16 continue
2755
+ iter=iter+ndim
2756
+ goto 1
2757
+ endif
2758
+ else
2759
+ iter=iter-1
2760
+ endif
2761
+ goto 2
2762
+ END
2763
+
2764
+
2765
+ REAL*8 FUNCTION amotry(p,y,psum,mp,np,ndim,funk,ihi,fac)
2766
+ C
2767
+ C Modified to be double precision
2768
+ C
2769
+ IMPLICIT REAL*8 (a-h,o-z)
2770
+ INTEGER ihi,mp,ndim,np,NMAX
2771
+ REAL*8 fac,p(mp,np),psum(np),y(mp),funk
2772
+ PARAMETER (NMAX=20)
2773
+ EXTERNAL funk
2774
+ CU USES funk
2775
+ INTEGER j
2776
+ REAL*8 fac1,fac2,ytry,ptry(NMAX)
2777
+ fac1=(1.0D0-fac)/ndim
2778
+ fac2=fac1-fac
2779
+ do 11 j=1,ndim
2780
+ ptry(j)=psum(j)*fac1-p(ihi,j)*fac2
2781
+ 11 continue
2782
+ ytry=funk(ptry)
2783
+ if (ytry.lt.y(ihi)) then
2784
+ y(ihi)=ytry
2785
+ do 12 j=1,ndim
2786
+ psum(j)=psum(j)-p(ihi,j)+ptry(j)
2787
+ p(ihi,j)=ptry(j)
2788
+ 12 continue
2789
+ endif
2790
+ amotry=ytry
2791
+ return
2792
+ END
2793
+
2794
+
2795
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2796
+ C
2797
+ C Numerical Recipes routines, transformed to double precision, for
2798
+ C Regularized VanderMonde matrix solution.
2799
+ C
2800
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2801
+
2802
+ SUBROUTINE ludcmp(a,n,np,indx,d)
2803
+ IMPLICIT REAL*8 (a-h,o-z)
2804
+ INTEGER n,np,indx(n),NMAX
2805
+ REAL*8 d,a(np,np),TINY
2806
+ PARAMETER (NMAX=500,TINY=1.0D-20)
2807
+ INTEGER i,imax,j,k
2808
+ REAL*8 aamax,dum,sum,vv(NMAX)
2809
+ d=1.0D0
2810
+ do 12 i=1,n
2811
+ aamax=0.0D0
2812
+ do 11 j=1,n
2813
+ if (abs(a(i,j)).gt.aamax) aamax=abs(a(i,j))
2814
+ 11 continue
2815
+ if (aamax.eq.0.0D0) STOP 'singular matrix in ludcmp'
2816
+ vv(i)=1.0D0/aamax
2817
+ 12 continue
2818
+ do 19 j=1,n
2819
+ do 14 i=1,j-1
2820
+ sum=a(i,j)
2821
+ do 13 k=1,i-1
2822
+ sum=sum-a(i,k)*a(k,j)
2823
+ 13 continue
2824
+ a(i,j)=sum
2825
+ 14 continue
2826
+ aamax=0.0D0
2827
+ do 16 i=j,n
2828
+ sum=a(i,j)
2829
+ do 15 k=1,j-1
2830
+ sum=sum-a(i,k)*a(k,j)
2831
+ 15 continue
2832
+ a(i,j)=sum
2833
+ dum=vv(i)*abs(sum)
2834
+ if (dum.ge.aamax) then
2835
+ imax=i
2836
+ aamax=dum
2837
+ endif
2838
+ 16 continue
2839
+ if (j.ne.imax)then
2840
+ do 17 k=1,n
2841
+ dum=a(imax,k)
2842
+ a(imax,k)=a(j,k)
2843
+ a(j,k)=dum
2844
+ 17 continue
2845
+ d=-d
2846
+ vv(imax)=vv(j)
2847
+ endif
2848
+ indx(j)=imax
2849
+ if(a(j,j).eq.0.0D0)a(j,j)=TINY
2850
+ if(j.ne.n)then
2851
+ dum=1.0D0/a(j,j)
2852
+ do 18 i=j+1,n
2853
+ a(i,j)=a(i,j)*dum
2854
+ 18 continue
2855
+ endif
2856
+ 19 continue
2857
+ return
2858
+ END
2859
+
2860
+
2861
+ SUBROUTINE lubksb(a,n,np,indx,b)
2862
+ IMPLICIT REAL*8 (a-h,o-z)
2863
+ INTEGER n,np,indx(n)
2864
+ REAL*8 a(np,np),b(n)
2865
+ INTEGER i,ii,j,ll
2866
+ REAL*8 sum
2867
+ ii=0
2868
+ do 12 i=1,n
2869
+ ll=indx(i)
2870
+ sum=b(ll)
2871
+ b(ll)=b(i)
2872
+ if (ii.ne.0)then
2873
+ do 11 j=ii,i-1
2874
+ sum=sum-a(i,j)*b(j)
2875
+ 11 continue
2876
+ else if (sum.ne.0.0D0) then
2877
+ ii=i
2878
+ endif
2879
+ b(i)=sum
2880
+ 12 continue
2881
+ do 14 i=n,1,-1
2882
+ sum=b(i)
2883
+ do 13 j=i+1,n
2884
+ sum=sum-a(i,j)*b(j)
2885
+ 13 continue
2886
+ b(i)=sum/a(i,i)
2887
+ 14 continue
2888
+ return
2889
+ END
2890
+
2891
+
2892
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2893
+ C
2894
+ C All routines below are obsolete. However, they were kept because they
2895
+ C might turn out to be useful one day.
2896
+ C
2897
+ C The function densradius defines the relation r(theta) for an isodensity
2898
+ C surface. The SUBROUTINE CONTOUR_ANALYSIS finds the best-fitting ellipse
2899
+ C and does a Fourier analysis. In doing so it uses the Numerical Recipes
2900
+ C routines cosft1, four1 and realft, which were kept at single precision.
2901
+ C
2902
+ C The calling sequence from the main program is:
2903
+ C EXTERNAL DENSRADIUS
2904
+ C CALL CONTOUR_ANALYSIS (DENSRADIUS)
2905
+ C
2906
+ C In our model the density is always perfectly spheroidal, so the results
2907
+ C are rather uninteresting. However, CONTOUR_ANALYSIS can be used for any
2908
+ C function r(theta), so it could be used, e.g., to determine the shape
2909
+ C of the contours of the projected velocity dispersion on the sky.
2910
+ C
2911
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
2912
+
2913
+ REAL*8 FUNCTION DENSRADIUS (theta)
2914
+ C
2915
+ C The radius r of a point at polar angle theta, on the isodensity
2916
+ C surface with rho = 1.
2917
+ C
2918
+ IMPLICIT REAL*8 (a-h,o-z)
2919
+ C
2920
+ COMMON /param/ gamma, beta, q, alpha, eta
2921
+ C
2922
+ DENSRADIUS = RHOVELMOM(theta,0,0,0)**(1.0/gamma)
2923
+ C
2924
+ END
2925
+
2926
+
2927
+ SUBROUTINE CONTOUR_ANALYSIS (RADIUS)
2928
+ C
2929
+ C Given a function RADIUS, that returns a radius as function of polar angle
2930
+ C theta, do a shape analysis of the contour defined by this function. Four-fold
2931
+ C symmetry is assumed.
2932
+ C
2933
+ IMPLICIT REAL*8 (a-h,o-z)
2934
+ C
2935
+ PARAMETER (pi=3.14159265358979D0)
2936
+ C
2937
+ EXTERNAL RADIUS
2938
+ C
2939
+ DIMENSION radarr(10000)
2940
+ REAL radreal(10000)
2941
+ C
2942
+ C Estimate the axis ratio by taking the ratio of points on the
2943
+ C major and minor axis
2944
+ C
2945
+ qest = RADIUS(0.0D0)/RADIUS(pi/2.0D0)
2946
+ C
2947
+ C We now write the radius to an array and Fourier analyse it.
2948
+ C Rather than using the conventional polar coordinates (r,theta), we
2949
+ C use elliptical coordinates, such that
2950
+ C R = s sin(tau)
2951
+ C z = s qcoord cos(tau)
2952
+ C
2953
+ N2pow = 256
2954
+ qcoord = qest
2955
+ C
2956
+ 25 DO i=1,N2pow+1
2957
+ C
2958
+ C Choose tau, spaced linearly between 0 and pi/2.
2959
+ C
2960
+ tau = ((pi/2.0D0)/(DBLE(N2pow)))*DBLE(i-1)
2961
+ C
2962
+ C Calculate the correspinding theta
2963
+ C
2964
+ theta = ATAN(TAN(tau)/qcoord)
2965
+ st = SIN(theta)
2966
+ ct = COS(theta)
2967
+ C
2968
+ C Calculate the corresponding radius
2969
+ C
2970
+ radthet = RADIUS(theta)
2971
+ C
2972
+ C Calculate and store the corresponding elliptical radius
2973
+ C
2974
+ radarr(i) = radthet *
2975
+ & SQRT((st**2.0D0)+((ct/qcoord)**2.0D0))
2976
+ radreal(i) = REAL(radarr(i))
2977
+ C
2978
+ END DO
2979
+ C
2980
+ C Get the Fourier cosine decomposition of the array radarr. If the
2981
+ C contour is a perfect ellipse, the only the lowest order (constant)
2982
+ C term in the transfrom is non-zero. If the cos (2 tau) is non-zero, then
2983
+ C we should choose a different qcoord, and iterate.
2984
+ C
2985
+ CALL COSFT1(radreal,N2pow)
2986
+ C
2987
+ C radarr now contains the Fourier cosine series, which we properly normalize,
2988
+ C and make double precision again.
2989
+ C
2990
+ semimajor = DBLE(radreal(1))/DBLE(N2pow)
2991
+ radarr(1) = 1.0D0
2992
+ DO i=2,N2pow+1
2993
+ radarr(i) = 2.0D0*DBLE(radreal(i))/(DBLE(N2pow)*semimajor)
2994
+ END DO
2995
+ C
2996
+ C No verbose output on the screen please
2997
+ C
2998
+ iverb = 0
2999
+ IF (iverb.EQ.1) THEN
3000
+ WRITE (*,'(A5,F12.8)') ' ', semimajor
3001
+ DO i=1,5
3002
+ WRITE (*,'(I5,F12.8)') 2*(i-1),radarr(i)
3003
+ END DO
3004
+ WRITE (*,*) ' '
3005
+ END IF
3006
+ C
3007
+ C If the COS(2 tau) coefficient is too big, then change qcoord.
3008
+ C The formula for doing this is obtained by writing the equations
3009
+ C for a pure ellipse with axial ratio q, in elliptical coordinates
3010
+ C with axial ratio q'. After Fourier expanding the equation s'(tau'),
3011
+ C the cos(2 tau') coefficient is to lowest order directly related to (q/q').
3012
+ C
3013
+ IF (ABS(radarr(2)).GE.1.0D-8) THEN
3014
+ qcoord = qcoord * (1.0D0 + (2.0D0*radarr(2)))
3015
+ qcoord = MAX(0.0D0,MIN(qcoord,1.0D0))
3016
+ GOTO 25
3017
+ END IF
3018
+ C
3019
+ C Write results to the screen
3020
+ C
3021
+ WRITE (*,'(A45,F15.8)') 'Ratio major/minor of contour',qest
3022
+ WRITE (*,'(A45,F15.8)') 'axial ratio best fitting ellipse',
3023
+ & qcoord
3024
+ WRITE (*,'(A45,F15.8)') 'semi-major axis best fitting ellipse',
3025
+ & semimajor
3026
+ WRITE (*,'(A45,F15.8)') 'cos(4 theta) coefficient',
3027
+ & radarr(3)/radarr(1)
3028
+ WRITE (*,'(A45,F15.8)') 'cos(6 theta) coefficient',
3029
+ & radarr(4)/radarr(1)
3030
+ WRITE (*,'(A45,F15.8)') 'cos(8 theta) coefficient',
3031
+ & radarr(5)/radarr(1)
3032
+ C
3033
+ END
3034
+
3035
+
3036
+ SUBROUTINE realft(data,n,isign)
3037
+ INTEGER isign,n
3038
+ REAL data(n)
3039
+ CU USES four1
3040
+ INTEGER i,i1,i2,i3,i4,n2p3
3041
+ REAL c1,c2,h1i,h1r,h2i,h2r,wis,wrs
3042
+ DOUBLE PRECISION theta,wi,wpi,wpr,wr,wtemp
3043
+ theta=3.141592653589793d0/dble(n/2)
3044
+ c1=0.5
3045
+ if (isign.eq.1) then
3046
+ c2=-0.5
3047
+ call four1(data,n/2,+1)
3048
+ else
3049
+ c2=0.5
3050
+ theta=-theta
3051
+ endif
3052
+ wpr=-2.0d0*sin(0.5d0*theta)**2
3053
+ wpi=sin(theta)
3054
+ wr=1.0d0+wpr
3055
+ wi=wpi
3056
+ n2p3=n+3
3057
+ do 11 i=2,n/4
3058
+ i1=2*i-1
3059
+ i2=i1+1
3060
+ i3=n2p3-i2
3061
+ i4=i3+1
3062
+ wrs=sngl(wr)
3063
+ wis=sngl(wi)
3064
+ h1r=c1*(data(i1)+data(i3))
3065
+ h1i=c1*(data(i2)-data(i4))
3066
+ h2r=-c2*(data(i2)+data(i4))
3067
+ h2i=c2*(data(i1)-data(i3))
3068
+ data(i1)=h1r+wrs*h2r-wis*h2i
3069
+ data(i2)=h1i+wrs*h2i+wis*h2r
3070
+ data(i3)=h1r-wrs*h2r+wis*h2i
3071
+ data(i4)=-h1i+wrs*h2i+wis*h2r
3072
+ wtemp=wr
3073
+ wr=wr*wpr-wi*wpi+wr
3074
+ wi=wi*wpr+wtemp*wpi+wi
3075
+ 11 continue
3076
+ if (isign.eq.1) then
3077
+ h1r=data(1)
3078
+ data(1)=h1r+data(2)
3079
+ data(2)=h1r-data(2)
3080
+ else
3081
+ h1r=data(1)
3082
+ data(1)=c1*(h1r+data(2))
3083
+ data(2)=c1*(h1r-data(2))
3084
+ call four1(data,n/2,-1)
3085
+ endif
3086
+ return
3087
+ END
3088
+
3089
+
3090
+ SUBROUTINE four1(data,nn,isign)
3091
+ INTEGER isign,nn
3092
+ REAL data(2*nn)
3093
+ INTEGER i,istep,j,m,mmax,n
3094
+ REAL tempi,tempr
3095
+ DOUBLE PRECISION theta,wi,wpi,wpr,wr,wtemp
3096
+ n=2*nn
3097
+ j=1
3098
+ do 11 i=1,n,2
3099
+ if(j.gt.i)then
3100
+ tempr=data(j)
3101
+ tempi=data(j+1)
3102
+ data(j)=data(i)
3103
+ data(j+1)=data(i+1)
3104
+ data(i)=tempr
3105
+ data(i+1)=tempi
3106
+ endif
3107
+ m=n/2
3108
+ 1 if ((m.ge.2).and.(j.gt.m)) then
3109
+ j=j-m
3110
+ m=m/2
3111
+ goto 1
3112
+ endif
3113
+ j=j+m
3114
+ 11 continue
3115
+ mmax=2
3116
+ 2 if (n.gt.mmax) then
3117
+ istep=2*mmax
3118
+ theta=6.28318530717959d0/(isign*mmax)
3119
+ wpr=-2.d0*sin(0.5d0*theta)**2
3120
+ wpi=sin(theta)
3121
+ wr=1.d0
3122
+ wi=0.d0
3123
+ do 13 m=1,mmax,2
3124
+ do 12 i=m,n,istep
3125
+ j=i+mmax
3126
+ tempr=sngl(wr)*data(j)-sngl(wi)*data(j+1)
3127
+ tempi=sngl(wr)*data(j+1)+sngl(wi)*data(j)
3128
+ data(j)=data(i)-tempr
3129
+ data(j+1)=data(i+1)-tempi
3130
+ data(i)=data(i)+tempr
3131
+ data(i+1)=data(i+1)+tempi
3132
+ 12 continue
3133
+ wtemp=wr
3134
+ wr=wr*wpr-wi*wpi+wr
3135
+ wi=wi*wpr+wtemp*wpi+wi
3136
+ 13 continue
3137
+ mmax=istep
3138
+ goto 2
3139
+ endif
3140
+ return
3141
+ END
3142
+
3143
+
3144
+ SUBROUTINE cosft1(y,n)
3145
+ INTEGER n
3146
+ REAL y(n+1)
3147
+ CU USES realft
3148
+ INTEGER j
3149
+ REAL sum,y1,y2
3150
+ DOUBLE PRECISION theta,wi,wpi,wpr,wr,wtemp
3151
+ theta=3.141592653589793d0/n
3152
+ wr=1.0d0
3153
+ wi=0.0d0
3154
+ wpr=-2.0d0*sin(0.5d0*theta)**2
3155
+ wpi=sin(theta)
3156
+ sum=0.5*(y(1)-y(n+1))
3157
+ y(1)=0.5*(y(1)+y(n+1))
3158
+ do 11 j=1,n/2-1
3159
+ wtemp=wr
3160
+ wr=wr*wpr-wi*wpi+wr
3161
+ wi=wi*wpr+wtemp*wpi+wi
3162
+ y1=0.5*(y(j+1)+y(n-j+1))
3163
+ y2=(y(j+1)-y(n-j+1))
3164
+ y(j+1)=y1-wi*y2
3165
+ y(n-j+1)=y1+wi*y2
3166
+ sum=sum+wr*y2
3167
+ 11 continue
3168
+ call realft(y,n,+1)
3169
+ y(n+1)=y(2)
3170
+ y(2)=sum
3171
+ do 12 j=4,n,2
3172
+ sum=sum+y(j)
3173
+ y(j)=sum
3174
+ 12 continue
3175
+ return
3176
+ END
3177
+
3178
+
3179
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
3180
+ C
3181
+ C Copies of routines already given above, but with slightly modified names,
3182
+ C to avoid recursive calling when evaluating double integrals.
3183
+ C
3184
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
3185
+
3186
+ SUBROUTINE qgauslegB(func,a,b,ss)
3187
+ C
3188
+ C Modified version of qgaus. Common block /gleg/ must have been
3189
+ C filled previously
3190
+ C
3191
+ IMPLICIT REAL*8 (a-h,o-z)
3192
+ REAL*8 a,b,ss,func
3193
+ EXTERNAL func
3194
+ COMMON /gleg/ qx(300),qw(300),nGL
3195
+ ss = 0.0D0
3196
+ DO i=1,nGL
3197
+ ss = ss + (qw(i)*func(a+(qx(i)*(b-a))))
3198
+ END DO
3199
+ ss = ss*(b-a)
3200
+ END
3201
+
3202
+
3203
+ SUBROUTINE qromoB(func,a,b,ss,choose)
3204
+ C
3205
+ C Modified to be double precision, and to receive eps from common block
3206
+ C
3207
+ IMPLICIT REAL*8 (a-h,o-z)
3208
+ INTEGER JMAX,JMAXP,K,KM
3209
+ REAL*8 a,b,func,ss,EPS
3210
+ COMMON /romoeps/ eps
3211
+ EXTERNAL func,choose
3212
+ PARAMETER (JMAX=14, JMAXP=JMAX+1, K=5, KM=K-1)
3213
+ CU USES polintB
3214
+ INTEGER j
3215
+ REAL*8 dss,h(JMAXP),s(JMAXP)
3216
+ h(1)=1.0D0
3217
+ do 11 j=1,JMAX
3218
+ call choose(func,a,b,s(j),j)
3219
+ if (j.ge.K) then
3220
+ call polintB(h(j-KM),s(j-KM),K,0.0D0,ss,dss)
3221
+ if (abs(dss).le.EPS*abs(ss)) return
3222
+ endif
3223
+ s(j+1)=s(j)
3224
+ h(j+1)=h(j)/9.0D0
3225
+ 11 continue
3226
+ STOP 'too many steps in qromo'
3227
+ END
3228
+
3229
+
3230
+ SUBROUTINE polintB(xa,ya,n,x,y,dy)
3231
+ C
3232
+ C Modified to be double precision
3233
+ C
3234
+ IMPLICIT REAL*8 (a-h,o-z)
3235
+ INTEGER n,NMAX
3236
+ REAL*8 dy,x,y,xa(n),ya(n)
3237
+ PARAMETER (NMAX=10)
3238
+ INTEGER i,m,ns
3239
+ REAL*8 den,dif,dift,ho,hp,w,c(NMAX),d(NMAX)
3240
+ ns=1
3241
+ dif=abs(x-xa(1))
3242
+ do 11 i=1,n
3243
+ dift=abs(x-xa(i))
3244
+ if (dift.lt.dif) then
3245
+ ns=i
3246
+ dif=dift
3247
+ endif
3248
+ c(i)=ya(i)
3249
+ d(i)=ya(i)
3250
+ 11 continue
3251
+ y=ya(ns)
3252
+ ns=ns-1
3253
+ do 13 m=1,n-1
3254
+ do 12 i=1,n-m
3255
+ ho=xa(i)-x
3256
+ hp=xa(i+m)-x
3257
+ w=c(i+1)-d(i)
3258
+ den=ho-hp
3259
+ if(den.eq.0.0D0)STOP 'failure in polintB'
3260
+ den=w/den
3261
+ d(i)=hp*den
3262
+ c(i)=ho*den
3263
+ 12 continue
3264
+ if (2*ns.lt.n-m)then
3265
+ dy=c(ns+1)
3266
+ else
3267
+ dy=d(ns)
3268
+ ns=ns-1
3269
+ endif
3270
+ y=y+dy
3271
+ 13 continue
3272
+ return
3273
+ END
3274
+
3275
+
3276
+ SUBROUTINE midpntB(func,a,b,s,n)
3277
+ C
3278
+ C Modified to be double precision
3279
+ C
3280
+ IMPLICIT REAL*8 (a-h,o-z)
3281
+ INTEGER n
3282
+ REAL*8 a,b,s,func
3283
+ EXTERNAL func
3284
+ INTEGER it,j
3285
+ REAL*8 ddel,del,sum,tnm,x
3286
+ if (n.eq.1) then
3287
+ s=(b-a)*func(0.5D0*(a+b))
3288
+ else
3289
+ it=3**(n-2)
3290
+ tnm=it
3291
+ del=(b-a)/(3.0D0*tnm)
3292
+ ddel=del+del
3293
+ x=a+0.5D0*del
3294
+ sum=0.0D0
3295
+ do 11 j=1,it
3296
+ sum=sum+func(x)
3297
+ x=x+ddel
3298
+ sum=sum+func(x)
3299
+ x=x+del
3300
+ 11 continue
3301
+ s=(s+(b-a)*sum/tnm)/3.0D0
3302
+ endif
3303
+ return
3304
+ END
3305
+
3306
+ INTEGER FUNCTION LENSTR(str)
3307
+ C
3308
+ C Return effective length of a character string (trailing blanks removed).
3309
+ C Returns 0 for an all-blank string.
3310
+ C
3311
+ IMPLICIT REAL*8 (a-h,o-z)
3312
+ CHARACTER*(*) str
3313
+ INTEGER i
3314
+ LENSTR = LEN(str)
3315
+ DO i=LEN(str),1,-1
3316
+ IF (str(i:i).NE.' ') THEN
3317
+ LENSTR = i
3318
+ RETURN
3319
+ END IF
3320
+ END DO
3321
+ LENSTR = 0
3322
+ RETURN
3323
+ END