• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eT-program / eT / 22369

04 Mar 2025 10:29PM UTC coverage: 88.56%. Remained the same
22369

push

gitlab-ci

Merge branch 'cas_qed_for_merge' into 'development'

qed cas

See merge request eT-program/eT!1529

99 of 101 new or added lines in 10 files covered. (98.02%)

116 existing lines in 8 files now uncovered.

53696 of 60632 relevant lines covered (88.56%)

3046842.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.41
/src/wavefunctions/wavefunction/wavefunction_class.F90
1

2

3
! eT - a coupled cluster program
4
! Copyright (C) 2016-2024 the authors of eT
5
!
6
! eT is free software: you can redistribute it and/or modify
7
! it under the terms of the GNU General Public License as published by
8
! the Free Software Foundation, either version 3 of the License, or
9
! (at your option) any later version.
10
!
11
! eT is distributed in the hope that it will be useful,
12
! but WITHOUT ANY WARRANTY; without even the implied warranty of
13
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
! GNU General Public License for more details.
15
!
16
! You should have received a copy of the GNU General Public License
17
! along with this program. If not, see <https://www.gnu.org/licenses/>.
18

19

20
module wavefunction_class
21

22
   !!
23
   !! Wavefunction class module
24
   !! Written by Eirik F. Kjønstad and Sarai D. Folkestad, 2018
25
   !!
26

27
   use parameters
28
   use global_out,                     only: output
29
   use memory_manager_class,           only: mem
30
   use ao_tool_class,                  only: ao_tool
31
   use environment_class,              only: environment
32
   use output_file_class,              only: output_file
33
   use abstract_ao_eri_getter_class,   only: abstract_ao_eri_getter
34
   use abstract_ao_oei_getter_class,   only: abstract_ao_oei_getter
35

36
   implicit none
37

38
   type, abstract :: wavefunction
39

40
      character(len=40) :: name_
41

42
      real(dp)    :: energy
43
      real(dp)    :: core_energy
44
      complex(dp) :: energy_complex
45

46
      complex(dp), dimension(3) :: dipole_moment_complex
47

48
      integer :: n_atomic_centers
49

50
      integer :: n_mo ! Number of molecular orbitals
51
      integer :: n_o  ! Number of occupied orbitals
52
      integer :: n_v  ! Number of virtual orbitals
53

54
      integer :: multiplicity
55
      integer :: n_alpha, n_beta
56

57
      logical :: embedded
58

59
      class(environment), allocatable :: embedding
60

61
      class(ao_tool), allocatable :: ao
62
      class(abstract_ao_eri_getter), allocatable :: ao_eri
63
      class(abstract_ao_oei_getter), allocatable :: ao_oei
64

65
      real(dp), dimension(:,:), allocatable :: orbital_coefficients
66
      real(dp), dimension(:), allocatable   :: orbital_energies
67

68
      ! Frozen orbital variables. Frozen orbitals are typically frozen core or frozen HF orbitals.
69

70
      real(dp), dimension(:,:), allocatable :: frozen_mo_fock
71

72
      real(dp), dimension(:), allocatable :: bilinear_core
73

74
      real(dp) :: cholesky_orbital_threshold = 1.0D-2
75

76
      logical :: exists_frozen_fock_terms ! Are there frozen Fock terms?
77

78
      real(dp), dimension(:,:), allocatable :: frozen_CCT   ! Matrix CC^T where the contraction is
79
      ! over frozen orbitals. Needed if
80
      ! PAO construction follows (e.g in mlcc)
81
      ! other reduction of orbitals
82
      real(dp), dimension(:,:), allocatable :: ao_fock
83
      real(dp), dimension(:,:), allocatable :: ao_G
84
      real(dp), dimension(:,:), allocatable :: mo_fock
85

86
      real(dp), dimension(3) :: frozen_dipole
87
      real(dp), dimension(6) :: frozen_quadrupole
88

89
      logical :: frozen_mos
90

91
   contains
92

93
      procedure :: initialize_orbital_coefficients &
94
                => initialize_orbital_coefficients_wavefunction
95

96
      procedure :: initialize_orbital_energies &
97
                => initialize_orbital_energies_wavefunction
98

99
      procedure :: destruct_orbital_coefficients &
100
                => destruct_orbital_coefficients_wavefunction
101

102
      procedure :: destruct_orbital_energies &
103
                => destruct_orbital_energies_wavefunction
104

105
      procedure :: initialize_frozen_CCT &
106
                => initialize_frozen_CCT_wavefunction
107

108
      procedure :: destruct_frozen_CCT &
109
                => destruct_frozen_CCT_wavefunction
110

111
      procedure :: initialize_ao_fock &
112
                => initialize_ao_fock_wavefunction
113

114
      procedure :: destruct_ao_fock &
115
                => destruct_ao_fock_wavefunction
116

117
      procedure :: initialize_mo_fock &
118
                => initialize_mo_fock_wavefunction
119

120
      procedure :: destruct_mo_fock &
121
                => destruct_mo_fock_wavefunction
122

123
      procedure :: mo_transform &
124
                => mo_transform_wavefunction
125

126
      procedure :: ao_transform &
127
                => ao_transform_wavefunction
128

129
      procedure :: transform_one_electron_state_to_ao
130

131
      procedure :: metric_ao_transform &
132
                => metric_ao_transform_wavefunction
133

134
      procedure :: project_atomic_orbitals  &
135
                => project_atomic_orbitals_wavefunction
136

137
      procedure :: get_orbital_overlap &
138
                => get_orbital_overlap_wavefunction
139

140
      procedure :: loewdin_orthonormalization &
141
                => loewdin_orthonormalization_wavefunction
142

143
      procedure :: initialize_frozen_mo_fock &
144
                => initialize_frozen_mo_fock_wavefunction
145

146
      procedure :: destruct_frozen_mo_fock &
147
                => destruct_frozen_mo_fock_wavefunction
148

149
      procedure :: get_mo_fock &
150
                => get_mo_fock_wavefunction
151

152
      procedure :: set_mo_fock &
153
                => set_mo_fock_wavefunction
154

155
      procedure :: prepare_ao_tool &
156
                => prepare_ao_tool_wavefunction
157

158
      procedure :: set_geometry &
159
                => set_geometry_wavefunction
160

161
      procedure :: set_orbital_coefficients &
162
                => set_orbital_coefficients_wavefunction
163

164
      procedure :: prepare_embedding &
165
                => prepare_embedding_wavefunction
166

167
      procedure :: construct_mo_basis_transformation &
168
                => construct_mo_basis_transformation_wavefunction
169

170
      procedure :: get_nuclear_dipole &
171
                => get_nuclear_dipole_wavefunction
172

173
      procedure :: get_nuclear_quadrupole &
174
                => get_nuclear_quadrupole_wavefunction
175

176
      procedure :: get_nuclear_repulsion &
177
                => get_nuclear_repulsion_wavefunction
178

179
      procedure :: get_nuclear_repulsion_1der &
180
                => get_nuclear_repulsion_1der_wavefunction
181

182
      procedure :: get_molecular_geometry &
183
                => get_molecular_geometry_wavefunction
184

185
      procedure :: get_orbital_differences &
186
                => get_orbital_differences_wavefunction
187

188
      procedure :: initialize_redundant_internal_coordinates &
189
                => initialize_redundant_internal_coordinates_wavefunction
190

191
      procedure :: calculate_and_print_dipole &
192
                => calculate_and_print_dipole_wavefunction
193

194
      procedure :: calculate_and_print_transition_dipole &
195
                => calculate_and_print_transition_dipole_wavefunction
196

197
      procedure(get_electronic_dipole), deferred :: get_electronic_dipole
198
      procedure(get_electronic_transition_dipole), deferred :: get_electronic_transition_dipole
199

200
      procedure :: calculate_and_print_quadrupole &
201
                => calculate_and_print_quadrupole_wavefunction
202

203
      procedure :: calculate_and_print_transition_quadrupole &
204
                => calculate_and_print_transition_quadrupole_wavefunction
205

206
      procedure(get_electronic_quadrupole), deferred :: get_electronic_quadrupole
207
      procedure(get_electronic_transition_quadrupole), deferred :: get_electronic_transition_quadrupole
208

209
      procedure :: write_orbitals &
