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

eT-program / eT / 22348

02 Mar 2025 10:34PM UTC coverage: 88.485%. Remained the same
22348

push

gitlab-ci

Merge branch 'es_variational_energy' into 'development'

Variational eom excitation energies

See merge request eT-program/eT!1539

28 of 29 new or added lines in 3 files covered. (96.55%)

89 existing lines in 2 files now uncovered.

53577 of 60549 relevant lines covered (88.49%)

3038231.45 hits per line

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

91.0
/src/io/input/input_tool_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 input_tool_class
21

22
   !!
23
   !! Input tool class module
24
   !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
25
   !!
26

27
   use kinds
28
   use section_class, only: section
29
   use global_out,    only: output
30

31
   use string_utilities, only: string_starts_with, first_index_of_substring
32
   use string_utilities, only: is_substring_in_string, is_empty, remove_substring_after_symbol
33

34

35
   type :: input_tool
36

37
      type(section),     allocatable, dimension(:), private :: sections
38

39
      character(len=30), allocatable, dimension(:), private :: rf_wfs
40
      character(len=30), allocatable, dimension(:), private :: cc_wfs
41
      character(len=30), allocatable, dimension(:), private :: ci_wfs
42

43
      integer, private :: n_keyword_lines ! Number of lines excluding the geometry section
44
      integer, private :: n_qm_atom_lines ! Number of QM atoms
45
      integer, private :: n_mm_atom_lines ! Number of MM atoms
46

47
      ! Arrays storing lines in the input
48
      character(len=200), dimension(:), allocatable, private :: keyword_lines
49
      character(len=200), dimension(:), allocatable, private :: qm_geometry
50
      character(len=200), dimension(:), allocatable, private :: mm_geometry
51

52
   contains
53

54
      procedure, public :: read_input
55
      procedure, public :: set_input
56
      procedure, public :: process_input
57

58
      procedure, private :: print_input_except_geometry
59

60
      procedure, public :: get_n_atoms &
61
                        => get_n_atoms_input_tool
62

63
      procedure, public :: get_n_mm_atoms &
64
                        => get_n_mm_atoms_input_tool
65

66
      procedure, public :: get_n_mm_molecules &
67
                        => get_n_mm_molecules_input_tool
68

69
      procedure, public :: get_geometry &
70
                        => get_geometry_input_tool
71

72
      procedure, public :: get_mm_geometry_fq &
73
                        => get_mm_geometry_fq_input_tool
74

75
      procedure, public :: get_mm_geometry_non_polarizable &
76
                        => get_mm_geometry_non_polarizable_input_tool
77

78
      procedure, public :: get_reference_wavefunction
79
      procedure, public :: get_cc_wavefunction
80
      procedure, public :: get_ci_wavefunction
81

82
      procedure, public :: requested_reference_calculation
83
      procedure, public :: requested_cc_calculation
84
      procedure, public :: requested_ci_calculation
85

86
      generic, public :: get_keyword                &
87
                      => get_32bit_integer_keyword, &
88
                         get_64bit_integer_keyword, &
89
                         get_string_keyword,        &
90
                         get_real_dp_keyword
91

92
      generic, public :: get_required_keyword                 &
93
                      => get_required_string_keyword,         &
94
                         get_required_32bit_integer_keyword,  &
95
                         get_required_64bit_integer_keyword,  &
96
                         get_required_real_dp_keyword
97

98
      procedure, public :: get_n_elements_for_keyword
99

100
      generic, public :: get_array_for_keyword          &
101
                      => get_integer_array_for_keyword, &
102
                         get_real_array_for_keyword,    &
103
                         get_string_array_for_keyword
104

105
      procedure, public :: string_in_array_keyword   => string_in_array_keyword
106

107
      procedure, public :: cleanup &
108
                        => cleanup_input_tool
109

110
      procedure, public :: is_section_present &
111
                        => is_section_present_input_tool
112

113
      procedure, public :: is_keyword_present &
114
                        => is_keyword_present_input_tool
115

116
      procedure, public :: is_embedding_on &
117
                        => is_embedding_on_input_tool
118

119
      procedure, public :: place_records_in_memory &
120
                        => place_records_in_memory_input_tool
121

122
      procedure, public :: get_n_state_guesses
123
      procedure, public :: get_state_guesses
124

125
      procedure, private :: process_keyword_lines
126
      procedure, private :: set_section_keywords
127
      procedure, private :: check_for_errors
128

129
      procedure, private :: get_wavefunction
130
      procedure, private :: requested_calculation
131

132
      procedure, private :: get_section_index
133
      procedure, private :: print_sections
134

135
      procedure, private :: get_32bit_integer_keyword
136
      procedure, private :: get_64bit_integer_keyword
137
      procedure, private :: get_string_keyword
138
      procedure, private :: get_real_dp_keyword
139
      procedure, private :: get_required_string_keyword
140
      procedure, private :: get_required_32bit_integer_keyword
141
      procedure, private :: get_required_64bit_integer_keyword
142
      procedure, private :: get_required_real_dp_keyword
143

144
      procedure, private :: get_n_elements_in_set_or_range
145
      procedure, private :: get_integers_from_set_or_range
146

147
      procedure, private :: get_integer_array_for_keyword
148
      procedure, private :: get_real_array_for_keyword
149
      procedure, private :: get_string_array_for_keyword
150

151
      procedure, private, nopass :: expect_range
152
      procedure, private, nopass :: expect_set
153
      procedure, private, nopass :: check_get_array_for_keyword
154

155
      procedure, private :: is_section_recognized
156
      procedure, private :: section_not_recognized
157

158
   end type input_tool
159

160
   interface input_tool
161

162
      procedure :: new_input_tool
163

164
   end interface input_tool
165

166

167
contains
168

169

170
   function new_input_tool() result(this)
3,169✔
171
      !!
172
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, June 2018
173
      !!
174
      implicit none
175

176
      type(input_tool) :: this
177

178
      type(section) :: active_atoms
179
      type(section) :: active_space
180
      type(section) :: boson
181
      type(section) :: calculations
182
      type(section) :: cc_mean_value
183
      type(section) :: cc_response
184
      type(section) :: cc_real_time
185
      type(section) :: ci_mean_value
186
      type(section) :: ci_transition_property
187
      type(section) :: dft_functional
188
      type(section) :: electric_field
189
      type(section) :: grid_info
190
      type(section) :: harmonic_frequencies
191
      type(section) :: hf_mean_value
192
      type(section) :: hf_response
193
      type(section) :: integrals
194
      type(section) :: lanczos
195
      type(section) :: memory
196
      type(section) :: method
197
      type(section) :: mlcc
198
      type(section) :: mlhf
199
      type(section) :: mm
200
      type(section) :: orbital_localization
201
      type(section) :: pcm
202
      type(section) :: print_
203
      type(section) :: solver_cc_es
204
      type(section) :: solver_cc_gs
205
      type(section) :: solver_cc_multipliers
206
      type(section) :: solver_cc_propagation
207
      type(section) :: solver_cc_response
208
      type(section) :: solver_cholesky
209
      type(section) :: solver_ci
210
      type(section) :: solver_cpp
211
      type(section) :: solver_fft_dipole_moment
212
      type(section) :: solver_fft_electric_field
213
      type(section) :: solver_geoopt
214
      type(section) :: solver_scf
215
      type(section) :: solver_hf_es
216
      type(section) :: solver_hf_response
217
      type(section) :: system
218
      type(section) :: visualization
219

220
      allocate(this%rf_wfs, source=[character(len=30) :: &
221
                                       'dft',            &
222
                                       'hf',             &
223
                                       'uhf',            &
224
                                       'mlhf',           &
225
                                       'qed-hf',         &
226
                                       'sc-qed-hf',      &
227
                                       'cuhf',           &
228
                                       'rohf'])
53,873✔
229

230
      allocate(this%cc_wfs, source=[character(len=30) :: &
231
                                       'ccs',            &
232
                                       'mp2',            &
233
                                       'cc2',            &
234
                                       'lowmem-cc2',     &
235
                                       'ccsd',           &
236
                                       'cc3',            &
237
                                       'ccsd(t)',        &
238
                                       'ccsdt',          &
239
                                       'mlcc2',          &
240
                                       'mlccsd',         &
241
                                       'qed-ccsd'])
72,887✔
242

243
      allocate(this%ci_wfs, source=[character(len=30) :: 'casci',     &
244
                                                         'fci',       &
245
                                                         'qed-fci'])
22,183✔
246

247
      method = section(name_            = 'method', &
248
                       required         = .false.,  &
249
                       allowed_keywords = [this%rf_wfs, this%cc_wfs, this%ci_wfs])
142,605✔
250

251
      ! Set other sections in alphabetical order
252

253
      active_atoms = section(name_            = 'active atoms',       &
254
                             required         = .false.,              &
255
                             allowed_keywords = [character(len=30) :: &
256
                                                 'selection type',    &
257
                                                 'central atom',      &
258
                                                 'hf',                &
259
                                                 'ccs',               &
260
                                                 'cc2',               &
261
                                                 'ccsd',              &
262
                                                 'cc3',               &
263
                                                 'ccsd(t)',           &
264
                                                 'inactive basis',    &
265
                                                 'hf basis',          &
266
                                                 'ccs basis',         &
267
                                                 'cc2 basis',         &
268
                                                 'ccsd basis',        &
269
                                                 'cc3 basis',         &
270
                                                 'ccsd(t) basis'])
50,704✔
271

272

273
      active_space = section(name_            = 'active space',         &
274
                             required         = .false.,                &
275
                             allowed_keywords = [character(len=30) ::   &
276
                                                 'canonical',           &
277
                                                 'freeze core',         &
278
                                                 'freeze atom cores',   &
279
                                                 'localized'])
15,845✔
280

281

282
      boson = section(name_            = 'boson',                         &
283
                      required         = .false.,                         &
284
                      allowed_keywords = [character(len=30) ::            &
285
                                         'boson number',                  &
286
                                         'boson states',                  &
287
                                         'cbo',                           &
288
                                         'coherent state',                &
289
                                         'coupling bilinear',             &
290
                                         'coupling self',                 &
291
                                         'coupling',                      &
292
                                         'frequency',                     &
293
                                         'interaction type',              &
294
                                         'modes',                         &
295
                                         'polarization',                  &
296
                                         'print dipole eri construction', &
297
                                         'quadrupole oei',                &
298
                                         'wavevector'])
47,535✔
299

300

301
      calculations = section(name_            = 'do',                      &
302
                             required         = .false.,                   &
303
                             allowed_keywords = [character(len=30) ::      &
304
                                                'cholesky eri',            &
305
                                                'ground state',            &
306
                                                'geometry optimization',   &
307
                                                'harmonic frequencies',    &
308
                                                'excited state',           &
309
                                                'response',                &
310
                                                'mean value',              &
311
                                                'real time',               &
312
                                                'restart'])
31,690✔
313

314

315
      cc_mean_value = section(name_            = 'cc mean value',           &
316
                              required         = .false.,                   &
317
                              allowed_keywords = [character(len=30) ::      &
318
                                                 'dipole',                  &
319
                                                 'quadrupole',              &
320
                                                 'molecular gradient'])
12,676✔
321

322

323
      cc_response = section(name_            = 'cc response',         &
324
                            required         = .false.,               &
325
                            allowed_keywords = [character(len=30) ::  &
326
                                               'asymmetric',          &
327
                                               'damping',             &
328
                                               'dipole length',       &
329
                                               'dipole velocity',     &
330
                                               'dyson orbitals',      &
331
                                               'eom',                 &
332
                                               'frequencies',         &
333
                                               'initial states',      &
334
                                               'lr',                  &
335
                                               'permanent moments',   &
336
                                               'polarizabilities',    &
337
                                               'response components', &
338
                                               'rotatory strength',   &
339
                                               'variational energy',  &
340
                                               'transition moments',  &
341
                                               'full-space transition moments'])
