1!--------------------------------------------------------------------------------------------------!
2!   CP2K: A general program to perform molecular dynamics simulations                              !
3!   Copyright (C) 2000 - 2019  CP2K developers group                                               !
4!--------------------------------------------------------------------------------------------------!
5
6! **************************************************************************************************
7!> \brief A DIIS implementation for the ALMO-based SCF methods
8!> \par History
9!>       2011.12 created [Rustam Z Khaliullin]
10!> \author Rustam Z Khaliullin
11! **************************************************************************************************
12MODULE almo_scf_diis_types
13   USE cp_log_handling,                 ONLY: cp_get_default_logger,&
14                                              cp_logger_get_default_unit_nr,&
15                                              cp_logger_type
16   USE dbcsr_api,                       ONLY: dbcsr_add,&
17                                              dbcsr_copy,&
18                                              dbcsr_create,&
19                                              dbcsr_dot,&
20                                              dbcsr_release,&
21                                              dbcsr_set,&
22                                              dbcsr_type
23   USE domain_submatrix_methods,        ONLY: add_submatrices,&
24                                              copy_submatrices,&
25                                              init_submatrices,&
26                                              release_submatrices,&
27                                              set_submatrices
28   USE domain_submatrix_types,          ONLY: domain_submatrix_type
29   USE kinds,                           ONLY: dp
30#include "./base/base_uses.f90"
31
32   IMPLICIT NONE
33
34   PRIVATE
35
36   INTEGER, PARAMETER :: diis_error_orthogonal = 1
37
38   INTEGER, PARAMETER :: diis_env_dbcsr = 1
39   INTEGER, PARAMETER :: diis_env_domain = 2
40
41   CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'almo_scf_diis_types'
42
43   PUBLIC :: almo_scf_diis_type, &
44             almo_scf_diis_init, almo_scf_diis_release, almo_scf_diis_push, &
45             almo_scf_diis_extrapolate
46
47   INTERFACE almo_scf_diis_init
48      MODULE PROCEDURE almo_scf_diis_init_dbcsr
49      MODULE PROCEDURE almo_scf_diis_init_domain
50   END INTERFACE
51
52   TYPE almo_scf_diis_type
53
54      INTEGER :: diis_env_type
55
56      INTEGER :: buffer_length
57      INTEGER :: max_buffer_length
58      !INTEGER, DIMENSION(:), ALLOCATABLE :: history_index
59
60      TYPE(dbcsr_type), DIMENSION(:), ALLOCATABLE :: m_var
61      TYPE(dbcsr_type), DIMENSION(:), ALLOCATABLE :: m_err
62
63      ! first dimension is history index, second - domain index
64      TYPE(domain_submatrix_type), DIMENSION(:, :), ALLOCATABLE :: d_var
65      TYPE(domain_submatrix_type), DIMENSION(:, :), ALLOCATABLE :: d_err
66
67      ! distributed matrix of error overlaps
68      TYPE(domain_submatrix_type), DIMENSION(:), ALLOCATABLE     :: m_b
69
70      ! insertion point
71      INTEGER :: in_point
72
73      ! in order to calculate the overlap between error vectors
74      ! it is desirable to know tensorial properties of the error
75      ! vector, e.g. convariant, contravariant, orthogonal
76      INTEGER :: error_type
77
78   END TYPE almo_scf_diis_type
79
80CONTAINS
81
82! **************************************************************************************************
83!> \brief initializes the diis structure
84!> \param diis_env ...
85!> \param sample_err ...
86!> \param sample_var ...
87!> \param error_type ...
88!> \param max_length ...
89!> \par History
90!>       2011.12 created [Rustam Z Khaliullin]
91!> \author Rustam Z Khaliullin
92! **************************************************************************************************
93   SUBROUTINE almo_scf_diis_init_dbcsr(diis_env, sample_err, sample_var, error_type, &
94                                       max_length)
95
96      TYPE(almo_scf_diis_type), INTENT(INOUT)            :: diis_env
97      TYPE(dbcsr_type), INTENT(IN)                       :: sample_err, sample_var
98      INTEGER, INTENT(IN)                                :: error_type, max_length
99
100      CHARACTER(len=*), PARAMETER :: routineN = 'almo_scf_diis_init_dbcsr', &
101         routineP = moduleN//':'//routineN
102
103      INTEGER                                            :: handle, idomain, im, ndomains
104
105      CALL timeset(routineN, handle)
106
107      IF (max_length .LE. 0) THEN
108         CPABORT("DIIS: max_length is less than zero")
109      END IF
110
111      diis_env%diis_env_type = diis_env_dbcsr
112
113      diis_env%max_buffer_length = max_length
114      diis_env%buffer_length = 0
115      diis_env%error_type = error_type
116      diis_env%in_point = 1
117
118      ALLOCATE (diis_env%m_err(diis_env%max_buffer_length))
119      ALLOCATE (diis_env%m_var(diis_env%max_buffer_length))
120
121      ! create matrices
122      DO im = 1, diis_env%max_buffer_length
123         CALL dbcsr_create(diis_env%m_err(im), &
124                           template=sample_err)
125         CALL dbcsr_create(diis_env%m_var(im), &
126                           template=sample_var)
127      ENDDO
128
129      ! current B matrices are only 1-by-1, they will be expanded on-the-fly
130      ! only one matrix is used with dbcsr version of DIIS
131      ndomains = 1
132      ALLOCATE (diis_env%m_b(ndomains))
133      CALL init_submatrices(diis_env%m_b)
134      ! hack into d_b structure to gain full control
135      diis_env%m_b(:)%domain = 100 ! arbitrary positive number
136      DO idomain = 1, ndomains
137         IF (diis_env%m_b(idomain)%domain .GT. 0) THEN
138            ALLOCATE (diis_env%m_b(idomain)%mdata(1, 1))
139            diis_env%m_b(idomain)%mdata(:, :) = 0.0_dp
140         ENDIF
141      ENDDO
142
143      CALL timestop(handle)
144
145   END SUBROUTINE almo_scf_diis_init_dbcsr
146
147! **************************************************************************************************
148!> \brief initializes the diis structure
149!> \param diis_env ...
150!> \param sample_err ...
151!> \param error_type ...
152!> \param max_length ...
153!> \par History
154!>       2011.12 created [Rustam Z Khaliullin]
155!> \author Rustam Z Khaliullin
156! **************************************************************************************************
157   SUBROUTINE almo_scf_diis_init_domain(diis_env, sample_err, error_type, &
158                                        max_length)
159
160      TYPE(almo_scf_diis_type), INTENT(INOUT)            :: diis_env
161      TYPE(domain_submatrix_type), DIMENSION(:), &
162         INTENT(IN)                                      :: sample_err
163      INTEGER, INTENT(IN)                                :: error_type, max_length
164
165      CHARACTER(len=*), PARAMETER :: routineN = 'almo_scf_diis_init_domain', &
166         routineP = moduleN//':'//routineN
167
168      INTEGER                                            :: handle, idomain, ndomains
169
170      CALL timeset(routineN, handle)
171
172      IF (max_length .LE. 0) THEN
173         CPABORT("DIIS: max_length is less than zero")
174      END IF
175
176      diis_env%diis_env_type = diis_env_domain
177
178      diis_env%max_buffer_length = max_length
179      diis_env%buffer_length = 0
180      diis_env%error_type = error_type
181      diis_env%in_point = 1
182
183      ndomains = SIZE(sample_err)
184
185      ALLOCATE (diis_env%d_err(diis_env%max_buffer_length, ndomains))
186      ALLOCATE (diis_env%d_var(diis_env%max_buffer_length, ndomains))
187
188      ! create matrices
189      CALL init_submatrices(diis_env%d_var)
190      CALL init_submatrices(diis_env%d_err)
191
192      ! current B matrices are only 1-by-1, they will be expanded on-the-fly
193      ALLOCATE (diis_env%m_b(ndomains))
194      CALL init_submatrices(diis_env%m_b)
195      ! hack into d_b structure to gain full control
196      ! distribute matrices as the err/var matrices
197      diis_env%m_b(:)%domain = sample_err(:)%domain
198      DO idomain = 1, ndomains
199         IF (diis_env%m_b(idomain)%domain .GT. 0) THEN
200            ALLOCATE (diis_env%m_b(idomain)%mdata(1, 1))
201            diis_env%m_b(idomain)%mdata(:, :) = 0.0_dp
202         ENDIF
203      ENDDO
204
205      CALL timestop(handle)
206
207   END SUBROUTINE almo_scf_diis_init_domain
208
209! **************************************************************************************************
210!> \brief adds a variable-error pair to the diis structure
211!> \param diis_env ...
212!> \param var ...
213!> \param err ...
214!> \param d_var ...
215!> \param d_err ...
216!> \par History
217!>       2011.12 created [Rustam Z Khaliullin]
218!> \author Rustam Z Khaliullin
219! **************************************************************************************************
220   SUBROUTINE almo_scf_diis_push(diis_env, var, err, d_var, d_err)
221      TYPE(almo_scf_diis_type), INTENT(INOUT)            :: diis_env
222      TYPE(dbcsr_type), INTENT(IN), OPTIONAL             :: var, err
223      TYPE(domain_submatrix_type), DIMENSION(:), &
224         INTENT(IN), OPTIONAL                            :: d_var, d_err
225
226      CHARACTER(len=*), PARAMETER :: routineN = 'almo_scf_diis_push', &
227         routineP = moduleN//':'//routineN
228
229      INTEGER                                            :: handle, idomain, in_point, irow, &
230                                                            ndomains, old_buffer_length
231      REAL(KIND=dp)                                      :: trace0
232      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: m_b_tmp
233
234      CALL timeset(routineN, handle)
235
236      IF (diis_env%diis_env_type .EQ. diis_env_dbcsr) THEN
237         IF (.NOT. (PRESENT(var) .AND. PRESENT(err))) THEN
238            CPABORT("provide DBCSR matrices")
239         ENDIF
240      ELSE IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
241         IF (.NOT. (PRESENT(d_var) .AND. PRESENT(d_err))) THEN
242            CPABORT("provide domain submatrices")
243         ENDIF
244      ELSE
245         CPABORT("illegal DIIS ENV type")
246      ENDIF
247
248      in_point = diis_env%in_point
249
250      ! store a var-error pair
251      IF (diis_env%diis_env_type .EQ. diis_env_dbcsr) THEN
252         CALL dbcsr_copy(diis_env%m_var(in_point), var)
253         CALL dbcsr_copy(diis_env%m_err(in_point), err)
254      ELSE IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
255         CALL copy_submatrices(d_var, diis_env%d_var(in_point, :), copy_data=.TRUE.)
256         CALL copy_submatrices(d_err, diis_env%d_err(in_point, :), copy_data=.TRUE.)
257      ENDIF
258
259      ! update the buffer length
260      old_buffer_length = diis_env%buffer_length
261      diis_env%buffer_length = diis_env%buffer_length + 1
262      IF (diis_env%buffer_length .GT. diis_env%max_buffer_length) &
263         diis_env%buffer_length = diis_env%max_buffer_length
264
265      !!!! resize B matrix
266      !!!IF (old_buffer_length.lt.diis_env%buffer_length) THEN
267      !!!   ALLOCATE(m_b_tmp(diis_env%buffer_length+1,diis_env%buffer_length+1))
268      !!!   m_b_tmp(1:diis_env%buffer_length,1:diis_env%buffer_length)=&
269      !!!      diis_env%m_b(:,:)
270      !!!   DEALLOCATE(diis_env%m_b)
271      !!!   ALLOCATE(diis_env%m_b(diis_env%buffer_length+1,&
272      !!!      diis_env%buffer_length+1))
273      !!!   diis_env%m_b(:,:)=m_b_tmp(:,:)
274      !!!   DEALLOCATE(m_b_tmp)
275      !!!ENDIF
276      !!!! update B matrix elements
277      !!!diis_env%m_b(1,in_point+1)=-1.0_dp
278      !!!diis_env%m_b(in_point+1,1)=-1.0_dp
279      !!!DO irow=1,diis_env%buffer_length
280      !!!   trace0=almo_scf_diis_error_overlap(diis_env,&
281      !!!      A=diis_env%m_err(irow),B=diis_env%m_err(in_point))
282      !!!
283      !!!   diis_env%m_b(irow+1,in_point+1)=trace0
284      !!!   diis_env%m_b(in_point+1,irow+1)=trace0
285      !!!ENDDO
286
287      ! resize B matrix and update its elements
288      ndomains = SIZE(diis_env%m_b)
289      IF (old_buffer_length .LT. diis_env%buffer_length) THEN
290         ALLOCATE (m_b_tmp(diis_env%buffer_length + 1, diis_env%buffer_length + 1))
291         DO idomain = 1, ndomains
292            IF (diis_env%m_b(idomain)%domain .GT. 0) THEN
293               m_b_tmp(:, :) = 0.0_dp
294               m_b_tmp(1:diis_env%buffer_length, 1:diis_env%buffer_length) = &
295                  diis_env%m_b(idomain)%mdata(:, :)
296               DEALLOCATE (diis_env%m_b(idomain)%mdata)
297               ALLOCATE (diis_env%m_b(idomain)%mdata(diis_env%buffer_length + 1, &
298                                                     diis_env%buffer_length + 1))
299               diis_env%m_b(idomain)%mdata(:, :) = m_b_tmp(:, :)
300            ENDIF
301         ENDDO
302         DEALLOCATE (m_b_tmp)
303      ENDIF
304      DO idomain = 1, ndomains
305         IF (diis_env%m_b(idomain)%domain .GT. 0) THEN
306            diis_env%m_b(idomain)%mdata(1, in_point + 1) = -1.0_dp
307            diis_env%m_b(idomain)%mdata(in_point + 1, 1) = -1.0_dp
308            DO irow = 1, diis_env%buffer_length
309               IF (diis_env%diis_env_type .EQ. diis_env_dbcsr) THEN
310                  trace0 = almo_scf_diis_error_overlap(diis_env, &
311                                                       A=diis_env%m_err(irow), B=diis_env%m_err(in_point))
312               ELSE IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
313                  trace0 = almo_scf_diis_error_overlap(diis_env, &
314                                                       d_A=diis_env%d_err(irow, idomain), &
315                                                       d_B=diis_env%d_err(in_point, idomain))
316               ENDIF
317               diis_env%m_b(idomain)%mdata(irow + 1, in_point + 1) = trace0
318               diis_env%m_b(idomain)%mdata(in_point + 1, irow + 1) = trace0
319            ENDDO ! loop over prev errors
320         ENDIF
321      ENDDO ! loop over domains
322
323      ! update the insertion point for the next "PUSH"
324      diis_env%in_point = diis_env%in_point + 1
325      IF (diis_env%in_point .GT. diis_env%max_buffer_length) diis_env%in_point = 1
326
327      CALL timestop(handle)
328
329   END SUBROUTINE almo_scf_diis_push
330
331! **************************************************************************************************
332!> \brief extrapolates the variable using the saved history
333!> \param diis_env ...
334!> \param extr_var ...
335!> \param d_extr_var ...
336!> \par History
337!>       2011.12 created [Rustam Z Khaliullin]
338!> \author Rustam Z Khaliullin
339! **************************************************************************************************
340   SUBROUTINE almo_scf_diis_extrapolate(diis_env, extr_var, d_extr_var)
341      TYPE(almo_scf_diis_type), INTENT(INOUT)            :: diis_env
342      TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL          :: extr_var
343      TYPE(domain_submatrix_type), DIMENSION(:), &
344         INTENT(INOUT), OPTIONAL                         :: d_extr_var
345
346      CHARACTER(len=*), PARAMETER :: routineN = 'almo_scf_diis_extrapolate', &
347         routineP = moduleN//':'//routineN
348
349      INTEGER                                            :: handle, idomain, im, INFO, LWORK, &
350                                                            ndomains, unit_nr
351      REAL(KIND=dp)                                      :: checksum
352      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: coeff, eigenvalues, tmp1, WORK
353      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: m_b_copy
354      TYPE(cp_logger_type), POINTER                      :: logger
355
356      CALL timeset(routineN, handle)
357
358      ! get a useful output_unit
359      logger => cp_get_default_logger()
360      IF (logger%para_env%ionode) THEN
361         unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
362      ELSE
363         unit_nr = -1
364      ENDIF
365
366      IF (diis_env%diis_env_type .EQ. diis_env_dbcsr) THEN
367         IF (.NOT. PRESENT(extr_var)) THEN
368            CPABORT("provide DBCSR matrix")
369         ENDIF
370      ELSE IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
371         IF (.NOT. PRESENT(d_extr_var)) THEN
372            CPABORT("provide domain submatrices")
373         ENDIF
374      ELSE
375         CPABORT("illegal DIIS ENV type")
376      ENDIF
377
378      ! Prepare data
379      ALLOCATE (eigenvalues(diis_env%buffer_length + 1))
380      ALLOCATE (m_b_copy(diis_env%buffer_length + 1, diis_env%buffer_length + 1))
381
382      ndomains = SIZE(diis_env%m_b)
383
384      DO idomain = 1, ndomains
385
386         IF (diis_env%m_b(idomain)%domain .GT. 0) THEN
387
388            m_b_copy(:, :) = diis_env%m_b(idomain)%mdata(:, :)
389
390            ! Query the optimal workspace for dsyev
391            LWORK = -1
392            ALLOCATE (WORK(MAX(1, LWORK)))
393            CALL DSYEV('V', 'L', diis_env%buffer_length + 1, m_b_copy, &
394                       diis_env%buffer_length + 1, eigenvalues, WORK, LWORK, INFO)
395            LWORK = INT(WORK(1))
396            DEALLOCATE (WORK)
397
398            ! Allocate the workspace and solve the eigenproblem
399            ALLOCATE (WORK(MAX(1, LWORK)))
400            CALL DSYEV('V', 'L', diis_env%buffer_length + 1, m_b_copy, &
401                       diis_env%buffer_length + 1, eigenvalues, WORK, LWORK, INFO)
402            IF (INFO .NE. 0) THEN
403               CPABORT("DSYEV failed")
404            END IF
405            DEALLOCATE (WORK)
406
407            ! use the eigensystem to invert (implicitly) B matrix
408            ! and compute the extrapolation coefficients
409            !! ALLOCATE(tmp1(diis_env%buffer_length+1,1))
410            !! ALLOCATE(coeff(diis_env%buffer_length+1,1))
411            !! tmp1(:,1)=-1.0_dp*m_b_copy(1,:)/eigenvalues(:)
412            !! coeff=MATMUL(m_b_copy,tmp1)
413            !! DEALLOCATE(tmp1)
414            ALLOCATE (tmp1(diis_env%buffer_length + 1))
415            ALLOCATE (coeff(diis_env%buffer_length + 1))
416            tmp1(:) = -1.0_dp*m_b_copy(1, :)/eigenvalues(:)
417            coeff(:) = MATMUL(m_b_copy, tmp1)
418            DEALLOCATE (tmp1)
419
420            !IF (unit_nr.gt.0) THEN
421            !   DO im=1,diis_env%buffer_length+1
422            !      WRITE(unit_nr,*) diis_env%m_b(idomain)%mdata(im,:)
423            !   ENDDO
424            !   WRITE (unit_nr,*) coeff(:,1)
425            !ENDIF
426
427            ! extrapolate the variable
428            checksum = 0.0_dp
429            IF (diis_env%diis_env_type .EQ. diis_env_dbcsr) THEN
430               CALL dbcsr_set(extr_var, 0.0_dp)
431               DO im = 1, diis_env%buffer_length
432                  CALL dbcsr_add(extr_var, diis_env%m_var(im), &
433                                 1.0_dp, coeff(im + 1))
434                  checksum = checksum + coeff(im + 1)
435               ENDDO
436            ELSE IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
437               CALL copy_submatrices(diis_env%d_var(1, idomain), &
438                                     d_extr_var(idomain), &
439                                     copy_data=.FALSE.)
440               CALL set_submatrices(d_extr_var(idomain), 0.0_dp)
441               DO im = 1, diis_env%buffer_length
442                  CALL add_submatrices(1.0_dp, d_extr_var(idomain), &
443                                       coeff(im + 1), diis_env%d_var(im, idomain), &
444                                       'N')
445                  checksum = checksum + coeff(im + 1)
446               ENDDO
447            ENDIF
448            !WRITE(*,*) checksum
449
450            DEALLOCATE (coeff)
451
452         ENDIF ! domain is local to this mpi node
453
454      ENDDO ! loop over domains
455
456      DEALLOCATE (eigenvalues)
457      DEALLOCATE (m_b_copy)
458
459      CALL timestop(handle)
460
461   END SUBROUTINE almo_scf_diis_extrapolate
462
463! **************************************************************************************************
464!> \brief computes elements of b-matrix
465!> \param diis_env ...
466!> \param A ...
467!> \param B ...
468!> \param d_A ...
469!> \param d_B ...
470!> \return ...
471!> \par History
472!>       2013.02 created [Rustam Z Khaliullin]
473!> \author Rustam Z Khaliullin
474! **************************************************************************************************
475   FUNCTION almo_scf_diis_error_overlap(diis_env, A, B, d_A, d_B)
476
477      TYPE(almo_scf_diis_type), INTENT(INOUT)            :: diis_env
478      TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL          :: A, B
479      TYPE(domain_submatrix_type), INTENT(INOUT), &
480         OPTIONAL                                        :: d_A, d_B
481      REAL(KIND=dp)                                      :: almo_scf_diis_error_overlap
482
483      CHARACTER(len=*), PARAMETER :: routineN = 'almo_scf_diis_error_overlap', &
484         routineP = moduleN//':'//routineN
485
486      INTEGER                                            :: handle
487      REAL(KIND=dp)                                      :: trace
488
489      CALL timeset(routineN, handle)
490
491      IF (diis_env%diis_env_type .EQ. diis_env_dbcsr) THEN
492         IF (.NOT. (PRESENT(A) .AND. PRESENT(B))) THEN
493            CPABORT("provide DBCSR matrices")
494         ENDIF
495      ELSE IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
496         IF (.NOT. (PRESENT(d_A) .AND. PRESENT(d_B))) THEN
497            CPABORT("provide domain submatrices")
498         ENDIF
499      ELSE
500         CPABORT("illegal DIIS ENV type")
501      ENDIF
502
503      SELECT CASE (diis_env%error_type)
504      CASE (diis_error_orthogonal)
505         IF (diis_env%diis_env_type .EQ. diis_env_dbcsr) THEN
506            CALL dbcsr_dot(A, B, trace)
507         ELSE IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
508            CPASSERT(SIZE(d_A%mdata, 1) .EQ. SIZE(d_B%mdata, 1))
509            CPASSERT(SIZE(d_A%mdata, 2) .EQ. SIZE(d_B%mdata, 2))
510            CPASSERT(d_A%domain .EQ. d_B%domain)
511            CPASSERT(d_A%domain .GT. 0)
512            CPASSERT(d_B%domain .GT. 0)
513            trace = SUM(d_A%mdata(:, :)*d_B%mdata(:, :))
514         ENDIF
515      CASE DEFAULT
516         CPABORT("Vector type is unknown")
517      END SELECT
518
519      almo_scf_diis_error_overlap = trace
520
521      CALL timestop(handle)
522
523   END FUNCTION almo_scf_diis_error_overlap
524
525! **************************************************************************************************
526!> \brief destroys the diis structure
527!> \param diis_env ...
528!> \par History
529!>       2011.12 created [Rustam Z Khaliullin]
530!> \author Rustam Z Khaliullin
531! **************************************************************************************************
532   SUBROUTINE almo_scf_diis_release(diis_env)
533      TYPE(almo_scf_diis_type), INTENT(INOUT)            :: diis_env
534
535      CHARACTER(len=*), PARAMETER :: routineN = 'almo_scf_diis_release', &
536         routineP = moduleN//':'//routineN
537
538      INTEGER                                            :: handle, im
539
540      CALL timeset(routineN, handle)
541
542      ! release matrices
543      DO im = 1, diis_env%max_buffer_length
544         IF (diis_env%diis_env_type .EQ. diis_env_dbcsr) THEN
545            CALL dbcsr_release(diis_env%m_err(im))
546            CALL dbcsr_release(diis_env%m_var(im))
547         ELSE IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
548            CALL release_submatrices(diis_env%d_var(im, :))
549            CALL release_submatrices(diis_env%d_err(im, :))
550         ENDIF
551      ENDDO
552
553      IF (diis_env%diis_env_type .EQ. diis_env_domain) THEN
554         CALL release_submatrices(diis_env%m_b(:))
555      ENDIF
556
557      IF (ALLOCATED(diis_env%m_b)) DEALLOCATE (diis_env%m_b)
558      IF (ALLOCATED(diis_env%m_err)) DEALLOCATE (diis_env%m_err)
559      IF (ALLOCATED(diis_env%m_var)) DEALLOCATE (diis_env%m_var)
560      IF (ALLOCATED(diis_env%d_err)) DEALLOCATE (diis_env%d_err)
561      IF (ALLOCATED(diis_env%d_var)) DEALLOCATE (diis_env%d_var)
562
563      CALL timestop(handle)
564
565   END SUBROUTINE almo_scf_diis_release
566
567END MODULE almo_scf_diis_types
568
569