193 ao_gradient, max_abs_error, workspace_budget_bytes)
194 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: phi
195 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(IN) :: int_3c
196 REAL(kind=
dp),
INTENT(IN) :: tikhonov
197 REAL(kind=
dp),
INTENT(OUT) :: normalized_error
198 LOGICAL,
INTENT(OUT) :: fit_successful
199 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT), &
200 OPTIONAL :: ao_gradient
201 REAL(kind=
dp),
INTENT(OUT),
OPTIONAL :: max_abs_error
202 REAL(kind=
dp),
INTENT(IN),
OPTIONAL :: workspace_budget_bytes
204 CHARACTER(LEN=*),
PARAMETER :: routinen =
'evaluate_ri_rs_fit'
205 INTEGER,
PARAMETER :: residual_block_size = 64
207 INTEGER :: first, handle, handle2, i, icache, imu, &
208 info, inu, ip, j, last, n_ao, &
209 n_cached, n_grid, n_panel, n_ri, &
210 panel_first, panel_last
211 REAL(kind=
dp) :: coefficient_norm2, error_scale, fixed_bytes, integral_norm2, na, ng, &
212 projection, residual_norm2, roundoff_estimate, row_norm2,
value, weight
213 REAL(kind=
dp),
ALLOCATABLE :: coefficient_work(:, :), factor(:, :), jacobi_scale(:), &
214 overlap(:, :), products(:, :, :), residual(:, :), v(:, :), z_prime(:, :)
216 CALL timeset(routinen, handle)
217 n_grid =
SIZE(phi, 1)
219 n_ri =
SIZE(int_3c, 3)
220 cpassert(
SIZE(int_3c, 1) == n_ao .AND.
SIZE(int_3c, 2) == n_ao)
221 cpassert(tikhonov >= 0.0_dp)
222 IF (
PRESENT(ao_gradient))
THEN
223 cpassert(all(shape(ao_gradient) == shape(phi)))
224 ao_gradient(:, :) = 0.0_dp
226 normalized_error = huge(normalized_error)
227 IF (
PRESENT(max_abs_error)) max_abs_error = huge(max_abs_error)
228 fit_successful = .false.
229 IF (n_grid < 1 .OR. n_ri < 1)
THEN
230 CALL timestop(handle)
233 integral_norm2 = 0.0_dp
236 integral_norm2 = integral_norm2 + int_3c(inu, inu, ip)**2 + &
237 2.0_dp*dot_product(int_3c(1:inu - 1, inu, ip), int_3c(1:inu - 1, inu, ip))
240 IF (integral_norm2 <= tiny(1.0_dp))
THEN
241 CALL timestop(handle)
247 IF (
PRESENT(ao_gradient))
THEN
249 IF (
PRESENT(workspace_budget_bytes))
THEN
250 IF (workspace_budget_bytes > 0.0_dp)
THEN
251 ng = real(n_grid,
dp)
255 fixed_bytes = 8.0_dp*(2.0_dp*ng**2 + ng*na + 2.0_dp*ng*real(n_ri,
dp) + ng + &
256 na*min(na, real(residual_block_size,
dp)))
257 n_panel = int(min(real(n_ri,
dp), max(0.0_dp, &
258 (workspace_budget_bytes - fixed_bytes)/(8.0_dp*ng*na))))
259 IF (n_panel < 1)
THEN
260 cpabort(
"RI-RS minimum fit workspace exceeds memory budget")
265 CALL factor_ri_rs_fit(phi, tikhonov, factor, jacobi_scale, info, overlap)
267 CALL factor_ri_rs_fit(phi, tikhonov, factor, jacobi_scale, info)
270 CALL timestop(handle)
273 ALLOCATE (v(n_grid, n_ao), products(n_grid, n_ao, n_cached), &
274 coefficient_work(n_grid, n_ri), z_prime(n_grid, n_ri))
276 v(:, imu) = sqrt(jacobi_scale)*phi(:, imu)
281 coefficient_norm2 = 0.0_dp
282 CALL timeset(routinen//
'_ri_panels', handle2)
283 DO panel_first = 1, n_ri, n_panel
284 panel_last = min(panel_first + n_panel - 1, n_ri)
285 DO ip = panel_first, panel_last
287 IF (
PRESENT(ao_gradient)) icache = ip - panel_first + 1
288 CALL dsymm(
'R',
'U', n_grid, n_ao, 1.0_dp, int_3c(:, :, ip), n_ao, v, n_grid, &
289 0.0_dp, products(:, :, icache), n_grid)
291 coefficient_work(i, ip) = dot_product(v(i, :), products(i, :, icache))
294 z_prime(:, panel_first:panel_last) = coefficient_work(:, panel_first:panel_last)
295 CALL dpotrs(
'L', n_grid, panel_last - panel_first + 1, factor, n_grid, &
296 z_prime(:, panel_first:panel_last), n_grid, info)
298 CALL timestop(handle2)
299 CALL timestop(handle)
302 DO ip = panel_first, panel_last
303 value =
value + dot_product(z_prime(:, ip), coefficient_work(:, ip))
304 coefficient_norm2 = coefficient_norm2 + dot_product(z_prime(:, ip), z_prime(:, ip))
307 IF (
PRESENT(ao_gradient))
THEN
309 coefficient_work(:, panel_first:panel_last) = z_prime(:, panel_first:panel_last)
310 IF (tikhonov > 0.0_dp)
THEN
311 CALL dpotrs(
'L', n_grid, panel_last - panel_first + 1, factor, n_grid, &
312 coefficient_work(:, panel_first:panel_last), n_grid, info)
314 CALL timestop(handle2)
315 CALL timestop(handle)
318 coefficient_work(:, panel_first:panel_last) = z_prime(:, panel_first:panel_last) + &
319 tikhonov*coefficient_work(:, panel_first:panel_last)
322 DO ip = panel_first, panel_last
323 icache = ip - panel_first + 1
325 ao_gradient(:, imu) = ao_gradient(:, imu) - coefficient_work(:, ip)*products(:, imu, icache)
328 IF (tikhonov > 0.0_dp)
THEN
330 coefficient_work(:, panel_first:panel_last) = coefficient_work(:, panel_first:panel_last) - &
331 0.5_dp*z_prime(:, panel_first:panel_last)
335 CALL timestop(handle2)
337 weight = tikhonov*coefficient_norm2
338 residual_norm2 = integral_norm2 -
value - weight
339 error_scale = integral_norm2 + abs(
value) + weight
342 roundoff_estimate = 8.0_dp*epsilon(1.0_dp)*real(n_grid,
dp)* &
343 (real(n_grid,
dp) + tikhonov)*coefficient_norm2
346 IF (
PRESENT(max_abs_error) .OR. &
347 residual_norm2 <= max(sqrt(epsilon(1.0_dp))*error_scale, roundoff_estimate))
THEN
348 CALL timeset(routinen//
'_residual', handle2)
349 ALLOCATE (residual(n_ao, min(residual_block_size, n_ao)))
350 residual_norm2 = 0.0_dp
351 IF (
PRESENT(max_abs_error)) max_abs_error = 0.0_dp
353 DO first = 1, n_ao, residual_block_size
354 last = min(first + residual_block_size - 1, n_ao)
356 products(:, inu - first + 1, 1) = z_prime(:, ip)*v(:, inu)
358 CALL dgemm(
'T',
'N', n_ao, last - first + 1, n_grid, -1.0_dp, v, n_grid, products(:, :, 1), n_grid, &
359 0.0_dp, residual, n_ao)
362 value = int_3c(imu, inu, ip) + residual(imu, inu - first + 1)
363 weight = real(2 - merge(1, 0, imu == inu),
dp)
364 residual_norm2 = residual_norm2 + weight*
value**2
365 IF (
PRESENT(max_abs_error)) max_abs_error = max(max_abs_error, abs(
value))
370 CALL timestop(handle2)
372 DEALLOCATE (products)
373 normalized_error = residual_norm2/integral_norm2
375 IF (
PRESENT(ao_gradient))
THEN
376 CALL timeset(routinen//
'_gradient', handle2)
378 IF (tikhonov > 0.0_dp)
THEN
379 CALL dsyr2k(
'L',
'N', n_grid, n_ri, 1.0_dp, z_prime, n_grid, coefficient_work, n_grid, &
380 0.0_dp, factor, n_grid)
382 CALL dsyrk(
'L',
'N', n_grid, n_ri, 1.0_dp, z_prime, n_grid, 0.0_dp, factor, n_grid)
386 factor(i, j) = factor(i, j)*overlap(i, j)
390 CALL dsymm(
'L',
'L', n_grid, n_ao, 1.0_dp, factor, n_grid, v, n_grid, &
391 1.0_dp, ao_gradient, n_grid)
392 ao_gradient(:, :) = (4.0_dp/integral_norm2)*ao_gradient
396 row_norm2 = dot_product(phi(i, :), phi(i, :))
397 IF (row_norm2 > sqrt(jacobi_floor))
THEN
398 projection = dot_product(phi(i, :), ao_gradient(i, :))/row_norm2
399 ao_gradient(i, :) = ao_gradient(i, :) - projection*phi(i, :)
401 ao_gradient(i, :) = sqrt(jacobi_scale(i))*ao_gradient(i, :)
403 CALL timestop(handle2)
405 fit_successful = .true.
406 CALL timestop(handle)