53,873✔
342

343

344
      cc_real_time = section(name_            = 'cc real time',       &
345
                             required         = .false.,              &
346
                             allowed_keywords = [character(len=30) :: &
347
                                                'propagation',        &
348
                                                'fft dipole moment',  &
349
                                                'fft electric field'])
12,676✔
350

351

352
      ci_mean_value = section(name_            = 'ci mean value',     &
353
                              required         = .false.,             &
354
                              allowed_keywords = [character(len=30) ::&
355
                                                 'dipole',            &
356
                                                 'quadrupole'])
9,507✔
357

358

359
      ci_transition_property = section(name_            = 'ci transition property',  &
360
                                       required         = .false.,                   &
361
                                       allowed_keywords = [character(len=30) ::      &
362
                                                          'dipole',                  &
363
                                                          'quadrupole',              &
364
                                                          'final states',            &
365
                                                          'initial states'])
15,845✔
366

367

368
      dft_functional = section(name_            = 'dft functional',     &
369
                               required         = .false.,              &
370
                               allowed_keywords = [character(len=30) :: &
371
                                                  'correlation',        &
372
                                                  'exchange',           &
373
                                                  'functional',         &
374
                                                  'hf percentage'])
15,845✔
375

376

377
      electric_field = section(name_            = 'electric field',             &
378
                               required         = .false.,                      &
379
                               allowed_keywords = [character(len=30) ::         &
380
                                                  'envelope',                   &
381
                                                  'x polarization',             &
382
                                                  'y polarization',             &
383
                                                  'z polarization',             &
384
                                                  'central time',               &
385
                                                  'width',                      &
386
                                                  'carrier angular frequency',  &
387
                                                  'peak strength',              &
388
                                                  'phase shift',                &
389
                                                  'repetition',                 &
390
                                                  'separation'])
38,028✔
391

392

393
      harmonic_frequencies = section(name_            = 'harmonic frequencies',      &
394
                                     required         = .false.,                     &
395
                                     allowed_keywords = [character(len=30) ::        &
396
                                                        'gradient displacement',     &
397
                                                        'gradient method',           &
398
                                                        'hessian displacement',      &
399
                                                        'run geometry optimization', &
400
                                                        'state',                     &
401
                                                        'wigner samples',            &
402
                                                        'wigner seed'])
25,352✔
403

404

405
      grid_info = section(name_            = 'grid info',             &
406
                          required         = .false.,                 &
407
                          allowed_keywords = [character(len=30) ::    &
408
                                             'cube side',             &
409
                                             'cube offset',           &
410
                                             'minimum angular order', &
411
                                             'maximum angular order', &
412
                                             'partitioning',          &
413
                                             'radial threshold',      &
414
                                             'quadrature'])
25,352✔
415

416

417
      hf_mean_value = section(name_            = 'hf mean value',      &
418
                              required         = .false.,              &
419
                              allowed_keywords = [character(len=30) :: &
420
                                                 'dipole',             &
421
                                                 'molecular gradient', &
422
                                                 'quadrupole'])
12,676✔
423

424
      hf_response = section(name_            = 'hf response',        &
425
                            required         = .false.,              &
426
                            allowed_keywords = [character(len=30) :: &
427
                                              'shielding', &
428
                                              'polarizabilities'])
9,507✔
429

430

431
      integrals = section(name_            = 'integrals',          &
432
                          required         = .false.,              &
433
                          allowed_keywords = [character(len=30) :: &
434
                                             'cholesky storage',   &
435
                                             'eri storage',        &
436
                                             'mo eri in memory',   &
437
                                             'ri',                 &
438
                                             't1 eri in memory'])
19,014✔
439

440

441
      lanczos = section(name_            = 'lanczos',                &
442
                        required         = .false.,                  &
443
                        allowed_keywords = [character(len=30) ::     &
444
                                           'biorthogonalize last',   &
445
                                           'chain length',           &
446
                                           'deflation threshold',    &
447
                                           'lanczos normalization',  &
448
                                           'max energy',             &
449
                                           'min energy',             &
450
                                           'min transition strength',&
451
                                           'operators',              &
452
                                           'overlap threshold',      &
453
                                           'restart states',         &
454
                                           'skip convergence'])
38,028✔
455

456

457
      memory = section(name_            = 'memory',             &
458
                       required         = .false.,              &
459
                       allowed_keywords = [character(len=30) :: &
460
                                          'available',          &
461
                                          'unit'])
9,507✔
462

463

464
      mlcc = section(name_            = 'mlcc',                   &
465
                     required         = .false.,                  &
466
                     allowed_keywords = [character(len=30) ::     &
467
                                        'levels',                 &
468
                                        'cc2 orbitals',           &
469
                                        'ccsd orbitals',          &
470
                                        'cholesky threshold',     &
471
                                        'nto restart',            &
472
                                        'cnto restart',           &
473
                                        'orbital restart',        &
474
                                        'cnto occupied cc2',      &
475
                                        'cnto virtual cc2',       &
476
                                        'cnto occupied ccsd',     &
477
                                        'cnto virtual ccsd',      &
478
                                        'cnto states',            &
479
                                        'nto states',             &
480
                                        'nto occupied cc2',       &
481
                                        'nto occupied ccsd',      &
482
                                        'canonical virtual cc2',  &
483
                                        'canonical virtual ccsd', &
484
                                        'print ccs calculation',  &
485
                                        'print cc2 calculation'])
63,380✔
486

487

488
      mlhf = section(name_            = 'multilevel hf',            &
489
                     required         = .false.,                    &
490
                     allowed_keywords = [character(len=30) ::       &
491
                                        'initial hf optimization',  &
492
                                        'initial hf threshold',     &
493
                                        'print initial hf',         &
494
                                        'cholesky threshold',       &
495
                                        'project on minimal basis', &
496
                                        'cholesky virtuals',        &
497
                                        'no mo screening'])
25,352✔
498

499

500
      mm = section(name_            = 'molecular mechanics', &
501
                   required         = .false.,               &
502
                   allowed_keywords = [character(len=30) ::  &
503
                                      'forcefield',          &
504
                                      'algorithm '])
9,507✔
505

506

507
      orbital_localization = section(name_            = 'orbital localization', &
508
                                     required         = .false.,                &
509
                                     allowed_keywords = [character(len=30) ::   &
510
                                                         'orbitals',            &
511
                                                         'threshold',           &
512
                                                         'type'])
12,676✔
513

514

515
      pcm = section(name_            = 'pcm',                &
516
                    required         = .false.,              &
517
                    allowed_keywords = [character(len=30) :: &
518
                                       'solvent',            &
519
                                       'input',              &
520
                                       'tesserae area',      &
521
                                       'solver type'])
15,845✔
522

523

524
      print_ = section(name_            = 'print',               &
525
                       required         = .false.,               &
526
                       allowed_keywords = [character(len=30) ::  &
527
                                          'output print level ', &
528
                                          'timing print level ', &
529
                                          'full references',     &
530
                                          'z-matrix'])
15,845✔
531

532

533
      solver_cpp = section(name_    = 'solver cpp',                    &
534
                           required = .false.,                         &
535
                           allowed_keywords = [character(len=30) ::    &
536
                                              'max iterations',        &
537
                                              'max reduced dimension', &
538
                                              'residual minimization', &
539
                                              'residual threshold',    &
540
                                              'restart',               &
541
                                              'storage'])
22,183✔
542

543

544
      solver_cc_es = section(name_            = 'solver cc es',          &
545
                             required         = .false.,                 &
546
                             allowed_keywords = [character(len=30) ::    &
547
                                                'algorithm',             &
548
                                                'olsen',                 &
549
                                                'core excitation',       &
550
                                                'electron attachment',   &
551
                                                'ionization',            &
552
                                                'energy threshold ',     &
553
                                                'crop',                  &
554
                                                'residual threshold',    &
555
                                                'max iterations',        &
556
                                                'restart',               &
557
                                                'left eigenvectors',     &
558
                                                'right eigenvectors',    &
559
                                                'storage',               &
560
                                                'singlet states',        &
561
                                                'triplet states',        &
562
                                                'diis dimension',        &
563
                                                'max reduced dimension', &
564
                                                'max micro iterations',  &
565
                                                'rel micro threshold',   &
566
                                                'remove core',           &
567
                                                'state guesses'])
69,718✔
568

569

570
      solver_cc_gs = section(name_            = 'solver cc gs',            &
571
                             required         = .false.,                   &
572
                             allowed_keywords = [character(len=30) ::      &
573
                                                'algorithm',               &
574
                                                'energy threshold',        &
575
                                                'residual threshold',      &
576
                                                'crop',                    &
577
                                                'micro iteration storage', &
578
                                                'max micro iterations',    &
579
                                                'multimodel newton',       &
580
                                                'rel micro threshold',     &
581
                                                'storage',                 &
582
                                                'max iterations',          &
583
                                                'diis dimension',          &
584
                                                'restart' ])
41,197✔
585

586

587
      solver_cc_multipliers = section(name_            = 'solver cc multipliers',   &
588
                                      required         = .false.,                   &
589
                                      allowed_keywords = [character(len=30) ::      &
590
                                                         'algorithm',               &
591
                                                         'threshold',               &
592
                                                         'storage',                 &
593
                                                         'crop',                    &
594
                                                         'micro iteration storage', &
595
                                                         'max micro iterations',    &
596
                                                         'multimodel newton',       &
597
                                                         'rel micro threshold',     &
598
                                                         'diis dimension',          &
599
                                                         'restart',                 &
600
                                                         'max reduced dimension',   &
601
                                                         'max iterations'])
41,197✔
602

603

604
      solver_cc_propagation = section(name_            = 'solver cc propagation',    &
605
                                      required         = .false.,                    &
606
                                      allowed_keywords = [character(len=30) ::       &
607
                                                         'initial time',             &
608
                                                         'final time',               &
609
                                                         'time step',                &
610
                                                         'steps between output',     &
611
                                                         'step reduction factor',    &
612
                                                         'implicit threshold',       &
613
                                                         'max error',                &
614
                                                         'min error',                &
615
                                                         'energy output',            &
616
                                                         'dipole moment output',     &
617
                                                         'electric field output',    &
618
                                                         'parameters output',        &
619
                                                         'mo density matrix output', &
620
                                                         'method',                   &
621
                                                         'integrator'])
50,704✔
622

623

624
      solver_cc_response = section(name_            = 'solver cc response', &
625
                                   required         = .false.,              &
626
                                   allowed_keywords = [character(len=30) :: &
627
                                                      'threshold',          &
628
                                                      'gradient response threshold', &
629
                                                      'storage',            &
630
                                                      'max iterations'])
15,845✔
631

632

633
      solver_cholesky = section(name_            = 'solver cholesky',    &
634
                                required         = .false.,              &
635
                                allowed_keywords = [character(len=30) :: &
636
                                                   'threshold',          &
637
                                                   'span',               &
638
                                                   'batches',            &
639
                                                   'qualified',          &
640
                                                   'one center',         &
641
                                                   'diagonal test',      &
642
                                                   'mo screening'])
25,352✔
643

644

645
      solver_ci = section(name_            = 'solver ci',              &
646
                          required         = .false.,                  &
647
                          allowed_keywords = [character(len=30) ::     &
648
                                              'energy threshold ',     &
649
                                              'max iterations',        &
650
                                              'max reduced dimension', &
651
                                              'residual threshold',    &
652
                                              'restart',               &
653
                                              'start guess',           &
654
                                              'states',                &
655
                                              'storage'])
28,521✔
656

