Skip to content

Commit 3e7f2de

Browse files
committed
refactor workspace 2
1 parent 74e33c1 commit 3e7f2de

1 file changed

Lines changed: 65 additions & 99 deletions

File tree

src/hompack_nf.f90

Lines changed: 65 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
923889
600 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

Comments
 (0)