68 transition_width, hamiltonian, &
69 connection, curvature, rho0, velocity, current, &
71 INTEGER,
INTENT(IN) :: order
72 REAL(kind=
dp),
INTENT(IN) :: omega(:), energies(:), rate1, rate2, &
74 COMPLEX(dp),
INTENT(IN) :: hamiltonian(:, :, :), &
75 connection(:, :, :, :), &
76 curvature(:, :, :), rho0(:, :, :), &
78 COMPLEX(dp),
INTENT(OUT) :: current(:, :)
79 LOGICAL,
INTENT(IN),
OPTIONAL :: elements(:, :)
81 CHARACTER(len=*),
PARAMETER :: routinen =
'nlo_current_tensor_derivatives'
83 COMPLEX(dp) :: curvature_term, extra(3, 243)
84 COMPLEX(dp),
ALLOCATABLE :: next_density(:, :, :), &
85 previous_density(:, :, :)
86 COMPLEX(dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: density
87 INTEGER :: code, current_start, direction, field, full_mask, handle, i_code, i_field, &
88 i_mask, i_radix, i_subset_code, index, iother, iother_direction, iother_position, &
89 ioutput, mask, multiplicity, n, na, ncodes(0:31), ncoeff(0:31), nh, &
90 offset_current(0:242, 0:31), offset_previous(0:242, 0:31), order_subset, position, &
91 previous_code, previous_end, previous_mask, previous_start, radix, &
92 representative_code(0:242, 0:31), total_coefficients
93 LOGICAL :: evaluate(0:242, 0:31), &
94 required(0:242, 0:31), selected(3, 243)
95 REAL(kind=
dp) :: subset_omega, weight
97 CALL timeset(routinen, handle)
101 cpassert(.NOT. (order < 2 .OR. order > 5 .OR. n < 2))
102 cpassert(
SIZE(omega) == order)
105 cpassert(all(shape(hamiltonian) == [n, n, nh]))
106 cpassert(all(shape(connection) == [n, n, 3, na]))
107 cpassert(all(shape(rho0) == [n, n, nh]))
108 cpassert(all(shape(curvature) == [n, n, 3]))
109 cpassert(all(shape(velocity) == [n, n, 3]))
110 cpassert(all(shape(current) == [3, 3**order]))
112 IF (
PRESENT(elements))
THEN
113 cpassert(all(shape(elements) == shape(current)))
114 IF (.NOT. any(elements))
THEN
115 CALL timestop(handle)
118 selected(:, 1:3**order) = elements
122 required(0, 0) = .true.
123 DO i_code = 0, 3**order - 1
124 IF (.NOT. any(selected(:, i_code + 1))) cycle
125 DO i_mask = 1, 2**order - 1
128 DO i_field = 1, order
129 IF (.NOT. btest(i_mask, i_field - 1)) cycle
130 i_subset_code = i_subset_code + mod(i_code/3**(i_field - 1), 3)*i_radix
133 required(i_subset_code, i_mask) = .true.
136 IF (.NOT. all(ieee_is_finite(omega)) .OR. .NOT. all(ieee_is_finite(energies)) .OR. &
137 .NOT. ieee_is_finite(rate1) .OR. .NOT. ieee_is_finite(rate2) .OR. &
138 .NOT. ieee_is_finite(transition_width) .OR. &
139 .NOT. all(ieee_is_finite(real(velocity, kind=
dp))) .OR. &
140 .NOT. all(ieee_is_finite(aimag(velocity))) .OR. &
141 .NOT. all(ieee_is_finite(real(hamiltonian, kind=
dp))) .OR. &
142 .NOT. all(ieee_is_finite(aimag(hamiltonian))) .OR. &
143 .NOT. all(ieee_is_finite(real(connection, kind=
dp))) .OR. &
144 .NOT. all(ieee_is_finite(aimag(connection))) .OR. &
145 .NOT. all(ieee_is_finite(real(rho0, kind=
dp))) .OR. &
146 .NOT. all(ieee_is_finite(aimag(rho0))) .OR. rate1 <= 0.0_dp .OR. &
147 rate2 < rate1 .OR. transition_width <= 0.0_dp &
148 .OR. abs(sum(omega)) <= 1.e-14_dp)
THEN
149 cpabort(
'NLO current response contains invalid data.')
151 full_mask = 2**order - 1
152 DO mask = 0, full_mask
154 ncodes(mask) = 3**popcnt(mask)
156 ALLOCATE (previous_density(n, n, ncoeff(0)), &
158 previous_density(:, :, :) = rho0(:, :, 1:ncoeff(0))
160 offset_previous(0, 0) = 1
162 DO order_subset = 1, order
164 CALL subset_density_offsets(order, order_subset, omega, required, ncoeff, &
165 offset_current, evaluate, representative_code, &
167 ALLOCATE (density(n, n, total_coefficients))
169 DO mask = 1, full_mask
170 IF (popcnt(mask) /= order_subset) cycle
171 subset_omega = 0.0_dp
173 IF (btest(mask, field - 1)) subset_omega = subset_omega + omega(field)
175 DO code = 0, ncodes(mask) - 1
176 IF (.NOT. evaluate(code, mask)) cycle
177 current_start = offset_current(code, mask)
179 IF (.NOT. btest(mask, field - 1)) cycle
180 position = popcnt(iand(mask, 2**(field - 1) - 1))
182 direction = mod(code/radix, 3) + 1
185 IF (iother == field .OR. .NOT. btest(mask, iother - 1)) cycle
186 IF (abs(omega(iother) - omega(field)) > 0.0_dp) cycle
187 iother_position = popcnt(iand(mask, 2**(iother - 1) - 1))
188 iother_direction = mod(code/3**iother_position, 3) + 1
189 IF (iother_direction /= direction) cycle
190 IF (iother < field)
EXIT
191 multiplicity = multiplicity + 1
193 IF (iother <= order) cycle
194 previous_code = mod(code, radix) + (code/(3*radix))*radix
195 previous_mask = ibclr(mask, field - 1)
196 previous_start = offset_previous(previous_code, previous_mask)
197 IF (order_subset == order)
THEN
199 weight = real(multiplicity, kind=
dp)/real(order, kind=
dp)
200 curvature_term = curvature_density_trace(curvature, &
201 & previous_density(:, :, previous_start), ioutput, direction)
202 extra(ioutput, code + 1) = extra(ioutput, code + 1) - &
203 curvature_term*weight
206 previous_end = previous_start + ncoeff(previous_mask) - 1
208 CALL nlo_density_step_derivatives(order - order_subset, direction, &
209 subset_omega, energies, rate1, rate2, &
211 hamiltonian, connection, &
212 previous_density(:, :, &
213 previous_start:previous_end), &
214 next_density(:, :, 1:ncoeff(mask)))
215 density(:, :, current_start:current_start + ncoeff(mask) - 1) = &
216 density(:, :, current_start:current_start + ncoeff(mask) - 1) + &
217 next_density(:, :, 1:ncoeff(mask))*real(multiplicity, &
218 kind=
dp)/real(order_subset, kind=
dp)
222 CALL move_alloc(density, previous_density)
223 offset_previous = offset_current
225 DO index = 1, 3**order
226 IF (.NOT. any(selected(:, index))) cycle
227 current_start = offset_previous(index - 1, full_mask)
229 IF (.NOT. selected(field, index)) cycle
231 current(field, index) = -sum(velocity(:, :, field)* &
232 transpose(previous_density(:, :, current_start))) + &
233 extra(field, representative_code(index - 1, full_mask) + 1)
236 IF (.NOT. all(ieee_is_finite(real(current, kind=
dp))) .OR. &
237 .NOT. all(ieee_is_finite(aimag(current))))
THEN
238 cpabort(
'NLO current response contains invalid data.')
241 CALL timestop(handle)