210
                => write_orbitals_wavefunction
211
      procedure :: write_orbitals_and_energies &
212
                => write_orbitals_and_energies_wavefunction
213
      procedure :: write_orbital_coefficients &
214
                => write_orbital_coefficients_wavefunction
215

216
      procedure :: get_orbital_spread &
217
                => get_orbital_spread_wavefunction
218

219
      procedure :: construct_molecular_gradient &
220
                => construct_molecular_gradient_wavefunction
221

222
      procedure :: calculate_and_print_molecular_gradient &
223
                => calculate_and_print_molecular_gradient_wavefunction
224

225
      procedure :: save_geometry_to_xyz &
226
                => save_geometry_to_xyz_wavefunction
227

228
   end type wavefunction
229

230

231
   abstract interface
232

233
      function get_electronic_dipole(wf, density) result(mu_electronic)
234

235
         use parameters
236
         import :: wavefunction
237

238
         implicit none
239

240
         class(wavefunction), intent(inout) :: wf
241
         real(dp), dimension(3) :: mu_electronic
242
         real(dp), dimension(:,:), intent(in) :: density
243

244
      end function get_electronic_dipole
245

246
      function get_electronic_quadrupole(wf, density) result(q_electronic)
247

248
         use parameters
249
         import :: wavefunction
250

251
         implicit none
252

253
         class(wavefunction), intent(inout) :: wf
254
         real(dp), dimension(6) :: q_electronic
255
         real(dp), dimension(:,:), intent(in) :: density
256

257
      end function get_electronic_quadrupole
258

259
      function get_electronic_transition_dipole(wf, density) result(mu_electronic)
260

261
         use parameters
262
         import :: wavefunction
263

264
         implicit none
265

266
         class(wavefunction), intent(inout) :: wf
267
         real(dp), dimension(3) :: mu_electronic
268
         real(dp), dimension(:,:), intent(in) :: density
269

270
      end function get_electronic_transition_dipole
271

272
      function get_electronic_transition_quadrupole(wf, density) result(q_electronic)
273

274
         use parameters
275
         import :: wavefunction
276

277
         implicit none
278

279
         class(wavefunction), intent(inout) :: wf
280
         real(dp), dimension(6) :: q_electronic
281
         real(dp), dimension(:,:), intent(in) :: density
282

283
      end function get_electronic_transition_quadrupole
284

285
   end interface
286

287

288
contains
289

290

291
   subroutine prepare_ao_tool_wavefunction(wf, centers, template, charge)
29,614✔
292
      !!
293
      !! Written by Eirik F. Kjønstad, 2020
294
      !!
295
      !! Initializes the AO tool, which handles the atomic orbital integrals in eT.
296
      !!
297
      !! centers:   Optional set of 'atomic_center' objects that represents the atomic orbital
298
      !!            basis used by the AO tool and the integral program (Libint). The default
299
      !!            centers are those specified by the QM geometry in the eT input file.
300
      !!
301
      !! template: Optional template_ao_tool from which the ao_tool is initialized.
302
      !!
303
      use atomic_center_class, only: atomic_center
304

305
      implicit none
306

307
      class(wavefunction) :: wf
308

309
      class(atomic_center), dimension(:), optional, intent(in) :: centers
310

311
      type(ao_tool), optional, intent(in) :: template
312
      integer, intent(in), optional :: charge
313

314
      wf%ao = ao_tool()
29,614✔
315

316
      if (present(template)) then
29,614✔
317

318
         call wf%ao%initialize_ao_tool_from_template(template)
5,409✔
319

320
      else
321

322
         call wf%ao%initialize(centers, charge)
24,205✔
323

324
      end if
325

326
      wf%n_atomic_centers = wf%ao%get_n_centers()
29,614✔
327

328
   end subroutine prepare_ao_tool_wavefunction
29,614✔
329

330

331
   subroutine set_geometry_wavefunction(wf, R, units)
9,872✔
332
      !!
333
      !! Written by Eirik F. Kjønstad, 2020
334
      !!
335
      !! Sets the position of the atomic nuclei.
336
      !!
337
      !!    R:     (3 x n_atoms) array containing the Cartesian coordinates of the atoms
338
      !!    units: specifies units of R ('angstrom' or 'bohr')
339
      !!
340
      !! This includes updating the atomic centers of the AO tool
341
      !! and the atomic positions of the molecule.
342
      !!
343
      implicit none
344

345
      class(wavefunction), intent(inout) :: wf
346

347
      character(len=*), intent(in) :: units
348

349
      real(dp), dimension(3, wf%n_atomic_centers) :: R
350

351
      call wf%ao%set_atomic_centers(R, units)
9,872✔
352

353
   end subroutine set_geometry_wavefunction
9,872✔
354

355

356
   subroutine initialize_orbital_coefficients_wavefunction(wf)
36,774✔
357
      !!
358
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
359
      !!
360
      implicit none
361

362
      class(wavefunction) :: wf
363

364
      if (.not. allocated(wf%orbital_coefficients)) call mem%alloc(wf%orbital_coefficients, wf%ao%n, wf%n_mo)
36,774✔
365

366
   end subroutine initialize_orbital_coefficients_wavefunction
36,774✔
367

368

369
   subroutine destruct_orbital_coefficients_wavefunction(wf)
30,220✔
370
      !!
371
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
372
      !!
373
      implicit none
374

375
      class(wavefunction) :: wf
376

377
      if (allocated(wf%orbital_coefficients)) call mem%dealloc(wf%orbital_coefficients)
30,220✔
378

379
   end subroutine destruct_orbital_coefficients_wavefunction
30,220✔
380

381

382
   subroutine initialize_orbital_energies_wavefunction(wf)
36,774✔
383
      !!
384
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
385
      !!
386
      implicit none
387

388
      class(wavefunction) :: wf
389

390
      if (.not. allocated(wf%orbital_energies)) call mem%alloc(wf%orbital_energies, wf%n_mo)
36,774✔
391

392
   end subroutine initialize_orbital_energies_wavefunction
36,774✔
393

394

395
   subroutine destruct_orbital_energies_wavefunction(wf)
30,220✔
396
      !!
397
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
398
      !!
399
      implicit none
400

401
      class(wavefunction) :: wf
402

403
      if (allocated(wf%orbital_energies)) call mem%dealloc(wf%orbital_energies)
30,220✔
404

405
   end subroutine destruct_orbital_energies_wavefunction
30,220✔
406

407

408
   subroutine mo_transform_wavefunction(wf, X_wx, Y_pq)
166,889✔
409
      !!
410
      !! Written by Eirik F. Kjønstad, Sep 2018
411
      !!
412
      !! Performs MO transformation of X and saves the result in Y:
413
      !!
414
      !!    Y_pq = sum_wx C_wp X_wx C_xq
415
      !!
416
      implicit none
417

418
      class(wavefunction), intent(in) :: wf
419

420
      real(dp), dimension(wf%ao%n, wf%ao%n), intent(in)    :: X_wx
421
      real(dp), dimension(wf%n_mo, wf%n_mo), intent(inout) :: Y_pq
422

423
      real(dp), dimension(:,:), allocatable :: Z_wq ! = sum_x X_wx C_xq
166,889✔
424

425
      call mem%alloc(Z_wq, wf%ao%n, wf%n_mo)
166,889✔
426

427
      call dgemm('N', 'N',                 &
428
                  wf%ao%n,                 &
429
                  wf%n_mo,                 &
430
                  wf%ao%n,                 &
431
                  one,                     &
432
                  X_wx,                    &
433
                  wf%ao%n,                 &
434
                  wf%orbital_coefficients, & ! C_xq
435
                  wf%ao%n,                 &
436
                  zero,                    &
437
                  Z_wq,                    &
438
                  wf%ao%n)
166,889✔
439

440
      call dgemm('T', 'N',                 &
441
                  wf%n_mo,                 &
442
                  wf%n_mo,                 &
443
                  wf%ao%n,                 &
444
                  one,                     &
445
                  wf%orbital_coefficients, & ! C_wp
446
                  wf%ao%n,                 &
447
                  Z_wq,                    &
448
                  wf%ao%n,                 &
449
                  zero,                    &
450
                  Y_pq,                    &
451
                  wf%n_mo)
