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

eT-program / eT / 22378

05 Mar 2025 10:46PM UTC coverage: 88.56%. Remained the same
22378

push

gitlab-ci

Merge branch 'cas_qed_for_merge' into 'development'

qed cas

See merge request eT-program/eT!1529

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

116 existing lines in 8 files now uncovered.

53696 of 60632 relevant lines covered (88.56%)

3045562.41 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,229✔
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'])
54,893✔
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'])
74,267✔
242

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

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

252
      ! Set other sections in alphabetical order
253

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

273

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

282

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

301

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

315

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

323

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

344

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

352

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

359

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

368

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

377

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

393

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

405

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

417

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

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

431

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

441

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

457

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

464

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

488

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

500

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

507

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

515

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

524

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

533

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

544

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

570

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

587

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

604

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

624

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

633

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

645

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

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

668

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

679

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

696

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

721

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

734

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

746

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

756

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

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

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

822
   end function new_input_tool
3,229✔
823

824

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

831
      implicit none
832

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

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

837
      type(input_file_parser), allocatable :: file_parser
838

839
      file_parser = input_file_parser(file_name)
3,217✔
840

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

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

848
      deallocate(file_parser)
3,217✔
849

850
   end subroutine read_input
3,217✔
851

852

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

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

861
      call this%process_keyword_lines()
3,229✔
862
      call this%print_input_except_geometry()
3,229✔
863
      call this%check_for_errors()
3,229✔
864

865
   end subroutine process_input
3,229✔
866

867

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

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

876
      integer :: n
877

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

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

883
      do n = 1, this%n_keyword_lines
107,909✔
884

885
         call output%printf('m', this%keyword_lines(n), fs='(t6,a)', ll=120)
107,909✔
886

887
      enddo
888

889
   end subroutine print_input_except_geometry
3,229✔
890

891

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

898
      class(input_tool) :: this
899

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

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

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

909
      else
910

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

914
         this%n_qm_atom_lines = 1
6✔
915

916
      endif
917

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

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

923
      else
924

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

928
         this%n_keyword_lines = 1
6✔
929

930
      endif
931

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

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

937
      endif
938

939
   end subroutine set_input
12✔
940

941

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

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

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

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

954
      do i = 1, this%n_keyword_lines
107,909✔
955

956
         line = trim(adjustl(this%keyword_lines(i)))
104,680✔
957

958
         if (.not. string_starts_with(line, '-')) cycle
104,680✔
959

960
         start_ = i + 1
26,108✔
961
         section = trim(adjustl(line(2:)))
26,108✔
962

963
         section = remove_substring_after_symbol(section,"!")
26,108✔
964

965
         if (.not. this%is_section_recognized(section)) call this%section_not_recognized(section)
26,108✔
966

967
         end_ = this%n_keyword_lines
26,108✔
968
         do j = start_, this%n_keyword_lines
104,638✔
969

970
            section_line = trim(adjustl(this%keyword_lines(j)))
101,415✔
971

972
            if (.not. string_starts_with(section_line, '-')) cycle
101,415✔
973

974
            end_ = j - 1
22,885✔
975
            exit
104,638✔
976

977
         enddo
978

979
         call this%set_section_keywords(section, this%keyword_lines(start_:end_))
107,909✔
980

981
      enddo
982

983
   end subroutine process_keyword_lines
3,229✔
984

985

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

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

994
      integer :: k
995

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

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

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

1002
      enddo
1003

UNCOV
1004
   end subroutine print_sections
×
1005

1006

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

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

1015
      logical :: requested
1016

1017
      requested = this%requested_calculation(this%rf_wfs)
3,053✔
1018

1019
   end function requested_reference_calculation
3,053✔
1020

1021

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

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

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

1035
      logical :: requested
1036

1037
      integer :: n_wfs, k, section_index
1038

1039
      n_wfs = 0
1040

1041
      section_index = this%get_section_index('method')
7,448✔
1042

1043
      do k = 1, size(wfs)
72,895✔
1044

1045
         if (this%sections(section_index)%is_keyword_present(wfs(k))) then
72,895✔
1046

1047
            n_wfs = n_wfs + 1
5,534✔
1048

1049
         endif
1050

1051
      enddo
1052

1053
      requested = .false.
1054

1055
      if (n_wfs == 1) then
7,448✔
1056

1057
         requested = .true.
1058

1059
      elseif (n_wfs > 1) then
1,914✔
1060

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