657
      solver_fft_dipole_moment = section(name_            = 'solver fft dipole moment', &
658
                                         required         = .false.,                    &
659
                                         allowed_keywords = [character(len=30) ::       &
660
                                                            'initial time',             &
661
                                                            'final time',               &
662
                                                            'time step',                &
663
                                                            'padding initial time',     &
664
                                                            'hann window',              &
665
                                                            'rectangular window'])
22,183✔
666

667

668
      solver_fft_electric_field = section(name_            = 'solver fft electric field', &
669
                                          required         = .false.,                     &
670
                                          allowed_keywords = [character(len=30) ::        &
671
                                                             'initial time',              &
672
                                                             'final time',                &
673
                                                             'time step',                 &
674
                                                             'padding initial time',      &
675
                                                             'hann window',               &
676
                                                             'rectangular window'])
22,183✔
677

678

679
      solver_geoopt = section(name_            = 'solver geometry optimization',              &
680
                              required         = .false.,                      &
681
                              allowed_keywords = [character(len=30) ::         &
682
                                                 'algorithm',                  &
683
                                                 'energy threshold',           &
684
                                                 'residual threshold',         &
685
                                                 'residual rms threshold',     &
686
                                                 'state',                      &
687
                                                 'max iterations',             &
688
                                                 'max step',                   &
689
                                                 'gradient method',            &
690
                                                 'restart',                    &
691
                                                 'step size',                  &
692
                                                 'displacement threshold',     &
693
                                                 'displacement rms threshold'])
41,197✔
694

695

696
      solver_scf = section(name_            = 'solver scf',                  &
697
                           required         = .false.,                       &
698
                           allowed_keywords = [character(len=30) ::          &
699
                                              'algorithm',                   &
700
                                              'ao density guess',            &
701
                                              'coulomb exchange terms',      &
702
                                              'coulomb threshold',           &
703
                                              'crop',                        &
704
                                              'cumulative fock threshold',   &
705
                                              'diis dimension',              &
706
                                              'diabatize orbitals',          &
707
                                              'energy threshold',            &
708
                                              'exchange threshold',          &
709
                                              'residual threshold',          &
710
                                              'gradient response threshold', &
711
                                              'max iterations',              &
712
                                              'population analysis',         &
713
                                              'write orbitals',              &
714
                                              'restart',                     &
715
                                              'rohf coupling parameters',    &
716
                                              'skip',                        &
717
                                              'storage',                     &
718
                                              'write molden'])
66,549✔
719

720

721
      solver_hf_es = section(name_            = 'solver hf es',         &
722
                               required         = .false.,                  &
723
                               allowed_keywords = [character(len=30) ::     &
724
                                                  'energy threshold',       &
725
                                                  'max iterations',         &
726
                                                  'max reduced dimension',  &
727
                                                  'residual threshold',     &
728
                                                  'restart',                &
729
                                                  'storage',                &
730
                                                  'singlet states',         &
731
                                                  'tamm-dancoff'])
28,521✔
732

733

734
      solver_hf_response = section(name_           = 'solver hf response',       &
735
                                  required         = .false.,                    &
736
                                  allowed_keywords = [character(len=30) ::       &
737
                                                        'frequencies',           &
738
                                                        'max iterations',        &
739
                                                        'max reduced dimension', &
740
                                                        'print iterations',      &
741
                                                        'residual threshold',    &
742
                                                        'restart',               &
743
                                                        'storage'])
25,352✔
744

745

746
      system = section(name_            = 'system',               &
747
                       required         = .false.,                &
748
                       allowed_keywords = [character(len=30) ::   &
749
                                          'cartesian gaussians',  &
750
                                          'write orbitals',       &
751
                                          'pure gaussians',       &
752
                                          'charge',               &
753
                                          'multiplicity'])
19,014✔
754

755

756
      visualization = section(name_            = 'visualization',             &
757
                              required         = .false.,                     &
758
                              allowed_keywords = [character(len=30) ::        &
759
                                                 'file format',               &
760
                                                 'grid spacing',              &
761
                                                 'grid buffer',               &
762
                                                 'grid min',                  &
763
                                                 'grid max',                  &
764
                                                 'plot cc density',           &
765
                                                 'plot cc orbitals',          &
766
                                                 'plot dyson orbitals',       &
767
                                                 'plot es densities',         &
768
                                                 'plot hf orbitals',          &
769
                                                 'plot hf density',           &
770
                                                 'plot hf active density',    &
771
                                                 'plot cntos',                &
772
                                                 'plot ntos',                 &
773
                                                 'nto threshold',             &
774
                                                 'plot transition densities', &
775
                                                 'states to plot'])
57,042✔
776

777
      ! Gather all sections into the file's section array
778

779
      this%sections = [active_atoms,              &
780
                       active_space,              &
781
                       boson,                     &
782
                       calculations,              &
783
                       cc_mean_value,             &
784
                       cc_response,               &
785
                       cc_real_time,              &
786
                       ci_mean_value,             &
787
                       ci_transition_property,    &
788
                       dft_functional,            &
789
                       electric_field,            &
790
                       grid_info,                 &
791
                       harmonic_frequencies,      &
792
                       hf_mean_value,             &
793
                       hf_response,               &
794
                       integrals,                 &
795
                       lanczos,                   &
796
                       memory,                    &
797
                       method,                    &
798
                       mlcc,                      &
799
                       mlhf,                      &
800
                       mm,                        &
801
                       orbital_localization,      &
802
                       pcm,                       &
803
                       print_,                    &
804
                       solver_cc_es,              &
805
                       solver_cc_gs,              &
806
                       solver_cc_multipliers,     &
807
                       solver_cc_propagation,     &
808
                       solver_cc_response,        &
809
                       solver_cholesky,           &
810
                       solver_ci,                 &
811
                       solver_cpp,                &
812
                       solver_fft_dipole_moment,  &
813
                       solver_fft_electric_field, &
814
                       solver_geoopt,             &
815
                       solver_scf,                &
816
                       solver_hf_es,            &
817
                       solver_hf_response,      &
818
                       system,                    &
819
                       visualization]
266,196✔
820

821
   end function new_input_tool
3,169✔
822

823

824
   subroutine read_input(this, file_name)
3,157✔
825
      !!
826
      !! Written by Eirik F. Kjønstad, May 2022
827
      !!
828
      use input_file_parser_class, only: input_file_parser
829

830
      implicit none
831

832
      class(input_tool), intent(inout) :: this
833

834
      character(len=*), intent(in) :: file_name
835

836
      type(input_file_parser), allocatable :: file_parser
837

838
      file_parser = input_file_parser(file_name)
3,157✔
839

840
      call file_parser%read_and_process_input_file()
3,157✔
841
      call file_parser%get_keyword_lines(this%keyword_lines, this%n_keyword_lines)
3,157✔
842
      call file_parser%get_qm_geometry_lines(this%qm_geometry, this%n_qm_atom_lines)
3,157✔
843

844
      if (file_parser%is_mm_geometry_present()) &
3,157✔
845
         call file_parser%get_mm_geometry_lines(this%mm_geometry, this%n_mm_atom_lines)
96✔
846

847
      deallocate(file_parser)
3,157✔
848

849
   end subroutine read_input
3,157✔
850

851

852
   subroutine process_input(this)
3,169✔
853
      !!
854
      !! Written by Eirik F. Kjønstad, Mar 2024
855
      !!
856
      implicit none
857

858
      class(input_tool), intent(inout) :: this
859

860
      call this%process_keyword_lines()
3,169✔
861
      call this%print_input_except_geometry()
3,169✔
862
      call this%check_for_errors()
3,169✔
863

864
   end subroutine process_input
3,169✔
865

866

867
   subroutine print_input_except_geometry(this)
3,169✔
868
      !!
869
      !! Written by Eirik F. Kjønstad, May 2022
870
      !!
871
      implicit none
872

873
      class(input_tool), intent(in) :: this
874

875
      integer :: n
876

877
      call output%printf('m', ':: Input file', fs='(//t3,a)')
3,169✔
878
      call output%print_separator('m', 13, '=', fs='(t3,a/)')
3,169✔
879

880
      call output%printf('m', 'Note: geometry section is excluded from this print.', fs='(t6,a/)')
3,169✔
881

882
      do n = 1, this%n_keyword_lines
105,263✔
883

884
         call output%printf('m', this%keyword_lines(n), fs='(t6,a)', ll=120)
105,263✔
885

886
      enddo
887

888
   end subroutine print_input_except_geometry
3,169✔
889

890

891
   subroutine set_input(this, keywords, geometry, mm_geometry)
12✔
892
      !!
893
      !! Written by Eirik F. Kjønstad, Mar 2024
894
      !!
895
      implicit none
896

897
      class(input_tool) :: this
898

899
      character(len=200), dimension(:), intent(in), optional :: keywords
900
      character(len=200), dimension(:), intent(in), optional :: geometry
901
      character(len=200), dimension(:), intent(in), optional :: mm_geometry
902

903
      if (present(geometry)) then
12✔
904

905
         this%qm_geometry = geometry
30✔
906
         this%n_qm_atom_lines = size(geometry)
6✔
907

908
      else
909

UNCOV
910
         allocate(this%qm_geometry, &
×
911
                  source=[character(len=200) :: '! no geometry'])
18✔
912

913
         this%n_qm_atom_lines = 1
6✔
914

915
      endif
916

917
      if (present(keywords)) then
12✔
918

919
         this%keyword_lines = keywords
24✔
920
         this%n_keyword_lines = size(keywords)
6✔
921

922
      else
923

UNCOV
924
         allocate(this%keyword_lines, &
×
925
                  source=[character(len=200) :: '! no input keywords'])
18✔
926

927
         this%n_keyword_lines = 1
6✔
928

929
      endif
930

931
      if (present(mm_geometry)) then
12✔
932

UNCOV
933
         this%mm_geometry = mm_geometry
×
934
         this%n_mm_atom_lines = size(mm_geometry)
×
935

936
      endif
937

938
   end subroutine set_input
12✔
939

940

941
   subroutine process_keyword_lines(this)
3,169✔
942
      !!
943
      !! Written by Sara Angelico and Alexander C. Paul, 2023
944
      !!
945
      implicit none
946

947
      class(input_tool), intent(inout) :: this
948

949
      integer :: start_, end_, i, j
950

951
      character(len=200) :: section, line, section_line
952

953
      do i = 1, this%n_keyword_lines
105,263✔
954

955
         line = trim(adjustl(this%keyword_lines(i)))
102,094✔
956

957
         if (.not. string_starts_with(line, '-')) cycle
102,094✔
958

959
         start_ = i + 1
25,574✔
960
         section = trim(adjustl(line(2:)))
25,574✔
961

962
         section = remove_substring_after_symbol(section,"!")
25,574✔
963

964
         if (.not. this%is_section_recognized(section)) call this%section_not_recognized(section)
25,574✔
965

966
         end_ = this%n_keyword_lines
25,574✔
967
         do j = start_, this%n_keyword_lines
102,076✔
968

969
            section_line = trim(adjustl(this%keyword_lines(j)))
98,913✔
970

971
            if (.not. string_starts_with(section_line, '-')) cycle
98,913✔
972

973
            end_ = j - 1
22,411✔
974
            exit
102,076✔
975

976
         enddo
977

978
         call this%set_section_keywords(section, this%keyword_lines(start_:end_))
105,263✔
979

980
      enddo
981

982
   end subroutine process_keyword_lines
3,169✔
983

984

UNCOV
985
   subroutine print_sections(this)
×
986
      !!
987
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
988
      !!
989
      implicit none
990

991
      class(input_tool), intent(in) :: this
992

993
      integer :: k
994

UNCOV
995
      call output%printf('m', 'The valid input sections are:', fs='(/t3,a/)')
