2 USE vmec_main,
ONLY: dp, rprec, neqs, ns, nthreed,
3 1 one, fsqr, fsqz, fsql
4 USE parallel_include_module
5 USE parallel_vmec_module,
ONLY:
copylastntype, saxpbylastntype,
6 1 saxpbylastns, saxpby1lastns,
7 2 getderivlastns, saxlastntype
8 USE precon2d,
ONLY: ictrl_prec2d
10 INTEGER :: nfcn = 0, lqmrstep = 0
11 INTEGER :: ier_flag_res
12 LOGICAL :: lqmr, lfirst
13 LOGICAL,
PARAMETER :: lscreen0 = .false.
21 SUBROUTINE matvec_par (ploc, Ap, nloc)
24 USE xstuff,
ONLY: pxc, px0=>pxsave, pgc0=>pxcdot, pgc
28 INTEGER,
INTENT(IN) :: nloc
29 REAL(dp),
INTENT(IN) ::
30 & ploc(ntmaxblocksize,tlglob:trglob)
31 REAL(dp),
INTENT(OUT) ::
32 & Ap(ntmaxblocksize,tlglob:trglob)
36 INTEGER :: mblk_size, istat
37 REAL(dp) :: delta, lmax, gmax, pmax, apmax
46 delta = sqrt(epsilon(delta))
48 lactive0:
IF (lactive)
THEN
49 IF (nloc .NE. (trglob - tlglob + 1)*mblk_size)
THEN
50 stop
'nloc wrong in matvec_par'
53 CALL mpi_allreduce(lmax, pmax, 1, mpi_real8, mpi_sum, ns_comm,
56 delta = delta/max(delta, pmax)
58 CALL saxpbylastns(delta, ploc, one, px0, pxc)
64 CALL funct3d_par(lscreen0, ier_flag_res)
68 CALL getderivlastns(pgc, pgc0, delta, ap)
71 IF (ier_flag_res.NE.0 .AND. rank.EQ.0)
THEN
72 print *,
'IN MATVEC_PAR, IER_FLAG = ', ier_flag_res
78 END SUBROUTINE matvec_par
80 SUBROUTINE getnlforce_par(xcstate, fsq_nl, bnorm)
81 USE xstuff,
ONLY: pxc, pgc, x0=>pxsave
85 REAL(dp),
INTENT(IN) :: xcstate(neqs), bnorm
86 REAL(dp),
INTENT(OUT) :: fsq_nl
90 lactive0:
IF (lactive)
THEN
91 CALL saxpby1lastns(bnorm, xcstate, one, x0, pxc)
96 CALL funct3d_par(lscreen0, ier_flag_res)
97 IF (lactive)
CALL last_ns_par
99 fsq_nl = fsqr + fsqz + fsql
102 END SUBROUTINE getnlforce_par
106 SUBROUTINE last_ns_par
109 REAL(dp),
ALLOCATABLE,
DIMENSION(:) :: tmp
110 ALLOCATE (tmp(ntmaxblocksize*ns))
112 CALL tolastns(pgc,tmp)
113 CALL copylastns(tmp,pgc)
115 CALL tolastns(pxcdot,tmp)
116 CALL copylastns(tmp,pxcdot)
118 CALL tolastns(pxc,tmp)
119 CALL copylastns(tmp,pxc)
121 CALL tolastns(pxsave,tmp)
122 CALL copylastns(tmp,pxsave)
126 END SUBROUTINE last_ns_par
130 SUBROUTINE last_ntype_par
133 REAL(dp),
ALLOCATABLE,
DIMENSION(:) :: tmp
134 ALLOCATE (tmp(ntmaxblocksize*ns))
136 CALL tolastntype(pgc,tmp)
139 CALL tolastntype(pxcdot,tmp)
142 CALL tolastntype(pxc,tmp)
145 CALL tolastntype(pxsave,tmp)
149 END SUBROUTINE last_ntype_par
153 SUBROUTINE gmres_fun_par (ier_flag, itype, lscreen)
154 USE precon2d,
ONLY: ictrl_prec2d, block_precond_par
156 USE vmec_main,
ONLY: fsqr, fsqz, fsql, ftolv
161 INTEGER,
INTENT(IN) :: itype
162 INTEGER,
INTENT(OUT) :: ier_flag
163 LOGICAL,
INTENT(IN) :: lscreen
167 TYPE (gmres_info) :: gi
169 INTEGER :: icntl(9), info(3)
170 REAL(dp) :: cntl(5), fact, fact_min, fsq_min, fsq2,
171 & fsqr_min, fsqz_min, fsql_min
172 CHARACTER(LEN=*),
PARAMETER :: qmr_message =
173 &
'Beginning GMRES iterations'
174 INTEGER,
PARAMETER :: noPrec=0, leftprec=1, rightprec=2
182 CALL gmresr_fun (ier_flag)
184 ELSE IF (itype == 3)
THEN
193 WRITE (*,
'(2x,a,/)') qmr_message
194 WRITE (nthreed,
'(2x,a,/)') qmr_message
202 CALL init_dgmres(icntl,cntl)
247 gi%m=m; gi%icntl=icntl; gi%cntl=cntl; gi%info = info
251 ALLOCATE(gi%rcounts(nranks),gi%disp(nranks))
252 gi%startglobrow=tlglob
256 gi%rcounts=ntblkrcounts
258 gi%mblk_size=ntmaxblocksize
261 gi%my_comm_world = runvmec_comm_world
264 gi%lverbose = lscreen
267 IF (icntl(4) .NE. noprec) ictrl_prec2d = -1
268 CALL funct3d_par(lscreen0, ier_flag_res)
283 CALL gmres_par(n, gi, matvec_par, block_precond_par,
284 & getnlforce_par, pxcdot, pgc)
291 fact = 1; fact_min = fact
293 fsqr_min = fsqr; fsqz_min = fsqz; fsql_min = fsql
297 1010
FORMAT(1x,
'LINE SEARCH - SCAN ||X|| FOR MIN FSQ_NL',/,
299 & 1x,
'ITER',7x,
'FSQ_NL',10x,
'||X||',9x,
'MAX|X|')
301 CALL mpi_bcast(fsq_min, 1, mpi_real8, 0, runvmec_comm_world,
305 fact = fact*sqrt(0.5_dp)
306 CALL saxpbylastntype(fact, pxcdot, one, pxsave, pxc)
308 CALL funct3d_par(lscreen0, ier_flag_res)
310 fsq2 = fsqr+fsqz+fsql
312 IF (fsq2 .LT. fsq_min)
THEN
315 fsqr_min = fsqr; fsqz_min = fsqz; fsql_min = fsql
316 IF (grank .EQ. 0) print 1020, fact, fsq2
322 1020
FORMAT(2x,
'GMRES_FUN, TIME_STEP: ',1p,e10.3,
' FSQ_MIN: ',1pe10.3)
324 fsqr = fsqr_min; fsqz = fsqz_min; fsql = fsql_min
325 IF (ictrl_prec2d .EQ. 1)
THEN
326 CALL saxlastntype(pxcdot,pcol_scale,pxcdot)
329 CALL saxpbylastntype(fact_min, pxcdot, one, pxsave, pxc)
332 DEALLOCATE(gi%rcounts,gi%disp)
335 END SUBROUTINE gmres_fun_par
337 SUBROUTINE getnlforce(xcstate, fsq_nl, bnorm)
338 USE xstuff,
ONLY: xc, gc, x0=>xsave
342 REAL(dp),
INTENT(IN) :: xcstate(neqs), bnorm
343 REAL(dp),
INTENT(OUT) :: fsq_nl
346 xc(1:neqs) = x0(1:neqs) + bnorm*xcstate(1:neqs)
348 CALL funct3d(lscreen0, ier_flag_res)
349 fsq_nl = fsqr+fsqz+fsql
353 END SUBROUTINE getnlforce
355 SUBROUTINE matvec (p, Ap, ndim)
356 USE xstuff,
ONLY: xc, x0=>xsave, gc0=>xcdot, gc
360 INTEGER,
INTENT(in) :: ndim
361 REAL(dp),
INTENT(in),
DIMENSION(ndim) :: p
362 REAL(dp),
INTENT(out),
DIMENSION(ndim) :: Ap
367 REAL(dp) :: delta, pmax
376 delta = sqrt(epsilon(delta))
377 pmax = sqrt(sum(p(1:ndim)**2))
378 delta = delta/max(delta, pmax)
380 xc(1:ndim) = x0(1:ndim) + delta*p(1:ndim)
381 CALL funct3d(lscreen0, ier_flag_res)
382 ap = (gc(1:ndim) - gc0(1:ndim))/delta
384 IF (ier_flag_res .NE. 0)
THEN
385 print *,
'IN MATVEC, IER_FLAG = ', ier_flag_res
391 END SUBROUTINE matvec
393 SUBROUTINE gmres_fun (ier_flag, itype)
394 USE precon2d,
ONLY: block_precond
396 USE vmec_main,
ONLY: fsqr, fsqz, fsql, ftolv
401 INTEGER,
INTENT(IN) :: itype
402 INTEGER,
INTENT(OUT) :: ier_flag
406 TYPE (gmres_info) :: gi
408 INTEGER :: icntl(9), info(3)
409 REAL(dp) :: cntl(5), fact, fact_min, fsq_min, fsq2,
410 & fsqr_min, fsqz_min, fsql_min
411 CHARACTER(LEN=*),
PARAMETER :: qmr_message =
412 &
'Beginning GMRES iterations'
413 INTEGER,
PARAMETER :: noPrec=0, leftprec=1, rightprec=2
421 CALL gmresr_fun (ier_flag)
423 ELSE IF (itype == 3)
THEN
431 WRITE (*,
'(2x,a,/)') qmr_message
432 WRITE (nthreed,
'(2x,a,/)') qmr_message
439 CALL init_dgmres(icntl,cntl)
484 gi%m=m; gi%icntl=icntl; gi%cntl=cntl; gi%info = info
489 IF (icntl(4) .NE. noprec) ictrl_prec2d = -1
490 CALL funct3d(lscreen0, ier_flag_res)
503 CALL gmres_ser(n, gi, matvec, block_precond, getnlforce,
513 fsq_min = huge(fsq_min)
518 xc(1:n) = xsave(1:n) + fact*xcdot(1:n)
520 CALL funct3d(lscreen0, ier_flag_res)
522 fsq2 = fsqr+fsqz+fsql
524 IF (fsq2 .LT. fsq_min)
THEN
527 fsqr_min = fsqr; fsqz_min = fsqz; fsql_min = fsql
538 xc(1:n) = xsave(1:n) + fact_min*xcdot(1:n)
539 fsqr = fsqr_min; fsqz = fsqz_min; fsql = fsql_min
542 END SUBROUTINE gmres_fun
544 SUBROUTINE gmresr_fun (ier_flag)
553 INTEGER :: ndim, jtrunc, mgmres, maxits, lwork
555 REAL(dp) :: eps, resid
556 REAL(dp),
ALLOCATABLE,
DIMENSION(:) :: work, delx, brhs
557 CHARACTER(len=3),
PARAMETER :: stc=
"rel"
558 CHARACTER(LEN=*),
PARAMETER :: qmr_message =
559 &
'Beginning GMRESR iterations'
563 WRITE (*,
'(2x,a,/)') qmr_message
564 WRITE (nthreed,
'(2x,a,/)') qmr_message
572 lwork = ndim*(2*jtrunc + mgmres + 2)
575 ALLOCATE(work(lwork), delx(ndim), brhs(ndim), stat=ier_flag_res)
576 IF (ier_flag_res .ne. 0) stop
'Allocation failed in gmresr'
581 CALL gmresr(oktest, ndim, jtrunc, mgmres, brhs, delx, work,
582 & eps, stc, maxits, resid, matvec, ier_flag_res)
584 xc(1:ndim) = xsave(1:ndim) + delx(1:ndim)
586 DEALLOCATE (work, delx, brhs)
590 END SUBROUTINE gmresr_fun
593 USE vmec_dim,
ONLY: ns, mpol1, ntor1
594 USE vmec_params,
ONLY: ntmax
595 USE vmec_main,
ONLY: lfreeb
600 INTEGER :: ndim, nlen, nlim, ierr, info(4)
601 INTEGER :: revcom, colx, colb
602 INTEGER :: nty, ntyp, mt, mp, nt, np, jp, js
603 REAL(dp),
DIMENSION(neqs,9) :: vecs
604 REAL(dp) :: tol = 1.e-3_dp
605 CHARACTER(LEN=*),
PARAMETER :: qmr_message =
606 1
'Beginning TF-QMR iterations'
607 LOGICAL,
PARAMETER :: ldump_fort33 = .false.
617 WRITE (*,
'(2x,a,/)') qmr_message
618 WRITE (nthreed,
'(2x,a,/)') qmr_message
619 IF (ldump_fort33)
THEN
626 WRITE(33,
'(a,i4)')
"NTYPE' (XC-pert) = ",nty
628 WRITE(33,
'(a,i4)')
"M' = ",mt
630 WRITE(33,
'(a,i4)')
"N' = ",nt
633 IF (ierr .gt. ndim)
EXIT
634 IF (mod(ierr,50).eq.0) print
'(2x,a,f8.2,a)',
'Progress: ',
635 1 real(100*ierr)/ndim,
' %'
636 IF (js.eq.ns .and. .not.lfreeb) cycle
638 vecs(:,colx) = 0; vecs(ierr,colx) = 1
639 CALL matvec(vecs(1,colx), vecs(1,colb), ndim)
640 WRITE (33,
'(a,i4,2x,a,i5,2x,a,1p,e12.2)')
"js' = ", js,
641 1
' ipert = ',ierr,
' Ap[ipert,ipert] = ', vecs(ierr, colb)
648 IF (colx .gt. ndim) cycle
649 IF (colx.eq.ierr .or.
650 1 abs(vecs(colx,colb)).lt.0.05_dp) cycle
651 WRITE (33, 123)
'ntype = ', ntyp,
' m = ',mp,
652 1
' n = ', np,
' js = ', jp,
' iforce = ',colx,
653 2
' Ap[iforce,ipert] = ', vecs(colx,colb)
663 print
'(/,2x,a,/)',
'Jacobian check in file FORT.33'
668 123
FORMAT(4x,4(a,i4),a,i6,a,1p,e12.3)
672 vecs(:ndim,2) = -gc(:ndim)
673 vecs(:ndim,3) = gc(:ndim)
679 10
CALL dutfx (ndim,nlen,nlim,vecs,tol,info)
683 IF (revcom .eq. 1)
THEN
684 CALL matvec (vecs(1,colx), vecs(1,colb), ndim)
688 xc(1:ndim) = xsave(1:ndim) + vecs(1:ndim,1)
690 END SUBROUTINE qmr_fun
694 SUBROUTINE truncate(num, iprec0)
695 USE stel_kinds,
ONLY: dp
701 INTEGER,
INTENT(IN) :: iprec0
702 REAL(dp),
INTENT(INOUT) :: num
707 CHARACTER*24 :: chnum, tchnum
719 END SUBROUTINE truncate