166,889✔
452

453
      call mem%dealloc(Z_wq)
166,889✔
454

455
   end subroutine mo_transform_wavefunction
166,889✔
456

457

458
   subroutine ao_transform_wavefunction(wf, L_mo, L_ao)
120✔
459
      !!
460
      !! Written by Regina Matveeva, Sept 2021
461
      !!
462
      !! Peforms transformation of a matrix with wf%n_mo x wf%n_mo dimensons
463
      !! to a matrix with wf%ao%n x xf%ao%n dimensions according to
464
      !!
465
      !!    L_wx = sum_pq C_wp L_pq C_wq
466
      !!
467
      implicit none
468

469
      class(wavefunction) :: wf
470

471
      real(dp), dimension(wf%n_mo, wf%n_mo), intent(in)  :: L_mo
472
      real(dp), dimension(wf%ao%n, wf%ao%n), intent(out) :: L_ao
473

474
      real(dp), dimension(:,:), allocatable :: Z_wq
120✔
475

476
      call mem%alloc(Z_wq, wf%ao%n, wf%n_mo)
120✔
477

478
      call dgemm('N', 'N',                 &
479
                  wf%ao%n,                 &
480
                  wf%n_mo,                 &
481
                  wf%n_mo,                 &
482
                  one,                     &
483
                  wf%orbital_coefficients, & ! C_wp
484
                  wf%ao%n,                 &
485
                  L_mo,                    & ! L_pq
486
                  wf%n_mo,                 &
487
                  zero,                    &
488
                  Z_wq,                    &
489
                  wf%ao%n)
120✔
490

491
      ! sum_wx Z_px C_qx
492

493
      call dgemm('N', 'T',                 &
494
                  wf%ao%n,                 &
495
                  wf%ao%n,                 &
496
                  wf%n_mo,                 &
497
                  one,                     &
498
                  Z_wq,                    &
499
                  wf%ao%n,                 &
500
                  wf%orbital_coefficients, & ! C_xq
501
                  wf%ao%n,                 &
502
                  zero,                    &
503
                  L_ao,                    & ! L_wx
504
                  wf%ao%n)
120✔
505

506
      call mem%dealloc(Z_wq)
120✔
507

508
   end subroutine ao_transform_wavefunction
120✔
509

510

511
   subroutine metric_ao_transform_wavefunction(wf, L_mo, L_ao)
6✔
512
      !!
513
      !! Written by Linda Goletto, Dec 2022
514
      !!
515
      !! Peforms transformation of a matrix with wf%n_mo x wf%n_mo dimensons
516
      !! to a matrix with wf%ao%n x xf%ao%n dimensions according to
517
      !!
518
      !!    L_wz = sum_pqxy S_wx C_xp L_pq C_yq S_yz
519
      !!
520
      !! where S is the AO overlap matrix.
521
      !!
522
      use array_utilities, only: symmetric_sandwich_right_transposition
523

524
      implicit none
525

526
      class(wavefunction) :: wf
527

528
      real(dp), dimension(wf%n_mo, wf%n_mo), intent(in)  :: L_mo
529
      real(dp), dimension(wf%ao%n, wf%ao%n), intent(out) :: L_ao
530

531
      real(dp), dimension(:,:), allocatable :: Z_wp
6✔
532

533
      ! Z_wp = sum_x S_wx C_xp
534

535
      call mem%alloc(Z_wp, wf%ao%n, wf%n_mo)
6✔
536

537
      call dgemm('N', 'N',                   &
538
                  wf%ao%n,                   &
539
                  wf%n_mo,                   &
540
                  wf%ao%n,                   &
541
                  one,                       &
542
                  wf%ao%s,                   & ! S_wx
543
                  wf%ao%n,                   &
544
                  wf%orbital_coefficients,   & ! C_xp
545
                  wf%ao%n,                   &
546
                  zero,                      &
547
                  Z_wp,                      &
548
                  wf%ao%n)
6✔
549

550
      ! L_ao = L_wz = sum_pq Z_wp L_pq Z_zq
551

552
      call symmetric_sandwich_right_transposition(L_ao, L_mo, Z_wp, wf%ao%n, wf%n_mo)
6✔
553

554
      call mem%dealloc(Z_wp)
6✔
555

556
   end subroutine metric_ao_transform_wavefunction
6✔
557

558

559
   subroutine project_atomic_orbitals_wavefunction(wf, D, PAO_coeff, n_orbitals, first_ao)
570✔
560
      !!
561
      !! Written by Linda Goletto and Sarai D. Folkestad, Jun 2019
562
      !!
563
      !! Projects the orbitals given by D out of the atomic orbitals (PAOs)
564
      !!
565
      !!    C^PAO = I - DS
566
      !!
567
      !! NOTE: n_orbitals must be equal to n_ao unless
568
      !! a restricted orbital space is requested.
569
      !!
570
      !! For restricted space optional argument first_ao
571
      !! may be used.
572
      !!
573
      use array_initialization, only: zero_array
574

575
      implicit none
576

577
      class(wavefunction), intent(inout) :: wf
578

579
      integer, intent(in) :: n_orbitals
580

581
      real(dp), dimension(wf%ao%n, wf%ao%n), intent(in)      :: D
582
      real(dp), dimension(wf%ao%n, n_orbitals), intent(out)  :: PAO_coeff
583

584
      integer, intent(in), optional :: first_ao
585

586
      integer :: local_first, local_last
587

588
      integer :: i
589

590
      real(dp), dimension(:,:), allocatable :: S
570✔
591

592
      ! Set offsets
593

594
      local_first = 1
595
      if (present(first_ao)) local_first = first_ao
570✔
596

597
      local_last = local_first + n_orbitals - 1
570✔
598

599
      ! Sanity checks and safety guards
600

601
      if (n_orbitals .gt. wf%ao%n) call output%error_msg('number of orbitals for PAOs exceeds number of AOs')
570✔
602
      if ((local_first .lt. 1) .or. (local_first .gt. wf%ao%n)) call output%error_msg('First PAO exceeds number of AOs')
570✔
603
      if ((local_last .lt. 1) .or. (local_last .gt. wf%ao%n)) call output%error_msg('Last PAO exceeds number of AOs')
570✔
604

605
      ! Construct PAO coefficients
606

607
      call zero_array(PAO_coeff, wf%ao%n*n_orbitals)
570✔
608

609
      !$omp parallel do private(i)
570✔
610
      do i = 1, n_orbitals
611

612
         PAO_coeff(i + local_first - 1, i) = one
613

614
      enddo
615
      !$omp end parallel do
616

617
      call mem%alloc(S, wf%ao%n, wf%ao%n)
570✔
618

619
      call wf%ao_oei%get_oei('overlap', S)
570✔
620

621
      call dgemm('N', 'N',             &
622
                  wf%ao%n,             &
623
                  n_orbitals,          &
624
                  wf%ao%n,             &
625
                  -one,                &
626
                  D,                   &
627
                  wf%ao%n,             &
628
                  S(1,local_first),    &
629
                  wf%ao%n,             &
630
                  one,                 &
631
                  PAO_coeff,           &
632
                  wf%ao%n)
570✔
633

634
      call mem%dealloc(S)
570✔
635

636
   end subroutine project_atomic_orbitals_wavefunction
570✔
637

638

639
   subroutine get_orbital_overlap_wavefunction(wf, orbital_coeff, n_orbitals, S)
570✔
640
      !!
641
      !! Written by Sarai D. Folkestad and Linda Goletto, Jun 2019
642
      !!
643
      !! Construct the orbital overlap
644
      !!
645
      !!    S = C^T S_AO C
646
      !!
647
      !! for some set of orbital coefficients.
648
      !!
649
      implicit none
650

651
      class(wavefunction) :: wf
652

653
      integer, intent(in) :: n_orbitals
654

655
      real(dp), dimension(wf%ao%n, n_orbitals), intent(in) :: orbital_coeff
656

657
      real(dp), dimension(n_orbitals, n_orbitals), intent(out) :: S
658

659
      real(dp), dimension(:,:), allocatable :: X
570✔
660

661
      call mem%alloc(X, n_orbitals, wf%ao%n)
570✔
662