×
996

UNCOV
997
      do k = 1, size(this%sections)
×
998

UNCOV
999
         call output%printf('m', '(a0)', chars=[trim(this%sections(k)%name_)], fs='(t6,a)')
×
1000

1001
      enddo
1002

UNCOV
1003
   end subroutine print_sections
×
1004

1005

1006
   function requested_reference_calculation(this) result(requested)
2,993✔
1007
      !!
1008
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1009
      !!
1010
      implicit none
1011

1012
      class(input_tool), intent(in) :: this
1013

1014
      logical :: requested
1015

1016
      requested = this%requested_calculation(this%rf_wfs)
2,993✔
1017

1018
   end function requested_reference_calculation
2,993✔
1019

1020

1021
   function requested_calculation(this, wfs) result(requested)
7,268✔
1022
      !!
1023
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1024
      !!
1025
      !! Looks for wfs(k) in method and returns true if it finds one such wf
1026
      !! in the input file. Gives an error if it finds more than one of wfs(k).
1027
      !!
1028
      implicit none
1029

1030
      class(input_tool), intent(in) :: this
1031

1032
      character(len=30), dimension(:), intent(in) :: wfs
1033

1034
      logical :: requested
1035

1036
      integer :: n_wfs, k, section_index
1037

1038
      n_wfs = 0
1039

1040
      section_index = this%get_section_index('method')
7,268✔
1041

1042
      do k = 1, size(wfs)
70,349✔
1043

1044
         if (this%sections(section_index)%is_keyword_present(wfs(k))) then
70,349✔
1045

1046
            n_wfs = n_wfs + 1
5,414✔
1047

1048
         endif
1049

1050
      enddo
1051

1052
      requested = .false.
1053

1054
      if (n_wfs == 1) then
7,268✔
1055

1056
         requested = .true.
1057

1058
      elseif (n_wfs > 1) then
1,854✔
1059