1064
      endif
1065

1066
   end function requested_calculation
7,448✔
1067

1068

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

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

1077
      logical :: requested
1078

1079
      requested = this%requested_calculation(this%cc_wfs)
3,349✔
1080

1081
   end function requested_cc_calculation
3,349✔
1082

1083

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

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

1092
      logical :: requested
1093

1094
      requested = this%requested_calculation(this%ci_wfs)
1,046✔
1095

1096
   end function requested_ci_calculation
1,046✔
1097

1098

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

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

1107
      character(len=30) :: ref_wf
1108

1109
      ref_wf = this%get_wavefunction(this%rf_wfs)
3,211✔
1110

1111
   end function get_reference_wavefunction
3,211✔
1112

1113

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

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

1122
      character(len=30) :: cc_wf
1123

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

1126
   end function get_cc_wavefunction
2,061✔
1127

1128

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

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

1137
      character(len=30) :: ci_wf
1138

1139
      ci_wf = this%get_wavefunction(this%ci_wfs)
372✔
1140

1141
   end function get_ci_wavefunction
372✔
1142

1143

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

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

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

1156
      character(len=30) :: wf
1157

1158
      integer :: k, section_index
1159

1160
      section_index = this%get_section_index('method')
5,644✔
1161

1162
      do k = 1, size(wfs)
20,376✔
1163

1164
         if (this%sections(section_index)%is_keyword_present(wfs(k))) then
20,376✔
1165

1166
            wf = wfs(k)
5,644✔
1167
            return
5,644✔
1168

1169
         endif
1170

1171
      enddo
1172

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

1176
   end function get_wavefunction
1177

1178

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

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

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

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

1194
      character(len=200) :: keyword_value_string
1195

1196
      keyword_value_string = ""
28,074✔
1197
      call this%get_string_keyword(keyword, section, keyword_value_string)
28,074✔
1198

1199
      if (is_empty(keyword_value_string)) return
28,074✔
1200

1201
      read(keyword_value_string, *) keyword_value
4,283✔
1202

1203
   end subroutine get_32bit_integer_keyword
1204

1205

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

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

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

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

1221
      character(len=200) :: keyword_value_string
1222

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

1226
      if (is_empty(keyword_value_string)) return
59,901✔
1227

1228
      read(keyword_value_string, *) keyword_value
11,538✔
1229

1230
   end subroutine get_64bit_integer_keyword
1231

1232

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

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

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

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

1249
      character(len=200) :: keyword_value_string
1250

1251
      keyword_value_string = ""
502✔
1252
      call this%get_string_keyword(keyword, section, keyword_value_string)
502✔
1253

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

1258
      endif
1259

1260
      read(keyword_value_string, *) keyword_value
502✔
1261

1262
   end subroutine get_required_32bit_integer_keyword
502✔
1263

1264

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

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

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

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

1281
      character(len=200) :: keyword_value_string
1282

1283
      keyword_value_string = ""
1,056✔
1284
      call this%get_string_keyword(keyword, section, keyword_value_string)
1,056✔
1285

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

1290
      endif
1291

1292
      read(keyword_value_string, *) keyword_value
1,056✔
1293

1294
   end subroutine get_required_64bit_integer_keyword
1,056✔
1295

1296

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

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

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

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

1312
      character(len=200) :: keyword_value_string
1313

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

1317
      if (is_empty(keyword_value_string)) return
75,796✔
1318

1319
      read(keyword_value_string, *) keyword_value
61,755✔
1320

1321
   end subroutine get_real_dp_keyword
1322

1323

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

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

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

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

1340
      character(len=200) :: keyword_value_string
1341

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

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

1349
      endif
1350

1351
      read(keyword_value_string, *) keyword_value
486✔
1352

1353
   end subroutine get_required_real_dp_keyword
486✔
1354

1355

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

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

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

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

1372
      integer :: section_index
1373

1374
      section_index = this%get_section_index(section)
298,962✔
1375

1376
      keyword_value_string = this%sections(section_index)%get_string_keyword(keyword)
298,962✔
1377

1378
      ! Make sure not to overwrite defaults set on the outside
1379
      if (is_empty(keyword_value_string)) return
298,962✔
1380

1381
      keyword_value = keyword_value_string
109,211✔
1382

1383
   end subroutine get_string_keyword
1384

1385

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

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

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

1399
      character(len=200) :: keyword_value
1400

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

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

1408
      endif
1409

