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