663
      call dgemm('T', 'N',       &
664
                  n_orbitals,    &
665
                  wf%ao%n,       &
666
                  wf%ao%n,       &
667
                  one,           &
668
                  orbital_coeff, &
669
                  wf%ao%n,       &
670
                  wf%ao%s,       &
671
                  wf%ao%n,       &
672
                  zero,          &
673
                  X,             &
674
                  n_orbitals)
570✔
675

676
      call dgemm('N', 'N',       &
677
                  n_orbitals,    &
678
                  n_orbitals,    &
679
                  wf%ao%n,       &
680
                  one,           &
681
                  X,             &
682
                  n_orbitals,    &
683
                  orbital_coeff, &
684
                  wf%ao%n,       &
685
                  zero,          &
686
                  S,             &
687
                  n_orbitals)
570✔
688

689
      call mem%dealloc(X)
570✔
690

691
   end subroutine get_orbital_overlap_wavefunction
570✔
692

693

694
   subroutine loewdin_orthonormalization_wavefunction(wf, orbital_coeff, S, n_orbitals, rank)
570✔
695
      !!
696
      !! Written by Linda Goletto and Sarai D. Folkestad, Jun 2019
697
      !!
698
      !! Orthonormalizes the orbital_coeff using Löwdin
699
      !! orthonormalization
700
      !!
701
      !! The orbital overlap
702
      !!
703
      !!    S = C^T S_AO C
704
      !!
705
      !! is diagonalized
706
      !!
707
      !!    S = U λ U^T
708
      !!
709
      !! and the orbitals are updated according to
710
      !!
711
      !!    C = C U λ^(-1/2).
712
      !!
713
      !! Linear dependence is removed by screening on the eigenvalues
714
      !! with a threshold of 1.0 * 10^-6
715
      !!
716
      !! Modified by SDF May 2020,
717
      !!
718
      !! Added flip of orbitals.
719
      !! Diagonalization using wrapper.
720
      !!
721
      use array_utilities, only: diagonalize_symmetric
722
      use array_initialization, only: copy_and_scale
723

724
      implicit none
725

726
      class(wavefunction) :: wf
727

728
      integer, intent(in)  :: n_orbitals
729
      integer, intent(out) :: rank
730

731
      real(dp), dimension(wf%ao%n, n_orbitals), intent(in)     :: orbital_coeff
732
      real(dp), dimension(n_orbitals, n_orbitals), intent(inout)  :: S
733

734
      real(dp), dimension(:), allocatable :: eigenvalues, inv_sqrt_eig
570✔
735
      real(dp), dimension(:,:), allocatable :: orbital_coeff_copy
570✔
736

737
      integer :: i
738

739
      real(dp), parameter :: threshold = 1.0d-6 ! Threshold for linear dependency.
740

741
      ! Diagonalize S
742

743
      call mem%alloc(eigenvalues, n_orbitals)
570✔
744

745
      call dscal(n_orbitals**2, -one, S, 1)
570✔
746
      call diagonalize_symmetric(S, n_orbitals, eigenvalues)
570✔
747

748
      ! Find the rank of S
749

750
      rank = 0
570✔
751

752
      do i = 1, n_orbitals
8,346✔
753

754
         if (abs(eigenvalues(i)) .lt. threshold) exit
8,334✔
755

756
         rank = rank + 1
8,346✔
757

758
      enddo
759

760
      ! Invert and square-root the eigenvalues (screening done here)
761

762
      call mem%alloc(inv_sqrt_eig, rank)
570✔
763

764
      do i = 1, rank
8,346✔
765

766
         inv_sqrt_eig(i) = 1/(sqrt(abs(eigenvalues(i))))
8,346✔
767

768
      enddo
769

770
      call mem%dealloc(eigenvalues)
570✔
771

772
      ! S = U λ^(-1/2)
773

774
      do i = 1, rank
8,346✔
775

776
         S(:, i) = S(:, i)*inv_sqrt_eig(i)
243,732✔
777

778
      enddo
779

780
      call mem%dealloc(inv_sqrt_eig)
570✔
781

782
      do i = rank + 1, n_orbitals
9,438✔
783

784
         S(:,i) = zero
374,964✔
785

786
      enddo
787

788
      ! Transform orbital coefficients
789

790
      call mem%alloc(orbital_coeff_copy, wf%ao%n, n_orbitals)
570✔
791

792
      call copy_and_scale(one, orbital_coeff, orbital_coeff_copy, (n_orbitals)*wf%ao%n)
570✔
793

794
      call dgemm('N', 'N',                   &
795
                  wf%ao%n,                   &
796
                  rank,                      &
797
                  n_orbitals,                &
798
                  one,                       &
799
                  orbital_coeff_copy,        &
800
                  wf%ao%n,                   &
801
                  S,                         &
802
                  n_orbitals,                &
803
                  zero,                      &
804
                  orbital_coeff,             &
805
                  wf%ao%n)
570✔
806

807
      call mem%dealloc(orbital_coeff_copy)
570✔
808

809
   end subroutine loewdin_orthonormalization_wavefunction
570✔
810

811

812
   subroutine initialize_frozen_mo_fock_wavefunction(wf)
1,092✔
813
      !!
814
      !! Written by Sarai D. Folkestad, Sep. 2019
815
      !!
816
      implicit none
817

818
      class(wavefunction) :: wf
819

820
      call mem%alloc(wf%frozen_mo_fock, wf%n_mo, wf%n_mo)
1,092✔
821

822
   end subroutine initialize_frozen_mo_fock_wavefunction
1,092✔
823

824

825
   subroutine destruct_frozen_mo_fock_wavefunction(wf)
29,380✔
826
      !!
827
      !! Written by Sarai D. Folkestad, Sep. 2019
828
      !!
829
      implicit none
830

831
      class(wavefunction) :: wf
832

833
      if (allocated(wf%frozen_mo_fock)) call mem%dealloc(wf%frozen_mo_fock)
29,380✔
834

835
   end subroutine destruct_frozen_mo_fock_wavefunction
29,380✔
836

837

838
   subroutine initialize_frozen_CCT_wavefunction(wf)
360✔
839
      !!
840
      !! Written by Sarai D. Folkestad, Jan 2020
841
      !!
842
      implicit none
843

844
      class(wavefunction) :: wf
845

846
      call mem%alloc(wf%frozen_CCT, wf%ao%n, wf%ao%n)
360✔
847

848
   end subroutine initialize_frozen_CCT_wavefunction
360✔
849

850

851
   subroutine destruct_frozen_CCT_wavefunction(wf)
5,085✔
852
      !!
853
      !! Written by Sarai D. Folkestad, Jan 2020
854
      !!
855
      implicit none
856

857
      class(wavefunction) :: wf
858

859
      if (allocated(wf%frozen_CCT)) call mem%dealloc(wf%frozen_CCT)
5,085✔
860

861
   end subroutine destruct_frozen_CCT_wavefunction
5,085✔
862

863

864
   subroutine initialize_ao_fock_wavefunction(wf)
31,311✔
865
      !!
866
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
867
      !!
868
      implicit none
869

870
      class(wavefunction) :: wf
871

872
      if (.not. allocated(wf%ao_fock)) call mem%alloc(wf%ao_fock, wf%ao%n, wf%ao%n)
31,311✔
873
      if (.not. allocated(wf%ao_G)) call mem%alloc(wf%ao_G, wf%ao%n, wf%ao%n)
31,311✔
874

875
   end subroutine initialize_ao_fock_wavefunction
31,311✔
876

877

878
   subroutine destruct_ao_fock_wavefunction(wf)
24,313✔
879
      !!
880
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
881
      !!
882
      implicit none
883

884
      class(wavefunction) :: wf
885

886
      if (allocated(wf%ao_fock)) call mem%dealloc(wf%ao_fock)
24,313✔
887
      if (allocated(wf%ao_G)) call mem%dealloc(wf%ao_G)
24,313✔
888

889
   end subroutine destruct_ao_fock_wavefunction
24,313✔
890

891

892
   subroutine initialize_mo_fock_wavefunction(wf)
264✔
893
      !!
894
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
895
      !!
896
      implicit none
897

898
      class(wavefunction) :: wf
899

900
      if (.not. allocated(wf%mo_fock)) call mem%alloc(wf%mo_fock, wf%n_mo, wf%n_mo)