1410
   end subroutine get_required_string_keyword
756✔
1411

1412

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

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

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

1423
      integer :: index, i
1424

1425
      index = 0
1426

1427
      do i = 1, size(this%sections)
28,694,805✔
1428
         if(trim(this%sections(i)%name_) == trim(section)) then
28,694,805✔
1429
            index = i
1430
            return
1,030,354✔
1431
         end if
1432
      enddo
1433

UNCOV
1434
      call this%section_not_recognized(section)
×
1435

UNCOV
1436
   end function get_section_index
×
1437

1438

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

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

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

1452
      logical :: is_present
1453

1454
      integer :: section_index
1455

1456
      section_index = this%get_section_index(section)
650,578✔
1457

1458
      is_present = this%sections(section_index)%is_keyword_present(keyword)
650,578✔
1459

1460
   end function is_keyword_present_input_tool
650,578✔
1461

1462

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

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

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

1475
      logical :: is_present
1476

1477
      integer :: section_index
1478

1479
      section_index = this%get_section_index(section)
41,614✔
1480

1481
      is_present = this%sections(section_index)%is_section_present()
41,614✔
1482

1483
   end function is_section_present_input_tool
41,614✔
1484

1485

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

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

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

1504
      integer :: n_elements
1505

1506
      character(len=200) :: keyword_value_string
1507

1508
      n_elements = 0
1509

1510
      call this%get_keyword(keyword, section, keyword_value_string)
2,748✔
1511

1512
      n_elements = this%get_n_elements_in_set_or_range(keyword_value_string)
2,748✔
1513

1514
   end function get_n_elements_for_keyword
2,748✔
1515

1516

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

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

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

1537
      integer, intent(in) :: n_elements
1538

1539
      integer, dimension(n_elements) :: array_
1540

1541
      character(len=200) :: keyword_value_string
1542

1543
      call check_get_array_for_keyword(keyword, section, n_elements)
1,856✔
1544

1545
      call this%get_keyword(keyword, section, keyword_value_string)
1,856✔
1546

1547
      call this%get_integers_from_set_or_range(keyword_value_string, n_elements, array_)
1,856✔
1548

1549
   end subroutine get_integer_array_for_keyword
1,856✔
1550

1551

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

1566
      implicit none
1567

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

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

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

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

1579
      call check_get_array_for_keyword(keyword, section, n_elements)
4,100✔
1580

1581
      call this%get_keyword(keyword, section, keyword_value_string)
4,100✔
1582

1583
      string = trim(adjustl(keyword_value_string))
4,100✔
1584
      call this%expect_set(string)
4,100✔
1585

1586
      call read_comma_separated_list(string(2:len(string)-1), array_, n_elements)
4,100✔
1587

1588
   end subroutine get_real_array_for_keyword
4,100✔
1589

1590

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

1605
      implicit none
1606

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

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

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

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

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

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

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

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

1627
   end subroutine get_string_array_for_keyword
126✔
1628

1629

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

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

1641
      integer :: n_atoms
1642

1643
      integer :: record
1644

1645
      n_atoms = 0
1646

1647
      do record = 1, this%n_qm_atom_lines
19,792✔
1648

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

1654
      enddo
1655

1656
   end function get_n_atoms_input_tool
3,229✔
1657

1658

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

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

1668
      integer :: n_atoms
1669

1670
      n_atoms = this%n_mm_atom_lines
156✔
1671

1672
   end function  get_n_mm_atoms_input_tool
156✔
1673

1674

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

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

1685
      integer :: n_molecules
1686

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

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

1691
      previous_molecule = 1
1692
      n_molecules       = 1
1693

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

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

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

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

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

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

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

UNCOV
1711
            n_molecules = n_molecules + 1
×
1712

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

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

1720
         endif
1721

1722
         previous_molecule = current_molecule
78✔
1723

1724
      enddo
1725

1726
   end function get_n_mm_molecules_input_tool
78✔
1727

1728

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

1744
      implicit none
1745

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

1748
      integer, intent(in) :: n_atoms
1749

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

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

1757
      logical, intent(out) :: units_angstrom
1758

1759
      integer :: current_atom, i
1760

1761
      integer :: start_
1762

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

1767
      integer :: cursor
1768

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

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

1774
      units_angstrom = .true. ! Default units are Angstrom
3,229✔
1775
      charge = 0 ! Default charge is zero
16,307✔
1776

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

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

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

1783
            units_angstrom = .false.