1060
         call output%error_msg('Requested more than one method &
UNCOV
1061
                               &of a single kind (e.g., two CC methods).')
×
1062

1063
      endif
1064

1065
   end function requested_calculation
7,268✔
1066

1067

1068
   function requested_cc_calculation(this) result(requested)
3,289✔
1069
      !!
1070
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1071
      !!
1072
      implicit none
1073

1074
      class(input_tool), intent(in) :: this
1075

1076
      logical :: requested
1077

1078
      requested = this%requested_calculation(this%cc_wfs)
3,289✔
1079

1080
   end function requested_cc_calculation
3,289✔
1081

1082

1083
   function requested_ci_calculation(this) result(requested)
986✔
1084
      !!
1085
      !! Written by Enrico Ronca, 2020
1086
      !!
1087
      implicit none
1088

1089
      class(input_tool), intent(in) :: this
1090

1091
      logical :: requested
1092

1093
      requested = this%requested_calculation(this%ci_wfs)
986✔
1094

1095
   end function requested_ci_calculation
986✔
1096

1097

1098
   function get_reference_wavefunction(this) result(ref_wf)
3,151✔
1099
      !!
1100
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1101
      !!
1102
      implicit none
1103

1104
      class(input_tool), intent(in) :: this
1105

1106
      character(len=30) :: ref_wf
1107

1108
      ref_wf = this%get_wavefunction(this%rf_wfs)
3,151✔
1109

1110
   end function get_reference_wavefunction
3,151✔
1111

1112

1113
   function get_cc_wavefunction(this) result(cc_wf)
2,061✔
1114
      !!
1115
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1116
      !!
1117
      implicit none
1118

1119
      class(input_tool), intent(in) :: this
1120

1121
      character(len=30) :: cc_wf
1122

1123
      cc_wf = this%get_wavefunction(this%cc_wfs)
2,061✔
1124

1125
   end function get_cc_wavefunction
2,061✔
1126

1127

1128
   function get_ci_wavefunction(this) result(ci_wf)
312✔
1129
      !!
1130
      !! Written by Enrico Ronca, Apr 2020
1131
      !!
1132
      implicit none
1133

1134
      class(input_tool), intent(in) :: this
1135

1136
      character(len=30) :: ci_wf
1137

1138
      ci_wf = this%get_wavefunction(this%ci_wfs)
312✔
1139

1140
   end function get_ci_wavefunction
312✔
1141

1142

1143
   function get_wavefunction(this, wfs) result(wf)
5,524✔
1144
      !!
1145
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1146
      !!
1147
      !! Looks for wfs(k) in the 'method' section of the input.
1148
      !!
1149
      implicit none
1150

1151
      class(input_tool), intent(in) :: this
1152

1153
      character(len=30), dimension(:), intent(in) :: wfs
1154

1155
      character(len=30) :: wf
1156

1157
      integer :: k, section_index
1158

1159
      section_index = this%get_section_index('method')
5,524✔
1160

1161
      do k = 1, size(wfs)
19,782✔
1162

1163
         if (this%sections(section_index)%is_keyword_present(wfs(k))) then
19,782✔
1164

1165
            wf = wfs(k)
5,524✔
1166
            return
5,524✔
1167

1168
         endif
1169

1170
      enddo
1171

1172
      call output%error_msg('Failed to read wavefunction from input. &
UNCOV
1173
         & Did you forget to specify all wavefunctions for the calculation?')
×
1174

1175
   end function get_wavefunction
1176

1177

1178
   subroutine get_32bit_integer_keyword(this, keyword, section, keyword_value)
27,840✔
1179
      !!
1180
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1181
      !!
1182
      !! If specified, reads keyword as an integer into keyword value.
1183
      !!
1184
      implicit none
1185

1186
      class(input_tool), intent(in) :: this
1187

1188
      character(len=*), intent(in) :: keyword
1189
      character(len=*), intent(in) :: section
1190

1191
      integer(i32), intent(inout) :: keyword_value
1192

1193
      character(len=200) :: keyword_value_string
1194

1195
      keyword_value_string = ""
27,840✔
1196
      call this%get_string_keyword(keyword, section, keyword_value_string)
27,840✔
1197

1198
      if (is_empty(keyword_value_string)) return
27,840✔
1199

1200
      read(keyword_value_string, *) keyword_value
4,163✔
1201

1202
   end subroutine get_32bit_integer_keyword
1203

1204

1205
   subroutine get_64bit_integer_keyword(this, keyword, section, keyword_value)
59,373✔
1206
      !!
1207
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1208
      !!
1209
      !! If specified, reads keyword as an integer into keyword value.
1210
      !!
1211
      implicit none
1212

1213
      class(input_tool), intent(in) :: this
1214

1215
      character(len=*), intent(in) :: keyword
1216
      character(len=*), intent(in) :: section
1217

1218
      integer(i64), intent(inout) :: keyword_value
1219

1220
      character(len=200) :: keyword_value_string
1221

1222
      keyword_value_string = ""
59,373✔
1223
      call this%get_string_keyword(keyword, section, keyword_value_string)
59,373✔
1224

1225
      if (is_empty(keyword_value_string)) return
59,373✔
1226

1227
      read(keyword_value_string, *) keyword_value
11,238✔
1228

1229
   end subroutine get_64bit_integer_keyword
1230

1231

1232
   subroutine get_required_32bit_integer_keyword(this, keyword, section, keyword_value)
412✔
1233
      !!
1234
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1235
      !!
1236
      !! Reads keyword as an integer into keyword value. If the keyword or the
1237
      !! section is not specified, an error occurs because the keyword is "required".
1238
      !!
1239
      implicit none
1240

1241
      class(input_tool), intent(in) :: this
1242

1243
      character(len=*), intent(in) :: keyword
1244
      character(len=*), intent(in) :: section
1245

1246
      integer(i32), intent(inout) :: keyword_value
1247

1248
      character(len=200) :: keyword_value_string
1249

1250
      keyword_value_string = ""
412✔
1251
      call this%get_string_keyword(keyword, section, keyword_value_string)
412✔
1252

1253
      if (is_empty(keyword_value_string)) then
412✔
1254
         call output%error_msg('could not find the required keyword '// trim(keyword) // &
UNCOV
1255
                               ' in section ' // trim(section))
×
1256

1257
      endif
1258

1259
      read(keyword_value_string, *) keyword_value
412✔
1260

1261
   end subroutine get_required_32bit_integer_keyword
412✔
1262

1263

1264
   subroutine get_required_64bit_integer_keyword(this, keyword, section, keyword_value)
876✔
1265
      !!
1266
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1267
      !!
1268
      !! Reads keyword as an integer into keyword value. If the keyword or the
1269
      !! section is not specified, an error occurs because the keyword is "required".
1270
      !!
1271
      implicit none
1272

1273
      class(input_tool), intent(in) :: this
1274

1275
      character(len=*), intent(in) :: keyword
1276
      character(len=*), intent(in) :: section
1277

1278
      integer(i64), intent(out) :: keyword_value
1279

1280
      character(len=200) :: keyword_value_string
1281

1282
      keyword_value_string = ""
876✔
1283
      call this%get_string_keyword(keyword, section, keyword_value_string)
876✔
1284

1285
      if (is_empty(keyword_value_string)) then
876✔
1286
         call output%error_msg('could not find the required keyword '// trim(keyword) // &
UNCOV
1287
                               ' in section ' // trim(section))
×
1288

1289
      endif
1290

1291
      read(keyword_value_string, *) keyword_value
876✔
1292

1293
   end subroutine get_required_64bit_integer_keyword
876✔
1294

1295

1296
   subroutine get_real_dp_keyword(this, keyword, section, keyword_value)
75,172✔
1297
      !!
1298
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1299
      !!
1300
      !! If specified, reads keyword as a real double precision into keyword value.
1301
      !!
1302
      implicit none
1303

1304
      class(input_tool), intent(in) :: this
1305

1306
      character(len=*), intent(in) :: keyword
1307
      character(len=*), intent(in) :: section
1308

1309
      real(dp), intent(inout) :: keyword_value
1310

1311
      character(len=200) :: keyword_value_string
1312

1313
      keyword_value_string = ""
75,172✔
1314
      call this%get_string_keyword(keyword, section, keyword_value_string)
75,172✔
1315

1316
      if (is_empty(keyword_value_string)) return
75,172✔
1317

1318
      read(keyword_value_string, *) keyword_value
61,269✔
1319

1320
   end subroutine get_real_dp_keyword
1321

1322

1323
   subroutine get_required_real_dp_keyword(this, keyword, section, keyword_value)
486✔
1324
      !!
1325
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1326
      !!
1327
      !! Reads keyword as an double precision into keyword value. If the keyword or the
1328
      !! section is not specified, an error occurs because the keyword is "required".
1329
      !!
1330
      implicit none
1331

1332
      class(input_tool), intent(in) :: this
1333

1334
      character(len=*), intent(in) :: keyword
1335
      character(len=*), intent(in) :: section
1336

1337
      real(dp), intent(out) :: keyword_value
1338

1339
      character(len=200) :: keyword_value_string
1340

1341
      keyword_value_string = ""
486✔
1342
      call this%get_string_keyword(keyword, section, keyword_value_string)
486✔
1343

1344
      if (is_empty(keyword_value_string)) then
486✔
1345
         call output%error_msg('could not find the required keyword '// trim(keyword) // &
UNCOV
1346
                               ' in section ' // trim(section))
×
1347

1348
      endif
1349

1350
      read(keyword_value_string, *) keyword_value
486✔
1351

1352
   end subroutine get_required_real_dp_keyword
486✔
1353

1354

1355
   subroutine get_string_keyword(this, keyword, section, keyword_value)
295,554✔
1356
      !!
1357
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1358
      !!
1359
      !! If specified, reads keyword as a string into keyword value.
1360
      !!
1361
      implicit none
1362

1363
      class(input_tool), intent(in) :: this
1364

1365
      character(len=*), intent(in) :: keyword
1366
      character(len=*), intent(in) :: section
1367

1368
      character(len=200), intent(inout) :: keyword_value
1369
      character(len=200) :: keyword_value_string
1370

1371
      integer :: section_index
1372

1373
      section_index = this%get_section_index(section)
295,554✔
1374

1375
      keyword_value_string = this%sections(section_index)%get_string_keyword(keyword)
295,554✔
1376

1377
      ! Make sure not to overwrite defaults set on the outside
1378
      if (is_empty(keyword_value_string)) return
295,554✔
1379

1380
      keyword_value = keyword_value_string
106,913✔
1381

1382
   end subroutine get_string_keyword
1383

1384

1385
   subroutine get_required_string_keyword(this, keyword, section, keyword_value)
756✔
1386
      !!
1387
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1388
      !!
1389
      !! If specified, reads keyword as a string into keyword value.
1390
      !!
1391
      implicit none
1392

1393
      class(input_tool), intent(in) :: this
1394

1395
      character(len=*), intent(in) :: keyword
1396
      character(len=*), intent(in) :: section
1397

1398
      character(len=200) :: keyword_value
1399

1400
      keyword_value = ""
756✔
1401
      call this%get_string_keyword(keyword, section, keyword_value)
756✔
1402

1403
      if (is_empty(keyword_value)) then
756✔
1404
         call output%error_msg('could not find the required keyword '// trim(keyword) // &
UNCOV
1405
                               ' in section ' // trim(section))
×
1406

1407
      endif
1408

1409
   end subroutine get_required_string_keyword
756✔
1410

1411

1412
   function get_section_index(this, section) result(index)
1,019,614✔
1413
      !!
1414
      !! Written by Sara Angelico and Alexander C. Paul, Feb 2023
1415
      !!
1416
      implicit none
1417

1418
      class(input_tool), intent(in) :: this
1419

1420
      character(len=*), intent(in) :: section
1421

1422
      integer :: index, i
1423

1424
      index = 0
1425

1426
      do i = 1, size(this%sections)
28,478,349✔
1427
         if(trim(this%sections(i)%name_) == trim(section)) then
28,478,349✔
1428
            index = i
1429
            return
1,019,614✔
1430
         end if
1431
      enddo
1432

UNCOV
1433
      call this%section_not_recognized(section)
×
1434

UNCOV
1435
   end function get_section_index
×
1436

1437

1438
   function is_keyword_present_input_tool(this, keyword, section) result(is_present)
644,248✔
1439
      !!
1440
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1441
      !!
1442
      !! Returns true if the keyword is in the section.
1443
      !!
1444
      implicit none
1445

1446
      class(input_tool), intent(in) :: this
1447

1448
      character(len=*), intent(in) :: keyword
1449
      character(len=*), intent(in) :: section
1450

1451
      logical :: is_present
1452

1453
      integer :: section_index
1454

1455
      section_index = this%get_section_index(section)
644,248✔
1456

1457
      is_present = this%sections(section_index)%is_keyword_present(keyword)
644,248✔
1458

1459
   end function is_keyword_present_input_tool
644,248✔
1460

1461

1462
   function is_section_present_input_tool(this, section) result(is_present)
41,446✔
1463
      !!
1464
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1465
      !!
1466
      !! Returns true if the section exists, false if it doesn't.
1467
      !!
1468
      implicit none
1469

1470
      class(input_tool), intent(in) :: this
1471

1472
      character(len=*), intent(in) :: section
1473

1474
      logical :: is_present
1475

1476
      integer :: section_index
1477

1478
      section_index = this%get_section_index(section)
41,446✔
1479

1480
      is_present = this%sections(section_index)%is_section_present()
41,446✔
1481

1482
   end function is_section_present_input_tool
41,446✔
1483

1484

1485
   function get_n_elements_for_keyword(this, keyword, section) result(n_elements)
2,736✔
1486
      !!
1487
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1488
      !!
1489
      !! Gets the number of elements specified for a keyword in set/range notation
1490
      !!
1491
      !! Ranges should always be given as [a,b].
1492
      !! Lists should always be given as {a, b, c, d}.
1493
      !!
1494
      !! Function is called in preparation for get_array_for_keyword
1495
      !!
1496
      implicit none
1497

1498
      class(input_tool), intent(in) :: this
1499

1500
      character(len=*), intent(in) :: keyword
1501
      character(len=*), intent(in) :: section
1502

1503
      integer :: n_elements
1504

1505
      character(len=200) :: keyword_value_string
1506

1507
      n_elements = 0
1508

1509
      call this%get_keyword(keyword, section, keyword_value_string)
2,736✔
1510

1511
      n_elements = this%get_n_elements_in_set_or_range(keyword_value_string)
2,736✔
1512

1513
   end function get_n_elements_for_keyword
2,736✔
1514

1515

1516
   subroutine get_integer_array_for_keyword(this, keyword, section, n_elements, array_)
1,664✔
1517
      !!
1518
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1519
      !!
1520
      !! Gets input variable array (array_) for keyword which is specified on input
1521
      !! by either an integer range or list (of length n_elements).
1522
      !!
1523
      !! Ranges should always be given as [a,b].
1524
      !! Lists should always be given as {a, b, c, d}.
1525
      !!
1526
      !! Routine should be called after the get_n_elements_for_keyword is called
1527
      !! in order to determine n_elements so that array_ can be allocated.
1528
      !!
1529
      implicit none
1530

1531
      class(input_tool), intent(in) :: this
1532

1533
      character(len=*), intent(in) :: keyword
1534
      character(len=*), intent(in) :: section
1535

1536
      integer, intent(in) :: n_elements
1537

1538
      integer, dimension(n_elements) :: array_
1539

1540
      character(len=200) :: keyword_value_string
1541

1542
      call check_get_array_for_keyword(keyword, section, n_elements)
1,664✔
1543

1544
      call this%get_keyword(keyword, section, keyword_value_string)
1,664✔
1545

1546
      call this%get_integers_from_set_or_range(keyword_value_string, n_elements, array_)
1,664✔
1547

1548
   end subroutine get_integer_array_for_keyword
1,664✔
1549

1550

1551
   subroutine get_real_array_for_keyword(this, keyword, section, n_elements, array_)
3,572✔
1552
      !!
1553
      !! Written by Sarai D. Folkestad, Eirik F. Kjønstad, Andreas Skeidsvoll and Alexander C. Paul, 2019-2023
1554
      !!
1555
      !! Gets input variable array (array_) for keyword
1556
      !! which is specified on input by a list
1557
      !!
1558
      !! Lists should always be given as {a, b, c, d}
1559
      !!
1560
      !! Routine should be called after the get_n_elements_for_keyword is called
1561
      !! in order to determine n_elements so that array_ can be allocated.
1562
      !!
1563
      use string_utilities, only: read_comma_separated_list
1564

1565
      implicit none
1566

1567
      class(input_tool), intent(in) :: this
1568

1569
      character(len=*), intent(in) :: keyword
1570
      character(len=*), intent(in) :: section
1571
      integer,          intent(in) :: n_elements
1572

1573
      real(dp), dimension(n_elements), intent(inout) :: array_
1574

1575
      character(len=200) :: keyword_value_string
1576
      character(len=:), allocatable :: string
1577

1578
      call check_get_array_for_keyword(keyword, section, n_elements)
3,572✔
1579

1580
      call this%get_keyword(keyword, section, keyword_value_string)
3,572✔
1581

1582
      string = trim(adjustl(keyword_value_string))
3,572✔
1583
      call this%expect_set(string)
3,572✔
1584

1585
      call read_comma_separated_list(string(2:len(string)-1), array_, n_elements)
3,572✔
1586

1587
   end subroutine get_real_array_for_keyword
3,572✔
1588

1589

1590
   subroutine get_string_array_for_keyword(this, keyword, section, n_elements, array_)
126✔
1591
      !!
1592
      !! Written by Anna Kristina Schnack-Petersen and Alexander C. Paul, 2022-2023
1593
      !!
1594
      !! Gets input variable array (array_) for keyword which is specified on input
1595
      !! by a list of strings (of length n_elements).
1596
      !!
1597
      !! Lists should always be given as {a, b, c, d}
1598
      !!
1599
      !! Routine should be called after the get_n_elements_for_keyword is called
1600
      !! in order to determine n_elements so that array_ can be allocated.
1601
      !!
1602
      use string_utilities, only: split_at_delimiter
1603

1604
      implicit none
1605

1606
      class(input_tool), intent(in) :: this
1607

1608
      character(len=*), intent(in) :: keyword
1609
      character(len=*), intent(in) :: section
1610
      integer,          intent(in) :: n_elements
1611

1612
      character(len=200), dimension(n_elements), intent(inout) :: array_
1613

1614
      character(len=200)            :: keyword_value_string
1615
      character(len=:), allocatable :: string
1616

1617
      call check_get_array_for_keyword(keyword, section, n_elements)
126✔
1618

1619
      call this%get_keyword(keyword, section, keyword_value_string)
126✔
1620

1621
      string = trim(adjustl(keyword_value_string))
126✔
1622
      call this%expect_set(string)
126✔
1623

1624
      call split_at_delimiter(string(2:len(string)-1), n_elements-1, array_, ',')
126✔
1625

1626
   end subroutine get_string_array_for_keyword
126✔
1627

1628

1629
   pure function get_n_atoms_input_tool(this) result(n_atoms)
3,169✔
1630
      !!
1631
      !! Get n atoms
1632
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1633
      !!
1634
      !! Reads the geometry section of the input and counts the number of atoms
1635
      !!
1636
      implicit none
1637

1638
      class(input_tool), intent(in) :: this
1639

1640
      integer :: n_atoms
1641

1642
      integer :: record
1643

1644
      n_atoms = 0
1645

1646
      do record = 1, this%n_qm_atom_lines
19,432✔
1647

1648
         if (this%qm_geometry(record)(1:6) .ne. 'basis:' &
1649
            .and. (this%qm_geometry(record)(1:6) .ne. 'units:') &
1650
            .and. (this%qm_geometry(record)(1:5) .ne. 'ghost')) &
16,263✔
1651
            n_atoms = n_atoms + 1
16,007✔
1652

1653
      enddo
1654

1655
   end function get_n_atoms_input_tool
3,169✔
1656

1657

1658
   pure function get_n_mm_atoms_input_tool(this) result(n_atoms)
156✔
1659
      !!
1660
      !! Get n MM atoms
1661
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1662
      !!
1663
      implicit none
1664

1665
      class(input_tool), intent(in) :: this
1666

1667
      integer :: n_atoms
1668

1669
      n_atoms = this%n_mm_atom_lines
156✔
1670

1671
   end function  get_n_mm_atoms_input_tool
156✔
1672

1673

1674
   function get_n_mm_molecules_input_tool(this) result(n_molecules)
78✔
1675
      !!
1676
      !! Written by Sarai D. Folkestad, Sep 2020
1677
      !!
1678
      !! Reads the MM geometry and counts the number of molecules
1679
      !!
1680
      implicit none
1681

1682
      class(input_tool), intent(in) :: this
1683

1684
      integer :: n_molecules
1685

1686
      integer :: cursor, record, current_molecule, previous_molecule
1687

1688
      character(len=200) :: string, imolecule
1689

1690
      previous_molecule = 1
1691
      n_molecules       = 1
1692

1693
      do record = 1, this%n_mm_atom_lines
312✔
1694

1695
         string = (trim(adjustl(this%mm_geometry(record))))
234✔
1696
         cursor = first_index_of_substring(string,'=')
234✔
1697

1698
         string = string(cursor+1:200)
234✔
1699

1700
         cursor = first_index_of_substring(string,']')
234✔
1701

1702
         imolecule = string(1:cursor-1)
234✔
1703
         read(imolecule,'(i4)') current_molecule
234✔
1704

1705
         if (record == 1 .and. current_molecule .ne. 1) &
234✔
UNCOV
1706
            call output%error_msg('Molecule 1 is missing!')
×
1707

1708
         if (current_molecule .eq. previous_molecule + 1) then
234✔
1709

UNCOV
1710
            n_molecules = n_molecules + 1
×
1711

1712
         elseif (current_molecule .ne. previous_molecule .and. &
234✔
1713
               current_molecule .ne. previous_molecule + 1) then
1714

1715
            call output%error_msg('Molecule (i0) missing even though (i0) &
1716
                                 &should be present in QM/MM calculation.', &
UNCOV
1717
                                 ints=[previous_molecule + 1, n_molecules])
×
1718

1719
         endif
1720

1721
         previous_molecule = current_molecule
78✔
1722

1723
      enddo
1724

1725
   end function get_n_mm_molecules_input_tool
78✔
1726

1727

1728
   subroutine get_geometry_input_tool(this, n_atoms, symbols,  &
3,169✔
1729
                                      positions, basis_sets,   &
1730
                                      charge, units_angstrom,  &
3,169✔
1731
                                      is_ghost)
1732
      !!
1733
      !! Written by Sarai D. Folkestad, Eirik F. Kjønstad
1734
      !! Åsmund H. Tveten and Tor S. Haugland, 2019-2021
1735
      !!
1736
      !! Reads the geometry from the output file and sets it in the list of atoms.
1737
      !!
1738
      !! Note: This routine should be called after a call to the function
1739
      !! get_n_atoms_input_tool which finds the number of atoms in the system
1740
      !!
1741
      use string_utilities, only: convert_character_to_uppercase
1742

1743
      implicit none
1744

1745
      class(input_tool), intent(in) :: this
1746

1747
      integer, intent(in) :: n_atoms
1748

1749
      character(len=2), dimension(n_atoms), intent(out)   :: symbols
1750
      character(len=100), dimension(n_atoms), intent(out) :: basis_sets
1751
      logical, dimension(n_atoms), intent(out) :: is_ghost
1752

1753
      real(dp), dimension(3, n_atoms), intent(out) :: positions ! x, y, z
1754
      integer, dimension(n_atoms), intent(out) :: charge
1755

1756
      logical, intent(out) :: units_angstrom
1757

1758
      integer :: current_atom, i
1759

1760
      integer :: start_
1761

1762
      character(len=200) :: string
1763
      character(len=100) :: current_basis
1764
      logical :: is_ghost_atom = .false.
1765

1766
      integer :: cursor
1767

1768
      start_ = 1 ! Specifies the line of the first and required basis
1769

1770
      ! Are units specified?
1771
      ! Note that units can only be specified as the first line of the geometry
1772

1773
      units_angstrom = .true. ! Default units are Angstrom
3,169✔
1774
      charge = 0 ! Default charge is zero
16,007✔
1775

1776
      if (this%qm_geometry(1)(1:6) == 'units:') then
3,169✔
1777

1778
         string = (trim(adjustl(this%qm_geometry(1)(7:200))))
220✔
1779

1780
         if (string(1:4) == 'bohr') then
220✔
1781

1782
            units_angstrom = .false.
220✔
1783

UNCOV
1784
         elseif (string(1:8) /= 'angstrom') then
×
1785

UNCOV
1786
            call output%error_msg('units of atom coordinates must be either angstrom or bohr')
×
1787

1788
         endif
1789

1790
         start_ = 2
1791

1792
      endif
1793

1794
      ! Error if next line is not a basis set line
1795

1796
      if(this%qm_geometry(start_)(1:6) /= 'basis:') &
3,169✔
UNCOV
1797
            call output%error_msg('did not find basis in geometry section.')
×
1798

1799
      current_atom = 0
1800

1801
      do i = start_, this%n_qm_atom_lines
19,212✔
1802

1803
         string = trim(adjustl(this%qm_geometry(i)))
16,043✔
1804

1805
         if (string(1:6) == 'units:') &
16,043✔
UNCOV
1806
            call output%error_msg('Units must be specified as the first line in the geometry section.')
×
1807

1808
         if(string(1:6) == 'basis:') then
19,212✔
1809

1810
            current_basis = trim(adjustl(string(7:200)))
3,199✔
1811
            current_basis = remove_substring_after_symbol(current_basis,"!")
3,199✔
1812

1813
         elseif (string(1:5) == 'ghost') then
12,844✔
1814

1815
            ! Every atom after 'ghost' keyword are ghosts
1816
            is_ghost_atom = .true.
6✔
1817

1818
         else
1819

1820
            current_atom = current_atom + 1
12,838✔
1821

1822
            basis_sets(current_atom) = current_basis
12,838✔
1823
            symbols(current_atom)    = string(1:2)
12,838✔
1824
            is_ghost(current_atom)   = is_ghost_atom
12,838✔
1825

1826
            string = adjustl(string(3:200))
12,838✔
1827

1828
            if (is_substring_in_string(string, 'q')) then
12,838✔
1829

1830
               cursor = first_index_of_substring(string, 'q')
12✔
1831
               read(string(1 : cursor - 1), *) positions(:, current_atom)
12✔
1832

1833
               string = adjustl(string(cursor+1:200))
12✔
1834

1835
               if (.not. string_starts_with(string, '=')) &
12✔
UNCOV
1836
                     call output%error_msg('in assignment of charge to atom in the geometry')
×
1837

1838
               string = adjustl(string(2:200))
12✔
1839
               read(string, *) charge(current_atom)
12✔
1840
            else
1841

1842
               read(string(1:), *) positions(:, current_atom)
12,826✔
1843

1844
            endif
1845

1846
         endif
1847

1848
      enddo
1849

1850
      ! First character of symbol should be upper case
1851

1852
      do i = 1, n_atoms
16,007✔
1853

1854
         symbols(i)(1:1) = convert_character_to_uppercase(symbols(i)(1:1))
16,007✔
1855

1856
      enddo
1857

1858
   end subroutine get_geometry_input_tool
3,169✔
1859

1860

1861
   subroutine get_mm_geometry_fq_input_tool(this, n_atoms, n_molecules, &
78✔
1862
                                          n_atoms_per_molecule, symbols,   &
78✔
1863
                                          positions, chi, eta)
1864
      !!
1865
      !! Written by Tommaso Giovanini and Sarai D. Folkestad, 2019-2020
1866
      !!
1867
      !! Reads the geometry of the MM portion from the input file in the case
1868
      !! of an fq calculation and sets it in the list of atoms.
1869
      !!
1870
      !! Note: In order to be run, you need to know the number of MM atoms and molecules
1871
      !!       in the system
1872
      !!
1873
      use string_utilities, only: convert_character_to_uppercase
1874
      use string_utilities, only: last_index_of_substring
1875

1876
      implicit none
1877

1878
      class(input_tool),   intent(in) :: this
1879
      integer,             intent(in) :: n_atoms
1880
      integer,             intent(in) :: n_molecules
1881

1882
      character(len=2), dimension(n_atoms),     intent(out) :: symbols
1883
      real(dp),         dimension(3, n_atoms),  intent(out) :: positions
1884
      real(dp),         dimension(n_atoms),     intent(out) :: chi
1885
      real(dp),         dimension(n_atoms),     intent(out) :: eta
1886
      integer,          dimension(n_molecules), intent(out) :: n_atoms_per_molecule
1887

1888
      integer :: record, cursor, current_atom, i, current_molecule
1889

1890
      character(len=200) :: string, coordinate
1891

1892
      current_atom = 0
1893

1894
      current_molecule     = 0
78✔
1895
      n_atoms_per_molecule = 0
156✔
1896
      cursor = 0
1897

1898
      do record = 1, this%n_mm_atom_lines
312✔
1899

1900
         current_atom = current_atom + 1
234✔
1901
         string = trim(adjustl(this%mm_geometry(record)))
234✔
1902

1903
         ! Determine symbol
1904

1905
         symbols(current_atom) = string(1:2)
234✔
1906
         string = adjustl(string(3:200))
234✔
1907

1908
         ! Determine molecule index
1909

1910
         if (is_substring_in_string(string, 'mol')) then
234✔
1911
            cursor = last_index_of_substring(string, 'mol')
234✔
1912
         else
UNCOV
1913
            call output%error_msg('could not find mol in MM geometry')
×
1914
         endif
1915

1916
         string = adjustl(string(cursor+1:200))
234✔
1917

1918
         if (string(1:1) .ne. '=') call output%error_msg('in mol specification in MM geometry')
234✔
1919
         string = adjustl(string(2:200))
234✔
1920

1921
         cursor = first_index_of_substring(string, ']')
234✔
1922

1923
         read(string(1:cursor-1),*) current_molecule
234✔
1924
         string = adjustl(string(cursor+1:200))
234✔
1925

1926
         n_atoms_per_molecule(current_molecule) = n_atoms_per_molecule(current_molecule) + 1
234✔
1927

1928
         cursor = first_index_of_substring(string, '[')
234✔
1929

1930
         coordinate = string(1:cursor-1)
234✔
1931
         read(coordinate, *) positions(:, current_atom)
234✔
1932

1933
         string = adjustl(string(cursor+1:200))
234✔
1934

1935
         ! Determine chi
1936

1937
         if (is_substring_in_string(string, 'chi')) then
234✔
1938
            cursor = last_index_of_substring(string, 'chi')
234✔
1939
         else
UNCOV
1940
            call output%error_msg('could not find chi in MM geometry')
×
1941
         endif
1942

1943
         string = adjustl(string(cursor+1:200))
234✔
1944

1945
         if (string(1:1) .ne. '=') call output%error_msg('in chi specification in MM geometry')
234✔
1946
         string = adjustl(string(2:200))
234✔
1947

1948
         cursor = first_index_of_substring(string,',')
234✔
1949
         read(string(1:cursor-1), * ) chi(current_atom)
234✔
1950
         string = adjustl(string(cursor+1:200))
234✔
1951

1952
         ! Determine eta
1953

1954
         if (is_substring_in_string(string, 'eta')) then
234✔
1955
            cursor = last_index_of_substring(string, 'eta')
234✔
1956
         else
UNCOV
1957
            call output%error_msg('could not find eta in MM geometry')
×
1958
         endif
1959

1960
         string = trim(adjustl(string(cursor+1:200)))
234✔
1961

1962
         if (string(1:1) .ne. '=') call output%error_msg('in chi specification in MM geometry')
234✔
1963
         string = adjustl(string(2:200))
234✔
1964

1965
         cursor = first_index_of_substring(string,']')
234✔
1966
         read(string(1:cursor-1), * ) eta(current_atom)
234✔
1967

1968
         if(abs(eta(current_atom)).lt.1.0d-8) then
312✔
1969

1970
            call output%error_msg('You have put zero chemical hardness on atom: (i0)', &
UNCOV
1971
                                  ints=[current_atom])
×
1972

1973
         endif
1974

1975
      enddo
1976

1977
      ! First character of symbol should be upper case
1978

1979
      do i = 1, n_atoms
312✔
1980

1981
         symbols(i)(1:1) = convert_character_to_uppercase(symbols(i)(1:1))
312✔
1982

1983
      enddo
1984

1985
   end subroutine get_mm_geometry_fq_input_tool
78✔
1986

1987

1988
   subroutine get_mm_geometry_non_polarizable_input_tool(this, n_atoms, symbols,   &
78✔
1989
                                                         positions, charge)
1990
      !!
1991
      !! Written by Tommaso Giovanini and Sarai D. Folkestad, 2019-2020
1992
      !!
1993
      !! Reads the geometry of the MM portion from the input file and
1994
      !! sets it in the list of atoms.
1995
      !!
1996
      !! Note: In order to be run, you need to know the number of MM atoms
1997
      !!       there are in the system
1998
      !!
1999
      use string_utilities, only: convert_character_to_uppercase
2000
      use string_utilities, only: last_index_of_substring
2001

2002
      implicit none
2003

2004
      class(input_tool), intent(in) :: this
2005

2006
      integer, intent(in) :: n_atoms
2007

2008
      character(len=2), dimension(n_atoms),     intent(out) :: symbols
2009
      real(dp),         dimension(3, n_atoms),  intent(out) :: positions
2010
      real(dp),         dimension(n_atoms),     intent(out) :: charge
2011

2012
      integer :: record, cursor, current_atom, i, current_molecule
2013

2014
      character(len=200) :: string, coordinate
2015

2016
      current_atom      = 0
2017
      current_molecule  = 0
78✔
2018
      cursor            = 0
2019

2020
      do record = 1, this%n_mm_atom_lines
312✔
2021

2022
         current_atom = current_atom + 1
234✔
2023
         string = trim(adjustl(this%mm_geometry(record)))
234✔
2024

2025
         ! Determine symbol
2026

2027
         symbols(current_atom) = string(1:2)
234✔
2028
         string = adjustl(string(3:200))
234✔
2029

2030
         ! Determine molecule index
2031

2032
         if (is_substring_in_string(string, 'mol')) then
234✔
2033
            cursor = last_index_of_substring(string, 'mol')
234✔
2034
         else
UNCOV
2035
            call output%error_msg('could not find mol in MM geometry')
×
2036
         endif
2037

2038
         string = adjustl(string(cursor+1:200))
234✔
2039

2040
         if (string(1:1) .ne. '=') call output%error_msg('in mol specification in MM geometry')
234✔
2041
         string = adjustl(string(2:200))
234✔
2042

2043
         cursor = first_index_of_substring(string, ']')
234✔
2044
         read(string(1:cursor-1),*) current_molecule
234✔
2045
         string = adjustl(string(cursor+1:200))
234✔
2046

2047
         ! Determine position
2048

2049
         cursor = first_index_of_substring(string, '[')
234✔
2050

2051
         coordinate = string(1:cursor-1)
234✔
2052
         read(coordinate, *) positions(:, current_atom)
234✔
2053

2054
         string = adjustl(string(cursor+1:200))
234✔
2055

2056
         ! Determine charge
2057

2058
         cursor = first_index_of_substring(string, 'q')
234✔
2059
         string = adjustl(string(cursor+1:200))
234✔
2060

2061
         if (string(1:1) .ne. '=') call output%error_msg('in charge specification in MM geometry')
234✔
2062
         string = adjustl(string(2:200))
234✔
2063

2064
         cursor = first_index_of_substring(string,']')
234✔
2065
         read(string(1:cursor-1), * ) charge(current_atom)
234✔
2066

2067
         if(abs(charge(current_atom)).lt.1.0d-8) then
312✔
2068

2069
            call output%warning_msg('You put zero charge on atom = (i0)', &
UNCOV
2070
                                     ints=[current_atom], fs='(t6,a)')
×
2071

2072
         endif
2073

2074
      enddo
2075

2076
      ! First character of symbol should be upper case
2077

2078
      do i = 1, n_atoms
312✔
2079

2080
         symbols(i)(1:1) = convert_character_to_uppercase(symbols(i)(1:1))
312✔
2081

2082
      enddo
2083

2084
   end subroutine get_mm_geometry_non_polarizable_input_tool
78✔
2085

2086

2087
   function string_in_array_keyword(this, keyword, section, string) result(in_list)
414✔
2088
      !!
2089
      !! Written by Sarai D. Folkestad and Alexander C. Paul, 2019-2023
2090
      !!
2091
      !! Determines if the 'string' is one of the keyword values in the comma separated
2092
      !! list given with 'keyword' in the given 'section' of the input file.
2093
      !!
2094
      !! Examples of such a keyword is 'levels' from the 'mlcc' section:
2095
      !!
2096
      !!    levels: ccs, cc2, ccsd
2097
      !!
2098
      !! This function assumes that the keyword is requested. If it is not, a test should be performed
2099
      !! before the routine is called
2100
      !!
2101
      use string_utilities, only: string_in_comma_separated_list
2102

2103
      implicit none
2104

2105
      class(input_tool), intent(in) :: this
2106

2107
      character(len=*), intent(in) :: section
2108
      character(len=*), intent(in) :: keyword
2109
      character(len=*), intent(in) :: string
2110

2111
      logical :: in_list
2112

2113
      character(len=200) :: keyword_value_string
2114

2115
      call this%get_required_keyword(keyword, section, keyword_value_string)
414✔
2116
      in_list = string_in_comma_separated_list(keyword_value_string, string)
414✔
2117

2118
   end function string_in_array_keyword
414✔
2119

2120

2121
   subroutine cleanup_input_tool(this)
3,139✔
2122
      !!
2123
      !! Written by Eirik F. Kjønstad, May 2022
2124
      !!
2125
      implicit none
2126

2127
      class(input_tool), intent(inout) :: this
2128

2129
      deallocate(this%keyword_lines)
3,139✔
2130
      deallocate(this%qm_geometry)
3,139✔
2131
      if (allocated(this%mm_geometry)) deallocate(this%mm_geometry)
3,139✔
2132

2133
   end subroutine cleanup_input_tool
3,139✔
2134

2135

2136
   function is_embedding_on_input_tool(this) result(embedding)
8,518✔
2137
      !!
2138
      !! Written by Sarai D. Folkestad, Sep 2020
2139
      !!
2140
      !! Returns true if wavefunction is embedded.
2141
      !!
2142
      implicit none
2143

2144
      class(input_tool), intent(in) :: this
2145

2146
      logical :: embedding
2147

2148
      embedding = this%is_section_present('molecular mechanics') .or. &
2149
                  this%is_section_present('pcm') .or. &
2150
                  this%is_keyword_present('cbo', 'boson')
8,518✔
2151

2152
   end function is_embedding_on_input_tool
8,518✔
2153

2154

2155
   subroutine place_records_in_memory_input_tool(this, section, records_in_memory)
14,884✔
2156
      !!
2157
      !! Written by Sarai D. Folkestad, 2021
2158
      !!
2159
      !! Checks if storage for 'section' is in memory or on disk
2160
      !!
2161
      !! records_in_mem is intent(inout) because it should be set
2162
      !! to a default value before a call to this routine
2163
      !!
2164
      implicit none
2165

2166
      class(input_tool), intent(in) :: this
2167
      character(len=*),  intent(in) :: section
2168

2169
      logical, intent(inout) :: records_in_memory
2170

2171
      character(len=200) :: storage
2172

2173
      if (.not. this%is_keyword_present('storage', trim(section))) return
14,884✔
2174

2175
      call this%get_keyword('storage', trim(section), storage)
30✔
2176

2177
      ! Determine whether to store records in memory or on file
2178

2179
      if (trim(storage) == 'memory') then
30✔
2180

2181
         records_in_memory = .true.
30✔
2182

UNCOV
2183
      elseif (trim(storage) == 'disk') then
×
2184

UNCOV
2185
         records_in_memory = .false.
×
2186

2187
      else
2188

2189
         call output%error_msg('Could not recognize keyword storage in solver: ', &
UNCOV
2190
                                 chars=[trim(storage)])
×
2191

2192
      endif
2193

2194
   end subroutine place_records_in_memory_input_tool
2195

2196

2197
   function get_n_sets_and_ranges(string) result(n_elements)
6✔
2198
      !!
2199
      !! Written by Sarai D. Folkstad and Eirik F. Kjønstad, Mar 2019
2200
      !!
2201
      !! Gets the number of sets/ranges in a string,
2202
      !!
2203
      !! Ranges should always be given as [a,b].
2204
      !!
2205
      !! Lists/ranges should always be given as {a, b, c, d},
2206
      !! that is, in set notation.
2207
      !!
2208
      implicit none
2209

2210
      character(len=200), intent(inout) :: string
2211

2212
      integer :: n_elements
2213

2214
      integer :: i
2215
      integer :: n_set_start, n_set_end
2216
      integer :: n_range_start, n_range_end
2217

2218
      n_set_start = 0
2219
      n_set_end   = 0
2220

2221
      n_range_start = 0
2222
      n_range_end   = 0
2223

2224
      string = adjustl(string)
6✔
2225

2226
      do i = 1, len_trim(string)
126✔
2227

2228
         if (string(i:i) == '{') n_set_start = n_set_start + 1
120✔
2229
         if (string(i:i) == '}') n_set_end = n_set_end + 1
120✔
2230

2231
         if (string(i:i) == '[') n_range_start = n_range_start + 1
120✔
2232
         if (string(i:i) == ']') n_range_end = n_range_end + 1
126✔
2233

2234
      enddo
2235

2236
      if (n_set_start /= n_set_end) call output%error_msg('found open set in input file')
6✔
2237
      if (n_range_start /= n_range_end) call output%error_msg('found open range in input file')
6✔
2238

2239
      n_elements = n_set_start + n_range_start
6✔
2240

2241
   end function get_n_sets_and_ranges
6✔
2242

2243

2244
   function get_n_elements_in_set_or_range(this, string) result(n_elements)
2,736✔
2245
      !!
2246
      !! Written by Sarai D. Folkstad and Eirik F. Kjønstad, Mar 2019
2247
      !!
2248
      !! Gets the number of elements in range or list,
2249
      !!
2250
      !! Ranges should always be given as [a,b], where a and b are integers.
2251
      !! Lists/Sets should always be given as {a, b, c, d}.
2252
      !!
2253
      use string_utilities, only: n_instances_of_character
2254

2255
      implicit none
2256

2257
      class(input_tool), intent(in) :: this
2258

2259
      character(len=200), intent(inout) :: string
2260

2261
      integer :: n_elements
2262

2263
      integer :: last, first, n_characters
2264
      integer :: comma_index
2265

2266
      n_elements = 0
2267

2268
      string = adjustl(string)
2,736✔
2269

2270
      n_characters = len_trim(string)
2,736✔
2271

2272
      if (string_starts_with(string, '[')) then ! range
2,736✔
2273

2274
         call expect_range(string)
198✔
2275

2276
         comma_index = index(string, ',')
198✔
2277

2278
         read(string(2 : comma_index-1), *) first
198✔
2279
         read(string(comma_index+1 : n_characters - 1), *) last
198✔
2280

2281
         n_elements = last - first + 1
198✔
2282

2283
      else if (string_starts_with(string, '{')) then ! set
2,538✔
2284

2285
         call this%expect_set(string)
2,424✔
2286

2287
         n_elements = 1 ! Assuming that the set contains at least one element (otherwise why give list?)
2288
         n_elements = n_elements + n_instances_of_character(string(2:), ',')
2,424✔
2289

2290
      else ! Did not find list or range
2291

2292
         n_elements = 0
2293

2294
      endif
2295

2296
   end function get_n_elements_in_set_or_range
2,736✔
2297

2298

2299
   subroutine get_integers_from_set_or_range(this, string, n_elements, elements)
1,664✔
2300
      !!
2301
      !! Written by Sarai D. Folkstad and Eirik F. Kjønstad, Mar 2019
2302
      !!
2303
      !! Ranges should always be given as [a,b].
2304
      !!
2305
      !! Lists should always be given as {a, b, c, d}.
2306
      !!
2307
      use string_utilities, only: read_comma_separated_list
2308

2309
      implicit none
2310

2311
      class(input_tool), intent(in) :: this
2312

2313
      character(len=200), intent(inout) :: string
2314

2315
      integer, intent(in) :: n_elements
2316

2317
      integer, dimension(n_elements), intent(out) :: elements
2318

2319
      integer :: first, last, length, n_characters
2320
      integer :: i, comma_index
2321

2322
      string = adjustl(string)
1,664✔
2323

2324
      n_characters = len_trim(string)
1,664✔
2325

2326
      if (string_starts_with(string, '[')) then ! range
1,664✔
2327

2328
         call expect_range(string)
198✔
2329

2330
         comma_index = index(string, ',')
198✔
2331

2332
         read(string(2 : comma_index-1), *) first
198✔
2333
         read(string(comma_index+1 : n_characters - 1), *) last
198✔
2334
         length = last - first + 1
198✔
2335

2336
         if (n_elements /= length) call output%error_msg('Mismatch in number of elements of range.')
198✔
2337

2338
         elements = [(i, i=first, last)]
1,482✔
2339

2340
      else if (string_starts_with(string, '{')) then ! set
1,466✔
2341

2342
         call this%expect_set(string)
1,466✔
2343
         call read_comma_separated_list(string(2:n_characters-1), elements, n_elements)
1,466✔
2344

2345
      else ! Did not find list or range
2346

UNCOV
2347
         call output%error_msg('neither list nor range was found.')
×
2348

2349
      endif
2350

2351
   end subroutine get_integers_from_set_or_range
1,664✔
2352

2353

2354
   function get_n_state_guesses(this) result(n_guesses)
6✔
2355
      !!
2356
      !! Written by Eirik F. Kjønstad, Dec 2021
2357
      !!
2358
      implicit none
2359

2360
      class(input_tool) :: this
2361

2362
      integer :: n_guesses
2363

2364
      character(len=200) :: state_guesses
2365

2366
      call this%get_keyword('state guesses', 'solver cc es', state_guesses)
6✔
2367

2368
      n_guesses = get_n_sets_and_ranges(state_guesses)
6✔
2369

2370
   end function get_n_state_guesses
6✔
2371

2372

2373
   subroutine get_state_guesses(this, occupied, virtual, n_states)
6✔
2374
      !!
2375
      !! Written by Sarai D. Folkestad, Dec 2021
2376
      !!
2377
      !! state guesses: {i=1, a=2}, {i=2, a=2}, {i=1, a=1}
2378
      !!
2379
      !! Provided as a (comma separated) list of sets.
2380
      !!
2381
      !! A set comprises of two elements which are
2382
      !! the occupied and virtual indices of the start vector
2383
      !!
2384
      !! 'i =' provides occupied index
2385
      !! 'a =' provides virtual index
2386
      !!
2387
      use string_utilities, only: remove_delimiter_from_string, split_at_delimiter
2388
      use string_utilities, only: n_instances_of_character
2389

2390
      implicit none
2391

2392
      class(input_tool) :: this
2393

2394
      integer, intent(in) :: n_states
2395
      integer, dimension(n_states), intent(out) :: virtual, occupied
2396

2397
      character(len=200) :: state_guesses
2398
      character(len=200), dimension(:), allocatable :: split_string
2399

2400
      integer :: n_elements, cursor_a, cursor_i, i, n_occupied, n_virtual
2401

2402
      call this%get_keyword('state guesses', 'solver cc es', state_guesses)
6✔
2403
      state_guesses = adjustl(state_guesses)
6✔
2404

2405
      n_occupied = n_instances_of_character(state_guesses, 'i')
6✔
2406
      n_virtual = n_instances_of_character(state_guesses, 'a')
6✔
2407

2408
      if (n_virtual /= n_occupied) &
6✔
UNCOV
2409
         call output%error_msg('in keyword (state guesses)')
×
2410

2411
      if (n_virtual /= n_states) &
6✔
UNCOV
2412
         call output%error_msg('in keyword (state guesses)')
×
2413

2414
      ! {i=1, a=2}, {i=2, a=2}, {i=1, a=1} -> i=1, a=2} i=2, a=2} i=1, a=1}
2415
      call remove_delimiter_from_string(state_guesses, '{')
6✔
2416

2417
      n_elements = n_instances_of_character(state_guesses, '}')
6✔
2418

2419
      if (n_elements /= n_states) &
6✔
UNCOV
2420
         call output%error_msg('in keyword (state guesses)')
×
2421

2422
      allocate(split_string(n_elements))
10✔
2423

2424
      ! i=1, a=2} i=2, a=2} i=1, a=1} -> string array ("i=1, a=2", "i=2, a=2", "i=1, a=1")