264✔
901

902
   end subroutine initialize_mo_fock_wavefunction
264✔
903

904

905
   subroutine destruct_mo_fock_wavefunction(wf)
24,925✔
906
      !!
907
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
908
      !!
909
      implicit none
910

911
      class(wavefunction) :: wf
912

913
      if (allocated(wf%mo_fock)) call mem%dealloc(wf%mo_fock)
24,925✔
914

915
   end subroutine destruct_mo_fock_wavefunction
24,925✔
916

917

UNCOV
918
   subroutine get_mo_fock_wavefunction(wf, F)
×
919
      !!
920
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
921
      !!
922
      !! Gets the MO Fock
923
      !!
924
      implicit none
925

926
      class(wavefunction), intent(in) :: wf
927

928
      real(dp), dimension(:,:), intent(out) :: F
929

UNCOV
930
      call dcopy(wf%n_mo**2, wf%mo_fock, 1, F, 1)
×
931

UNCOV
932
   end subroutine get_mo_fock_wavefunction
×
933

934

UNCOV
935
   subroutine set_mo_fock_wavefunction(wf, F)
×
936
      !!
937
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2018
938
      !!
939
      !! Sets the MO Fock from input
940
      !!
941
      implicit none
942

943
      class(wavefunction), intent(in) :: wf
944

945
      real(dp), dimension(:, :), intent(in) :: F
946

UNCOV
947
      call dcopy(wf%n_mo**2, F, 1, wf%mo_fock, 1)
×
948

UNCOV
949
   end subroutine set_mo_fock_wavefunction
×
950

951

952
   subroutine prepare_embedding_wavefunction(wf, embedding)
29,614✔
953
      !!
954
      !! Written by Sarai D. Folkestad
955
      !!
956
      !! Initializes the embedding object
957
      !! Embedding is either non-polarizable
958
      !! or polarizable (QM/FQ or PCM)
959
      !!
960
      use environment_factory_class, only: environment_factory
961
      use global_in, only: input
962

963
      implicit none
964

965
      class(wavefunction), intent(inout)        :: wf
966
      type(environment_factory), allocatable    :: factory
967

968
      logical, intent(in), optional :: embedding
969

970
      if (present(embedding)) then
29,614✔
971

972
         wf%embedded = embedding
20,982✔
973

974
      else
975

976
         wf%embedded = input%is_embedding_on()
8,632✔
977

978
      endif
979

980
      if (wf%embedded) then
29,614✔
981

982
         factory = environment_factory()
372✔
983

984
         call factory%create(wf%embedding)
372✔
985
         call wf%embedding%initialize(wf%ao)
372✔
986

987
      end if
988

989
   end subroutine prepare_embedding_wavefunction
372✔
990

991

992
   subroutine construct_mo_basis_transformation_wavefunction(wf, C1, C2, T)
750✔
993
      !!
994
      !! Written by Sarai D. Folekstad, Nov 2019
995
      !!
996
      !! Constructs a transformation matrix 'T' which
997
      !! takes a matrix from one molecular orbital basis
998
      !! to another.
999
      !!
1000
      !! 'C1' : coefficients of the MO basis we end up in
1001
      !!
1002
      !! 'C2' : coefficients of the MO basis we start out with
1003
      !!
1004
      !! The transformation matrix is defined as
1005
      !!
1006
      !!    T = C1^T S C2
1007
      !!
1008
      !! where S is the AO overlap matrix.
1009
      !!
1010
      implicit none
1011

1012
      class(wavefunction), intent(inout) :: wf
1013

1014
      real(dp), dimension(wf%ao%n, wf%n_mo), intent(in) :: C1, C2
1015

1016
      real(dp), dimension(wf%n_mo, wf%n_mo), intent(out) :: T
1017

1018
      real(dp), dimension(:,:), allocatable :: X, S
750✔
1019

1020
      call mem%alloc(S, wf%ao%n, wf%ao%n)
750✔
1021
      call wf%ao_oei%get_oei('overlap', S)
750✔
1022

1023
      ! X = C1^T S
1024

1025
      call mem%alloc(X, wf%n_mo, wf%ao%n)
750✔
1026

1027
      call dgemm('T', 'N', &
1028
                  wf%n_mo, &
1029
                  wf%ao%n, &
1030
                  wf%ao%n, &
1031
                  one,     &
1032
                  C1,      &
1033
                  wf%ao%n, &
1034
                  S,       &
1035
                  wf%ao%n, &
1036
                  zero,    &
1037
                  X,       &
1038
                  wf%n_mo)
750✔
1039

1040
      call mem%dealloc(S)
750✔
1041

1042
      ! T = X C2
1043

1044
      call dgemm('N', 'N', &
1045
                  wf%n_mo, &
1046
                  wf%n_mo, &
1047
                  wf%ao%n, &
1048
                  one,     &
1049
                  X,       &
1050
                  wf%n_mo, &
1051
                  C2,      &
1052
                  wf%ao%n, &
1053
                  zero,    &
1054
                  T,       &
1055
                  wf%n_mo)
750✔
1056

1057
      call mem%dealloc(X)
750✔
1058

1059
   end subroutine construct_mo_basis_transformation_wavefunction
750✔
1060

1061

1062
   function get_nuclear_dipole_wavefunction(wf) result(d)
1,413✔
1063
      !!
1064
      !! Written by Eirik F. Kjønstad, Oct 2020
1065
      !!
1066
      use point_charges_class,         only: point_charges
1067

1068
      implicit none
1069

1070
      class(wavefunction), intent(in) :: wf
1071

1072
      real(dp), dimension(3) :: d
1073

1074
      type(point_charges) :: pc
1,413✔
1075

1076
      call wf%ao%get_point_charges(pc)
1,413✔
1077
      d  = pc%get_dipole()
1,413✔
1078

1079
   end function get_nuclear_dipole_wavefunction
1,413✔
1080

1081

1082
   function get_nuclear_quadrupole_wavefunction(wf) result(q)
132✔
1083
      !!
1084
      !! Written by Eirik F. Kjønstad, Oct 2020
1085
      !!
1086
      use point_charges_class,         only: point_charges
1087

1088
      implicit none
1089

1090
      class(wavefunction), intent(in) :: wf
1091

1092
      real(dp), dimension(6) :: q
1093

1094
      type(point_charges) :: pc
66✔
1095

1096
      call wf%ao%get_point_charges(pc)
66✔
1097
      q  = pc%get_quadrupole()
66✔
1098

1099
   end function get_nuclear_quadrupole_wavefunction
66✔
1100

1101

1102
   function get_nuclear_repulsion_wavefunction(wf) result(E)
278,280✔
1103
      !!
1104
      !! Written by Eirik F. Kjønstad, Oct 2020
1105
      !!
1106
      use point_charges_class, only: point_charges
1107

1108
      implicit none
1109

1110
      class(wavefunction), intent(in) :: wf
1111

1112
      real(dp) :: E
1113

1114
      type(point_charges) :: pc
278,280✔
1115

1116
      call wf%ao%get_point_charges(pc)
278,280✔
1117
      E = pc%get_coulomb_interaction()
278,280✔
1118

1119
   end function get_nuclear_repulsion_wavefunction
278,280✔
1120

1121

1122
   function get_nuclear_repulsion_1der_wavefunction(wf) result(E)
2,406✔
1123
      !!
1124
      !! Written by Eirik F. Kjønstad, Oct 2020
1125
      !!
1126
      !! Gets first derivative of nuclear repulsion
1127
      !!
1128
      use point_charges_class,         only: point_charges
1129

1130
      implicit none
1131

1132
      class(wavefunction), intent(in) :: wf
1133

1134
      real(dp), dimension(3, wf%ao%get_n_centers()) :: E
1135

1136
      type(point_charges) :: pc
2,406✔
1137

1138
      call wf%ao%get_point_charges(pc)
2,406✔
1139
      E  = pc%get_coulomb_interaction_1der()
2,406✔
1140

1141
   end function get_nuclear_repulsion_1der_wavefunction
2,406✔
1142

1143

1144
   function get_molecular_geometry_wavefunction(wf) result(R)
2,376✔
1145
      !!
1146
      !! Written by Eirik F. Kjønstad, June 2019
1147
      !!
1148
      implicit none
1149

1150
      class(wavefunction), intent(in) :: wf
1151

1152
      real(dp), dimension(3, wf%n_atomic_centers) :: R
1153

1154
      R = wf%ao%get_center_coordinates()
48,216✔
1155
      R = R * angstrom_to_bohr
48,216✔
1156

1157
   end function get_molecular_geometry_wavefunction
2,376✔
1158

1159

1160
   subroutine set_orbital_coefficients_wavefunction(wf, C, n_orbitals, mo_offset)
990✔
1161
      !!
1162
      !! Written by Ida-Marie Høyvik and Linda Goletto, 2019
1163
      !!
1164
      !! Generalized by SDF 2021, from 'set_active_mo_coefficients_mlhf'
1165
      !!
1166
      implicit none
1167

1168
      class(wavefunction),                      intent(inout) :: wf
1169
      integer,                                  intent(in)    :: n_orbitals
1170
      real(dp), dimension(wf%ao%n, n_orbitals), intent(in)    :: C
1171
      integer,                                  intent(in)    :: mo_offset
1172

1173
      integer :: ao, mo
1174

1175
      !$omp parallel do private(ao, mo)
990✔
1176
      do mo = 1, n_orbitals
1177
         do ao = 1, wf%ao%n
1178

1179
            wf%orbital_coefficients(ao, mo_offset - 1 + mo) = C(ao, mo)
1180

1181
         enddo
1182
      enddo
1183
      !$omp end parallel do
1184

1185
   end subroutine set_orbital_coefficients_wavefunction
990✔
1186

1187

1188
   subroutine get_orbital_differences_wavefunction(wf, orbital_differences, N)
81,545✔
1189
      !!
1190
      !! Get orbital differences
1191
      !! Written by Sarai D. Folkestad, Sep 2018
1192
      !!
1193
      !! Sets the (ground state) orbital differences vector:
1194
      !!
1195
      !!    orbital_differences_ai = epsilon_a - epsilon_i
1196
      !!
1197
      implicit none
1198

1199
      class(wavefunction), intent(in) :: wf
1200
      integer, intent(in) :: N
1201
      real(dp), dimension(N), intent(out) :: orbital_differences
1202

1203
      integer :: a, i, ai
1204

1205
      !$omp parallel do private(i,a,ai)
81,545✔
1206
      do i = 1, wf%n_o
1207
         do a = 1, wf%n_v
1208

1209
            ai = wf%n_v*(i - 1) + a
1210

1211
            orbital_differences(ai) = wf%orbital_energies(a + wf%n_o) - wf%orbital_energies(i)
1212

1213
         enddo
1214
      enddo
1215
      !$omp end parallel do
1216

1217

1218
   end subroutine get_orbital_differences_wavefunction
81,545✔
1219

1220

1221
   subroutine initialize_redundant_internal_coordinates_wavefunction(wf, internals)
158✔
1222
      !!
1223
      !! Written by Eirik F. Kjønstad, 2021
1224
      !!
1225
      use atomic_center_class, only: atomic_center
1226
      use redundant_internal_coordinates_class, only: redundant_internal_coords
1227

1228
      implicit none
1229

1230
      class(wavefunction), intent(in) :: wf
1231

1232
      class(redundant_internal_coords), intent(inout) :: internals
1233

1234
      integer, dimension(:), allocatable :: Z
158✔
1235
      real(dp), dimension(:,:), allocatable :: R
158✔
1236

1237
      type(atomic_center), allocatable :: center
1238

1239
      integer :: k
1240

1241
      call mem%alloc(Z, wf%n_atomic_centers)
158✔
1242
      call mem%alloc(R, 3, wf%n_atomic_centers)
158✔
1243

1244
      R = wf%get_molecular_geometry()
2,884✔
1245

1246
      allocate(center)
158✔
1247

1248
      do k = 1, wf%n_atomic_centers
800✔
1249

1250
         call wf%ao%get_center(k, center)
642✔
1251

1252
         Z(k) = center%number_
800✔
1253

1254
      enddo
1255

1256
      call internals%initialize(R, Z)
158✔
1257

1258
      call mem%dealloc(R)
158✔
1259
      call mem%dealloc(Z)
158✔
1260

1261
   end subroutine initialize_redundant_internal_coordinates_wavefunction
440✔
1262

1263

1264
   subroutine calculate_and_print_dipole_wavefunction(wf, density)
123✔
1265
      !!
1266
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad
1267
      !! Linda Goletto, and Alexander C. Paul, Apr 2019
1268
      !!
1269
      use math_utilities, only: norm_R3
1270

1271
      implicit none
1272

1273
      class(wavefunction), intent(inout) :: wf
1274

1275
      real(dp), dimension(:,:), intent(in) :: density
1276

1277
      real(dp), dimension(3, 3) :: dipole
1278

1279
      character(len=5), dimension(3) :: components
1280
      character(len=18), dimension(3) :: labels
1281

1282
      call output%printf('m', 'Dipole moment [Debye]:', fs='(/t6,a)')
123✔
1283
      call output%print_separator('m', 25, '=', fs='(t6,a)')
123✔
1284

1285
      dipole(:,1) = wf%get_electronic_dipole(density) * au_to_debye
984✔
1286

1287
      dipole(:,2) = wf%get_nuclear_dipole() * au_to_debye
984✔
1288

1289
      dipole(:,3) = dipole(:,1) + dipole(:,2)
492✔
1290

1291
      components = ['x', 'y', 'z']
492✔
1292
      labels = [character(len=18) :: 'Electronic', 'Nuclear', 'Total']
492✔
1293

1294
      call output%printf('m', 'Conversion factor from Debye a.u.: (f11.9)', &
1295
                          reals=[one/au_to_debye], fs='(/t6,a)')
123✔
1296

1297
      call output%print_table("Comp.", components, labels, dipole, 3, 3)
123✔
1298

1299
      call output%printf('m', 'Norm of the total dipole moment: (f0.7)', &
1300
                         reals=[norm_R3(dipole(:,3))], fs='(t6,a)')
246✔
1301

1302
   end subroutine calculate_and_print_dipole_wavefunction
123✔
1303

1304

1305
   subroutine calculate_and_print_transition_dipole_wavefunction(wf, density, omega)
42✔
1306
      !!
1307
      !! Written by Matteo Rinaldi, June 2023
1308
      !! Modified by Matteo Castagnola, Feb 2025
1309
      !!
1310
      use math_utilities, only: norm_R3
1311

1312
      implicit none
1313

1314
      class(wavefunction), intent(inout) :: wf
1315

1316
      real(dp), dimension(:,:), intent(in) :: density
1317

1318
      real(dp), dimension(3, 2) :: dipole
1319

1320
      character(len=5), dimension(3) :: components
1321
      character(len=20), dimension(1) :: labels
1322

1323
      real(dp) :: oscillator_strength
1324

1325
      real(dp),  intent(in) :: omega
1326

1327
      call output%printf('m', 'Transition strength (length gauge) [a.u.]:', fs='(/t6,a)')
42✔
1328

1329
      dipole(:,1) = abs(wf%get_electronic_transition_dipole(density))
168✔
1330

1331
      dipole(:,2) = dipole(:,1)**2
168✔
1332

1333
      components = ['x', 'y', 'z']
168✔
1334
      labels = [character(len=20) :: '|< n | r | m >|^2']
84✔
1335

1336
      call output%print_table("Comp.", components, labels, dipole(:,2), 3, 1)
42✔
1337

1338
      oscillator_strength = (two/three)*omega*sum(dipole(:,2))
168✔
1339

1340
      call output%printf('m', 'Oscillator strength: (f0.7)', &
1341
                         reals=[oscillator_strength], fs='(t6,a)')
84✔
1342

1343
   end subroutine calculate_and_print_transition_dipole_wavefunction
42✔
1344

1345

1346
   subroutine calculate_and_print_quadrupole_wavefunction(wf, density)
72✔
1347
      !!
1348
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad,
1349
      !! Linda Goletto, and Alexander C. Paul, Apr 2019
1350
      !!
1351
      use array_utilities, only: remove_trace
1352

1353
      implicit none
1354

1355
      class(wavefunction), intent(inout) :: wf
1356

1357
      real(dp), dimension(:,:), intent(in) :: density
1358

1359
      real(dp), dimension(6, 3) :: quadrupole
1360
      character(len=5),  dimension(6) :: components
1361
      character(len=18), dimension(3) :: labels
1362

1363
      integer :: i
1364

1365
      call output%printf('m', 'Quadrupole moment [Debye*Ang]:', fs='(/t6,a)')
72✔
1366
      call output%print_separator('m', 33, '=', fs='(t6,a)')
72✔
1367

1368
      quadrupole(:,1) = wf%get_electronic_quadrupole(density) * au_to_debye*bohr_to_angstrom
1,008✔
1369

1370
      quadrupole(:,2) = wf%get_nuclear_quadrupole() * au_to_debye*bohr_to_angstrom
1,008✔
1371

1372
      quadrupole(:,3) = quadrupole(:,1) + quadrupole(:,2)
504✔
1373

1374
      call output%printf('m', 'Conversion factor from Debye*Ang to a.u.: (f11.9)', &
1375
                          reals=[one/(au_to_debye*bohr_to_angstrom)], fs='(/t6,a)')
72✔
1376

1377
      components = ['xx', 'xy', 'xz', 'yy', 'yz', 'zz']
504✔
1378
      labels = [character(len=18) :: 'Electronic', 'Nuclear', 'Total']
288✔
1379

1380
      call output%print_table("Comp.", components, labels, quadrupole, 6, 3)
72✔
1381

1382
      call remove_trace(quadrupole(:,1))
72✔
1383
      call remove_trace(quadrupole(:,2))
72✔
1384

1385
      do i = 1, 6
504✔
1386
         quadrupole(i,3) = quadrupole(i,1) + quadrupole(i,2)
504✔
1387
      end do
1388

1389
      call output%printf('m', 'The traceless quadrupole is calculated as:', fs='(/t6,a)')
72✔
1390
      call output%printf('m', 'Q_ij = 1/2 [3*q_ij - tr(q)*delta_ij]', fs='(t9,a)')
72✔
1391
      call output%printf('m', 'where q_ij are the non-traceless matrix elements.', fs='(t6,a)')
72✔
1392

1393
      call output%printf('m', 'Traceless quadrupole [Debye*Ang]', fs='(/t6,a)')
72✔
1394

1395
      call output%print_table("Comp.", components, labels, quadrupole, 6, 3)
72✔
1396

1397
   end subroutine calculate_and_print_quadrupole_wavefunction
72✔
1398

1399

1400
   subroutine calculate_and_print_transition_quadrupole_wavefunction(wf, density)
42✔
1401
      !!
1402
      !! Written by Matteo Rinaldi, June 2023
1403
      !! Modified by Matteo Castagnola, Feb 2025
1404
      !!
1405
      use array_utilities, only: remove_trace
1406

1407
      implicit none
1408

1409
      class(wavefunction), intent(inout) :: wf
1410

1411
      real(dp), dimension(:,:), intent(in) :: density
1412

1413
      real(dp), dimension(6,2) :: quadrupole
1414
      character(len=5),  dimension(6) :: components
1415
      character(len=10), dimension(2) :: labels
1416

1417
      call output%printf('m', 'Transition quadrupole moment [Debye*Ang]:', fs='(/t6,a)')
42✔
1418

1419
      quadrupole(:,1) = wf%get_electronic_transition_quadrupole(density) * au_to_debye*bohr_to_angstrom
588✔
1420
      quadrupole(:,2) = wf%get_electronic_transition_quadrupole(density) * au_to_debye*bohr_to_angstrom
588✔
1421
      call remove_trace(quadrupole(:,2))
42✔
1422

1423
      call output%printf('m', 'The traceless quadrupole moment is Q_rs = 1/2 [3*q_rs - tr(q)*delta_rs],', fs='(/t6,a)')
42✔
1424
      call output%printf('m', 'where q_rs = < n | rs | m > are the non-traceless matrix elements.', fs='(t6,a)')
42✔
1425

1426
      components = ['xx', 'xy', 'xz', 'yy', 'yz', 'zz']
294✔
1427
      labels = [character(len=10) :: 'q_rs', 'Q_rs']
126✔
1428

1429
      call output%print_table("Comp.", components, labels, quadrupole, 6, 2)
42✔
1430
      call output%printf('m', 'Conversion factor from Debye*Ang to a.u.: (f11.9)', &
1431
                          reals=[one/(au_to_debye*bohr_to_angstrom)], fs='(t6,a)')
42✔
1432

1433
   end subroutine calculate_and_print_transition_quadrupole_wavefunction
42✔
1434

1435

1436
   subroutine write_orbitals_wavefunction(wf, prefix)
18✔
1437
      !!
1438
      !! Written by Alexander C. Paul, July 2022
1439
      !!
1440
      !! prefix: string to identify which orbitals are printed
1441
      !!         determines filename and print in the file
1442
      !!
1443
      implicit none
1444

1445
      class(wavefunction), intent(in) :: wf
1446
      character(len=*), intent(in) :: prefix
1447

1448
      type(output_file) :: orbital_file
1449
      character(len=200) :: file_name
1450

1451
      file_name = "eT." // prefix // "_mo_information.out"
18✔
1452

1453
      orbital_file = output_file(trim(file_name))
18✔
1454
      call orbital_file%open_('rewind')
18✔
1455