220✔
1784

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

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

1789
         endif
1790

1791
         start_ = 2
1792

1793
      endif
1794

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

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

1800
      current_atom = 0
1801

1802
      do i = start_, this%n_qm_atom_lines
19,572✔
1803

1804
         string = trim(adjustl(this%qm_geometry(i)))
16,343✔
1805

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

1809
         if(string(1:6) == 'basis:') then
19,572✔
1810

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

1814
         elseif (string(1:5) == 'ghost') then
13,084✔
1815

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

1819
         else
1820

1821
            current_atom = current_atom + 1
13,078✔
1822

1823
            basis_sets(current_atom) = current_basis
13,078✔
1824
            symbols(current_atom)    = string(1:2)
13,078✔
1825
            is_ghost(current_atom)   = is_ghost_atom
13,078✔
1826

1827
            string = adjustl(string(3:200))
13,078✔
1828

1829
            if (is_substring_in_string(string, 'q')) then
13,078✔
1830

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

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

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

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

1843
               read(string(1:), *) positions(:, current_atom)
13,066✔
1844

1845
            endif
1846

1847
         endif
1848

1849
      enddo
1850

1851
      ! First character of symbol should be upper case
1852

1853
      do i = 1, n_atoms
16,307✔
1854

1855
         symbols(i)(1:1) = convert_character_to_uppercase(symbols(i)(1:1))
16,307✔
1856

1857
      enddo
1858

1859
   end subroutine get_geometry_input_tool
3,229✔
1860

1861

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

1877
      implicit none
1878

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

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

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

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

1893
      current_atom = 0
1894

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

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

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

1904
         ! Determine symbol
1905

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

1909
         ! Determine molecule index
1910

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

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

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

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

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

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

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

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

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

1936
         ! Determine chi
1937

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

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

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

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

1953
         ! Determine eta
1954

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

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

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

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

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

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

1974
         endif
1975

1976
      enddo
1977

1978
      ! First character of symbol should be upper case
1979

1980
      do i = 1, n_atoms
312✔
1981

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

1984
      enddo
1985

1986
   end subroutine get_mm_geometry_fq_input_tool
78✔
1987

1988

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

2003
      implicit none
2004

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

2007
      integer, intent(in) :: n_atoms
2008

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

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

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

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

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

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

2026
         ! Determine symbol
2027

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

2031
         ! Determine molecule index
2032

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

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

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

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

2048
         ! Determine position
2049

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

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

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

2057
         ! Determine charge
2058

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

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

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

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

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

2073
         endif
2074

2075
      enddo
2076

2077
      ! First character of symbol should be upper case
2078

2079
      do i = 1, n_atoms
312✔
2080

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

2083
      enddo
2084

2085
   end subroutine get_mm_geometry_non_polarizable_input_tool
78✔
2086

2087

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

2104
      implicit none
2105

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

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

2112
      logical :: in_list
2113

2114
      character(len=200) :: keyword_value_string
2115

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

2119
   end function string_in_array_keyword
414✔
2120

2121

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

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

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

2134
   end subroutine cleanup_input_tool
3,199✔
2135

2136

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

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

2147
      logical :: embedding
2148

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

2153
   end function is_embedding_on_input_tool
8,638✔
2154

2155

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

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

2170
      logical, intent(inout) :: records_in_memory
2171

2172
      character(len=200) :: storage
2173

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

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

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

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

2182
         records_in_memory = .true.
30✔
2183

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

UNCOV
2186
         records_in_memory = .false.
×
2187

2188
      else
2189

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

2193
      endif
2194

2195
   end subroutine place_records_in_memory_input_tool
2196

2197

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

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

2213
      integer :: n_elements
2214

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

2219
      n_set_start = 0
2220
      n_set_end   = 0
2221

2222
      n_range_start = 0
2223
      n_range_end   = 0
2224

2225
      string = adjustl(string)
6✔
2226

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

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

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

2235
      enddo
2236

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

2240
      n_elements = n_set_start + n_range_start
6✔
2241

2242
   end function get_n_sets_and_ranges
6✔
2243

2244

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

2256
      implicit none
2257

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

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

2262
      integer :: n_elements
2263

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

2267
      n_elements = 0
2268

2269
      string = adjustl(string)
2,748✔
2270

2271
      n_characters = len_trim(string)
2,748✔
2272

2273
      if (string_starts_with(string, '[')) then ! range
2,748✔
2274

2275
         call expect_range(string)
198✔
2276

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

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

2282
         n_elements = last - first + 1
198✔
2283

2284
      else if (string_starts_with(string, '{')) then ! set
2,550✔
2285

2286
         call this%expect_set(string)
2,436✔
2287

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

2291
      else ! Did not find list or range
2292

2293
         n_elements = 0
2294

2295
      endif
2296

2297
   end function get_n_elements_in_set_or_range
2,748✔
2298

2299

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

2310
      implicit none
2311

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

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

2316
      integer, intent(in) :: n_elements
2317

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

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

2323
      string = adjustl(string)
1,856✔
2324

2325
      n_characters = len_trim(string)
1,856✔
2326

2327
      if (string_starts_with(string, '[')) then ! range
1,856✔
2328

2329
         call expect_range(string)
198✔
2330

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

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

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

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

2341
      else if (string_starts_with(string, '{')) then ! set
1,658✔
2342

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

2346
      else ! Did not find list or range
2347

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

2350
      endif
2351

2352
   end subroutine get_integers_from_set_or_range
1,856✔
2353

2354

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

2361
      class(input_tool) :: this
2362

2363
      integer :: n_guesses
2364

2365
      character(len=200) :: state_guesses
2366

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

2369
      n_guesses = get_n_sets_and_ranges(state_guesses)
6✔
2370

2371
   end function get_n_state_guesses
6✔
2372

2373

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

2391
      implicit none
2392

2393
      class(input_tool) :: this
2394

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

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

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

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

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

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

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

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

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

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

2423
      allocate(split_string(n_elements))
10✔
2424

2425
      ! 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")
2426
      call split_at_delimiter(state_guesses, n_elements, split_string, '}')
6✔
2427

2428
      do i = 1, n_elements
18✔
2429

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

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

2436
         if (cursor_i < cursor_a) then
18✔
2437

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

2441
         else
2442

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

2446
         endif
2447

2448
      enddo
2449

2450
      deallocate(split_string)
6✔
2451

2452
   end subroutine get_state_guesses
6✔
2453

2454

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

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

2466
      do k = 1, size(this%sections)
135,618✔
2467

2468
         call this%sections(k)%check_section_for_illegal_keywords()
135,618✔
2469

2470
      enddo
2471

2472
   end subroutine check_for_errors
3,229✔
2473

2474

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

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

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

2485
      logical :: allowed
2486

2487
      integer :: k
2488

2489
      allowed = .false.
2490

2491
      do k = 1, size(this%sections)
612,409✔
2492

2493
         if (this%sections(k)%name_ == trim(section)) then
612,409✔
2494
            allowed = .true.
2495
            return
2496
         end if
2497

2498
      enddo
2499

2500
   end function is_section_recognized
2501

2502

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

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

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

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

UNCOV
2518
   end subroutine section_not_recognized
×
2519

2520

2521
   subroutine expect_set(string)
8,320✔
2522
      !!
2523
      !! Written by Alexander C. Paul, Mar 2023
2524
      !!
2525
      implicit none
2526

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

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

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

2536
      if (closing < opening) call output%error_msg('Expected set, but "}" found before "{".')
8,320✔
2537

2538
   end subroutine expect_set
8,320✔
2539

2540

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

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

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

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

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

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

2562
   end subroutine expect_range
396✔
2563

2564

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

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

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

2582
      allocate(keyword_lines, mold=section_lines)
52,216✔
2583

2584
      n_lines = 0
2585
      do l = 1, size(section_lines)
104,638✔
2586

2587
         line = trim(adjustl(section_lines(l)))
78,530✔
2588

2589
         if (string_starts_with(line, "!")) cycle
78,530✔
2590
         if (is_empty(line)) cycle
78,410✔
2591

2592
         line = remove_substring_after_symbol(line,'!')
52,092✔
2593

2594
         n_lines = n_lines + 1
52,092✔
2595
         keyword_lines(n_lines) = adjustl(line)
104,638✔
2596

2597
      end do
2598

2599
      section_index = this%get_section_index(trim(section))
26,108✔
2600

2601
      call this%sections(section_index)%set_keyword_lines(keyword_lines(1:n_lines))
26,108✔
2602

2603
      deallocate(keyword_lines)
26,108✔
2604

2605
   end subroutine set_section_keywords
26,108✔
2606

2607

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

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

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

2623
   end subroutine check_get_array_for_keyword
6,082✔
2624

2625

UNCOV
2626
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