2425
      call split_at_delimiter(state_guesses, n_elements, split_string, '}')
6✔
2426

2427
      do i = 1, n_elements
18✔
2428

2429
         call remove_delimiter_from_string(split_string(i), '=')
12✔
2430
         call remove_delimiter_from_string(split_string(i), ',')
12✔
2431

2432
         cursor_i = first_index_of_substring(split_string(i), 'i')
12✔
2433
         cursor_a = first_index_of_substring(split_string(i), 'a')
12✔
2434

2435
         if (cursor_i < cursor_a) then
18✔
2436

2437
            read(split_string(i)(cursor_i + 1 : cursor_a -1), *) occupied(i)
6✔
2438
            read(split_string(i)(cursor_a + 1:), *) virtual(i)
6✔
2439

2440
         else
2441

2442
            read(split_string(i)(cursor_a + 1 : cursor_i -1), *) virtual(i)
6✔
2443
            read(split_string(i)(cursor_i + 1:), *) occupied(i)
6✔
2444

2445
         endif
2446

2447
      enddo
2448

2449
      deallocate(split_string)
6✔
2450

2451
   end subroutine get_state_guesses
6✔
2452

2453

2454
   subroutine check_for_errors(this)
3,169✔
2455
      !!
2456
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
2457
      !!
2458
      !! Looks for errors the user may have made when writing the input file.
2459
      !!
2460
      implicit none
2461

2462
      class(input_tool), intent(in) :: this
2463
      integer :: k
2464

2465
      do k = 1, size(this%sections)
133,098✔
2466

2467
         call this%sections(k)%check_section_for_illegal_keywords()
133,098✔
2468

2469
      enddo
2470

2471
   end subroutine check_for_errors
3,169✔
2472

2473

2474
   function is_section_recognized(this, section) result(allowed)
25,574✔
2475
      !!
2476
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2019-2021
2477
      !!
2478
      implicit none
2479

2480
      class(input_tool), intent(in) :: this
2481

2482
      character(len=*), intent(in) :: section
2483

2484
      logical :: allowed
2485

2486
      integer :: k
2487

2488
      allowed = .false.
2489

2490
      do k = 1, size(this%sections)
601,867✔
2491

2492
         if (this%sections(k)%name_ == trim(section)) then
601,867✔
2493
            allowed = .true.
2494
            return
2495
         end if
2496

2497
      enddo
2498

2499
   end function is_section_recognized
2500

2501

UNCOV
2502
   subroutine section_not_recognized(this, section)
×
2503
      !!
2504
      !! Written by Sara Angelico and Alexander C. Paul, 2023
2505
      !!
2506
      implicit none
2507

2508
      class(input_tool), intent(in) :: this
2509

2510
      character(len=*), intent(in) :: section
2511

2512
      call output%printf('m', 'Could not recognize section named "(a0)".', &
UNCOV
2513
                        chars=[trim(section)], fs='(/t3,a)')
×
2514
      call this%print_sections()
×
2515
      call output%error_msg('Something is wrong in the input file. See above.')
×
2516

UNCOV
2517
   end subroutine section_not_recognized
×
2518

2519

2520
   subroutine expect_set(string)
7,588✔
2521
      !!
2522
      !! Written by Alexander C. Paul, Mar 2023
2523
      !!
2524
      implicit none
2525

2526
      character(len=*), intent(in) :: string
2527
      integer :: opening, closing
2528

2529
      opening = index(string, '{')
7,588✔
2530
      if (opening == 0) call output%error_msg('Expected set, but no "{" found in string.')
7,588✔
2531

2532
      closing = index(string, '}')
7,588✔
2533
      if (closing == 0) call output%error_msg('Expected set, but no "}" found in string.')
7,588✔
2534

2535
      if (closing < opening) call output%error_msg('Expected set, but "}" found before "{".')
7,588✔
2536

2537
   end subroutine expect_set
7,588✔
2538

2539

2540
   subroutine expect_range(string)
396✔
2541
      !!
2542
      !! Written by Alexander C. Paul, Mar 2023
2543
      !!
2544
      implicit none
2545

2546
      character(len=*), intent(in) :: string
2547
      integer :: opening, closing, comma
2548

2549
      opening = index(string, '[')
396✔
2550
      if (opening == 0) call output%error_msg('Expected range, but no "[" found in string.')
396✔
2551

2552
      closing = index(string, ']')
396✔
2553
      if (closing == 0) call output%error_msg('Expected range, but no "]" found in string.')
396✔
2554

2555
      comma = index(string, ',')
396✔
2556
      if (comma == 0) call output%error_msg('Expected range, but no "," found in string.')
396✔
2557

2558
      if (comma < opening) call output%error_msg('Expected range, but "," found before "[".')
396✔
2559
      if (closing < comma) call output%error_msg('Expected range, but "]" found before ",".')
396✔
2560

2561
   end subroutine expect_range
396✔
2562

2563

2564
   subroutine set_section_keywords(this, section, section_lines)
25,574✔
2565
      !!
2566
      !! Written by Sara Angelico and Alexander C. Paul, Apr 2023
2567
      !!
2568
      !! This routine removes empty lines and comment lines and
2569
      !! sets the keywords for the section
2570
      !!
2571
      implicit none
2572

2573
      class(input_tool),                intent(inout) :: this
2574
      character(len=*),                 intent(in)    :: section
2575
      character(len=200), dimension(:), intent(in)    :: section_lines
2576

2577
      character(len=200), dimension(:), allocatable :: keyword_lines
2578
      character(len=200) :: line
2579
      integer :: section_index, n_lines, l
2580

2581
      allocate(keyword_lines, mold=section_lines)
51,148✔
2582

2583
      n_lines = 0
2584
      do l = 1, size(section_lines)
102,076✔
2585

2586
         line = trim(adjustl(section_lines(l)))
76,502✔
2587

2588
         if (string_starts_with(line, "!")) cycle
76,502✔
2589
         if (is_empty(line)) cycle
76,382✔
2590

2591
         line = remove_substring_after_symbol(line,'!')
50,598✔
2592

2593
         n_lines = n_lines + 1
50,598✔
2594
         keyword_lines(n_lines) = adjustl(line)
102,076✔
2595

2596
      end do
2597

2598
      section_index = this%get_section_index(trim(section))
25,574✔
2599

2600
      call this%sections(section_index)%set_keyword_lines(keyword_lines(1:n_lines))
25,574✔
2601

2602
      deallocate(keyword_lines)
25,574✔
2603

2604
   end subroutine set_section_keywords
25,574✔
2605

2606

2607
   subroutine check_get_array_for_keyword(keyword, section, n_elements)
5,362✔
2608
      !!
2609
      !! Written by Alexander C. Paul, May 2023
2610
      !!
2611
      implicit none
2612

2613
      character(len=*), intent(in) :: keyword, section
2614
      integer,          intent(in) :: n_elements
2615

2616
      if (n_elements .le. 0) then
5,362✔
2617
         call output%error_msg("Get array for keyword called with n_elements=(i0). &
2618
                              &Keyword: (a0) Section: " // section, &
UNCOV
2619
                               ints=[n_elements], chars=[keyword])
×
2620
      end if
2621

2622
   end subroutine check_get_array_for_keyword
5,362✔
2623

2624

UNCOV
2625
end module input_tool_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