ShakeConstraints Subroutine

public subroutine ShakeConstraints()

Arguments

None

Contents

Source Code


Source Code

    subroutine ShakeConstraints()

        ! DerivCoeff(k,a) is the unconstrained force on the original coefficients (CoeffT1(a,k)).

        integer :: w, l, a, m, ShakeIteration, ConvergeCount, SymM, SymMin
        real(dp) :: TotCorConstraints, TotConstraints, TotLambdas
        real(dp) :: TotUncorForce, TotDiffUncorCoeffs, TotDiffCorCoeffs
        logical :: tShakeNotConverged
        integer, save :: shake_io

        if (Iteration == 1) then
            shake_io = get_free_unit()
            open(shake_io, file='SHAKEstats', status='unknown')
            write(shake_io, '(A20, 4A35, A20)') 'Shake Iteration', 'Sum Lambdas', 'Total of corrected forces', &
                & 'Sum unconstrained constraints',&
                                        &'Sum corrected constraints', 'Converge count'
        end if
        if (Mod(Iteration, 10) == 0) write(shake_io, *) 'Orbital rotation iteration  =  ', Iteration

        ShakeIteration = 0
        tShakeNotConverged = .true.

! Before we start iterating, take the current coefficients and find the derivative of the constraints with respect to them.

        call CalcDerivConstr(CoeffT1, DerivConstrT1)

! Then find the coefficients at time t2, when moved by the completely unconstrained force and the values of the each
! constraint at these positions.

        Correction(:, :) = 0.0_dp
        call FindandUsetheForce(TotUncorForce, TotDiffUncorCoeffs, CoeffUncorT2)

        call CalcConstraints(CoeffUncorT2, Constraint, TotConstraints)

        call set_timer(Shake_Time, 30)

        if (tShakeDelay) then
            if (Iteration < ShakeStart) then
                ShakeIterMax = 1
            else
                ShakeIterMax = ShakeIterInput
            end if
        end if

        ! Actually starting the calculation.
        do while (tShakeNotConverged)

            ShakeIteration = ShakeIteration + 1

            ForceCorrect(:, :) = 0.0_dp          ! Zeroing terms that are re-calculated each iteration.
            CoeffCorT2(:, :) = 0.0_dp
            ConstraintCor(:) = 0.0_dp
            DerivConstrT2(:, :, :) = 0.0_dp
            TotLambdas = 0.0_dp
            TotCorrectedForce = 0.0_dp
            TotDiffCorCoeffs = 0.0_dp

            if (ShakeIteration /= 1) then
                call UpdateLambdas()
            end if

            ShakeLambdaNew(:) = 0.0_dp

            ! For a particular set of coefficients cm:
            ! Force(corrected) = Force(uncorrected)-Lambdas.DerivConstrT1
            ! Use these derivatives, and the current lambdas to find the trial corrected force.
            ! Then use this to get the (trial) shifted coefficients.

            ! Use the lambdas of this iteration to calculate the correction to the force due to the constraints.
            Correction(:, :) = 0.0_dp

            do w = MinOccVirt, MaxOccVirt
                if (w == 1) then
                    SymMin = 1
                    MinMZ = 1
                    if (tSeparateOccVirt) then
                        MaxMZ = NoOcc
                    else
                        MaxMZ = NoOrbs
                    end if
                else
                    SymMin = 9
                    MinMZ = NoOcc + 1
                    MaxMZ = NoOrbs
                end if

                do m = MinMZ, MaxMZ
                    if (tStoreSpinOrbs) then
                        SymM = int(G1(SymLabelList2_rot(m))%sym%S)
                    else
                        SymM = int(G1(SymLabelList2_rot(m) * 2)%sym%S)
                    end if
                    do a = SymLabelCounts2_rot(1, SymM + SymMin), &
                        (SymLabelCounts2_rot(1, SymM + SymMin) + &
                         SymLabelCounts2_rot(2, SymM + SymMin) - 1)
                        do l = 1, TotNoConstraints
                            Correction(a, m) = Correction(a, m) + (ShakeLambda(l) * DerivConstrT1(a, m, l))
                        end do
                    end do
                end do
            end do

            call FindandUsetheForce(TotCorrectedForce, TotDiffCorCoeffs, CoeffCorT2)

            ! Use these new shifted coefficients to calculate the derivative of the constraints
            ! (at time t2).

            call CalcDerivConstr(CoeffCorT2, DerivConstrT2)

! Test for convergence, if convergence is reached, make the new coefficients the original ones to start the whole process again.
! Then exit out of this do loop and hence the subroutine.
            call TestShakeConvergence(ConvergeCount, TotCorConstraints, ShakeIteration, tShakeNotConverged)

! If the convergence criteria is met, exit out of this subroutine, a rotation has been made which keeps the coefficients
! orthogonal.

! and to SHAKEstats file:
            call neci_flush(stdout)
            call neci_flush(shake_io)
            if (Mod(Iteration, 10) == 0) then
                write(shake_io, '(I20, 4F35.20, I20)') ShakeIteration, TotLambdas, TotCorrectedForce, TotConstraints, &
                    TotCorConstraints, ConvergeCount
            end if

! If the convergence criteria is not met, use either the full matrix inversion method to
!find a new set of lambdas, or the shake algorithm
! (in which case SHAKEAPPROX is required in the system block of the input).

            if (tShakeApprox .and. tShakeNotConverged) then
                call ShakeApproximation()
            else if (tShakeNotConverged) then
                call FullShake()
            else
                DistCs = TotDiffCorCoeffs
            end if

        end do

        call halt_timer(Shake_Time)

    end subroutine ShakeConstraints