1456
      call wf%write_orbitals_and_energies(orbital_file,  &
1457
                                          wf%orbital_energies,     &
1458
                                          wf%orbital_coefficients, &
1459
                                          prefix // ' molecular orbital')
18✔
1460

1461
      call orbital_file%close_()
18✔
1462

1463
   end subroutine write_orbitals_wavefunction
180✔
1464

1465

1466
   subroutine write_orbitals_and_energies_wavefunction(wf, mo_file, mo_energies, &
96✔
1467
                                                       mo_coefficients, prefix)
1468
      !!
1469
      !! Written by Eirik F. Kjønstad, Tor S. Haugland, Alexander C. Paul, 2019-2020
1470
      !!
1471
      !! Note: mo_file is expected to be open already
1472
      !!
1473
      implicit none
1474

1475
      class(wavefunction), intent(in) :: wf
1476

1477
      type(output_file), intent(inout) :: mo_file
1478
      real(dp), dimension(wf%n_mo), intent(in) :: mo_energies
1479
      real(dp), dimension(wf%ao%n, wf%n_mo), intent(in) :: mo_coefficients
1480

1481
      character(len=*), intent(in) :: prefix
1482
      character(len=200) :: header
1483

1484
      write(header, '(a,a)') trim(prefix), ' energies'
96✔
1485

1486
      call mo_file%print_vector('m', header, wf%n_mo, mo_energies, &
1487
                                 fn='(f20.12)', columns=3)
96✔
1488

1489
      write(header, '(a,a)') trim(prefix), ' coefficients'
96✔
1490
      call mo_file%printf('m', header, fs='(//t3,a)')
96✔
1491

1492
      call wf%write_orbital_coefficients(mo_file, mo_coefficients)
96✔
1493

1494
   end subroutine write_orbitals_and_energies_wavefunction
96✔
1495

1496

1497
   subroutine write_orbital_coefficients_wavefunction(wf, mo_file, orbital_coefficients)
96✔
1498
      !!
1499
      !! Written by Eirik F. Kjønstad, Tor S. Haugland, Alexander C. Paul, 2019-2020
1500
      !!
1501
      !! Prints the orbitals from coefficients with atom & orbital information given.
1502
      !!
1503
      !! Note: mo_file is expected to be open already
1504
      !!
1505
      implicit none
1506

1507
      class(wavefunction), intent(in) :: wf
1508
      type(output_file), intent(inout) :: mo_file
1509
      real(dp), dimension(wf%ao%n, wf%n_mo), intent(in) :: orbital_coefficients
1510

1511
      integer, parameter :: n_entries = 5
1512

1513
      integer :: mo_offset, first_mo, last_mo
1514

1515
      ! Print at most n_entries (5) MOs at a time
1516

1517
      do mo_offset = 1, wf%n_mo, n_entries
654✔
1518

1519
         first_mo = mo_offset
1520
         last_mo  = min(mo_offset + n_entries - 1, wf%n_mo)
558✔
1521

1522
         ! Print the current set of MO vectors
1523

1524
         call wf%ao%print_ao_vectors(C        = orbital_coefficients(:, first_mo : last_mo),&
1525
                                     out_file = mo_file, &
1526
                                     m        = last_mo - first_mo + 1, &
1527
                                     offset   = first_mo - 1)
654✔
1528

1529
      enddo
1530

1531
   end subroutine write_orbital_coefficients_wavefunction
96✔
1532

1533

1534
   subroutine get_orbital_spread_wavefunction(wf, C, sigma, n)
48✔
1535
      !!
1536
      !! Written by Sarai D. Folkestad, Nov 2021
1537
      !!
1538
      !! Calculates:
1539
      !!
1540
      !!    s_p^2 = sum_{k = x,y,z} (<phi_p|k^2|phi_p> - <phi_p|k|phi_p>^2 )
1541
      !!
1542
      use array_utilities, only: symmetric_sandwich
1543
      use array_initialization, only: zero_array
1544

1545
      implicit none
1546

1547
      class(wavefunction) :: wf
1548

1549
      integer, intent(in) :: n
1550
      real(dp), dimension(wf%ao%n, n), intent(in)  :: C
1551
      real(dp), dimension(n), intent(out)  :: sigma
1552

1553
      real(dp), dimension(:,:,:), allocatable :: mu_wxk, mu_pqk
48✔
1554
      real(dp), dimension(:,:,:), allocatable :: q_wxk, R_sq_pqk
48✔
1555

1556
      integer :: p, component
1557

1558
      call mem%alloc(mu_wxk, wf%ao%n, wf%ao%n, 3)
48✔
1559
      call wf%ao%get_oei('dipole', mu_wxk)
48✔
1560

1561
      ! <phi_p|k^2|phi_p> are the diagonal elements of the quadrupole operator
1562
      call mem%alloc(q_wxk, wf%ao%n, wf%ao%n, 6)
48✔
1563
      call wf%ao%get_oei('quadrupole', q_wxk)
48✔
1564

1565
      call mem%alloc(mu_pqk, n, n, 3)
48✔
1566

1567
      do component = 1, 3
192✔
1568

1569
         call symmetric_sandwich(mu_pqk(:,:,component), mu_wxk(:,:,component), C, wf%ao%n, n)
192✔
1570

1571
      enddo
1572

1573
      call mem%alloc(R_sq_pqk, n, n, 3)
48✔
1574

1575
      call symmetric_sandwich(R_sq_pqk(:,:,1), q_wxk(:,:,1), C, wf%ao%n, n)
48✔
1576
      call symmetric_sandwich(R_sq_pqk(:,:,2), q_wxk(:,:,4), C, wf%ao%n, n)
48✔
1577
      call symmetric_sandwich(R_sq_pqk(:,:,3), q_wxk(:,:,6), C, wf%ao%n, n)
48✔
1578

1579
      call mem%dealloc(q_wxk)
48✔
1580
      call mem%dealloc(mu_wxk)
48✔
1581

1582
      call dscal(n**2*3, -one, R_sq_pqk, 1) ! Sign convension, quadrupole defined as -xx, -xy, etc.
48✔
1583

1584
      call zero_array(sigma, n)
48✔
1585

1586
      !$omp parallel do private(p, component)
48✔
1587
      do p = 1, n
1588
         do component = 1, 3
1589

1590
            sigma(p) = sigma(p) + R_sq_pqk(p, p, component) - mu_pqk(p, p, component)**2
1591

1592
         enddo
1593

1594
         sigma(p) = sqrt(sigma(p))
1595

1596
      enddo
1597
      !$omp end parallel do
1598

1599
      call mem%dealloc(mu_pqk)
48✔
1600
      call mem%dealloc(R_sq_pqk)
48✔
1601

1602
   end subroutine get_orbital_spread_wavefunction
48✔
1603

1604

UNCOV
1605
   subroutine construct_molecular_gradient_wavefunction(wf, E_qk)
×
1606
      !!
1607
      !! Written by Marcus T. Lexander, 2022
1608
      !!
1609
      !! This is a blanket implementation that is only called if molecular gradients are
1610
      !! requested for methods where it is not implemented.
1611
      !! This routine should be overridden for methods implementing molecular gradients.
1612
      !!
1613
      use warning_suppressor, only: do_nothing
1614

1615
      implicit none
1616

1617
      class(wavefunction), intent(in) :: wf
1618
      real(dp), dimension(3, wf%n_atomic_centers), intent(out) :: E_qk
1619

UNCOV
1620
      call output%error_msg("Molecular gradients not implemented for wavefunction type " // wf%name_)
×
1621

UNCOV
1622
      call do_nothing(E_qk(1,1))
×
1623

UNCOV
1624
   end subroutine construct_molecular_gradient_wavefunction
×
1625

1626

1627
   subroutine calculate_and_print_molecular_gradient_wavefunction(wf)
14✔
1628
      !!
1629
      !! Written by Marcus T. Lexander, Nov 2022
1630
      !!
1631
      use atomic_center_class, only: atomic_center
1632

1633
      implicit none
1634

1635
      class(wavefunction), intent(in) :: wf
1636

1637
      real(dp), dimension(:,:), allocatable :: E_qk
14✔
1638

1639
      type(output_file) :: gradient_file
1640

1641
      type(atomic_center) :: center
14✔
1642

1643
      integer :: i
1644

1645
      call mem%alloc(E_qk, 3, wf%ao%n_centers)
14✔
1646
      call wf%construct_molecular_gradient(E_qk)
14✔
1647

1648
      gradient_file = output_file('eT.molecular_gradient.out')
14✔
1649
      call gradient_file%open_('rewind')
14✔
1650

1651
      call gradient_file%printf('m', '- Molecular gradient (Hartree/bohr)', fs='(/t3,a)')
14✔
1652

1653
      call gradient_file%printf('m', '     Center                 x                y                z', fs='(/t3,a)')
14✔
1654

1655
      call gradient_file%print_separator(pl='m', n=70, symbol='-')
14✔
1656

1657
      do i = 1, wf%ao%n_centers
70✔
1658

1659
         call wf%ao%get_center(i, center)
56✔
1660

1661
         call gradient_file%printf('m', '  (i4) (b4)       3(f17.12)', &
1662
                                   chars=[center%symbol], ints=[i], reals=[E_qk(:,i)])
518✔
1663

1664
      end do
1665

1666
      call gradient_file%print_separator(pl='m', n=70, symbol='-')
14✔
1667

1668
      call gradient_file%close_()
14✔
1669

1670
      call mem%dealloc(E_qk)
14✔
1671

1672
   end subroutine calculate_and_print_molecular_gradient_wavefunction
44✔
1673

1674

1675
   subroutine transform_one_electron_state_to_ao(wf, mo_orbital, ao_orbital)
12✔
1676
      !!
1677
      !! Written by Alexander C. Paul, Dec 2020
1678
      !!
1679
      !! Transforms an one-electron state expressed in MO basis to AO basis
1680
      !!
1681
      implicit none
1682

1683
      class(wavefunction), intent(in) :: wf
1684

1685
      real(dp), dimension(wf%n_mo), intent(in)  :: mo_orbital
1686
      real(dp), dimension(wf%ao%n), intent(out) :: ao_orbital
1687

1688
      call dgemv('N',                      &
1689
                  wf%ao%n,                 &
1690
                  wf%n_mo,                 &
1691
                  one,                     &
1692
                  wf%orbital_coefficients, &
1693
                  wf%ao%n,                 &
1694
                  mo_orbital, 1,           &
1695
                  zero,                    &
1696
                  ao_orbital, 1)
12✔
1697

1698
   end subroutine transform_one_electron_state_to_ao
12✔
1699

1700

1701
   subroutine save_geometry_to_xyz_wavefunction(wf, file_)
158✔
1702
      !!
1703
      !! Written by Eirik F. Kjønstad, 2023
1704
      !!
1705
      implicit none
1706

1707
      class(wavefunction) :: wf
1708

1709
      class(output_file) :: file_
1710

1711
      call wf%ao%save_geometry_to_xyz(file_)
158✔
1712

1713
   end subroutine save_geometry_to_xyz_wavefunction
158✔
1714

1715

UNCOV
1716
end module wavefunction_class
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc