• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gyrokinetics / gs2 / 2078172070

03 Oct 2025 09:22AM UTC coverage: 10.835% (+0.03%) from 10.806%
2078172070

push

gitlab-ci

David Dickinson
Merged in experimental/user_controlled_output_base_name (pull request #1184)

5049 of 46599 relevant lines covered (10.83%)

119786.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/programs/rungridgen.f90
1
!> FIXME : Add documentation  
2
program rungridgen
×
3
  use file_utils, only: init_file_utils, run_name, input_unit, &
4
       open_output_file, close_output_file, finish_file_utils
×
5
  use gridgen4mod, only: gridgen4_1
6
  use constants, only: pi, twopi, run_name_size
7
  use mp, only: init_mp, finish_mp
8
  use warning_helpers, only: exactly_equal, not_exactly_equal, is_zero, is_not_zero
9
  implicit none
10

11
  ! input parameters
12
  character(len = run_name_size) :: source, gingrid, gsource
13
  integer :: nthetaout, nlambdaout, nperiodout
14
  integer :: npadd, iperiod
15
  real :: alknob, epsknob, extrknob, bpknob, smoothknob
16
  integer :: nfinegrid
17
  real :: thetamax, deltaw, widthw, tension
18
  logical :: screenout
19
  logical :: auto_width, three_dim
20
  real :: cv_fraction, delth_max
21
  integer :: max_autoiter
22
  logical :: list = .false.
23
  logical :: no_end_point
24
  character(len = run_name_size) :: ncsource
25

26
  ! work variables
27
  integer :: ntheta, nlambda, ntgrid
28
  integer :: ntgridin, nperiodin, nthetain
29
  real, dimension (:), allocatable :: thetain, bmagin, bmagsm
×
30
  real, dimension (:), allocatable :: thetaout, bmagout, alambdaout
×
31

32
  real :: drhodpsi, rmaj, shat, kxfac, qval
33
  real, dimension (:), allocatable :: thetagrid
×
34
  real, dimension (:), allocatable :: gbdrift, gradpar, grho
×
35
  real, dimension (:), allocatable :: cvdrift, gds2, bmag
×
36
  real, dimension (:), allocatable :: gds21, gds22
×
37
  real, dimension (:), allocatable :: cvdrift0, gbdrift0
×
38
  real, dimension (:), allocatable :: Rplot, Rprime
×
39
  real, dimension (:), allocatable :: Zplot, Zprime
×
40
  real, dimension (:), allocatable :: aplot, aprime
×
41
  
42
  call init_mp
×
43
  call init_file_utils (list, name="grid")
×
44
  call read_parameters
×
45
  if (three_dim) then
×
46
     call allocate_arrays_3d
×
47
     call get_initial_grids_3d
×
48
  else
49
     call allocate_arrays
×
50
     call get_initial_grids
×
51
  end if
52
  call do_smoothing
×
53
  call generate_grids
×
54
  call write_output
×
55
  call finish_file_utils
×
56
  call finish_mp
×
57
  stop
×
58

59
contains
60
  !> FIXME : Add documentation  
61
  subroutine read_parameters
×
62
    implicit none
63
    namelist /testgridgen/ source, gsource, &
64
         nthetaout,nlambdaout,nperiodout, &
65
         npadd,alknob,epsknob,bpknob,extrknob,smoothknob, nfinegrid, &
66
         thetamax, deltaw, widthw, tension, gingrid, screenout, &
67
         auto_width, cv_fraction, delth_max, max_autoiter, three_dim, &
68
         iperiod, &
69
         no_end_point, ncsource
70
    gsource = "eik6.out"
×
71
    source = "eik.out"
×
72
    nthetaout = 32
×
73
    nlambdaout = 20
×
74
    nperiodout = 2
×
75
    npadd = 2
×
76
    alknob = 0.1
×
77
    bpknob = 1.e-8
×
78
    epsknob = 1e-9
×
79
    extrknob = 10.0
×
80
    smoothknob = 0.0
×
81
    nfinegrid=200
×
82
    thetamax = 0.0
×
83
    deltaw = 0.0
×
84
    widthw = 1.0
×
85
    tension = 1.0
×
86
    screenout = .false.
×
87
    auto_width = .false.
×
88
    cv_fraction = 0.6
×
89
    delth_max = 0.5
×
90
    max_autoiter = 3
×
91
    gingrid = "gingrid"
×
92
    three_dim = .false.
×
93
    iperiod = 1
×
94
    no_end_point = .false.
×
95
    ncsource = ""
×
96
    read (unit=input_unit("testgridgen"), nml=testgridgen)
×
97
    nthetaout = nthetaout + 1
×
98
  end subroutine read_parameters
×
99

100
  !> FIXME : Add documentation  
101
  subroutine allocate_arrays
×
102
    use gs2_io_grids, only:nc_grid_file_open
103
    use gs2_io_grids, only: nc_get_grid_sizes, nc_get_grid_scalars
104
    implicit none
105
    integer :: unit
106
    character(200) :: line
107
    logical :: ncsource_exist
108

109
    inquire(file=ncsource, exist=ncsource_exist)
×
110
    if (ncsource_exist) then
×
111
       call nc_grid_file_open(ncsource, "r")
×
112
       call nc_get_grid_sizes(nthetain, ntgridin, nperiodin)
×
113
       call nc_get_grid_scalars(shat, drhodpsi, kxfac, qval, rmaj)
×
114
    else
115
       open (newunit=unit, file=trim(source), status="old")
×
116
       read (unit=unit, fmt="(a)") line
×
117
       read (unit=unit, fmt=*,err=10) ntgridin, nperiodin, nthetain, drhodpsi, rmaj, shat, kxfac, qval
×
118
10     continue
119
       close (unit=unit)
×
120
    end if
121

122
    allocate (thetain(nthetain+1),bmagin(nthetain+1),bmagsm(nthetain+1))
×
123
    allocate (thetaout(nthetaout),bmagout(nthetaout),alambdaout(nlambdaout))
×
124
    allocate (thetagrid(-ntgridin:ntgridin))
×
125
    allocate (gbdrift(-ntgridin:ntgridin))
×
126
    allocate (gradpar(-ntgridin:ntgridin))
×
127
    allocate (grho(-ntgridin:ntgridin))
×
128
    allocate (cvdrift(-ntgridin:ntgridin))
×
129
    allocate (gds2(-ntgridin:ntgridin))
×
130
    allocate (bmag(-ntgridin:ntgridin))
×
131
    allocate (gds21(-ntgridin:ntgridin))
×
132
    allocate (gds22(-ntgridin:ntgridin))
×
133
    allocate (cvdrift0(-ntgridin:ntgridin))
×
134
    allocate (gbdrift0(-ntgridin:ntgridin))
×
135
    allocate (Rplot(-ntgridin:ntgridin))
×
136
    allocate (Rprime(-ntgridin:ntgridin))
×
137
    allocate (Zplot(-ntgridin:ntgridin))
×
138
    allocate (Zprime(-ntgridin:ntgridin))
×
139
    allocate (aplot(-ntgridin:ntgridin))
×
140
    allocate (aprime(-ntgridin:ntgridin))
×
141
  end subroutine allocate_arrays
×
142

143
  !> FIXME : Add documentation    
144
  subroutine allocate_arrays_3d
×
145
    implicit none
146
    integer :: unit, ntor
147
    open (newunit=unit, file=trim(source), status="old")
×
148
    read (unit=unit, fmt=*) ntgridin, nthetain, ntor
×
149
    close (unit=unit)
×
150
    
151
    drhodpsi = 1.0  ! assumes our radial variable matches VVBAL
×
152

153
    nthetain = nthetain * iperiod
×
154

155
    allocate (thetain(nthetain+1),bmagin(nthetain+1),bmagsm(nthetain+1))
×
156
    allocate (thetaout(nthetaout),bmagout(nthetaout),alambdaout(nlambdaout))
×
157
    allocate (thetagrid(-ntgridin:ntgridin))
×
158
    allocate (gbdrift(-ntgridin:ntgridin))
×
159
    allocate (gradpar(-ntgridin:ntgridin))
×
160
    allocate (grho(-ntgridin:ntgridin))
×
161
    allocate (cvdrift(-ntgridin:ntgridin))
×
162
    allocate (gds2(-ntgridin:ntgridin))
×
163
    allocate (bmag(-ntgridin:ntgridin))
×
164
    allocate (gds21(-ntgridin:ntgridin))
×
165
    allocate (gds22(-ntgridin:ntgridin))
×
166
    allocate (cvdrift0(-ntgridin:ntgridin))
×
167
    allocate (gbdrift0(-ntgridin:ntgridin))
×
168
    allocate (Rplot(-ntgridin:ntgridin))
×
169
    allocate (Rprime(-ntgridin:ntgridin))
×
170
    allocate (Zplot(-ntgridin:ntgridin))
×
171
    allocate (Zprime(-ntgridin:ntgridin))
×
172
    allocate (aplot(-ntgridin:ntgridin))
×
173
    allocate (aprime(-ntgridin:ntgridin))
×
174

175
    cvdrift0 = 0.   ! assumes theta0 = 0.
×
176
    gbdrift0 = 0.   ! assumes theta0 = 0.
×
177
    gds21 = 0.      ! assumes theta0 = 0.
×
178
    gds22 = 0.      ! assumes theta0 = 0.
×
179
    grho  = 1.      ! assumes linear calculation
×
180
    Rplot = 1.      ! pure fiction
×
181
    Rprime = 1.     ! pure fiction
×
182
    Zplot = 1.      ! pure fiction
×
183
    Zprime = 1.     ! pure fiction
×
184
    aplot = 1.      ! pure fiction
×
185
    aprime = 1.     ! pure fiction
×
186
    
187
  end subroutine allocate_arrays_3d
×
188

189
  !> FIXME : Add documentation  
190
  subroutine get_initial_grids
×
191
    use gs2_io_grids, only: nc_get_grids, nc_grid_file_close
192
    implicit none
193
    integer :: unit
194
    integer :: i
195
!    real :: discard
196
    character(200) :: line
197
    logical :: ncsource_exist
198

199
    inquire(file=ncsource, exist=ncsource_exist)
×
200
    if (ncsource_exist) then
×
201
       call nc_get_grids(ntgridin, &
202
            bmag, gradpar, gbdrift, gbdrift0, cvdrift, cvdrift0, &
203
            gds2, gds21, gds22, grho, thetagrid, &
204
            Rplot=Rplot, Rprime=Rprime, Zplot=Zplot, Zprime=Zprime, aplot=aplot, aprime=aprime)
×
205
       call nc_grid_file_close()
×
206
    else
207
       open (newunit=unit, file=trim(source), status="old")
×
208
       read (unit=unit, fmt="(a)") line
×
209
       read (unit=unit, fmt="(a)") line
×
210

211
       ! gbdrift gradpar grho theta
212
       read (unit=unit, fmt="(a)") line
×
213
       do i = -ntgridin,ntgridin
×
214
          read (unit=unit, fmt=*) gbdrift(i),gradpar(i),grho(i),thetagrid(i)
×
215
       end do
216

217
       ! cvdrift gds2 bmag theta
218
       read (unit=unit, fmt="(a)") line
×
219
       do i = -ntgridin,ntgridin
×
220
          read (unit=unit, fmt=*) cvdrift(i),gds2(i),bmag(i),thetagrid(i)
×
221
       end do
222

223
       ! gds21 gds22 theta
224
       read (unit=unit, fmt="(a)") line
×
225
       do i = -ntgridin,ntgridin
×
226
          read (unit=unit, fmt=*) gds21(i),gds22(i),thetagrid(i)
×
227
       end do
228

229
       ! cvdrift0 gbdrift0 theta
230
       read (unit=unit, fmt="(a)") line
×
231
       do i = -ntgridin,ntgridin
×
232
          read (unit=unit, fmt=*) cvdrift0(i),gbdrift0(i),thetagrid(i)
×
233
       end do
234

235
       close (unit=unit)
×
236

237
       call get_plotdata
×
238
    end if
239

240
    thetain = thetagrid(-nthetain/2:nthetain/2)
×
241
    bmagin = bmag(-nthetain/2:nthetain/2)
×
242

243
  end subroutine get_initial_grids
×
244

245
  subroutine get_plotdata
×
246
    implicit none
247
    integer :: unit
248
    integer :: i
249
    character(200) :: line
250
    real, allocatable :: dummy(:)
×
251

252
    allocate (dummy(-ntgridin:ntgridin))
×
253

254
    Rplot = 0.; Rprime = 0.
×
255
    Zplot = 0.; Zprime = 0.
×
256
    aplot = 0.; aprime = 0.
×
257

258
    open (newunit=unit, file=trim(gsource), status="old", err=100)
×
259
    read (unit=unit, fmt="(a)", err=100) line
×
260
    read (unit=unit, fmt="(a)", err=100) line
×
261
    read (unit=unit, fmt="(a)", err=100) line
×
262

263
    do i = -ntgridin, ntgridin
×
264
       read (unit=unit, fmt=*, err=100) dummy(i), Rplot(i), Zplot(i), aplot(i), Rprime(i), Zprime(i), aprime(i), dummy(i)
×
265
    end do
266

267
    close(unit=unit)
×
268

269
    return
×
270

271
100 continue
272
    close(unit=unit)
×
273
    write(6,*) 'read error: ', gsource
×
274

275
    return
×
276

277
  end subroutine get_plotdata
×
278

279
  !> FIXME : Add documentation  
280
  subroutine get_initial_grids_3d
×
281
    implicit none
282
    integer :: unit
283
    integer :: i, ntor
284
    real :: dpdpsi, pres, bavg, cvavg
285

286
    open (newunit=unit, file=trim(source), status="old", action="read")
×
287
    read (unit=unit, fmt=*) ntgridin, nthetain, ntor
×
288

289
    nthetain = nthetain * iperiod
×
290
    do i = -ntgridin,ntgridin
×
291
       read (unit=unit, fmt=*) thetagrid(i),bmag(i),gradpar(i),gds2(i),cvdrift(i),gbdrift(i),dpdpsi,pres
×
292
    end do
293

294
    close (unit=unit)
×
295

296
    bavg = sum(bmag(-nthetain/2:nthetain/2))/(nthetain+1)
×
297
    cvavg = sum(cvdrift)/size(cvdrift)
×
298
    
299
    write(*,*) 'bavg = ',bavg
×
300
    write(*,*) 'cvavg = ',cvavg,' and remember that cvdrift assumed beta_prime=0'
×
301

302
!    bmag = bmag / bavg
303

304
    gds2 = gds2 * ntor**2 
×
305
    gbdrift = gbdrift * ntor * 2. / bmag**2
×
306
!    cvdrift = cvdrift * ntor * 2. / bmag**3    ! not correct for beta_prime term, so use: 
307
    cvdrift = gbdrift 
×
308

309
!    alp = -1./pres*dpdpsi
310

311
!
312
! these are theta and mod(b) grids that are periodic
313
!
314
    thetain = thetagrid(-nthetain/2:nthetain/2)
×
315
    bmagin = bmag(-nthetain/2:nthetain/2)
×
316
  end subroutine get_initial_grids_3d
×
317

318
  !> FIXME : Add documentation  
319
  subroutine do_smoothing
×
320
    implicit none
321
    real :: var
322
    integer :: ifail
323
    if (is_zero(smoothknob)) then
×
324
       bmagsm = bmagin
×
325
    else
326
       var = smoothknob
×
327
       ifail = 0
×
328
       call smooth (nthetain+1,thetain,bmagin,var,bmagsm,ifail)
×
329
       if (ifail /= 0) then
×
330
          print *, "smooth failed: ",ifail
×
331
          select case (ifail)
×
332
          case (129)
333
             print *, "IC IS LESS THAN N-1."
×
334
          case (130)
335
             print *, "N IS lESS THAN 3."
×
336
          case (131)
337
             print *, "INPUT ABSCISSAE ARE NOT ORDERED SO THAT X(I).LT.X(I+1)."
×
338
          case (132)
339
             print *, "DF(I) IS NOT POSITIVE FOR SOME I."
×
340
          case (133)
341
             print *, "JOB IS NOT 0 OR 1."
×
342
          case default
343
          end select
344
          stop
×
345
       end if
346
    end if
347
  end subroutine do_smoothing
×
348

349
  !> FIXME : Add documentation  
350
  subroutine generate_grids
×
351
    implicit none
352
    integer :: i, iter, nin
353
    real :: d, deltaw_ok
354

355
    if (.not. auto_width) then
×
356
       ntheta = nthetaout
×
357
       nlambda = nlambdaout
×
358
       call gridgen4_1 (iperiod,nthetain+1,thetain,bmagsm, npadd, &
359
            alknob,epsknob,bpknob,extrknob,thetamax,deltaw,widthw,tension, &
360
            ntheta,nlambda,thetaout,bmagout,alambdaout)
×
361
       return
×
362
    end if
363

364
    widthw = pi
×
365
    do i = 0, nthetain/2
×
366
       if (cvdrift(i) < 0.0) then
×
367
          widthw = thetagrid(i)
×
368
          exit
×
369
       end if
370
    end do
371

372
    print *, "widthw: ", widthw
×
373
    deltaw_ok = 0.0
×
374
    do iter = 1, max_autoiter
×
375
       ntheta = nthetaout
×
376
       nlambda = nlambdaout
×
377
       call gridgen4_1 (iperiod,nthetain+1,thetain,bmagsm, npadd, &
378
            alknob,epsknob,bpknob,extrknob,thetamax,deltaw,widthw,tension, &
379
            ntheta,nlambda,thetaout,bmagout,alambdaout)
×
380
       print *, "iter: ", iter
×
381
       d = maxval(thetaout(2:ntheta) - thetaout(1:ntheta-1))
×
382
       print *, "max deltheta: ", d
×
383
       nin = count(abs(thetaout(1:ntheta) - thetamax) < widthw &
×
384
                   .or. abs(thetaout(1:ntheta) + thetamax) < widthw)
×
385
       print *, "count in +ve cvdrift: ", nin
×
386
       print *, "fraction in +ve cvdrift: ", real(nin)/real(ntheta)
×
387
       print *, "deltaw: ", deltaw
×
388
       if (d > delth_max) then
×
389
          if (is_not_zero(deltaw_ok)) then
×
390
             deltaw = sqrt(deltaw*deltaw_ok)
×
391
          else
392
             deltaw = 0.5*deltaw
×
393
          end if
394
          print *, "max deltheta too large: ", d
×
395
          if (deltaw < deltaw_ok) exit
×
396
       else if (real(nin)/real(ntheta) < cv_fraction) then
×
397
          print *, "fraction in +ve cvdrift too small: ", &
×
398
               real(nin)/real(ntheta)
×
399
          deltaw_ok = deltaw
×
400
          deltaw = deltaw*(cv_fraction/(real(nin)/real(ntheta)))**2
×
401
       end if
402
    end do
403

404
    if (is_not_zero(deltaw_ok) .and. d > delth_max) then
×
405
       deltaw = deltaw_ok
×
406
       ntheta = nthetaout
×
407
       nlambda = nlambdaout
×
408
       call gridgen4_1 (iperiod,nthetain+1,thetain,bmagsm, npadd, &
409
            alknob,epsknob,bpknob,extrknob,thetamax,deltaw,widthw,tension, &
410
            ntheta,nlambda,thetaout,bmagout,alambdaout)
×
411
       d = maxval(thetaout(2:ntheta) - thetaout(1:ntheta-1))
×
412
       print *, "max deltheta: ", d
×
413
       nin = count(abs(thetaout(1:ntheta) - thetamax) < widthw &
×
414
                   .or. abs(thetaout(1:ntheta) + thetamax) < widthw)
×
415
       print *, "count in +ve cvdrift: ", nin
×
416
       print *, "fraction in +ve cvdrift: ", real(nin)/real(ntheta)
×
417
       print *, "deltaw: ", deltaw
×
418
    end if
419

420
  end subroutine generate_grids
421

422
  !> FIXME : Add documentation    
423
  subroutine write_output
×
424
    use splines, only: inter_cspl
425
    use gs2_io_grids, only: nc_write_grid_sizes, nc_write_grid_scalars, nc_write_grids
426
    use gs2_io_grids, only: nc_write_lambda_grid
427
    use gs2_io_grids, only: nc_grid_file_open, nc_grid_file_close
428
    use constants, only: run_name_size
429
    use mp, only: proc0
430
    implicit none
431
    integer :: unit
432
    integer :: i
433
!    real, allocatable, dimension (:) :: bmaginaux, bmagsmaux, tmp
434
    real, allocatable, dimension (:) :: thetagridout
×
435
    real, allocatable, dimension (:) :: gbdriftout, gradparout, grhoout
×
436
    real, allocatable, dimension (:) :: cvdriftout, gds2out, bmaggridout
×
437
    real, allocatable, dimension (:) :: gds21out, gds22out
×
438
    real, allocatable, dimension (:) :: cvdrift0out, gbdrift0out
×
439
    real, allocatable, dimension (:) :: Rplotout, Rprimeout
×
440
    real, allocatable, dimension (:) :: Zplotout, Zprimeout
×
441
    real, allocatable, dimension (:) :: aplotout, aprimeout
×
442
!    real :: th, bmin
443
    real :: bmin
444
!    integer :: ierr
445
    integer, dimension (1) :: minloca
446
    character(len=run_name_size) :: ncout
447

448
    call open_output_file (unit, ".input.out")
×
449
    write (unit=unit, fmt="('#',i5)") nthetain+1
×
450
    do i = 1, nthetain+1
×
451
       write (unit=unit, fmt="(3(1x,g19.12))") thetain(i), bmagin(i), bmagsm(i)
×
452
    enddo
453
    call close_output_file (unit)
×
454

455
!    allocate (bmaginaux(nthetain+1), bmagsmaux(nthetain+1), tmp(2*nthetain))
456
!    call fitp_curvp1 (nthetain,thetain,bmagin,twopi,bmaginaux,tmp,1.0,ierr)
457
!    call fitp_curvp1 (nthetain,thetain,bmagsm,twopi,bmagsmaux,tmp,1.0,ierr)
458
!    call open_output_file (unit, ".input.fine")
459
!    do i = -nfinegrid, nfinegrid
460
!       th = pi*real(i)/real(nfinegrid)
461
!       write (unit=unit, fmt="(3(x,g19.12))") th, &
462
!            fitp_curvp2(th,nthetain,thetain,bmagin,twopi,bmaginaux,1.0), &
463
!            fitp_curvp2(th,nthetain,thetain,bmagsm,twopi,bmagsmaux,1.0)
464
!    end do
465
!    call close_output_file (unit)
466
!    deallocate (bmaginaux, bmagsmaux, tmp)
467

468
    call open_output_file (unit, ".bmag.out")
×
469
    write (unit=unit, fmt="('#',i5)") ntheta
×
470
    do i = 1, ntheta
×
471
       write (unit=unit, fmt="(2(1x,g19.12))") thetaout(i), bmagout(i)
×
472
    enddo
473
    call close_output_file (unit)
×
474

475
    call open_output_file (unit, ".lambda.out")
×
476
    write (unit=unit, fmt="('#',i5)") nlambda
×
477
    do i = 1, nlambda
×
478
       write (unit=unit, fmt=*) alambdaout(i)
×
479
    enddo
480
    call close_output_file (unit)
×
481

482
    ntgrid = ntheta/2 + (nperiodout-1)*ntheta
×
483
    allocate (thetagridout(-ntgrid:ntgrid))
×
484
    allocate (gbdriftout(-ntgrid:ntgrid))
×
485
    allocate (gradparout(-ntgrid:ntgrid))
×
486
    allocate (grhoout(-ntgrid:ntgrid))
×
487
    allocate (cvdriftout(-ntgrid:ntgrid))
×
488
    allocate (gds2out(-ntgrid:ntgrid))
×
489
    allocate (bmaggridout(-ntgrid:ntgrid))
×
490
    allocate (gds21out(-ntgrid:ntgrid))
×
491
    allocate (gds22out(-ntgrid:ntgrid))
×
492
    allocate (cvdrift0out(-ntgrid:ntgrid))
×
493
    allocate (gbdrift0out(-ntgrid:ntgrid))
×
494
    allocate (Rplotout(-ntgrid:ntgrid))
×
495
    allocate (Rprimeout(-ntgrid:ntgrid))
×
496
    allocate (Zplotout(-ntgrid:ntgrid))
×
497
    allocate (Zprimeout(-ntgrid:ntgrid))
×
498
    allocate (aplotout(-ntgrid:ntgrid))
×
499
    allocate (aprimeout(-ntgrid:ntgrid))
×
500

501
    thetagridout(-ntheta/2:ntheta/2-1) = thetaout(:ntheta)
×
502
    bmaggridout(-ntheta/2:ntheta/2-1) = bmagout(:ntheta)
×
503
    thetagridout(ntheta/2) = thetagridout(-ntheta/2) + twopi*iperiod
×
504
    bmaggridout(ntheta/2) = bmaggridout(-ntheta/2)
×
505
    do i = 1, nperiodout - 1
×
506
       thetagridout(-ntheta/2-ntheta*i:ntheta/2-ntheta*i-1) &
×
507
            = thetagridout(-ntheta/2:ntheta/2-1) - twopi*i
×
508
       thetagridout(-ntheta/2+ntheta*i+1:ntheta/2+ntheta*i) &
×
509
            = thetagridout(-ntheta/2+1:ntheta/2) + twopi*i
×
510
       bmaggridout(-ntheta/2-ntheta*i:ntheta/2-ntheta*i-1) &
×
511
            = bmaggridout(-ntheta/2:ntheta/2-1)
×
512
       bmaggridout(-ntheta/2+ntheta*i+1:ntheta/2+ntheta*i) &
×
513
            = bmaggridout(-ntheta/2+1:ntheta/2)
×
514
    end do
515

516
    call inter_cspl(thetagrid, gbdrift, thetagridout, gbdriftout)
×
517
    call inter_cspl(thetagrid, gradpar, thetagridout, gradparout)
×
518
    call inter_cspl(thetagrid, grho, thetagridout, grhoout)
×
519
    call inter_cspl(thetagrid, cvdrift, thetagridout, cvdriftout)
×
520
    call inter_cspl(thetagrid, gds2, thetagridout, gds2out)
×
521
    call inter_cspl(thetagrid, bmag, thetagridout, bmagout)
×
522
    call inter_cspl(thetagrid, gds21, thetagridout, gds21out)
×
523
    call inter_cspl(thetagrid, gds22, thetagridout, gds22out)
×
524
    call inter_cspl(thetagrid, cvdrift0, thetagridout, cvdrift0out)
×
525
    call inter_cspl(thetagrid, gbdrift0, thetagridout, gbdrift0out)
×
526
    call inter_cspl(thetagrid, Rplot, thetagridout, Rplotout)
×
527
    call inter_cspl(thetagrid, Rprime, thetagridout, Rprimeout)
×
528
    call inter_cspl(thetagrid, Zplot, thetagridout, Zplotout)
×
529
    call inter_cspl(thetagrid, Zprime, thetagridout, Zprimeout)
×
530
    call inter_cspl(thetagrid, aplot, thetagridout, aplotout)
×
531
    call inter_cspl(thetagrid, aprime, thetagridout, aprimeout)
×
532

533
    call open_output_file (unit, ".out")
×
534
    write (unit=unit, fmt=*) 'nlambda'
×
535
    write (unit=unit, fmt=*) nlambda
×
536
    write (unit=unit, fmt=*) 'lambda'
×
537
    do i = 1, nlambda
×
538
       write (unit=unit, fmt=*) alambdaout(i)
×
539
    enddo
540

541
    write (unit=unit, fmt=*) 'ntgrid nperiod ntheta drhodpsi rmaj shat kxfac q'
×
542
    write (unit=unit, fmt="(3i4,5(1x,g19.10))") ntgrid, nperiodout, ntheta, drhodpsi, rmaj, shat, kxfac, qval
×
543

544
    write (unit=unit, fmt=*) 'gbdrift gradpar grho tgrid'
×
545
    do i = -ntgrid,ntgrid
×
546
       write (unit=unit, fmt="(8(1x,g19.10))") &
×
547
            gbdriftout(i),gradparout(i),grhoout(i),thetagridout(i)
×
548
    end do
549

550
    write (unit=unit, fmt=*) 'cvdrift gds2 bmag tgrid'
×
551
    do i = -ntgrid,ntgrid
×
552
       write (unit=unit, fmt="(8(1x,g19.10))") &
×
553
            cvdriftout(i),gds2out(i),bmaggridout(i),thetagridout(i)
×
554
    end do
555

556
    write (unit=unit, fmt=*) 'gds21 gds22 tgrid'
×
557
    do i = -ntgrid,ntgrid
×
558
       write (unit=unit, fmt="(8(1x,g19.10))") &
×
559
            gds21out(i),gds22out(i),thetagridout(i)
×
560
    end do
561

562
    write (unit=unit, fmt=*) 'cvdrift0 gbdrift0 tgrid'
×
563
    do i = -ntgrid,ntgrid
×
564
       write (unit=unit, fmt="(8(1x,g19.10))") &
×
565
            cvdrift0out(i),gbdrift0out(i),thetagridout(i)
×
566
    end do
567

568
    write (unit=unit, fmt=*) 'Rplot Rprime tgrid'
×
569
    do i = -ntgrid,ntgrid
×
570
       write (unit=unit, fmt="(8(1x,g19.10))") &
×
571
            Rplotout(i),Rprimeout(i),thetagridout(i)
×
572
    end do
573

574
    write (unit=unit, fmt=*) 'Zplot Zprime tgrid'
×
575
    do i = -ntgrid,ntgrid
×
576
       write (unit=unit, fmt="(8(1x,g19.10))") &
×
577
            Zplotout(i),Zprimeout(i),thetagridout(i)
×
578
    end do
579

580
    write (unit=unit, fmt=*) 'aplot aprime tgrid'
×
581
    do i = -ntgrid,ntgrid
×
582
       write (unit=unit, fmt="(8(1x,g19.10))") &
×
583
            aplotout(i),aprimeout(i),thetagridout(i)
×
584
    end do
585

586
    call close_output_file (unit)
×
587

588
    if (screenout) then
×
589
       write (*, *) 'cvdrift       gds2          bmag          theta'
×
590
       do i = -ntheta/2,ntheta/2
×
591
          write (unit=*, fmt="(4(1x,g13.5))") &
×
592
               cvdriftout(i),gds2out(i),bmaggridout(i),thetagridout(i)
×
593
       end do
594
    end if
595

596
    minloca = minloc(bmagout(:ntheta))
×
597
    bmin = bmagout(minloca(1))
×
598
    print *, "theta,bmag minimum: ", thetaout(minloca(1)), bmin
×
599

600
    minloca = minloc(bmagin)
×
601
    print *, "theta,bmag input minimum: ", &
×
602
         thetain(minloca(1)), bmagin(minloca(1))
×
603

604
    if (bmin < bmagin(minloca(1))) print *, "WARNING: interpolated new minimum"
×
605

606
    if (proc0) then
×
607
       ncout = trim(run_name)//".out.nc"
×
608
       call nc_grid_file_open(ncout, "w")
×
609
       call nc_write_grid_sizes(ntheta, ntgrid, nperiodout)
×
610
       call nc_write_grid_scalars(shat, drhodpsi, kxfac, qval, rmaj)
×
611
       call nc_write_grids(ntgrid, bmaggridout, gradparout, gbdriftout, gbdrift0out, &
612
            cvdriftout, cvdrift0out, gds2out, gds21out, gds22out, grhoout, thetagridout, &
613
            Rplot=Rplotout, Rprime=Rprimeout, Zplot=Zplotout, Zprime=Zprimeout, &
614
            aplot=aplotout, aprime=aprimeout, no_end_point_in=no_end_point)
×
615
       call nc_write_lambda_grid(nlambda, alambdaout(:nlambda))
×
616
       call nc_grid_file_close()
×
617
    end if
618

619
  end subroutine write_output
×
620

621
  !> FIXME : Add documentation
622
  subroutine smooth (n, xin, yin, var, yout, ifail)
×
623
    implicit none
624

625
    integer, intent(in) :: n
626
    real, dimension (:), intent (in) :: xin, yin
627
    real, dimension (:), intent (out) :: yout
628
    real, intent(in out) :: var
629
    integer, intent(out) :: ifail
630

631
! these next arrays should be double precision, which we usually get with
632
! compiler options
633
    real, dimension (1) :: se
634
    real, dimension (:), allocatable :: x, f, y, df
×
635
    real, dimension (:,:), allocatable :: wk, c
×
636
    real :: dvar
637

638
    allocate (x(n), f(n), y(n), df(n), c(n, 3))
×
639
    allocate (wk(n+2,7))
×
640

641
    ifail = 0
×
642
    x = xin
×
643
    f = yin
×
644
    df = 1.
×
645
    dvar=var
×
646
    call cubgcv (x,f,df,n,y,c,n,dvar,0,se,wk,ifail)
×
647
    var=dvar
×
648
    yout = y
×
649

650
    deallocate (x, f, y, df, c, wk)
×
651

652
  end subroutine smooth
×
653

654
!     algorithm 642 collected algorithms from acm.
655
!     algorithm appeared in acm-trans. math. software, vol.12, no. 2,
656
!     jun., 1986, p. 150.
657
!   subroutine name     - cubgcv
658
!
659
!--------------------------------------------------------------------------
660
!
661
!   computer            - vax/double
662
!
663
!   author              - m.f.hutchinson
664
!                         csiro division of mathematics and statistics
665
!                         p.o. box 1965
666
!                         canberra, act 2601
667
!                         australia
668
!
669
!   latest revision     - 15 august 1985
670
!
671
!   purpose             - cubic spline data smoother
672
!
673
!   usage               - call cubgcv (x,f,df,n,y,c,ic,var,job,se,wk,ier)
674
!
675
!   arguments    x      - vector of length n containing the
676
!                           abscissae of the n data points
677
!                           (x(i),f(i)) i=1..n. (input) x
678
!                           must be ordered so that
679
!                           x(i) .lt. x(i+1).
680
!                f      - vector of length n containing the
681
!                           ordinates (or function values)
682
!                           of the n data points (input).
683
!                df     - vector of length n. (input/output)
684
!                           df(i) is the relative standard deviation
685
!                           of the error associated with data point i.
686
!                           each df(i) must be positive.  the values in
687
!                           df are scaled by the subroutine so that
688
!                           their mean square value is 1, and unscaled
689
!                           again on normal exit.
690
!                           the mean square value of the df(i) is returned
691
!                           in wk(7) on normal exit.
692
!                           if the absolute standard deviations are known,
693
!                           these should be provided in df and the error
694
!                           variance parameter var (see below) should then
695
!                           be set to 1.
696
!                           if the relative standard deviations are unknown,
697
!                           set each df(i)=1.
698
!                n      - number of data points (input).
699
!                           n must be .ge. 3.
700
!                y,c    - spline coefficients. (output) y
701
!                           is a vector of length n. c is
702
!                           an n-1 by 3 matrix. the value
703
!                           of the spline approximation at t is
704
!                           s(t)=((c(i,3)*d+c(i,2))*d+c(i,1))*d+y(i)
705
!                           where x(i).le.t.lt.x(i+1) and
706
!                           d = t-x(i).
707
!                ic     - row dimension of matrix c exactly
708
!                           as specified in the dimension
709
!                           statement in the calling program. (input)
710
!                var    - error variance. (input/output)
711
!                           if var is negative (i.e. unknown) then
712
!                           the smoothing parameter is determined
713
!                           by minimizing the generalized cross validation
714
!                           and an estimate of the error variance is
715
!                           returned in var.
716
!                           if var is non-negative (i.e. known) then the
717
!                           smoothing parameter is determined to minimize
718
!                           an estimate, which depends on var, of the true
719
!                           mean square error, and var is unchanged.
720
!                           in particular, if var is zero, then an
721
!                           interpolating natural cubic spline is calculated.
722
!                           var should be set to 1 if absolute standard
723
!                           deviations have been provided in df (see above).
724
!                job    - job selection parameter. (input)
725
!                         job = 0 should be selected if point standard error
726
!                           estimates are not required in se.
727
!                         job = 1 should be selected if point standard error
728
!                           estimates are required in se.
729
!                se     - vector of length n containing bayesian standard
730
!                           error estimates of the fitted spline values in y.
731
!                           se is not referenced if job=0. (output)
732
!                wk     - work vector of length 7*(n + 2). on normal exit the
733
!                           first 7 values of wk are assigned as follows:-
734
!
735
!                           wk(1) = smoothing parameter (= rho/(rho + 1))
736
!                           wk(2) = estimate of the number of degrees of
737
!                                   freedom of the residual sum of squares
738
!                           wk(3) = generalized cross validation
739
!                           wk(4) = mean square residual
740
!                           wk(5) = estimate of the true mean square error
741
!                                   at the data points
742
!                           wk(6) = estimate of the error variance
743
!                           wk(7) = mean square value of the df(i)
744
!
745
!                           if wk(1)=0 (rho=0) an interpolating natural cubic
746
!                           spline has been calculated.
747
!                           if wk(1)=1 (rho=infinite) a least squares
748
!                           regression line has been calculated.
749
!                           wk(2) is an estimate of the number of degrees of
750
!                           freedom of the residual which reduces to the
751
!                           usual value of n-2 when a least squares regression
752
!                           line is calculated.
753
!                           wk(3),wk(4),wk(5) are calculated with the df(i)
754
!                           scaled to have mean square value 1.  the
755
!                           unscaled values of wk(3),wk(4),wk(5) may be
756
!                           calculated by dividing by wk(7).
757
!                           wk(6) coincides with the output value of var if
758
!                           var is negative on input.  it is calculated with
759
!                           the unscaled values of the df(i) to facilitate
760
!                           comparisons with a priori variance estimates.
761
!
762
!                ier    - error parameter. (output)
763
!                         terminal error
764
!                           ier = 129, ic is less than n-1.
765
!                           ier = 130, n is less than 3.
766
!                           ier = 131, input abscissae are not
767
!                             ordered so that x(i).lt.x(i+1).
768
!                           ier = 132, df(i) is not positive for some i.
769
!                           ier = 133, job is not 0 or 1.
770
!
771
!   precision/hardware  - double
772
!
773
!   required routines   - spint1,spfit1,spcof1,sperr1
774
!
775
!   remarks      the number of arithmetic operations required by the
776
!                subroutine is proportional to n.  the subroutine
777
!                uses an algorithm developed by m.f. hutchinson and
778
!                f.r. de hoog, 'smoothing noisy data with spline
779
!                functions', numer. math. (in press)
780
!
781
!-----------------------------------------------------------------------
782
!
783
  !> FIXME : Add documentation
784
  subroutine cubgcv(x,f,df,n,y,c,ic,var,job,se,wk,ier)
×
785
!
786
!---specifications for arguments---
787
    integer, intent(in) :: n,ic,job
788
    integer, intent(out) :: ier
789
!
790
! All real variables should be double precision:
791
!
792
    real, dimension(:), intent(in) :: x, f
793
    real, dimension(:), intent(in out) :: df
794
    real, dimension(:), intent(out) :: y, se
795
    real, dimension(:, :), intent(out) :: c
796
    real, dimension(0:n+1, 7), intent(out) :: wk
797
    real, intent(in out) :: var
798
!
799
!---specifications for local variables---
800
    real :: delta,err,gf1,gf2,gf3,gf4,r1,r2,r3,r4,avh,avdf,avar,stat(6),p,q
801
    real, parameter :: ratio = 2., tau = 1.618033989, zero = 0., one = 1.
802
    integer :: i
803
!
804
!---initialize---
805
    ier = 133
×
806
    if (job<0 .or. job>1) go to 140
×
807
    call spint1(x,avh,f,df,avdf,n,y,c,ic,wk,wk(0,4),ier)
×
808
    if (ier/=0) go to 140
×
809
    avar = var
×
810
    if (var>zero) avar = var*avdf*avdf
×
811
!
812
!---check for zero variance---
813
    if (not_exactly_equal(var, zero)) go to 10
×
814
    r1 = zero
×
815
    go to 90
×
816
!
817
!---find local minimum of gcv or the expected mean square error---
818
10  r1 = one
×
819
    r2 = ratio*r1
×
820
    call spfit1(x,avh,df,n,r2,p,q,gf2,avar,stat,y,c,ic,wk(:,1:3),wk(:,4:5),wk(:,6),wk(:,7))
×
821
20  call spfit1(x,avh,df,n,r1,p,q,gf1,avar,stat,y,c,ic,wk(:,1:3),wk(:,4:5),wk(:,6),wk(:,7))
×
822
    if (gf1>gf2) go to 30
×
823
!
824
!---exit if p zero---
825
    if (p<=zero) go to 100
×
826
    r2 = r1
×
827
    gf2 = gf1
×
828
    r1 = r1/ratio
×
829
    go to 20
×
830

831
30  r3 = ratio*r2
×
832
40  call spfit1(x,avh,df,n,r3,p,q,gf3,avar,stat,y,c,ic,wk(:,1:3),wk(:,4:5),wk(:,6),wk(:,7))
×
833
    if (gf3>gf2) go to 50
×
834
!
835
!---exit if q zero---
836
    if (q<=zero) go to 100
×
837
    r2 = r3
×
838
    gf2 = gf3
×
839
    r3 = ratio*r3
×
840
    go to 40
×
841

842
50  r2 = r3
×
843
    gf2 = gf3
×
844
    delta = (r2-r1)/tau
×
845
    r4 = r1 + delta
×
846
    r3 = r2 - delta
×
847
    call spfit1(x,avh,df,n,r3,p,q,gf3,avar,stat,y,c,ic,wk(:,1:3),wk(:,4:5),wk(:,6),wk(:,7))
×
848
    call spfit1(x,avh,df,n,r4,p,q,gf4,avar,stat,y,c,ic,wk(:,1:3),wk(:,4:5),wk(:,6),wk(:,7))
×
849
!
850
!---golden section search for local minimum---
851
60  if (gf3>gf4) go to 70
×
852
    r2 = r4
×
853
    gf2 = gf4
×
854
    r4 = r3
×
855
    gf4 = gf3
×
856
    delta = delta/tau
×
857
    r3 = r2 - delta
×
858
    call spfit1(x,avh,df,n,r3,p,q,gf3,avar,stat,y,c,ic,wk(:,1:3),wk(:,4:5),wk(:,6),wk(:,7))
×
859
    go to 80
×
860

861
70  r1 = r3
×
862
    gf1 = gf3
×
863
    r3 = r4
×
864
    gf3 = gf4
×
865
    delta = delta/tau
×
866
    r4 = r1 + delta
×
867
    call spfit1(x,avh,df,n,r4,p,q,gf4,avar,stat,y,c,ic,wk(:,1:3),wk(:,4:5),wk(:,6),wk(:,7))
×
868
80  err = (r2-r1)/ (r1+r2)
×
869
    if (err*err+one>one .and. err>1.0e-6) go to 60
×
870
    r1 = (r1+r2)*0.5
×
871
!
872
!---calculate spline coefficients---
873
90  call spfit1(x,avh,df,n,r1,p,q,gf1,avar,stat,y,c,ic,wk(:,1:3),wk(:,4:5),wk(:,6),wk(:,7))
×
874
100 call spcof1(x,avh,f,df,n,p,q,y,c,ic,wk(:,6),wk(:,7))
×
875
!
876
!---optionally calculate standard error estimates---
877
    if (var>=zero) go to 110
×
878
    avar = stat(6)
×
879
    var = avar/ (avdf*avdf)
×
880
110 if (job==1) call sperr1(x,avh,df,n,wk,p,avar,se)
×
881
!
882
!---unscale df---
883
    df = df * avdf
×
884
!
885
!--put statistics in wk---
886
    do i = 0,5
×
887
       wk(i,1) = stat(i+1)
×
888
    end do
889
    wk(5,1) = stat(6)/ (avdf*avdf)
×
890
    wk(6,1) = avdf*avdf
×
891
    go to 150
×
892
!
893
!---check for error condition---
894
140 continue
895
!     if (ier.ne.0) continue
896
150 return
×
897
  end subroutine cubgcv
898

899
  !> FIXME : Add documentation
900
  subroutine spint1(x,avh,y,dy,avdy,n,a,c,ic,r,t,ier)
×
901
!
902
! initializes the arrays c, r and t for one dimensional cubic
903
! smoothing spline fitting by subroutine spfit1.  the values
904
! df(i) are scaled so that the sum of their squares is n
905
! and the average of the differences x(i+1) - x(i) is calculated
906
! in avh in order to avoid underflow and overflow problems in
907
! spfit1.
908
!
909
! subroutine sets ier if elements of x are non-increasing,
910
! if n is less than 3, if ic is less than n-1 or if dy(i) is
911
! not positive for some i.
912
!
913
!---specifications for arguments---
914
    integer, intent(in) :: n, ic
915
    integer, intent(out) :: ier
916
! All variables should be double precision
917
    real, dimension(:), intent(in) :: x, y
918
    real, dimension(:), intent(in out) :: dy
919
    real, dimension(:), intent(out) :: a
920
    real, dimension(:, :), intent(out) :: c
921
    real, dimension(0:n+1, 3), intent(out) :: r
922
    real, dimension(0:n+1, 2), intent(out) :: t
923
    real, intent(out) :: avh, avdy
924
!
925
!---specifications for local variables---
926
    integer :: i
927
    real :: e,f,g,h
928
    real, parameter :: zero = 0.
929

930
!
931
!---initialization and input checking---
932
    ier = 0
×
933
    if (n<3) go to 60
×
934
    if (ic<n-1) go to 70
×
935
!
936
!---get average x spacing in avh---
937
    g = zero
×
938
    do i = 1,n - 1
×
939
       h = x(i+1) - x(i)
×
940
       if (h<=zero) go to 80
×
941
       g = g + h
×
942
    end do
943
    avh = g/ (n-1)
×
944
!
945
!---scale relative weights---
946
    g = zero
×
947
    do i = 1,n
×
948
       if (dy(i)<=zero) go to 90
×
949
       g = g + dy(i)*dy(i)
×
950
    end do
951
    avdy = sqrt(g/n)
×
952

953
    dy = dy / avdy
×
954

955
!
956
!---initialize h,f---
957
    h = (x(2)-x(1))/avh
×
958
    f = (y(2)-y(1))/h
×
959
!
960
!---calculate a,t,r---
961
    do i = 2,n - 1
×
962
       g = h
×
963
       h = (x(i+1)-x(i))/avh
×
964
       e = f
×
965
       f = (y(i+1)-y(i))/h
×
966
       a(i) = f - e
×
967
       t(i,1) = 2.0d0* (g+h)/3.0d0
×
968
       t(i,2) = h/3.0d0
×
969
       r(i,3) = dy(i-1)/g
×
970
       r(i,1) = dy(i+1)/h
×
971
       r(i,2) = -dy(i)/g - dy(i)/h
×
972
    end do
973
!
974
!---calculate c = r'*r---
975
    r(n,2) = zero
×
976
    r(n,3) = zero
×
977
    r(n+1,3) = zero
×
978
    do i = 2,n - 1
×
979
       c(i,1) = r(i,1)*r(i,1) + r(i,2)*r(i,2) + r(i,3)*r(i,3)
×
980
       c(i,2) = r(i,1)*r(i+1,2) + r(i,2)*r(i+1,3)
×
981
       c(i,3) = r(i,1)*r(i+2,3)
×
982
    end do
983
    return
×
984
!
985
!---error conditions---
986
60  ier = 130
×
987
    return
×
988

989
70  ier = 129
×
990
    return
×
991

992
80  ier = 131
×
993
    return
×
994

995
   90 ier = 132
×
996
    return
×
997
  end subroutine spint1
998

999
  !> FIXME : Add documentation
1000
  subroutine spfit1(x,avh,dy,n,rho,p,q,fun,var,stat,a,c,ic,r,t,u,v)
×
1001
!
1002
! fits a cubic smoothing spline to data with relative
1003
! weighting dy for a given value of the smoothing parameter
1004
! rho using an algorithm based on that of c.h. reinsch (1967),
1005
! numer. math. 10, 177-183.
1006
!
1007
! the trace of the influence matrix is calculated using an
1008
! algorithm developed by m.f.hutchinson and f.r.de hoog (numer.
1009
! math., in press), enabling the generalized cross validation
1010
! and related statistics to be calculated in order n operations.
1011
!
1012
! the arrays a, c, r and t are assumed to have been initialized
1013
! by the subroutine spint1.  overflow and underflow problems are
1014
! avoided by using p=rho/(1 + rho) and q=1/(1 + rho) instead of
1015
! rho and by scaling the differences x(i+1) - x(i) by avh.
1016
!
1017
! the values in df are assumed to have been scaled so that the
1018
! sum of their squared values is n.  the value in var, when it is
1019
! non-negative, is assumed to have been scaled to compensate for
1020
! the scaling of the values in df.
1021
!
1022
! the value returned in fun is an estimate of the true mean square
1023
! when var is non-negative, and is the generalized cross validation
1024
! when var is negative.
1025
!
1026
!---specifications for arguments---
1027
    integer, intent(in) :: ic,n
1028
! all variables should be double precision:
1029
    real, dimension(:), intent(in) :: x, dy, a
1030
    real, dimension(6), intent(out) :: stat
1031
    real, dimension(ic, 3), intent(in) :: c
1032
    real, dimension(0:n+1, 3), intent(in out) :: r
1033
    real, dimension(0:n+1, 2), intent(in) :: t
1034
    real, dimension(0:n+1), intent(out) :: u, v
1035
    real, intent(in) :: var, avh, rho
1036
    real, intent(out) :: fun, p, q
1037
!
1038
!---local variables---
1039
    integer :: i
1040
    real :: e,f,g,h,rho1
1041
    real, parameter :: zero = 0., one = 1., two = 2.
1042
!
1043
!---use p and q instead of rho to prevent overflow or underflow---
1044
    rho1 = one + rho
×
1045
    p = rho/rho1
×
1046
    q = one/rho1
×
1047
    if (exactly_equal(rho1, one)) p = zero
×
1048
    if (exactly_equal(rho1, rho)) q = zero
×
1049
!
1050
!---rational cholesky decomposition of p*c + q*t---
1051
    f = zero
×
1052
    g = zero
×
1053
    h = zero
×
1054
    do i = 0,1
×
1055
       r(i,1) = zero
×
1056
    end do
1057
    do i = 2,n - 1
×
1058
       r(i-2,3) = g*r(i-2,1)
×
1059
       r(i-1,2) = f*r(i-1,1)
×
1060
       r(i,1) = one/ (p*c(i,1)+q*t(i,1)-f*r(i-1,2)-g*r(i-2,3))
×
1061
       f = p*c(i,2) + q*t(i,2) - h*r(i-1,2)
×
1062
       g = h
×
1063
       h = p*c(i,3)
×
1064
    end do
1065
!
1066
!---solve for u---
1067
    u(0) = zero
×
1068
    u(1) = zero
×
1069
    do i = 2,n - 1
×
1070
       u(i) = a(i) - r(i-1,2)*u(i-1) - r(i-2,3)*u(i-2)
×
1071
    end do
1072
    u(n) = zero
×
1073
    u(n+1) = zero
×
1074
    do i = n - 1,2,-1
×
1075
       u(i) = r(i,1)*u(i) - r(i,2)*u(i+1) - r(i,3)*u(i+2)
×
1076
    end do
1077
!
1078
!---calculate residual vector v---
1079
    e = zero
×
1080
    h = zero
×
1081
    do i = 1,n - 1
×
1082
       g = h
×
1083
       h = (u(i+1)-u(i))/ ((x(i+1)-x(i))/avh)
×
1084
       v(i) = dy(i)* (h-g)
×
1085
       e = e + v(i)*v(i)
×
1086
    end do
1087
    v(n) = dy(n)* (-h)
×
1088
    e = e + v(n)*v(n)
×
1089
!
1090
!---calculate upper three bands of inverse matrix---
1091
    r(n,1) = zero
×
1092
    r(n,2) = zero
×
1093
    r(n+1,1) = zero
×
1094
    do i = n - 1,2,-1
×
1095
       g = r(i,2)
×
1096
       h = r(i,3)
×
1097
       r(i,2) = -g*r(i+1,1) - h*r(i+1,2)
×
1098
       r(i,3) = -g*r(i+1,2) - h*r(i+2,1)
×
1099
       r(i,1) = r(i,1) - g*r(i,2) - h*r(i,3)
×
1100
    end do
1101
!
1102
!---calculate trace---
1103
    f = zero
×
1104
    g = zero
×
1105
    h = zero
×
1106
    do i = 2,n - 1
×
1107
       f = f + r(i,1)*c(i,1)
×
1108
       g = g + r(i,2)*c(i,2)
×
1109
       h = h + r(i,3)*c(i,3)
×
1110
    end do
1111
    f = f + two* (g+h)
×
1112
!
1113
!---calculate statistics---
1114
    stat(1) = p
×
1115
    stat(2) = f*p
×
1116
    stat(3) = n*e/ (f*f)
×
1117
    stat(4) = e*p*p/n
×
1118
    stat(6) = e*p/f
×
1119
    if (var>=zero) go to 80
×
1120
    stat(5) = stat(6) - stat(4)
×
1121
    fun = stat(3)
×
1122
    go to 90
×
1123

1124
80  stat(5) = amax1(stat(4)-two*var*stat(2)/n+var,zero)
×
1125
    fun = stat(5)
×
1126
90  return
×
1127
  end subroutine spfit1
1128

1129
  !> FIXME : Add documentation
1130
  subroutine sperr1(x,avh,dy,n,r,p,var,se)
×
1131
!
1132
! calculates bayesian estimates of the standard errors of the fitted
1133
! values of a cubic smoothing spline by calculating the diagonal elements
1134
! of the influence matrix.
1135
!
1136
!---specifications for arguments---
1137
    integer, intent(in) :: n
1138
    real, dimension(:), intent(in) :: x, dy
1139
    real, dimension(:), intent(out) :: se
1140
    real, dimension(0:n+1, 3), intent(in out) :: r
1141
    real, intent(in) :: avh, p, var
1142
!
1143
!---specifications for local variables---
1144
    integer :: i
1145
    real :: f,g,h,f1,g1,h1
1146
    real, parameter :: zero = 0.
1147
    real, parameter :: one = 1.
1148
!
1149
!---initialize---
1150
    h = avh/ (x(2)-x(1))
×
1151
    se(1) = one - p*dy(1)*dy(1)*h*h*r(2,1)
×
1152
    r(1,1) = zero
×
1153
    r(1,2) = zero
×
1154
    r(1,3) = zero
×
1155
!
1156
!---calculate diagonal elements---
1157
    do i = 2,n - 1
×
1158
       f = h
×
1159
       h = avh/ (x(i+1)-x(i))
×
1160
       g = -f - h
×
1161
       f1 = f*r(i-1,1) + g*r(i-1,2) + h*r(i-1,3)
×
1162
       g1 = f*r(i-1,2) + g*r(i,1) + h*r(i,2)
×
1163
       h1 = f*r(i-1,3) + g*r(i,2) + h*r(i+1,1)
×
1164
       se(i) = one - p*dy(i)*dy(i)* (f*f1+g*g1+h*h1)
×
1165
    end do
1166
    se(n) = one - p*dy(n)*dy(n)*h*h*r(n-1,1)
×
1167
!
1168
!---calculate standard error estimates---
1169
    do i = 1,n
×
1170
       se(i) = sqrt(amax1(se(i)*var,zero))*dy(i)
×
1171
    end do
1172

1173
  end subroutine sperr1
×
1174

1175
  !> FIXME : Add documentation
1176
  subroutine spcof1(x,avh,y,dy,n,p,q,a,c,ic,u,v)
×
1177
!
1178
! calculates coefficients of a cubic smoothing spline from
1179
! parameters calculated by subroutine spfit1.
1180
!
1181
!---specifications for arguments---
1182
    integer, intent(in) :: ic,n
1183
    real, dimension (:), intent(in) :: x, y, dy
1184
    real, dimension (:), intent(out) :: a
1185
    real, dimension (ic, 3), intent(out) :: c
1186
    real, dimension (0:n+1), intent(in out) :: u
1187
    real, dimension (0:n+1), intent(in) :: v
1188
    real, intent(in) :: p, q, avh
1189
!
1190
!---specifications for local variables---
1191
    integer :: i
1192
    real :: h,qh
1193
!
1194
!---calculate a---
1195
    qh = q/ (avh*avh)
×
1196
    do i = 1,n
×
1197
       a(i) = y(i) - p*dy(i)*v(i)
×
1198
       u(i) = qh*u(i)
×
1199
    end do
1200
!
1201
!---calculate c---
1202
    do i = 1,n - 1
×
1203
       h = x(i+1) - x(i)
×
1204
       c(i,3) = (u(i+1)-u(i))/ (3.0d0*h)
×
1205
       c(i,1) = (a(i+1)-a(i))/h - (h*c(i,3)+u(i))*h
×
1206
       c(i,2) = u(i)
×
1207
    end do
1208
  end subroutine spcof1
×
1209

1210
!---c cubgcv test driver
1211
!---c ------------------
1212
!---c
1213
!---c author          - m.f.hutchinson
1214
!---c                   csiro division of water and land resources
1215
!---c                   gpo box 1666
1216
!---c                   canberra act 2601
1217
!---c                   australia
1218
!---c
1219
!---c latest revision - 7 august 1986
1220
!---c
1221
!---c computer        - vax/double
1222
!---c
1223
!---c usage           - main program
1224
!---c
1225
!---c required routines - cubgcv,spint1,spfit1,spcof1,sperr1,ggrand
1226
!---c
1227
!---c remarks   uses subroutine cubgcv to fit a cubic smoothing spline
1228
!---c           to 50 data points which are generated by adding a random
1229
!---c           variable with uniform density in the interval [-0.3,0.3]
1230
!---c           to 50 points sampled from the curve  y=sin(3*pi*x/2).
1231
!---c           random deviates in the interval [0,1] are generated by the
1232
!---c           double precision function ggrand (similar to imsl function
1233
!---c           ggubfs).  the abscissae are unequally spaced in [0,1].
1234
!---c
1235
!---c           point standard error estimates are returned in se by
1236
!---c           setting job=1.  the error variance estimate is returned
1237
!---c           in var.  it compares favourably with the true value of 0.03.
1238
!---c           summary statistics from the array wk are written to
1239
!---c           unit 6.  data values and fitted values with estimated
1240
!---c           standard errors are also written to unit 6.
1241
!---c
1242
!---      parameter (n=50, ic=49)
1243
!---c
1244
!---      integer            job,ier
1245
!---      double precision   x(n),f(n),y(n),df(n),c(ic,3),wk(7*(n+2)),
1246
!---     *                   var,se(n)
1247
!---      double precision   ggrand,dseed
1248
!---c
1249
!---c---initialize---
1250
!---      dseed=1.2345d4
1251
!---      job=1
1252
!---      var=-1.0d0
1253
!---c
1254
!---c---calculate data points---
1255
!---      do 10 i=1,n
1256
!---      x(i)=(i - 0.5)/n + (2.0*ggrand(dseed) - 1.0)/(3.0*n)
1257
!---      f(i)=dsin(4.71238*x(i)) + (2.0*ggrand(dseed) - 1.0)*0.3
1258
!---      df(i)=1.0d0
1259
!---  10  continue
1260
!---c
1261
!---c---fit cubic spline---
1262
!---      call cubgcv(x,f,df,n,y,c,ic,var,job,se,wk,ier)
1263
!---c
1264
!---c---write out results---
1265
!---      write(6,20)
1266
!---  20  format(' cubgcv test driver results:')
1267
!---      write(6,30) ier,var,wk(3),wk(4),wk(2)
1268
!---  30  format(/' ier =',i4/' var =',f7.4/
1269
!---     *        ' generalized cross validation =',f7.4/
1270
!---     *        ' mean square residual         =',f7.4/
1271
!---     *        ' residual degrees of freedom  =',f7.2)
1272
!---      write(6,40)
1273
!---  40  format(/' input data',17x,'output results'//
1274
!---     *         '   i    x(i)    f(i)',6x,'    y(i)   se(i)',
1275
!---     *          '      c(i,1)      c(i,2)      c(i,3)')
1276
!---      do 60 i=1,n-1
1277
!---      write(6,50) i,x(i),f(i),y(i),se(i),(c(i,j),j=1,3)
1278
!---  50  format(i4,2f8.4,6x,2f8.4,3e12.4)
1279
!---  60  continue
1280
!---      write(6,50) n,x(n),f(n),y(n),se(n)
1281
!---      stop
1282
!---      end
1283
!---      double precision function ggrand(dseed)
1284
!---c
1285
!---c double precision uniform random number generator
1286
!---c
1287
!---c constants: a = 7**5
1288
!---c            b = 2**31 - 1
1289
!---c            c = 2**31
1290
!---c
1291
!---c reference: imsl manual, chapter g - generation and testing of
1292
!---c                                     random numbers
1293
!---c
1294
!---c---specifications for arguments---
1295
!---      double precision dseed
1296
!---c
1297
!---c---specifications for local variables---
1298
!---      double precision a,b,c,s
1299
!---c
1300
!---      data a,b,c/16807.0d0, 2147483647.0d0, 2147483648.0d0/
1301
!---c
1302
!---      s=dseed
1303
!---      s=dmod(a*s, b)
1304
!---      ggrand=s/c
1305
!---      dseed=s
1306
!---      return
1307
!---      end
1308
!---
1309
!---cubgcv test driver results:
1310
!---
1311
!---ier =   0
1312
!---var = 0.0279
1313
!---generalized cross validation = 0.0318
1314
!---mean square residual         = 0.0246
1315
!---residual degrees of freedom  =  43.97
1316
!---
1317
!---input data                 output results
1318
!---
1319
!---  i    x(i)    f(i)          y(i)   se(i)      c(i,1)      c(i,2)      c(i,3)
1320
!---  1  0.0046  0.2222        0.0342  0.1004  0.3630e+01  0.0000e+00  0.2542e+02
1321
!---  2  0.0360 -0.1098        0.1488  0.0750  0.3705e+01  0.2391e+01 -0.9537e+01
1322
!---  3  0.0435 -0.0658        0.1767  0.0707  0.3740e+01  0.2175e+01 -0.4233e+02
1323
!---  4  0.0735  0.3906        0.2900  0.0594  0.3756e+01 -0.1642e+01 -0.2872e+02
1324
!---  5  0.0955  0.6054        0.3714  0.0558  0.3642e+01 -0.3535e+01  0.2911e+01
1325
!---  6  0.1078  0.3034        0.4155  0.0549  0.3557e+01 -0.3428e+01 -0.1225e+02
1326
!---  7  0.1269  0.7386        0.4822  0.0544  0.3412e+01 -0.4131e+01  0.2242e+02
1327
!---  8  0.1565  0.4616        0.5800  0.0543  0.3227e+01 -0.2143e+01  0.6415e+01
1328
!---  9  0.1679  0.4315        0.6165  0.0543  0.3180e+01 -0.1923e+01 -0.1860e+02
1329
!--- 10  0.1869  0.5716        0.6762  0.0544  0.3087e+01 -0.2985e+01 -0.3274e+02
1330
!--- 11  0.2149  0.6736        0.7595  0.0542  0.2843e+01 -0.5733e+01 -0.4435e+02
1331
!--- 12  0.2356  0.7388        0.8155  0.0539  0.2549e+01 -0.8486e+01 -0.5472e+02
1332
!--- 13  0.2557  1.1953        0.8630  0.0537  0.2139e+01 -0.1180e+02 -0.9784e+01
1333
!--- 14  0.2674  1.0299        0.8864  0.0536  0.1860e+01 -0.1214e+02  0.9619e+01
1334
!--- 15  0.2902  0.7981        0.9225  0.0534  0.1322e+01 -0.1149e+02 -0.7202e+01
1335
!--- 16  0.3155  0.8973        0.9485  0.0532  0.7269e+00 -0.1203e+02 -0.1412e+02
1336
!--- 17  0.3364  1.2695        0.9583  0.0530  0.2040e+00 -0.1292e+02  0.2796e+02
1337
!--- 18  0.3557  0.7253        0.9577  0.0527 -0.2638e+00 -0.1130e+02 -0.3453e+01
1338
!--- 19  0.3756  1.2127        0.9479  0.0526 -0.7176e+00 -0.1151e+02  0.3235e+02
1339
!--- 20  0.3881  0.7304        0.9373  0.0525 -0.9889e+00 -0.1030e+02  0.4381e+01
1340
!--- 21  0.4126  0.9810        0.9069  0.0525 -0.1486e+01 -0.9977e+01  0.1440e+02
1341
!--- 22  0.4266  0.7117        0.8842  0.0525 -0.1756e+01 -0.9373e+01 -0.8925e+01
1342
!--- 23  0.4566  0.7203        0.8227  0.0524 -0.2344e+01 -0.1018e+02 -0.2278e+02
1343
!--- 24  0.4704  0.9242        0.7884  0.0524 -0.2637e+01 -0.1112e+02 -0.4419e+01
1344
!--- 25  0.4914  0.7345        0.7281  0.0523 -0.3110e+01 -0.1140e+02 -0.3562e+01
1345
!--- 26  0.5084  0.7378        0.6720  0.0524 -0.3500e+01 -0.1158e+02  0.5336e+01
1346
!--- 27  0.5277  0.7441        0.6002  0.0525 -0.3941e+01 -0.1127e+02  0.2479e+02
1347
!--- 28  0.5450  0.5612        0.5286  0.0527 -0.4310e+01 -0.9980e+01  0.2920e+02
1348
!--- 29  0.5641  0.5049        0.4429  0.0529 -0.4659e+01 -0.8309e+01  0.3758e+02
1349
!--- 30  0.5857  0.4725        0.3390  0.0531 -0.4964e+01 -0.5878e+01  0.5563e+02
1350
!--- 31  0.6159  0.1380        0.1850  0.0531 -0.5167e+01 -0.8307e+00  0.4928e+02
1351
!--- 32  0.6317  0.1412        0.1036  0.0531 -0.5157e+01  0.1499e+01  0.5437e+02
1352
!--- 33  0.6446 -0.1110        0.0371  0.0531 -0.5091e+01  0.3614e+01  0.3434e+02
1353
!--- 34  0.6707 -0.2605       -0.0927  0.0532 -0.4832e+01  0.6302e+01  0.1164e+02
1354
!--- 35  0.6853 -0.1284       -0.1619  0.0533 -0.4640e+01  0.6812e+01  0.1617e+02
1355
!--- 36  0.7064 -0.3452       -0.2564  0.0536 -0.4332e+01  0.7834e+01  0.4164e+01
1356
!--- 37  0.7310 -0.5527       -0.3582  0.0538 -0.3939e+01  0.8141e+01 -0.2214e+02
1357
!--- 38  0.7531 -0.3459       -0.4415  0.0540 -0.3611e+01  0.6674e+01 -0.9205e+01
1358
!--- 39  0.7686 -0.5902       -0.4961  0.0541 -0.3410e+01  0.6245e+01 -0.2193e+02
1359
!--- 40  0.7952 -0.7644       -0.5828  0.0541 -0.3125e+01  0.4494e+01 -0.4649e+02
1360
!--- 41  0.8087 -0.5392       -0.6242  0.0541 -0.3029e+01  0.2614e+01 -0.3499e+02
1361
!--- 42  0.8352 -0.4247       -0.7031  0.0539 -0.2964e+01 -0.1603e+00  0.2646e+01
1362
!--- 43  0.8501 -0.6327       -0.7476  0.0538 -0.2967e+01 -0.4132e-01  0.1817e+02
1363
!--- 44  0.8726 -0.9983       -0.8139  0.0538 -0.2942e+01  0.1180e+01 -0.6774e+01
1364
!--- 45  0.8874 -0.9082       -0.8574  0.0542 -0.2911e+01  0.8778e+00 -0.1364e+02
1365
!--- 46  0.9139 -0.8930       -0.9340  0.0566 -0.2893e+01 -0.2044e+00 -0.8094e+01
1366
!--- 47  0.9271 -1.0233       -0.9723  0.0593 -0.2903e+01 -0.5258e+00 -0.1498e+02
1367
!--- 48  0.9473 -0.8839       -1.0313  0.0665 -0.2942e+01 -0.1433e+01  0.4945e+01
1368
!--- 49  0.9652 -1.0172       -1.0843  0.0766 -0.2989e+01 -0.1168e+01  0.1401e+02
1369
!--- 50  0.9930 -1.2715       -1.1679  0.0998
1370
!---
1371
!---
1372
!---algorithm
1373
!---
1374
!---cubgcv calculates a natural cubic spline curve which smoothes a given set
1375
!---of data points, using statistical considerations to determine the amount
1376
!---of smoothing required, as described in reference 2.  if the error variance
1377
!---is known, it should be supplied to the routine in var.  the degree of
1378
!---smoothing is then determined by minimizing an unbiased estimate of the true
1379
!---mean square error.  on the other hand, if the error variance is not known, var
1380
!---should be set to -1.0.  the routine then determines the degree of smoothing
1381
!---by minimizing the generalized cross validation.  this is asymptotically the
1382
!---same as minimizing the true mean square error (see reference 1).  in this
1383
!---case, an estimate of the error variance is returned in var which may be
1384
!---compared with any a priori approximate estimates.  in either case, an
1385
!---estimate of the true mean square error is returned in wk(5).  this estimate,
1386
!---however, depends on the error variance estimate, and should only be accepted
1387
!---if the error variance estimate is reckoned to be correct.
1388
!---
1389
!---if job is set to 1, bayesian estimates of the standard error of each
1390
!---smoothed data value are returned in the array se.  these also depend on
1391
!---the error variance estimate and should only be accepted if the error
1392
!---variance estimate is reckoned to be correct.  see reference 4.
1393
!---
1394
!---the number of arithmetic operations and the amount of storage required by
1395
!---the routine are both proportional to n, so that very large data sets may be
1396
!---analysed.  the data points do not have to be equally spaced or uniformly
1397
!---weighted.  the residual and the spline coefficients are calculated in the
1398
!---manner described in reference 3, while the trace and various statistics,
1399
!---including the generalized cross validation, are calculated in the manner
1400
!---described in reference 2.
1401
!---
1402
!---when var is known, any value of n greater than 2 is acceptable.  it is
1403
!---advisable, however, for n to be greater than about 20 when var is unknown.
1404
!---if the degree of smoothing done by cubgcv when var is unknown is not
1405
!---satisfactory, the user should try specifying the degree of smoothing by
1406
!---setting var to a reasonable value.
1407
!---
1408
!---references:
1409
!---
1410
!---1.  craven, peter and wahba, grace, "smoothing noisy data with spline
1411
!---    functions", numer. math. 31, 377-403 (1979).
1412
!---2.  hutchinson, m.f. and de hoog, f.r., "smoothing noisy data with spline
1413
!---    functions", numer. math. (in press).
1414
!---3.  reinsch, c.h., "smoothing by spline functions", numer. math. 10,
1415
!---    177-183 (1967).
1416
!---4.  wahba, grace, "bayesian 'confidence intervals' for the cross-validated
1417
!---    smoothing spline", j.r.statist. soc. b 45, 133-150 (1983).
1418
!---
1419
!---
1420
!---example
1421
!---
1422
!---a sequence of 50 data points are generated by adding a random variable with
1423
!---uniform density in the interval [-0.3,0.3] to the curve y=sin(3*pi*x/2).
1424
!---the abscissae are unequally spaced in [0,1].  point standard error estimates
1425
!---are returned in se by setting job to 1.  the error variance estimate is
1426
!---returned in var.  it compares favourably with the true value of 0.03.
1427
!---the imsl function ggubfs is used to generate sample values of a uniform
1428
!---variable on [0,1].
1429
!---
1430
!---
1431
!---input:
1432
!---
1433
!---      integer          n,ic,job,ier
1434
!---      double precision x(50),f(50),y(50),df(50),c(49,3),wk(400),
1435
!---     *                 var,se(50)
1436
!---      double precision ggubfs,dseed,dn
1437
!---      data dseed/1.2345d4/
1438
!---c
1439
!---      n=50
1440
!---      ic=49
1441
!---      job=1
1442
!---      var=-1.0d0
1443
!---      dn=n
1444
!---c
1445
!---      do 10 i=1,n
1446
!---      x(i)=(i - 0.5)/dn + (2.0*ggubfs(dseed) - 1.0)/(3.0*dn)
1447
!---      f(i)=dsin(4.71238*x(i)) + (2.0*ggubfs(dseed) - 1.0)*0.3
1448
!---      df(i)=1.0d0
1449
!---  10  continue
1450
!---      call cubgcv(x,f,df,n,y,c,ic,var,job,se,wk,ier)
1451
!---       .
1452
!---       .
1453
!---       .
1454
!---      end
1455
!---
1456
!---output:
1457
!---
1458
!---ier = 0
1459
!---var = 0.0279
1460
!---generalized cross validation = 0.0318
1461
!---mean square residual = 0.0246
1462
!---residual degrees of freedom = 43.97
1463
!---for checking purposes the following output is given:
1464
!---
1465
!---x(1)  = 0.0046    f(1)  =  0.2222     y(1)  =  0.0342     se(1)  = 0.1004
1466
!---x(21) = 0.4126    f(21) =  0.9810     y(21) =  0.9069     se(21) = 0.0525
1467
!---x(41) = 0.8087    f(41) = -0.5392     y(41) = -0.6242     se(41) = 0.0541
1468
!---
1469
end program rungridgen
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc