@@ -50,15 +50,23 @@ end subroutine rhojac_t
5050 end type hompack_callbacks
5151
5252 type fixnpf_workspace
53- ! ! Workspace for 'fixpnf'.
53+ ! ! Linear-algebra workspace for 'fixpnf'.
5454 real (dp), allocatable :: alpha(:)
55+ ! ! Array used during interpolation and Newton-step calculations.
5556 real (dp), allocatable :: qr(:, :)
57+ ! ! Matrix for QR factorizations used in Newton-step calculations.
5658 real (dp), allocatable :: tz(:)
59+ ! ! Array used in QR-factorization and Newton-step computations.
5760 real (dp), allocatable :: w(:)
61+ ! ! Array used during interpolation and Newton-step calculations.
5862 real (dp), allocatable :: wp(:)
63+ ! ! Array used during interpolation and Newton-step calculations.
5964 real (dp), allocatable :: z0(:)
65+ ! ! Array used for estimating the optimal next step size.
6066 real (dp), allocatable :: z1(:)
67+ ! ! Array used for estimating the optimal next step size.
6168 integer , allocatable :: pivot(:)
69+ ! ! Pivot indices used by the QR factorization.
6270 contains
6371 procedure :: alloc = > allocate_workspace
6472 end type fixnpf_workspace
@@ -81,7 +89,7 @@ end subroutine rhojac_t
8189 real (dp), allocatable :: yold(:)
8290 real (dp), allocatable :: yp(:)
8391 real (dp), allocatable :: ypold(:)
84- type (fixnpf_workspace) :: workspace
92+ type (fixnpf_workspace) :: ws
8593 contains
8694 procedure :: alloc = > allocate_state
8795 end type fixnpf_state
@@ -350,9 +358,6 @@ impure subroutine fixpnf( &
350358
351359 integer :: info, iter, np1
352360
353- real (dp) :: alpha(3 * n + 3 ), qr(n, n + 2 ), tz(n + 1 ), w(n + 1 ), wp(n + 1 ), z0(n + 1 ), z1(n + 1 )
354- integer :: pivot(n + 1 )
355-
356361 np1 = n + 1
357362
358363 ! Check for illegal input parameters
@@ -483,7 +488,7 @@ impure subroutine fixpnf( &
483488 end if
484489
485490 ! Take a step along the curve
486- call stepnf(callbacks, state, y, a, qr, alpha, tz, pivot, w, wp, z0, z1, sspar)
491+ call stepnf(callbacks, state, y, a, sspar)
487492
488493 ! Print latest point on curve if requested
489494 if (trace > 0 ) then
@@ -518,8 +523,8 @@ impure subroutine fixpnf( &
518523 if (y(1 ) >= one) then
519524
520525 ! Save 'yold' for arc length calculation later
521- z0 = state% yold
522- call rootnf(callbacks, state, ansre, ansae, y, a, qr, alpha, tz, pivot, w, wp )
526+ state % ws % z0 = state% yold
527+ call rootnf(callbacks, state, ansre, ansae, y, a)
523528 nfe = state% nfe
524529 iflag = 1
525530
@@ -528,8 +533,8 @@ impure subroutine fixpnf( &
528533 if (state% iflag > 0 ) iflag = state% iflag
529534
530535 ! Calculate final arc length
531- w = y - z0
532- arclen = state% s - state% hold + norm2(w)
536+ state % ws % w = y - state % ws % z0
537+ arclen = state% s - state% hold + norm2(state % ws % w)
533538 return
534539
535540 end if
@@ -554,8 +559,7 @@ impure subroutine fixpnf( &
554559
555560 end subroutine fixpnf
556561
557- subroutine rootnf ( &
558- callbacks , state , relerr , abserr , y , a , qr , alpha , tz , pivot , w , wp )
562+ subroutine rootnf (callbacks , state , relerr , abserr , y , a )
559563 ! ! This subroutine finds the point `ybar = (1, xbar)` on the zero curve of the homotopy
560564 ! ! map. It starts with two points `yold = (lambdaold, xold)` and `y = (lambda, x)` such
561565 ! ! that `lambdaold < 1 <= lambda` , and alternates between secant estimates of `ybar`
@@ -583,24 +587,6 @@ subroutine rootnf( &
583587 ! ! at `lambda = 1`.
584588 real (dp), intent (in ) :: a(:)
585589 ! ! Parameter vector used in the homotopy map.
586- real (dp), intent (inout ) :: qr(:, :)
587- ! ! Workspace for QR factorizations used in Newton-step computations.
588- ! ! `Shape: (n, n+2)`.
589- real (dp), intent (inout ) :: alpha(:)
590- ! ! Workspace used during interpolation and Newton iteration.
591- ! ! `Shape: (3*n+3)`.
592- real (dp), intent (inout ) :: tz(:)
593- ! ! Workspace array used in QR-factorization and Newton-step calculations.
594- ! ! `Shape: (n+1)`.
595- integer , intent (inout ) :: pivot(:)
596- ! ! Pivot indices used by the QR factorization.
597- ! ! `Shape: (n+1)`.
598- real (dp), intent (inout ) :: w(:)
599- ! ! Workspace array used for interpolation and Newton-step calculations.
600- ! ! `Shape: (n+1)`.
601- real (dp), intent (inout ) :: wp(:)
602- ! ! Workspace array used for interpolation and Newton-step calculations.
603- ! ! `Shape: (n+1)`.
604590
605591 real (dp) :: dels, qsout, aerr, rerr, sa, sb, sout, u
606592 integer :: judy, jw, lcode, limit, np1
@@ -615,8 +601,8 @@ subroutine rootnf( &
615601 ! following parameter statement
616602 limit = 2 * (int (abs (log10 (aerr + rerr))) + 1 )
617603
618- tz = y - state% yold
619- dels = norm2(tz)
604+ state % ws % tz = y - state% yold
605+ dels = norm2(state % ws % tz)
620606
621607 ! Using two points and tangents on the homotopy zero curve, construct the Hermite
622608 ! cubic interpolant q(s). Then use 'root' to find the 's' corresponding to
@@ -638,7 +624,7 @@ subroutine rootnf( &
638624
639625 ! Calculate q(sa) as the initial point for a Newton iteration
640626 do jw = 1 , np1
641- w(jw) = qofs(state% yold(jw), state% ypold(jw), y(jw), state% yp(jw), dels, sa)
627+ state % ws % w(jw) = qofs(state% yold(jw), state% ypold(jw), y(jw), state% yp(jw), dels, sa)
642628 end do
643629
644630 ! Tangent information 'yp' is no longer needed. Hereafter, 'yp' represents the most
@@ -656,29 +642,29 @@ subroutine rootnf( &
656642
657643 ! Calculate Newton step at current estimate 'w'
658644 call tangnf(callbacks, &
659- sa, w, wp, state% ypold, a, qr, alpha, tz, pivot, &
645+ sa, state % ws % w, state % ws % wp, state% ypold, a, state % ws % qr, state % ws % alpha, state % ws % tz, state % ws % pivot, &
660646 state% nfe, state% n, state% iflag)
661647 if (state% iflag > 0 ) return
662648
663649 ! Next point = current point + Newton step
664- w = w + tz
650+ state % ws % w = state % ws % w + state % ws % tz
665651
666652 ! Check for convergence
667- if ((abs (w(1 ) - one) <= rerr + aerr) .and. &
668- (norm2(tz) <= rerr* norm2(w(2 :np1)) + aerr)) then
669- y = w
653+ if ((abs (state % ws % w(1 ) - one) <= rerr + aerr) .and. &
654+ (norm2(state % ws % tz) <= rerr* norm2(state % ws % w(2 :np1)) + aerr)) then
655+ y = state % ws % w
670656 return
671657 end if
672658
673659 ! Prepare for next iteration
674- if (abs (w(1 ) - one) <= rerr + aerr) then
675- state% ypold = wp
660+ if (abs (state % ws % w(1 ) - one) <= rerr + aerr) then
661+ state% ypold = state % ws % wp
676662 cycle
677663 end if
678664
679665 ! Update 'y' and 'yold'
680666 state% yold = y
681- y = w
667+ y = state % ws % w
682668
683669 ! Update 'yp' such that 'yp' is the most recent point opposite of 'lambda=1'
684670 ! from 'y'. Set bracket=.true. iff 'y' and 'yold' bracket 'lambda=1' so that
@@ -691,27 +677,27 @@ subroutine rootnf( &
691677 end if
692678
693679 ! Compute dels=||y-yp||
694- tz = y - state% yp
695- dels = norm2(tz)
680+ state % ws % tz = y - state% yp
681+ dels = norm2(state % ws % tz)
696682
697683 ! Compute tz for the linear predictor w = y + tz, where tz = sa*(yold-y).
698684 sa = (one - y(1 ))/ (state% yold(1 ) - y(1 ))
699- tz = sa* (state% yold - y)
685+ state % ws % tz = sa* (state% yold - y)
700686
701687 ! To insure stability, the linear prediction must be no farther from y than yp is.
702688 ! This is guaranteed if bracket=true. If linear prediction is too far away, use
703689 ! bracketing points to compute linear prediction.
704690 if (.not. bracket) then
705- if (norm2(tz) > dels) then
691+ if (norm2(state % ws % tz) > dels) then
706692 ! Compute tz = sa*(yp-y)
707693 sa = (one - y(1 ))/ (state% yp(1 ) - y(1 ))
708- tz = sa* (state% yp - y)
694+ state % ws % tz = sa* (state% yp - y)
709695 end if
710696 end if
711697
712698 ! Compute estimate w = y + tz and save old tangent vector.
713- w = w + tz
714- state% ypold = wp
699+ state % ws % w = state % ws % w + state % ws % tz
700+ state% ypold = state % ws % wp
715701
716702 end do
717703
@@ -721,8 +707,7 @@ subroutine rootnf( &
721707
722708 end subroutine rootnf
723709
724- subroutine stepnf ( &
725- callbacks , state , y , a , qr , alpha , tz , pivot , w , wp , z0 , z1 , sspar )
710+ subroutine stepnf (callbacks , state , y , a , sspar )
726711 ! ! This subroutine takes one step along the zero curve of the homotopy map using a
727712 ! ! predictor-corrector algorithm. The predictor uses a Hermite cubic interpolant, and
728713 ! ! the corrector returns to the zero curve along the flow normal to the Davidenko flow.
@@ -743,27 +728,6 @@ subroutine stepnf( &
743728 ! ! On output, updated to the latest point found by the continuation algorithm.
744729 real (dp), intent (in ) :: a(:)
745730 ! ! Parameter vector used in the homotopy map.
746- real (dp), intent (inout ) :: qr(:, :)
747- ! ! Workspace for QR factorizations used in Newton-step calculations.
748- ! ! `Shape: (n, n+2)`.
749- real (dp), intent (inout ) :: alpha(:)
750- ! ! Workspace array used during interpolation and Newton-step calculations.
751- ! ! `Shape: (3*n+3)`.
752- real (dp), intent (inout ) :: tz(:)
753- ! ! Workspace array used in QR-factorization and Newton-step computations.
754- ! ! `Shape: (n+1)`.
755- integer , intent (inout ) :: pivot(:)
756- ! ! Pivot indices used by the QR factorization. `Shape: (n+1)`.
757- real (dp), intent (inout ) :: w(:)
758- ! ! Workspace array used during interpolation and Newton-step calculations.
759- ! ! `Shape: (n+1)`.
760- real (dp), intent (inout ) :: wp(:)
761- ! ! Workspace array used during interpolation and Newton-step calculations.
762- ! ! `Shape: (n+1)`.
763- real (dp), intent (inout ) :: z0(:)
764- ! ! Workspace array used for estimating the optimal next step size. `Shape: (n+1)`.
765- real (dp), intent (inout ) :: z1(:)
766- ! ! Workspace array used for estimating the optimal next step size. `Shape: (n+1)`.
767731 real (dp), intent (in ) :: sspar(8 )
768732 ! ! Step-size estimation parameters:
769733 ! ! `(lideal, rideal, dideal, hmin, hmax, bmin, bmax, p)`.
@@ -804,6 +768,7 @@ subroutine stepnf( &
804768 end if
805769
806770 ! STARTUP SECTION (FIRST STEP ALONG ZERO CURVE)
771+
807772 state% crash = .false.
808773 startup: if (state% start) then
809774 fail = .false.
@@ -815,40 +780,40 @@ subroutine stepnf( &
815780 ! Use linear predictor along tangent direction to start Newton iteration
816781 state% ypold(1 ) = one
817782 state% ypold(2 :np1) = zero
818- call tangnf(callbacks, &
819- state% s, y, state % yp , state% ypold, a, qr, alpha, tz, pivot, &
783+ call tangnf(callbacks, state % s, y, state % yp, state % ypold, a, &
784+ state% ws % qr , state% ws % alpha, state % ws % tz, state % ws % pivot, &
820785 state% nfe, state% n, state% iflag)
821786
822787 if (state% iflag > 0 ) return
823788
824789 lp: do
825- w = y + state% h* state% yp
826- z0 = w
790+ state % ws % w = y + state% h* state% yp
791+ state % ws % z0 = state % ws % w
827792 do judy = 1 , litfh
828793 rholen = - one
829794
830795 ! Calculate the Newton step 'tz' at the current point 'w'
831796 call tangnf(callbacks, &
832- rholen, w, wp, state% ypold, a, qr, alpha, tz, pivot, &
797+ rholen, state % ws % w, state % ws % wp, state% ypold, a, state % ws % qr, state % ws % alpha, state % ws % tz, state % ws % pivot, &
833798 state% nfe, state% n, state% iflag)
834799 if (state% iflag > 0 ) return
835800
836801 ! Take Newton step and check convergence
837- w = w + tz
802+ state % ws % w = state % ws % w + state % ws % tz
838803 itnum = judy
839804
840805 ! Compute quantities used for optimal step size estimation
841806 if (judy == 1 ) then
842- lcalc = norm2(tz)
807+ lcalc = norm2(state % ws % tz)
843808 rcalc = rholen
844- z1 = w
809+ state % ws % z1 = state % ws % w
845810 else if (judy == 2 ) then
846- lcalc = norm2(tz)/ lcalc
811+ lcalc = norm2(state % ws % tz)/ lcalc
847812 rcalc = rholen/ rcalc
848813 end if
849814
850815 ! Go to mop-up section after convergence
851- if (norm2(tz) <= state% relerr* norm2(w) + state% abserr) go to 600
816+ if (norm2(state % ws % tz) <= state% relerr* norm2(state % ws % w) + state% abserr) go to 600
852817
853818 end do
854819
@@ -863,43 +828,44 @@ subroutine stepnf( &
863828 end if startup
864829
865830 ! PREDICTOR SECTION
831+
866832 fail = .false.
867833 hp: do
868834
869835 ! Compute point predicted by Hermite interpolant. Use step size 'h' computed on
870836 ! last call to 'stepnf'.
871837 do j = 1 , np1
872- w(j) = qofs(state% yold(j), state% ypold(j), y(j), state% yp(j), &
873- state% hold, state% hold + state% h)
838+ state % ws % w(j) = qofs(state% yold(j), state% ypold(j), y(j), state% yp(j), &
839+ state% hold, state% hold + state% h)
874840 end do
875- z0 = w
841+ state % ws % z0 = state % ws % w
876842
877843 ! CORRECTOR SECTION
878844 corrector: do judy = 1 , litfh
879845
880846 ! Calculate the Newton step 'tz' at the current point 'w'
881847 rholen = - one
882848 call tangnf(callbacks, &
883- rholen, w, wp, state% yp, a, qr, alpha, tz, pivot, &
849+ rholen, state % ws % w, state % ws % wp, state% yp, a, state % ws % qr, state % ws % alpha, state % ws % tz, state % ws % pivot, &
884850 state% nfe, state% n, state% iflag)
885851 if (state% iflag > 0 ) return
886852
887853 ! Take Newton step and check convergence
888- w = w + tz
854+ state % ws % w = state % ws % w + state % ws % tz
889855 itnum = judy
890856
891857 ! Compute quantities used for optimal step size estimation.
892858 if (judy == 1 ) then
893- lcalc = norm2(tz)
859+ lcalc = norm2(state % ws % tz)
894860 rcalc = rholen
895- z1 = w
861+ state % ws % z1 = state % ws % w
896862 else if (judy == 2 ) then
897- lcalc = norm2(tz)/ lcalc
863+ lcalc = norm2(state % ws % tz)/ lcalc
898864 rcalc = rholen/ rcalc
899865 end if
900866
901867 ! Go to mop-up section after convergence.
902- if (norm2(tz) <= state% relerr* norm2(w) + state% abserr) go to 600
868+ if (norm2(state % ws % tz) <= state% relerr* norm2(state % ws % w) + state% abserr) go to 600
903869
904870 end do corrector
905871
@@ -922,21 +888,21 @@ subroutine stepnf( &
922888 ! at 'yold' and 'y' , respectively.
923889600 state% ypold = state% yp
924890 state% yold = y
925- y = w
926- state% yp = wp
927- w = y - state% yold
891+ y = state % ws % w
892+ state% yp = state % ws % wp
893+ state % ws % w = y - state% yold
928894
929895 ! Update arc length
930- state% hold = norm2(w)
896+ state% hold = norm2(state % ws % w)
931897 state% s = state% s + state% hold
932898
933899 ! OPTIMAL STEP SIZE ESTIMATION SECTION
934900
935901 ! Calculate the distance factor 'dcalc'
936- tz = z0 - y
937- w = z1 - y
938- dcalc = norm2(tz)
939- if (dcalc /= zero) dcalc = norm2(w)/ dcalc
902+ state % ws % tz = state % ws % z0 - y
903+ state % ws % w = state % ws % z1 - y
904+ dcalc = norm2(state % ws % tz)
905+ if (dcalc /= zero) dcalc = norm2(state % ws % w)/ dcalc
940906
941907 ! The optimal step size hbar is defined by
942908 !
@@ -1233,7 +1199,7 @@ pure subroutine allocate_state(self, n, stat)
12331199 end if
12341200
12351201 ! Deep-allocate the internal workspace
1236- call self% workspace % alloc(n)
1202+ call self% ws % alloc(n)
12371203
12381204 end subroutine allocate_state
12391205
0 commit comments