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

eT-program / eT / 23895

04 Sep 2025 11:02PM UTC coverage: 88.582% (-0.02%) from 88.597%
23895

push

gitlab-ci

Merge branch 'cleanup-td-prints' into 'development'

Cleanup of oscillator and rotatory strengths output

See merge request eT-program/eT!1578

53979 of 60937 relevant lines covered (88.58%)

3115005.9 hits per line

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

91.07
/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, public :: get_present_keywords &
126
                        => get_present_keywords_input_tool
127

128
      procedure, private :: process_keyword_lines
129
      procedure, private :: set_section_keywords
130
      procedure, private :: check_for_errors
131

132
      procedure, private :: get_wavefunction
133
      procedure, private :: requested_calculation
134

135
      procedure, private :: get_section_index
136
      procedure, private :: print_sections
137

138
      procedure, private :: get_32bit_integer_keyword
139
      procedure, private :: get_64bit_integer_keyword
140
      procedure, private :: get_string_keyword
141
      procedure, private :: get_real_dp_keyword
142
      procedure, private :: get_required_string_keyword
143
      procedure, private :: get_required_32bit_integer_keyword
144
      procedure, private :: get_required_64bit_integer_keyword
145
      procedure, private :: get_required_real_dp_keyword
146

147
      procedure, private :: get_n_elements_in_set_or_range
148
      procedure, private :: get_integers_from_set_or_range
149

150
      procedure, private :: get_integer_array_for_keyword
151
      procedure, private :: get_real_array_for_keyword
152
      procedure, private :: get_string_array_for_keyword
153

154
      procedure, private, nopass :: expect_range
155
      procedure, private, nopass :: expect_set
156
      procedure, private, nopass :: check_get_array_for_keyword
157

158
      procedure, private :: is_section_recognized
159
      procedure, private :: section_not_recognized
160

161
   end type input_tool
162

163
   interface input_tool
164

165
      procedure :: new_input_tool
166

167
   end interface input_tool
168

169

170
contains
171

172

173
   function new_input_tool() result(this)
3,265✔
174
      !!
175
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, June 2018
176
      !!
177
      implicit none
178

179
      type(input_tool) :: this
180

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

223
      allocate(this%rf_wfs, source=[character(len=30) :: &
224
                                       'dft',            &
225
                                       'hf',             &
226
                                       'uhf',            &
227
                                       'mlhf',           &
228
                                       'qed-hf',         &
229
                                       'sc-qed-hf',      &
230
                                       'cuhf',           &
231
                                       'rohf'])
55,505✔
232

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

246
      allocate(this%ci_wfs, source=[character(len=30) :: 'casci',     &
247
                                                         'fci',       &
248
                                                         'qed-casci', &
249
                                                         'qed-fci'])
29,385✔
250

251
      method = section(name_            = 'method', &
252
                       required         = .false.,  &
253
                       allowed_keywords = [this%rf_wfs, this%cc_wfs, this%ci_wfs])
153,455✔
254

255
      ! Set other sections in alphabetical order
256

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

276

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

285

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

304

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

318

319
      cc_mean_value = section(name_            = 'cc mean value',           &
320
                              required         = .false.,                   &
321
                              allowed_keywords = [character(len=30) ::      &
322
                                                 'dipole',                  &
323
                                                 'quadrupole',              &
324
                                                 'molecular gradient'])
13,060✔
325

326

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

347

348
      cc_real_time = section(name_            = 'cc real time',       &
349
                             required         = .false.,              &
350
                             allowed_keywords = [character(len=30) :: &
351
                                                'propagation',        &
352
                                                'fft dipole moment',  &
353
                                                'fft electric field'])
13,060✔
354

355

356
      ci_mean_value = section(name_            = 'ci mean value',     &
357
                              required         = .false.,             &
358
                              allowed_keywords = [character(len=30) ::&
359
                                                 'dipole',            &
360
                                                 'quadrupole'])
9,795✔
361

362

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

371

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

380

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

396

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

408

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

420

421
      hf_mean_value = section(name_            = 'hf mean value',      &
422
                              required         = .false.,              &
423
                              allowed_keywords = [character(len=30) :: &
424
                                                 'dipole',             &
425
                                                 'molecular gradient', &
426
                                                 'quadrupole'])
13,060✔
427

428
      hf_response = section(name_            = 'hf response',        &
429
                            required         = .false.,              &
430
                            allowed_keywords = [character(len=30) :: &
431
                                              'shielding', &
432
                                              'dipole velocity',        &
433
                                              'rotatory strength',      &
434
                                              'polarizabilities'])
16,325✔
435

436

437
      integrals = section(name_            = 'integrals',          &
438
                          required         = .false.,              &
439
                          allowed_keywords = [character(len=30) :: &
440
                                             'cholesky storage',   &
441
                                             'eri storage',        &
442
                                             'mo eri in memory',   &
443
                                             'ri',                 &
444
                                             't1 eri in memory'])
19,590✔
445

446

447
      lanczos = section(name_            = 'lanczos',                &
448
                        required         = .false.,                  &
449
                        allowed_keywords = [character(len=30) ::     &
450
                                           'biorthogonalize last',   &
451
                                           'chain length',           &
452
                                           'deflation threshold',    &
453
                                           'lanczos normalization',  &
454
                                           'max energy',             &
455
                                           'min energy',             &
456
                                           'min transition strength',&
457
                                           'operators',              &
458
                                           'overlap threshold',      &
459
                                           'restart states',         &
460
                                           'skip convergence'])
39,180✔
461

462

463
      memory = section(name_            = 'memory',             &
464
                       required         = .false.,              &
465
                       allowed_keywords = [character(len=30) :: &
466
                                          'available',          &
467
                                          'unit'])
9,795✔
468

469

470
      mlcc = section(name_            = 'mlcc',                   &
471
                     required         = .false.,                  &
472
                     allowed_keywords = [character(len=30) ::     &
473
                                        'levels',                 &
474
                                        'cc2 orbitals',           &
475
                                        'ccsd orbitals',          &
476
                                        'cholesky threshold',     &
477
                                        'nto restart',            &
478
                                        'cnto restart',           &
479
                                        'orbital restart',        &
480
                                        'cnto occupied cc2',      &
481
                                        'cnto virtual cc2',       &
482
                                        'cnto occupied ccsd',     &
483
                                        'cnto virtual ccsd',      &
484
                                        'cnto states',            &
485
                                        'nto states',             &
486
                                        'nto occupied cc2',       &
487
                                        'nto occupied ccsd',      &
488
                                        'canonical virtual cc2',  &
489
                                        'canonical virtual ccsd', &
490
                                        'print ccs calculation',  &
491
                                        'print cc2 calculation'])
65,300✔
492

493

494
      mlhf = section(name_            = 'multilevel hf',            &
495
                     required         = .false.,                    &
496
                     allowed_keywords = [character(len=30) ::       &
497
                                        'initial hf optimization',  &
498
                                        'initial hf threshold',     &
499
                                        'print initial hf',         &
500
                                        'cholesky threshold',       &
501
                                        'project on minimal basis', &
502
                                        'cholesky virtuals',        &
503
                                        'no mo screening'])
26,120✔
504

505

506
      mm = section(name_            = 'molecular mechanics', &
507
                   required         = .false.,               &
508
                   allowed_keywords = [character(len=30) ::  &
509
                                      'forcefield',          &
510
                                      'algorithm '])
9,795✔
511

512

513
      orbital_localization = section(name_            = 'orbital localization', &
514
                                     required         = .false.,                &
515
                                     allowed_keywords = [character(len=30) ::   &
516
                                                         'orbitals',            &
517
                                                         'threshold',           &
518
                                                         'type'])
13,060✔
519

520

521
      pcm = section(name_            = 'pcm',                &
522
                    required         = .false.,              &
523
                    allowed_keywords = [character(len=30) :: &
524
                                       'solvent',            &
525
                                       'input',              &
526
                                       'tesserae area',      &
527
                                       'solver type'])
16,325✔
528

529

530
      print_ = section(name_            = 'print',               &
531
                       required         = .false.,               &
532
                       allowed_keywords = [character(len=30) ::  &
533
                                          'output print level ', &
534
                                          'timing print level ', &
535
                                          'full references',     &
536
                                          'z-matrix'])
16,325✔
537

538

539
      solver_cpp = section(name_    = 'solver cpp',                    &
540
                           required = .false.,                         &
541
                           allowed_keywords = [character(len=30) ::    &
542
                                              'max iterations',        &
543
                                              'max reduced dimension', &
544
                                              'residual minimization', &
545
                                              'residual threshold',    &
546
                                              'restart',               &
547
                                              'storage'])
22,855✔
548

549

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

575

576
      solver_cc_gs = section(name_            = 'solver cc gs',            &
577
                             required         = .false.,                   &
578
                             allowed_keywords = [character(len=30) ::      &
579
                                                'algorithm',               &
580
                                                'energy threshold',        &
581
                                                'residual threshold',      &
582
                                                'crop',                    &
583
                                                'micro iteration storage', &
584
                                                'max micro iterations',    &
585
                                                'multimodel newton',       &
586
                                                'rel micro threshold',     &
587
                                                'storage',                 &
588
                                                'max iterations',          &
589
                                                'diis dimension',          &
590
                                                'restart' ])
42,445✔
591

592

593
      solver_cc_multipliers = section(name_            = 'solver cc multipliers',   &
594
                                      required         = .false.,                   &
595
                                      allowed_keywords = [character(len=30) ::      &
596
                                                         'algorithm',               &
597
                                                         'threshold',               &
598
                                                         'storage',                 &
599
                                                         'crop',                    &
600
                                                         'micro iteration storage', &
601
                                                         'max micro iterations',    &
602
                                                         'multimodel newton',       &
603
                                                         'rel micro threshold',     &
604
                                                         'diis dimension',          &
605
                                                         'restart',                 &
606
                                                         'max reduced dimension',   &
607
                                                         'max iterations'])
42,445✔
608

609

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

629

630
      solver_cc_response = section(name_            = 'solver cc response', &
631
                                   required         = .false.,              &
632
                                   allowed_keywords = [character(len=30) :: &
633
                                                      'threshold',          &
634
                                                      'gradient response threshold', &
635
                                                      'storage',            &
636
                                                      'max iterations'])
16,325✔
637

638

639
      solver_cholesky = section(name_            = 'solver cholesky',    &
640
                                required         = .false.,              &
641
                                allowed_keywords = [character(len=30) :: &
642
                                                   'threshold',          &
643
                                                   'span',               &
644
                                                   'batches',            &
645
                                                   'qualified',          &
646
                                                   'one center',         &
647
                                                   'diagonal test',      &
648
                                                   'mo screening'])
26,120✔
649

650

651
      solver_ci = section(name_            = 'solver ci',              &
652
                          required         = .false.,                  &
653
                          allowed_keywords = [character(len=30) ::     &
654
                                              'energy threshold ',     &
655
                                              'max iterations',        &
656
                                              'max reduced dimension', &
657
                                              'residual threshold',    &
658
                                              'restart',               &
659
                                              'start guess',           &
660
                                              'states',                &
661
                                              'storage'])
29,385✔
662

663
      solver_fft_dipole_moment = section(name_            = 'solver fft dipole moment', &
664
                                         required         = .false.,                    &
665
                                         allowed_keywords = [character(len=30) ::       &
666
                                                            'initial time',             &
667
                                                            'final time',               &
668
                                                            'time step',                &
669
                                                            'padding initial time',     &
670
                                                            'hann window',              &
671
                                                            'rectangular window'])
22,855✔
672

673

674
      solver_fft_electric_field = section(name_            = 'solver fft electric field', &
675
                                          required         = .false.,                     &
676
                                          allowed_keywords = [character(len=30) ::        &
677
                                                             'initial time',              &
678
                                                             'final time',                &
679
                                                             'time step',                 &
680
                                                             'padding initial time',      &
681
                                                             'hann window',               &
682
                                                             'rectangular window'])
22,855✔
683

684

685
      solver_geoopt = section(name_            = 'solver geometry optimization',              &
686
                              required         = .false.,                      &
687
                              allowed_keywords = [character(len=30) ::         &
688
                                                 'algorithm',                  &
689
                                                 'energy threshold',           &
690
                                                 'residual threshold',         &
691
                                                 'residual rms threshold',     &
692
                                                 'state',                      &
693
                                                 'max iterations',             &
694
                                                 'max step',                   &
695
                                                 'gradient method',            &
696
                                                 'restart',                    &
697
                                                 'step size',                  &
698
                                                 'displacement threshold',     &
699
                                                 'displacement rms threshold'])
42,445✔
700

701

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

726

727
      solver_hf_es = section(name_            = 'solver hf es',         &
728
                               required         = .false.,                  &
729
                               allowed_keywords = [character(len=30) ::     &
730
                                                  'energy threshold',       &
731
                                                  'max iterations',         &
732
                                                  'max reduced dimension',  &
733
                                                  'residual threshold',     &
734
                                                  'restart',                &
735
                                                  'storage',                &
736
                                                  'singlet states',         &
737
                                                  'tamm-dancoff'])
29,385✔
738

739

740
      solver_hf_response = section(name_           = 'solver hf response',       &
741
                                  required         = .false.,                    &
742
                                  allowed_keywords = [character(len=30) ::       &
743
                                                        'frequencies',           &
744
                                                        'max iterations',        &
745
                                                        'max reduced dimension', &
746
                                                        'print iterations',      &
747
                                                        'residual threshold',    &
748
                                                        'restart',               &
749
                                                        'storage'])
26,120✔
750

751

752
      system = section(name_            = 'system',               &
753
                       required         = .false.,                &
754
                       allowed_keywords = [character(len=30) ::   &
755
                                          'cartesian gaussians',  &
756
                                          'write orbitals',       &
757
                                          'pure gaussians',       &
758
                                          'charge',               &
759
                                          'multiplicity'])
19,590✔
760

761

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

783
      ! Gather all sections into the file's section array
784

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

827
   end function new_input_tool
3,265✔
828

829

830
   subroutine read_input(this, file_name)
3,253✔
831
      !!
832
      !! Written by Eirik F. Kjønstad, May 2022
833
      !!
834
      use input_file_parser_class, only: input_file_parser
835

836
      implicit none
837

838
      class(input_tool), intent(inout) :: this
839

840
      character(len=*), intent(in) :: file_name
841

842
      type(input_file_parser), allocatable :: file_parser
843

844
      file_parser = input_file_parser(file_name)
3,253✔
845

846
      call file_parser%read_and_process_input_file()
3,253✔
847
      call file_parser%get_keyword_lines(this%keyword_lines, this%n_keyword_lines)
3,253✔
848
      call file_parser%get_qm_geometry_lines(this%qm_geometry, this%n_qm_atom_lines)
3,253✔
849

850
      if (file_parser%is_mm_geometry_present()) &
3,253✔
851
         call file_parser%get_mm_geometry_lines(this%mm_geometry, this%n_mm_atom_lines)
96✔
852

853
      deallocate(file_parser)
3,253✔
854

855
   end subroutine read_input
3,253✔
856

857

858
   subroutine process_input(this)
3,265✔
859
      !!
860
      !! Written by Eirik F. Kjønstad, Mar 2024
861
      !!
862
      implicit none
863

864
      class(input_tool), intent(inout) :: this
865

866
      call this%process_keyword_lines()
3,265✔
867
      call this%print_input_except_geometry()
3,265✔
868
      call this%check_for_errors()
3,265✔
869

870
   end subroutine process_input
3,265✔
871

872

873
   subroutine print_input_except_geometry(this)
3,265✔
874
      !!
875
      !! Written by Eirik F. Kjønstad, May 2022
876
      !!
877
      implicit none
878

879
      class(input_tool), intent(in) :: this
880

881
      integer :: n
882

883
      call output%printf('m', ':: Input file', fs='(//t3,a)')
3,265✔
884
      call output%print_separator('m', 13, '=', fs='(t3,a/)')
3,265✔
885

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

888
      do n = 1, this%n_keyword_lines
108,384✔
889

890
         call output%printf('m', this%keyword_lines(n), fs='(t6,a)', ll=120)
108,384✔
891

892
      enddo
893

894
   end subroutine print_input_except_geometry
3,265✔
895

896

897
   subroutine set_input(this, keywords, geometry, mm_geometry)
12✔
898
      !!
899
      !! Written by Eirik F. Kjønstad, Mar 2024
900
      !!
901
      implicit none
902

903
      class(input_tool) :: this
904

905
      character(len=200), dimension(:), intent(in), optional :: keywords
906
      character(len=200), dimension(:), intent(in), optional :: geometry
907
      character(len=200), dimension(:), intent(in), optional :: mm_geometry
908

909
      if (present(geometry)) then
12✔
910

911
         this%qm_geometry = geometry
30✔
912
         this%n_qm_atom_lines = size(geometry)
6✔
913

914
      else
915

916
         allocate(this%qm_geometry, &
×
917
                  source=[character(len=200) :: '! no geometry'])
18✔
918

919
         this%n_qm_atom_lines = 1
6✔
920

921
      endif
922

923
      if (present(keywords)) then
12✔
924

925
         this%keyword_lines = keywords
24✔
926
         this%n_keyword_lines = size(keywords)
6✔
927

928
      else
929

930
         allocate(this%keyword_lines, &
×
931
                  source=[character(len=200) :: '! no input keywords'])
18✔
932

933
         this%n_keyword_lines = 1
6✔
934

935
      endif
936

937
      if (present(mm_geometry)) then
12✔
938

939
         this%mm_geometry = mm_geometry
×
940
         this%n_mm_atom_lines = size(mm_geometry)
×
941

942
      endif
943

944
   end subroutine set_input
12✔
945

946

947
   subroutine process_keyword_lines(this)
3,265✔
948
      !!
949
      !! Written by Sara Angelico and Alexander C. Paul, 2023
950
      !!
951
      implicit none
952

953
      class(input_tool), intent(inout) :: this
954

955
      integer :: start_, end_, i, j
956

957
      character(len=200) :: section, line, section_line
958

959
      do i = 1, this%n_keyword_lines
108,384✔
960

961
         line = trim(adjustl(this%keyword_lines(i)))
105,119✔
962

963
         if (.not. string_starts_with(line, '-')) cycle
105,119✔
964

965
         start_ = i + 1
26,350✔
966
         section = trim(adjustl(line(2:)))
26,350✔
967

968
         section = remove_substring_after_symbol(section,"!")
26,350✔
969

970
         if (.not. this%is_section_recognized(section)) call this%section_not_recognized(section)
26,350✔
971

972
         end_ = this%n_keyword_lines
26,350✔
973
         do j = start_, this%n_keyword_lines
105,077✔
974

975
            section_line = trim(adjustl(this%keyword_lines(j)))
101,818✔
976

977
            if (.not. string_starts_with(section_line, '-')) cycle
101,818✔
978

979
            end_ = j - 1
23,091✔
980
            exit
105,077✔
981

982
         enddo
983

984
         call this%set_section_keywords(section, this%keyword_lines(start_:end_))
108,384✔
985

986
      enddo
987

988
   end subroutine process_keyword_lines
3,265✔
989

990

991
   subroutine print_sections(this)
×
992
      !!
993
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
994
      !!
995
      implicit none
996

997
      class(input_tool), intent(in) :: this
998

999
      integer :: k
1000

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

1003
      do k = 1, size(this%sections)
×
1004

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

1007
      enddo
1008

1009
   end subroutine print_sections
×
1010

1011

1012
   function requested_reference_calculation(this) result(requested)
3,089✔
1013
      !!
1014
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1015
      !!
1016
      implicit none
1017

1018
      class(input_tool), intent(in) :: this
1019

1020
      logical :: requested
1021

1022
      requested = this%requested_calculation(this%rf_wfs)
3,089✔
1023

1024
   end function requested_reference_calculation
3,089✔
1025

1026

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

1036
      class(input_tool), intent(in) :: this
1037

1038
      character(len=30), dimension(:), intent(in) :: wfs
1039

1040
      logical :: requested
1041

1042
      integer :: n_wfs, k, section_index
1043

1044
      n_wfs = 0
1045

1046
      section_index = this%get_section_index('method')
7,550✔
1047

1048
      do k = 1, size(wfs)
73,801✔
1049

1050
         if (this%sections(section_index)%is_keyword_present(wfs(k))) then
73,801✔
1051

1052
            n_wfs = n_wfs + 1
5,576✔
1053

1054
         endif
1055

1056
      enddo
1057

1058
      requested = .false.
1059

1060
      if (n_wfs == 1) then
7,550✔
1061

1062
         requested = .true.
1063

1064
      elseif (n_wfs > 1) then
1,974✔
1065

1066
         call output%error_msg('Requested more than one method &
1067
                               &of a single kind (e.g., two CC methods).')
×
1068

1069
      endif
1070

1071
   end function requested_calculation
7,550✔
1072

1073

1074
   function requested_cc_calculation(this) result(requested)
3,385✔
1075
      !!
1076
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1077
      !!
1078
      implicit none
1079

1080
      class(input_tool), intent(in) :: this
1081

1082
      logical :: requested
1083

1084
      requested = this%requested_calculation(this%cc_wfs)
3,385✔
1085

1086
   end function requested_cc_calculation
3,385✔
1087

1088

1089
   function requested_ci_calculation(this) result(requested)
1,076✔
1090
      !!
1091
      !! Written by Enrico Ronca, 2020
1092
      !!
1093
      implicit none
1094

1095
      class(input_tool), intent(in) :: this
1096

1097
      logical :: requested
1098

1099
      requested = this%requested_calculation(this%ci_wfs)
1,076✔
1100

1101
   end function requested_ci_calculation
1,076✔
1102

1103

1104
   function get_reference_wavefunction(this) result(ref_wf)
3,247✔
1105
      !!
1106
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1107
      !!
1108
      implicit none
1109

1110
      class(input_tool), intent(in) :: this
1111

1112
      character(len=30) :: ref_wf
1113

1114
      ref_wf = this%get_wavefunction(this%rf_wfs)
3,247✔
1115

1116
   end function get_reference_wavefunction
3,247✔
1117

1118

1119
   function get_cc_wavefunction(this) result(cc_wf)
2,067✔
1120
      !!
1121
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1122
      !!
1123
      implicit none
1124

1125
      class(input_tool), intent(in) :: this
1126

1127
      character(len=30) :: cc_wf
1128

1129
      cc_wf = this%get_wavefunction(this%cc_wfs)
2,067✔
1130

1131
   end function get_cc_wavefunction
2,067✔
1132

1133

1134
   function get_ci_wavefunction(this) result(ci_wf)
372✔
1135
      !!
1136
      !! Written by Enrico Ronca, Apr 2020
1137
      !!
1138
      implicit none
1139

1140
      class(input_tool), intent(in) :: this
1141

1142
      character(len=30) :: ci_wf
1143

1144
      ci_wf = this%get_wavefunction(this%ci_wfs)
372✔
1145

1146
   end function get_ci_wavefunction
372✔
1147

1148

1149
   function get_wavefunction(this, wfs) result(wf)
5,686✔
1150
      !!
1151
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Apr 2019
1152
      !!
1153
      !! Looks for wfs(k) in the 'method' section of the input.
1154
      !!
1155
      implicit none
1156

1157
      class(input_tool), intent(in) :: this
1158

1159
      character(len=30), dimension(:), intent(in) :: wfs
1160

1161
      character(len=30) :: wf
1162

1163
      integer :: k, section_index
1164

1165
      section_index = this%get_section_index('method')
5,686✔
1166

1167
      do k = 1, size(wfs)
20,550✔
1168

1169
         if (this%sections(section_index)%is_keyword_present(wfs(k))) then
20,550✔
1170

1171
            wf = wfs(k)
5,686✔
1172
            return
5,686✔
1173

1174
         endif
1175

1176
      enddo
1177

1178
      call output%error_msg('Failed to read wavefunction from input. &
1179
         & Did you forget to specify all wavefunctions for the calculation?')
×
1180

1181
   end function get_wavefunction
1182

1183

1184
   subroutine get_32bit_integer_keyword(this, keyword, section, keyword_value)
28,166✔
1185
      !!
1186
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1187
      !!
1188
      !! If specified, reads keyword as an integer into keyword value.
1189
      !!
1190
      implicit none
1191

1192
      class(input_tool), intent(in) :: this
1193

1194
      character(len=*), intent(in) :: keyword
1195
      character(len=*), intent(in) :: section
1196

1197
      integer(i32), intent(inout) :: keyword_value
1198

1199
      character(len=200) :: keyword_value_string
1200

1201
      keyword_value_string = ""
28,166✔
1202
      call this%get_string_keyword(keyword, section, keyword_value_string)
28,166✔
1203

1204
      if (is_empty(keyword_value_string)) return
28,166✔
1205

1206
      read(keyword_value_string, *) keyword_value
4,307✔
1207

1208
   end subroutine get_32bit_integer_keyword
1209

1210

1211
   subroutine get_64bit_integer_keyword(this, keyword, section, keyword_value)
60,225✔
1212
      !!
1213
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1214
      !!
1215
      !! If specified, reads keyword as an integer into keyword value.
1216
      !!
1217
      implicit none
1218

1219
      class(input_tool), intent(in) :: this
1220

1221
      character(len=*), intent(in) :: keyword
1222
      character(len=*), intent(in) :: section
1223

1224
      integer(i64), intent(inout) :: keyword_value
1225

1226
      character(len=200) :: keyword_value_string
1227

1228
      keyword_value_string = ""
60,225✔
1229
      call this%get_string_keyword(keyword, section, keyword_value_string)
60,225✔
1230

1231
      if (is_empty(keyword_value_string)) return
60,225✔
1232

1233
      read(keyword_value_string, *) keyword_value
11,636✔
1234

1235
   end subroutine get_64bit_integer_keyword
1236

1237

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

1247
      class(input_tool), intent(in) :: this
1248

1249
      character(len=*), intent(in) :: keyword
1250
      character(len=*), intent(in) :: section
1251

1252
      integer(i32), intent(inout) :: keyword_value
1253

1254
      character(len=200) :: keyword_value_string
1255

1256
      keyword_value_string = ""
504✔
1257
      call this%get_string_keyword(keyword, section, keyword_value_string)
504✔
1258

1259
      if (is_empty(keyword_value_string)) then
504✔
1260
         call output%error_msg('could not find the required keyword '// trim(keyword) // &
1261
                               ' in section ' // trim(section))
×
1262

1263
      endif
1264

1265
      read(keyword_value_string, *) keyword_value
504✔
1266

1267
   end subroutine get_required_32bit_integer_keyword
504✔
1268

1269

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

1279
      class(input_tool), intent(in) :: this
1280

1281
      character(len=*), intent(in) :: keyword
1282
      character(len=*), intent(in) :: section
1283

1284
      integer(i64), intent(out) :: keyword_value
1285

1286
      character(len=200) :: keyword_value_string
1287

1288
      keyword_value_string = ""
1,068✔
1289
      call this%get_string_keyword(keyword, section, keyword_value_string)
1,068✔
1290

1291
      if (is_empty(keyword_value_string)) then
1,068✔
1292
         call output%error_msg('could not find the required keyword '// trim(keyword) // &
1293
                               ' in section ' // trim(section))
×
1294

1295
      endif
1296

1297
      read(keyword_value_string, *) keyword_value
1,068✔
1298

1299
   end subroutine get_required_64bit_integer_keyword
1,068✔
1300

1301

1302
   subroutine get_real_dp_keyword(this, keyword, section, keyword_value)
76,072✔
1303
      !!
1304
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1305
      !!
1306
      !! If specified, reads keyword as a real double precision into keyword value.
1307
      !!
1308
      implicit none
1309

1310
      class(input_tool), intent(in) :: this
1311

1312
      character(len=*), intent(in) :: keyword
1313
      character(len=*), intent(in) :: section
1314

1315
      real(dp), intent(inout) :: keyword_value
1316

1317
      character(len=200) :: keyword_value_string
1318

1319
      keyword_value_string = ""
76,072✔
1320
      call this%get_string_keyword(keyword, section, keyword_value_string)
76,072✔
1321

1322
      if (is_empty(keyword_value_string)) return
76,072✔
1323

1324
      read(keyword_value_string, *) keyword_value
61,971✔
1325

1326
   end subroutine get_real_dp_keyword
1327

1328

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

1338
      class(input_tool), intent(in) :: this
1339

1340
      character(len=*), intent(in) :: keyword
1341
      character(len=*), intent(in) :: section
1342

1343
      real(dp), intent(out) :: keyword_value
1344

1345
      character(len=200) :: keyword_value_string
1346

1347
      keyword_value_string = ""
486✔
1348
      call this%get_string_keyword(keyword, section, keyword_value_string)
486✔
1349

1350
      if (is_empty(keyword_value_string)) then
486✔
1351
         call output%error_msg('could not find the required keyword '// trim(keyword) // &
1352
                               ' in section ' // trim(section))
×
1353

1354
      endif
1355

1356
      read(keyword_value_string, *) keyword_value
486✔
1357

1358
   end subroutine get_required_real_dp_keyword
486✔
1359

1360

1361
   subroutine get_string_keyword(this, keyword, section, keyword_value)
300,342✔
1362
      !!
1363
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1364
      !!
1365
      !! If specified, reads keyword as a string into keyword value.
1366
      !!
1367
      implicit none
1368

1369
      class(input_tool), intent(in) :: this
1370

1371
      character(len=*), intent(in) :: keyword
1372
      character(len=*), intent(in) :: section
1373

1374
      character(len=200), intent(inout) :: keyword_value
1375
      character(len=200) :: keyword_value_string
1376

1377
      integer :: section_index
1378

1379
      section_index = this%get_section_index(section)
300,342✔
1380

1381
      keyword_value_string = this%sections(section_index)%get_string_keyword(keyword)
300,342✔
1382

1383
      ! Make sure not to overwrite defaults set on the outside
1384
      if (is_empty(keyword_value_string)) return
300,342✔
1385

1386
      keyword_value = keyword_value_string
109,713✔
1387

1388
   end subroutine get_string_keyword
1389

1390

1391
   subroutine get_required_string_keyword(this, keyword, section, keyword_value)
756✔
1392
      !!
1393
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1394
      !!
1395
      !! If specified, reads keyword as a string into keyword value.
1396
      !!
1397
      implicit none
1398

1399
      class(input_tool), intent(in) :: this
1400

1401
      character(len=*), intent(in) :: keyword
1402
      character(len=*), intent(in) :: section
1403

1404
      character(len=200) :: keyword_value
1405

1406
      keyword_value = ""
756✔
1407
      call this%get_string_keyword(keyword, section, keyword_value)
756✔
1408

1409
      if (is_empty(keyword_value)) then
756✔
1410
         call output%error_msg('could not find the required keyword '// trim(keyword) // &
1411
                               ' in section ' // trim(section))
×
1412

1413
      endif
1414

1415
   end subroutine get_required_string_keyword
756✔
1416

1417

1418
   function get_section_index(this, section) result(index)
1,039,654✔
1419
      !!
1420
      !! Written by Sara Angelico and Alexander C. Paul, Feb 2023
1421
      !!
1422
      implicit none
1423

1424
      class(input_tool), intent(in) :: this
1425

1426
      character(len=*), intent(in) :: section
1427

1428
      integer :: index, i
1429

1430
      index = 0
1431

1432
      do i = 1, size(this%sections)
28,864,206✔
1433
         if(trim(this%sections(i)%name_) == trim(section)) then
28,864,206✔
1434
            index = i
1435
            return
1,039,654✔
1436
         end if
1437
      enddo
1438

1439
      call this%section_not_recognized(section)
×
1440

1441
   end function get_section_index
×
1442

1443

1444
   function is_keyword_present_input_tool(this, keyword, section) result(is_present)
654,601✔
1445
      !!
1446
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1447
      !!
1448
      !! Returns true if the keyword is in the section.
1449
      !!
1450
      implicit none
1451

1452
      class(input_tool), intent(in) :: this
1453

1454
      character(len=*), intent(in) :: keyword
1455
      character(len=*), intent(in) :: section
1456

1457
      logical :: is_present
1458

1459
      integer :: section_index
1460

1461
      section_index = this%get_section_index(section)
654,601✔
1462

1463
      is_present = this%sections(section_index)%is_keyword_present(keyword)
654,601✔
1464

1465
   end function is_keyword_present_input_tool
654,601✔
1466

1467

1468
   subroutine get_present_keywords_input_tool(this, section, keywords)
3,253✔
1469
      !!
1470
      !! Written by Leo Stoll, 2025
1471
      !!
1472
      !! For a given section returns the keywords given in the input file.
1473
      !!
1474
      implicit none
1475

1476
      class(input_tool), intent(inout) :: this
1477

1478
      character(len=*), intent(in) :: section
1479

1480
      character(len=200), dimension(:), allocatable, intent(inout) :: keywords
1481

1482
      integer :: section_index
1483

1484
      section_index = this%get_section_index(section)
3,253✔
1485

1486
      keywords = this%sections(section_index)%get_present_keywords()
9,927✔
1487

1488
   end subroutine get_present_keywords_input_tool
3,253✔
1489

1490

1491
   function is_section_present_input_tool(this, section) result(is_present)
41,872✔
1492
      !!
1493
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1494
      !!
1495
      !! Returns true if the section exists, false if it doesn't.
1496
      !!
1497
      implicit none
1498

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

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

1503
      logical :: is_present
1504

1505
      integer :: section_index
1506

1507
      section_index = this%get_section_index(section)
41,872✔
1508

1509
      is_present = this%sections(section_index)%is_section_present()
41,872✔
1510

1511
   end function is_section_present_input_tool
41,872✔
1512

1513

1514
   function get_n_elements_for_keyword(this, keyword, section) result(n_elements)
2,748✔
1515
      !!
1516
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1517
      !!
1518
      !! Gets the number of elements specified for a keyword in set/range notation
1519
      !!
1520
      !! Ranges should always be given as [a,b].
1521
      !! Lists should always be given as {a, b, c, d}.
1522
      !!
1523
      !! Function is called in preparation for get_array_for_keyword
1524
      !!
1525
      implicit none
1526

1527
      class(input_tool), intent(in) :: this
1528

1529
      character(len=*), intent(in) :: keyword
1530
      character(len=*), intent(in) :: section
1531

1532
      integer :: n_elements
1533

1534
      character(len=200) :: keyword_value_string
1535

1536
      n_elements = 0
1537

1538
      call this%get_keyword(keyword, section, keyword_value_string)
2,748✔
1539

1540
      n_elements = this%get_n_elements_in_set_or_range(keyword_value_string)
2,748✔
1541

1542
   end function get_n_elements_for_keyword
2,748✔
1543

1544

1545
   subroutine get_integer_array_for_keyword(this, keyword, section, n_elements, array_)
1,856✔
1546
      !!
1547
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1548
      !!
1549
      !! Gets input variable array (array_) for keyword which is specified on input
1550
      !! by either an integer range or list (of length n_elements).
1551
      !!
1552
      !! Ranges should always be given as [a,b].
1553
      !! Lists should always be given as {a, b, c, d}.
1554
      !!
1555
      !! Routine should be called after the get_n_elements_for_keyword is called
1556
      !! in order to determine n_elements so that array_ can be allocated.
1557
      !!
1558
      implicit none
1559

1560
      class(input_tool), intent(in) :: this
1561

1562
      character(len=*), intent(in) :: keyword
1563
      character(len=*), intent(in) :: section
1564

1565
      integer, intent(in) :: n_elements
1566

1567
      integer, dimension(n_elements) :: array_
1568

1569
      character(len=200) :: keyword_value_string
1570

1571
      call check_get_array_for_keyword(keyword, section, n_elements)
1,856✔
1572

1573
      call this%get_keyword(keyword, section, keyword_value_string)
1,856✔
1574

1575
      call this%get_integers_from_set_or_range(keyword_value_string, n_elements, array_)
1,856✔
1576

1577
   end subroutine get_integer_array_for_keyword
1,856✔
1578

1579

1580
   subroutine get_real_array_for_keyword(this, keyword, section, n_elements, array_)
4,142✔
1581
      !!
1582
      !! Written by Sarai D. Folkestad, Eirik F. Kjønstad, Andreas Skeidsvoll and Alexander C. Paul, 2019-2023
1583
      !!
1584
      !! Gets input variable array (array_) for keyword
1585
      !! which is specified on input by a list
1586
      !!
1587
      !! Lists should always be given as {a, b, c, d}
1588
      !!
1589
      !! Routine should be called after the get_n_elements_for_keyword is called
1590
      !! in order to determine n_elements so that array_ can be allocated.
1591
      !!
1592
      use string_utilities, only: read_comma_separated_list
1593

1594
      implicit none
1595

1596
      class(input_tool), intent(in) :: this
1597

1598
      character(len=*), intent(in) :: keyword
1599
      character(len=*), intent(in) :: section
1600
      integer,          intent(in) :: n_elements
1601

1602
      real(dp), dimension(n_elements), intent(inout) :: array_
1603

1604
      character(len=200) :: keyword_value_string
1605
      character(len=:), allocatable :: string
1606

1607
      call check_get_array_for_keyword(keyword, section, n_elements)
4,142✔
1608

1609
      call this%get_keyword(keyword, section, keyword_value_string)
4,142✔
1610

1611
      string = trim(adjustl(keyword_value_string))
4,142✔
1612
      call this%expect_set(string)
4,142✔
1613

1614
      call read_comma_separated_list(string(2:len(string)-1), array_, n_elements)
4,142✔
1615

1616
   end subroutine get_real_array_for_keyword
4,142✔
1617

1618

1619
   subroutine get_string_array_for_keyword(this, keyword, section, n_elements, array_)
126✔
1620
      !!
1621
      !! Written by Anna Kristina Schnack-Petersen and Alexander C. Paul, 2022-2023
1622
      !!
1623
      !! Gets input variable array (array_) for keyword which is specified on input
1624
      !! by a list of strings (of length n_elements).
1625
      !!
1626
      !! Lists should always be given as {a, b, c, d}
1627
      !!
1628
      !! Routine should be called after the get_n_elements_for_keyword is called
1629
      !! in order to determine n_elements so that array_ can be allocated.
1630
      !!
1631
      use string_utilities, only: split_at_delimiter
1632

1633
      implicit none
1634

1635
      class(input_tool), intent(in) :: this
1636

1637
      character(len=*), intent(in) :: keyword
1638
      character(len=*), intent(in) :: section
1639
      integer,          intent(in) :: n_elements
1640

1641
      character(len=200), dimension(n_elements), intent(inout) :: array_
1642

1643
      character(len=200)            :: keyword_value_string
1644
      character(len=:), allocatable :: string
1645

1646
      call check_get_array_for_keyword(keyword, section, n_elements)
126✔
1647

1648
      call this%get_keyword(keyword, section, keyword_value_string)
126✔
1649

1650
      string = trim(adjustl(keyword_value_string))
126✔
1651
      call this%expect_set(string)
126✔
1652

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

1655
   end subroutine get_string_array_for_keyword
126✔
1656

1657

1658
   pure function get_n_atoms_input_tool(this) result(n_atoms)
3,265✔
1659
      !!
1660
      !! Get n atoms
1661
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1662
      !!
1663
      !! Reads the geometry section of the input and counts the number of atoms
1664
      !!
1665
      implicit none
1666

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

1669
      integer :: n_atoms
1670

1671
      integer :: record
1672

1673
      n_atoms = 0
1674

1675
      do record = 1, this%n_qm_atom_lines
20,104✔
1676

1677
         if (this%qm_geometry(record)(1:6) .ne. 'basis:' &
1678
            .and. (this%qm_geometry(record)(1:6) .ne. 'units:') &
1679
            .and. (this%qm_geometry(record)(1:5) .ne. 'ghost')) &
16,839✔
1680
            n_atoms = n_atoms + 1
16,575✔
1681

1682
      enddo
1683

1684
   end function get_n_atoms_input_tool
3,265✔
1685

1686

1687
   pure function get_n_mm_atoms_input_tool(this) result(n_atoms)
156✔
1688
      !!
1689
      !! Get n MM atoms
1690
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
1691
      !!
1692
      implicit none
1693

1694
      class(input_tool), intent(in) :: this
1695

1696
      integer :: n_atoms
1697

1698
      n_atoms = this%n_mm_atom_lines
156✔
1699

1700
   end function  get_n_mm_atoms_input_tool
156✔
1701

1702

1703
   function get_n_mm_molecules_input_tool(this) result(n_molecules)
78✔
1704
      !!
1705
      !! Written by Sarai D. Folkestad, Sep 2020
1706
      !!
1707
      !! Reads the MM geometry and counts the number of molecules
1708
      !!
1709
      implicit none
1710

1711
      class(input_tool), intent(in) :: this
1712

1713
      integer :: n_molecules
1714

1715
      integer :: cursor, record, current_molecule, previous_molecule
1716

1717
      character(len=200) :: string, imolecule
1718

1719
      previous_molecule = 1
1720
      n_molecules       = 1
1721

1722
      do record = 1, this%n_mm_atom_lines
312✔
1723

1724
         string = (trim(adjustl(this%mm_geometry(record))))
234✔
1725
         cursor = first_index_of_substring(string,'=')
234✔
1726

1727
         string = string(cursor+1:200)
234✔
1728

1729
         cursor = first_index_of_substring(string,']')
234✔
1730

1731
         imolecule = string(1:cursor-1)
234✔
1732
         read(imolecule,'(i4)') current_molecule
234✔
1733

1734
         if (record == 1 .and. current_molecule .ne. 1) &
234✔
1735
            call output%error_msg('Molecule 1 is missing!')
×
1736

1737
         if (current_molecule .eq. previous_molecule + 1) then
234✔
1738

1739
            n_molecules = n_molecules + 1
×
1740

1741
         elseif (current_molecule .ne. previous_molecule .and. &
234✔
1742
               current_molecule .ne. previous_molecule + 1) then
1743

1744
            call output%error_msg('Molecule (i0) missing even though (i0) &
1745
                                 &should be present in QM/MM calculation.', &
1746
                                 ints=[previous_molecule + 1, n_molecules])
×
1747

1748
         endif
1749

1750
         previous_molecule = current_molecule
78✔
1751

1752
      enddo
1753

1754
   end function get_n_mm_molecules_input_tool
78✔
1755

1756

1757
   subroutine get_geometry_input_tool(this, n_atoms, symbols,  &
3,265✔
1758
                                      positions, basis_sets,   &
1759
                                      charge, units_angstrom,  &
3,265✔
1760
                                      is_ghost)
1761
      !!
1762
      !! Written by Sarai D. Folkestad, Eirik F. Kjønstad
1763
      !! Åsmund H. Tveten and Tor S. Haugland, 2019-2021
1764
      !!
1765
      !! Reads the geometry from the output file and sets it in the list of atoms.
1766
      !!
1767
      !! Note: This routine should be called after a call to the function
1768
      !! get_n_atoms_input_tool which finds the number of atoms in the system
1769
      !!
1770
      use string_utilities, only: convert_character_to_uppercase
1771

1772
      implicit none
1773

1774
      class(input_tool), intent(in) :: this
1775

1776
      integer, intent(in) :: n_atoms
1777

1778
      character(len=2), dimension(n_atoms), intent(out)   :: symbols
1779
      character(len=100), dimension(n_atoms), intent(out) :: basis_sets
1780
      logical, dimension(n_atoms), intent(out) :: is_ghost
1781

1782
      real(dp), dimension(3, n_atoms), intent(out) :: positions ! x, y, z
1783
      integer, dimension(n_atoms), intent(out) :: charge
1784

1785
      logical, intent(out) :: units_angstrom
1786

1787
      integer :: current_atom, i
1788

1789
      integer :: start_
1790

1791
      character(len=200) :: string
1792
      character(len=100) :: current_basis
1793
      logical :: is_ghost_atom = .false.
1794

1795
      integer :: cursor
1796

1797
      start_ = 1 ! Specifies the line of the first and required basis
1798

1799
      ! Are units specified?
1800
      ! Note that units can only be specified as the first line of the geometry
1801

1802
      units_angstrom = .true. ! Default units are Angstrom
3,265✔
1803
      charge = 0 ! Default charge is zero
16,575✔
1804

1805
      if (this%qm_geometry(1)(1:6) == 'units:') then
3,265✔
1806

1807
         string = (trim(adjustl(this%qm_geometry(1)(7:200))))
228✔
1808

1809
         if (string(1:4) == 'bohr') then
228✔
1810

1811
            units_angstrom = .false.
228✔
1812

1813
         elseif (string(1:8) /= 'angstrom') then
×
1814

1815
            call output%error_msg('units of atom coordinates must be either angstrom or bohr')
×
1816

1817
         endif
1818

1819
         start_ = 2
1820

1821
      endif
1822

1823
      ! Error if next line is not a basis set line
1824

1825
      if(this%qm_geometry(start_)(1:6) /= 'basis:') &
3,265✔
1826
            call output%error_msg('did not find basis in geometry section.')
×
1827

1828
      current_atom = 0
1829

1830
      do i = start_, this%n_qm_atom_lines
19,876✔
1831

1832
         string = trim(adjustl(this%qm_geometry(i)))
16,611✔
1833

1834
         if (string(1:6) == 'units:') &
16,611✔
1835
            call output%error_msg('Units must be specified as the first line in the geometry section.')
×
1836

1837
         if(string(1:6) == 'basis:') then
19,876✔
1838

1839
            current_basis = trim(adjustl(string(7:200)))
3,295✔
1840
            current_basis = remove_substring_after_symbol(current_basis,"!")
3,295✔
1841

1842
         elseif (string(1:5) == 'ghost') then
13,316✔
1843

1844
            ! Every atom after 'ghost' keyword are ghosts
1845
            is_ghost_atom = .true.
6✔
1846

1847
         else
1848

1849
            current_atom = current_atom + 1
13,310✔
1850

1851
            basis_sets(current_atom) = current_basis
13,310✔
1852
            symbols(current_atom)    = string(1:2)
13,310✔
1853
            is_ghost(current_atom)   = is_ghost_atom
13,310✔
1854

1855
            string = adjustl(string(3:200))
13,310✔
1856

1857
            if (is_substring_in_string(string, 'q')) then
13,310✔
1858

1859
               cursor = first_index_of_substring(string, 'q')
12✔
1860
               read(string(1 : cursor - 1), *) positions(:, current_atom)
12✔
1861

1862
               string = adjustl(string(cursor+1:200))
12✔
1863

1864
               if (.not. string_starts_with(string, '=')) &
12✔
1865
                     call output%error_msg('in assignment of charge to atom in the geometry')
×
1866

1867
               string = adjustl(string(2:200))
12✔
1868
               read(string, *) charge(current_atom)
12✔
1869
            else
1870

1871
               read(string(1:), *) positions(:, current_atom)
13,298✔
1872

1873
            endif
1874

1875
         endif
1876

1877
      enddo
1878

1879
      ! First character of symbol should be upper case
1880

1881
      do i = 1, n_atoms
16,575✔
1882

1883
         symbols(i)(1:1) = convert_character_to_uppercase(symbols(i)(1:1))
16,575✔
1884

1885
      enddo
1886

1887
   end subroutine get_geometry_input_tool
3,265✔
1888

1889

1890
   subroutine get_mm_geometry_fq_input_tool(this, n_atoms, n_molecules, &
78✔
1891
                                          n_atoms_per_molecule, symbols,   &
78✔
1892
                                          positions, chi, eta)
1893
      !!
1894
      !! Written by Tommaso Giovanini and Sarai D. Folkestad, 2019-2020
1895
      !!
1896
      !! Reads the geometry of the MM portion from the input file in the case
1897
      !! of an fq calculation and sets it in the list of atoms.
1898
      !!
1899
      !! Note: In order to be run, you need to know the number of MM atoms and molecules
1900
      !!       in the system
1901
      !!
1902
      use string_utilities, only: convert_character_to_uppercase
1903
      use string_utilities, only: last_index_of_substring
1904

1905
      implicit none
1906

1907
      class(input_tool),   intent(in) :: this
1908
      integer,             intent(in) :: n_atoms
1909
      integer,             intent(in) :: n_molecules
1910

1911
      character(len=2), dimension(n_atoms),     intent(out) :: symbols
1912
      real(dp),         dimension(3, n_atoms),  intent(out) :: positions
1913
      real(dp),         dimension(n_atoms),     intent(out) :: chi
1914
      real(dp),         dimension(n_atoms),     intent(out) :: eta
1915
      integer,          dimension(n_molecules), intent(out) :: n_atoms_per_molecule
1916

1917
      integer :: record, cursor, current_atom, i, current_molecule
1918

1919
      character(len=200) :: string, coordinate
1920

1921
      current_atom = 0
1922

1923
      current_molecule     = 0
78✔
1924
      n_atoms_per_molecule = 0
156✔
1925
      cursor = 0
1926

1927
      do record = 1, this%n_mm_atom_lines
312✔
1928

1929
         current_atom = current_atom + 1
234✔
1930
         string = trim(adjustl(this%mm_geometry(record)))
234✔
1931

1932
         ! Determine symbol
1933

1934
         symbols(current_atom) = string(1:2)
234✔
1935
         string = adjustl(string(3:200))
234✔
1936

1937
         ! Determine molecule index
1938

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

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

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

1950
         cursor = first_index_of_substring(string, ']')
234✔
1951

1952
         read(string(1:cursor-1),*) current_molecule
234✔
1953
         string = adjustl(string(cursor+1:200))
234✔
1954

1955
         n_atoms_per_molecule(current_molecule) = n_atoms_per_molecule(current_molecule) + 1
234✔
1956

1957
         cursor = first_index_of_substring(string, '[')
234✔
1958

1959
         coordinate = string(1:cursor-1)
234✔
1960
         read(coordinate, *) positions(:, current_atom)
234✔
1961

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

1964
         ! Determine chi
1965

1966
         if (is_substring_in_string(string, 'chi')) then
234✔
1967
            cursor = last_index_of_substring(string, 'chi')
234✔
1968
         else
1969
            call output%error_msg('could not find chi in MM geometry')
×
1970
         endif
1971

1972
         string = adjustl(string(cursor+1:200))
234✔
1973

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

1977
         cursor = first_index_of_substring(string,',')
234✔
1978
         read(string(1:cursor-1), * ) chi(current_atom)
234✔
1979
         string = adjustl(string(cursor+1:200))
234✔
1980

1981
         ! Determine eta
1982

1983
         if (is_substring_in_string(string, 'eta')) then
234✔
1984
            cursor = last_index_of_substring(string, 'eta')
234✔
1985
         else
1986
            call output%error_msg('could not find eta in MM geometry')
×
1987
         endif
1988

1989
         string = trim(adjustl(string(cursor+1:200)))
234✔
1990

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

1994
         cursor = first_index_of_substring(string,']')
234✔
1995
         read(string(1:cursor-1), * ) eta(current_atom)
234✔
1996

1997
         if(abs(eta(current_atom)).lt.1.0d-8) then
312✔
1998

1999
            call output%error_msg('You have put zero chemical hardness on atom: (i0)', &
2000
                                  ints=[current_atom])
×
2001

2002
         endif
2003

2004
      enddo
2005

2006
      ! First character of symbol should be upper case
2007

2008
      do i = 1, n_atoms
312✔
2009

2010
         symbols(i)(1:1) = convert_character_to_uppercase(symbols(i)(1:1))
312✔
2011

2012
      enddo
2013

2014
   end subroutine get_mm_geometry_fq_input_tool
78✔
2015

2016

2017
   subroutine get_mm_geometry_non_polarizable_input_tool(this, n_atoms, symbols,   &
78✔
2018
                                                         positions, charge)
2019
      !!
2020
      !! Written by Tommaso Giovanini and Sarai D. Folkestad, 2019-2020
2021
      !!
2022
      !! Reads the geometry of the MM portion from the input file and
2023
      !! sets it in the list of atoms.
2024
      !!
2025
      !! Note: In order to be run, you need to know the number of MM atoms
2026
      !!       there are in the system
2027
      !!
2028
      use string_utilities, only: convert_character_to_uppercase
2029
      use string_utilities, only: last_index_of_substring
2030

2031
      implicit none
2032

2033
      class(input_tool), intent(in) :: this
2034

2035
      integer, intent(in) :: n_atoms
2036

2037
      character(len=2), dimension(n_atoms),     intent(out) :: symbols
2038
      real(dp),         dimension(3, n_atoms),  intent(out) :: positions
2039
      real(dp),         dimension(n_atoms),     intent(out) :: charge
2040

2041
      integer :: record, cursor, current_atom, i, current_molecule
2042

2043
      character(len=200) :: string, coordinate
2044

2045
      current_atom      = 0
2046
      current_molecule  = 0
78✔
2047
      cursor            = 0
2048

2049
      do record = 1, this%n_mm_atom_lines
312✔
2050

2051
         current_atom = current_atom + 1
234✔
2052
         string = trim(adjustl(this%mm_geometry(record)))
234✔
2053

2054
         ! Determine symbol
2055

2056
         symbols(current_atom) = string(1:2)
234✔
2057
         string = adjustl(string(3:200))
234✔
2058

2059
         ! Determine molecule index
2060

2061
         if (is_substring_in_string(string, 'mol')) then
234✔
2062
            cursor = last_index_of_substring(string, 'mol')
234✔
2063
         else
2064
            call output%error_msg('could not find mol in MM geometry')
×
2065
         endif
2066

2067
         string = adjustl(string(cursor+1:200))
234✔
2068

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

2072
         cursor = first_index_of_substring(string, ']')
234✔
2073
         read(string(1:cursor-1),*) current_molecule
234✔
2074
         string = adjustl(string(cursor+1:200))
234✔
2075

2076
         ! Determine position
2077

2078
         cursor = first_index_of_substring(string, '[')
234✔
2079

2080
         coordinate = string(1:cursor-1)
234✔
2081
         read(coordinate, *) positions(:, current_atom)
234✔
2082

2083
         string = adjustl(string(cursor+1:200))
234✔
2084

2085
         ! Determine charge
2086

2087
         cursor = first_index_of_substring(string, 'q')
234✔
2088
         string = adjustl(string(cursor+1:200))
234✔
2089

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

2093
         cursor = first_index_of_substring(string,']')
234✔
2094
         read(string(1:cursor-1), * ) charge(current_atom)
234✔
2095

2096
         if(abs(charge(current_atom)).lt.1.0d-8) then
312✔
2097

2098
            call output%warning_msg('You put zero charge on atom = (i0)', &
2099
                                     ints=[current_atom], fs='(t6,a)')
×
2100

2101
         endif
2102

2103
      enddo
2104

2105
      ! First character of symbol should be upper case
2106

2107
      do i = 1, n_atoms
312✔
2108

2109
         symbols(i)(1:1) = convert_character_to_uppercase(symbols(i)(1:1))
312✔
2110

2111
      enddo
2112

2113
   end subroutine get_mm_geometry_non_polarizable_input_tool
78✔
2114

2115

2116
   function string_in_array_keyword(this, keyword, section, string) result(in_list)
414✔
2117
      !!
2118
      !! Written by Sarai D. Folkestad and Alexander C. Paul, 2019-2023
2119
      !!
2120
      !! Determines if the 'string' is one of the keyword values in the comma separated
2121
      !! list given with 'keyword' in the given 'section' of the input file.
2122
      !!
2123
      !! Examples of such a keyword is 'levels' from the 'mlcc' section:
2124
      !!
2125
      !!    levels: ccs, cc2, ccsd
2126
      !!
2127
      !! This function assumes that the keyword is requested. If it is not, a test should be performed
2128
      !! before the routine is called
2129
      !!
2130
      use string_utilities, only: string_in_comma_separated_list
2131

2132
      implicit none
2133

2134
      class(input_tool), intent(in) :: this
2135

2136
      character(len=*), intent(in) :: section
2137
      character(len=*), intent(in) :: keyword
2138
      character(len=*), intent(in) :: string
2139

2140
      logical :: in_list
2141

2142
      character(len=200) :: keyword_value_string
2143

2144
      call this%get_required_keyword(keyword, section, keyword_value_string)
414✔
2145
      in_list = string_in_comma_separated_list(keyword_value_string, string)
414✔
2146

2147
   end function string_in_array_keyword
414✔
2148

2149

2150
   subroutine cleanup_input_tool(this)
3,235✔
2151
      !!
2152
      !! Written by Eirik F. Kjønstad, May 2022
2153
      !!
2154
      implicit none
2155

2156
      class(input_tool), intent(inout) :: this
2157

2158
      deallocate(this%keyword_lines)
3,235✔
2159
      deallocate(this%qm_geometry)
3,235✔
2160
      if (allocated(this%mm_geometry)) deallocate(this%mm_geometry)
3,235✔
2161

2162
   end subroutine cleanup_input_tool
3,235✔
2163

2164

2165
   function is_embedding_on_input_tool(this) result(embedding)
8,680✔
2166
      !!
2167
      !! Written by Sarai D. Folkestad, Sep 2020
2168
      !!
2169
      !! Returns true if wavefunction is embedded.
2170
      !!
2171
      implicit none
2172

2173
      class(input_tool), intent(in) :: this
2174

2175
      logical :: embedding
2176

2177
      embedding = this%is_section_present('molecular mechanics') .or. &
2178
                  this%is_section_present('pcm') .or. &
2179
                  this%is_keyword_present('cbo', 'boson')
8,680✔
2180

2181
   end function is_embedding_on_input_tool
8,680✔
2182

2183

2184
   subroutine place_records_in_memory_input_tool(this, section, records_in_memory)
15,010✔
2185
      !!
2186
      !! Written by Sarai D. Folkestad, 2021
2187
      !!
2188
      !! Checks if storage for 'section' is in memory or on disk
2189
      !!
2190
      !! records_in_mem is intent(inout) because it should be set
2191
      !! to a default value before a call to this routine
2192
      !!
2193
      implicit none
2194

2195
      class(input_tool), intent(in) :: this
2196
      character(len=*),  intent(in) :: section
2197

2198
      logical, intent(inout) :: records_in_memory
2199

2200
      character(len=200) :: storage
2201

2202
      if (.not. this%is_keyword_present('storage', trim(section))) return
15,010✔
2203

2204
      call this%get_keyword('storage', trim(section), storage)
30✔
2205

2206
      ! Determine whether to store records in memory or on file
2207

2208
      if (trim(storage) == 'memory') then
30✔
2209

2210
         records_in_memory = .true.
30✔
2211

2212
      elseif (trim(storage) == 'disk') then
×
2213

2214
         records_in_memory = .false.
×
2215

2216
      else
2217

2218
         call output%error_msg('Could not recognize keyword storage in solver: ', &
2219
                                 chars=[trim(storage)])
×
2220

2221
      endif
2222

2223
   end subroutine place_records_in_memory_input_tool
2224

2225

2226
   function get_n_sets_and_ranges(string) result(n_elements)
6✔
2227
      !!
2228
      !! Written by Sarai D. Folkstad and Eirik F. Kjønstad, Mar 2019
2229
      !!
2230
      !! Gets the number of sets/ranges in a string,
2231
      !!
2232
      !! Ranges should always be given as [a,b].
2233
      !!
2234
      !! Lists/ranges should always be given as {a, b, c, d},
2235
      !! that is, in set notation.
2236
      !!
2237
      implicit none
2238

2239
      character(len=200), intent(inout) :: string
2240

2241
      integer :: n_elements
2242

2243
      integer :: i
2244
      integer :: n_set_start, n_set_end
2245
      integer :: n_range_start, n_range_end
2246

2247
      n_set_start = 0
2248
      n_set_end   = 0
2249

2250
      n_range_start = 0
2251
      n_range_end   = 0
2252

2253
      string = adjustl(string)
6✔
2254

2255
      do i = 1, len_trim(string)
126✔
2256

2257
         if (string(i:i) == '{') n_set_start = n_set_start + 1
120✔
2258
         if (string(i:i) == '}') n_set_end = n_set_end + 1
120✔
2259

2260
         if (string(i:i) == '[') n_range_start = n_range_start + 1
120✔
2261
         if (string(i:i) == ']') n_range_end = n_range_end + 1
126✔
2262

2263
      enddo
2264

2265
      if (n_set_start /= n_set_end) call output%error_msg('found open set in input file')
6✔
2266
      if (n_range_start /= n_range_end) call output%error_msg('found open range in input file')
6✔
2267

2268
      n_elements = n_set_start + n_range_start
6✔
2269

2270
   end function get_n_sets_and_ranges
6✔
2271

2272

2273
   function get_n_elements_in_set_or_range(this, string) result(n_elements)
2,748✔
2274
      !!
2275
      !! Written by Sarai D. Folkstad and Eirik F. Kjønstad, Mar 2019
2276
      !!
2277
      !! Gets the number of elements in range or list,
2278
      !!
2279
      !! Ranges should always be given as [a,b], where a and b are integers.
2280
      !! Lists/Sets should always be given as {a, b, c, d}.
2281
      !!
2282
      use string_utilities, only: n_instances_of_character
2283

2284
      implicit none
2285

2286
      class(input_tool), intent(in) :: this
2287

2288
      character(len=200), intent(inout) :: string
2289

2290
      integer :: n_elements
2291

2292
      integer :: last, first, n_characters
2293
      integer :: comma_index
2294

2295
      n_elements = 0
2296

2297
      string = adjustl(string)
2,748✔
2298

2299
      n_characters = len_trim(string)
2,748✔
2300

2301
      if (string_starts_with(string, '[')) then ! range
2,748✔
2302

2303
         call expect_range(string)
198✔
2304

2305
         comma_index = index(string, ',')
198✔
2306

2307
         read(string(2 : comma_index-1), *) first
198✔
2308
         read(string(comma_index+1 : n_characters - 1), *) last
198✔
2309

2310
         n_elements = last - first + 1
198✔
2311

2312
      else if (string_starts_with(string, '{')) then ! set
2,550✔
2313

2314
         call this%expect_set(string)
2,436✔
2315

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

2319
      else ! Did not find list or range
2320

2321
         n_elements = 0
2322

2323
      endif
2324

2325
   end function get_n_elements_in_set_or_range
2,748✔
2326

2327

2328
   subroutine get_integers_from_set_or_range(this, string, n_elements, elements)
1,856✔
2329
      !!
2330
      !! Written by Sarai D. Folkstad and Eirik F. Kjønstad, Mar 2019
2331
      !!
2332
      !! Ranges should always be given as [a,b].
2333
      !!
2334
      !! Lists should always be given as {a, b, c, d}.
2335
      !!
2336
      use string_utilities, only: read_comma_separated_list
2337

2338
      implicit none
2339

2340
      class(input_tool), intent(in) :: this
2341

2342
      character(len=200), intent(inout) :: string
2343

2344
      integer, intent(in) :: n_elements
2345

2346
      integer, dimension(n_elements), intent(out) :: elements
2347

2348
      integer :: first, last, length, n_characters
2349
      integer :: i, comma_index
2350

2351
      string = adjustl(string)
1,856✔
2352

2353
      n_characters = len_trim(string)
1,856✔
2354

2355
      if (string_starts_with(string, '[')) then ! range
1,856✔
2356

2357
         call expect_range(string)
198✔
2358

2359
         comma_index = index(string, ',')
198✔
2360

2361
         read(string(2 : comma_index-1), *) first
198✔
2362
         read(string(comma_index+1 : n_characters - 1), *) last
198✔
2363
         length = last - first + 1
198✔
2364

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

2367
         elements = [(i, i=first, last)]
1,482✔
2368

2369
      else if (string_starts_with(string, '{')) then ! set
1,658✔
2370

2371
         call this%expect_set(string)
1,658✔
2372
         call read_comma_separated_list(string(2:n_characters-1), elements, n_elements)
1,658✔
2373

2374
      else ! Did not find list or range
2375

2376
         call output%error_msg('neither list nor range was found.')
×
2377

2378
      endif
2379

2380
   end subroutine get_integers_from_set_or_range
1,856✔
2381

2382

2383
   function get_n_state_guesses(this) result(n_guesses)
6✔
2384
      !!
2385
      !! Written by Eirik F. Kjønstad, Dec 2021
2386
      !!
2387
      implicit none
2388

2389
      class(input_tool) :: this
2390

2391
      integer :: n_guesses
2392

2393
      character(len=200) :: state_guesses
2394

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

2397
      n_guesses = get_n_sets_and_ranges(state_guesses)
6✔
2398

2399
   end function get_n_state_guesses
6✔
2400

2401

2402
   subroutine get_state_guesses(this, occupied, virtual, n_states)
6✔
2403
      !!
2404
      !! Written by Sarai D. Folkestad, Dec 2021
2405
      !!
2406
      !! state guesses: {i=1, a=2}, {i=2, a=2}, {i=1, a=1}
2407
      !!
2408
      !! Provided as a (comma separated) list of sets.
2409
      !!
2410
      !! A set comprises of two elements which are
2411
      !! the occupied and virtual indices of the start vector
2412
      !!
2413
      !! 'i =' provides occupied index
2414
      !! 'a =' provides virtual index
2415
      !!
2416
      use string_utilities, only: remove_delimiter_from_string, split_at_delimiter
2417
      use string_utilities, only: n_instances_of_character
2418

2419
      implicit none
2420

2421
      class(input_tool) :: this
2422

2423
      integer, intent(in) :: n_states
2424
      integer, dimension(n_states), intent(out) :: virtual, occupied
2425

2426
      character(len=200) :: state_guesses
2427
      character(len=200), dimension(:), allocatable :: split_string
2428

2429
      integer :: n_elements, cursor_a, cursor_i, i, n_occupied, n_virtual
2430

2431
      call this%get_keyword('state guesses', 'solver cc es', state_guesses)
6✔
2432
      state_guesses = adjustl(state_guesses)
6✔
2433

2434
      n_occupied = n_instances_of_character(state_guesses, 'i')
6✔
2435
      n_virtual = n_instances_of_character(state_guesses, 'a')
6✔
2436

2437
      if (n_virtual /= n_occupied) &
6✔
2438
         call output%error_msg('in keyword (state guesses)')
×
2439

2440
      if (n_virtual /= n_states) &
6✔
2441
         call output%error_msg('in keyword (state guesses)')
×
2442

2443
      ! {i=1, a=2}, {i=2, a=2}, {i=1, a=1} -> i=1, a=2} i=2, a=2} i=1, a=1}
2444
      call remove_delimiter_from_string(state_guesses, '{')
6✔
2445

2446
      n_elements = n_instances_of_character(state_guesses, '}')
6✔
2447

2448
      if (n_elements /= n_states) &
6✔
2449
         call output%error_msg('in keyword (state guesses)')
×
2450

2451
      allocate(split_string(n_elements))
10✔
2452

2453
      ! 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")
2454
      call split_at_delimiter(state_guesses, n_elements, split_string, '}')
6✔
2455

2456
      do i = 1, n_elements
18✔
2457

2458
         call remove_delimiter_from_string(split_string(i), '=')
12✔
2459
         call remove_delimiter_from_string(split_string(i), ',')
12✔
2460

2461
         cursor_i = first_index_of_substring(split_string(i), 'i')
12✔
2462
         cursor_a = first_index_of_substring(split_string(i), 'a')
12✔
2463

2464
         if (cursor_i < cursor_a) then
18✔
2465

2466
            read(split_string(i)(cursor_i + 1 : cursor_a -1), *) occupied(i)
6✔
2467
            read(split_string(i)(cursor_a + 1:), *) virtual(i)
6✔
2468

2469
         else
2470

2471
            read(split_string(i)(cursor_a + 1 : cursor_i -1), *) virtual(i)
6✔
2472
            read(split_string(i)(cursor_i + 1:), *) occupied(i)
6✔
2473

2474
         endif
2475

2476
      enddo
2477

2478
      deallocate(split_string)
6✔
2479

2480
   end subroutine get_state_guesses
6✔
2481

2482

2483
   subroutine check_for_errors(this)
3,265✔
2484
      !!
2485
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, Mar 2019
2486
      !!
2487
      !! Looks for errors the user may have made when writing the input file.
2488
      !!
2489
      implicit none
2490

2491
      class(input_tool), intent(in) :: this
2492
      integer :: k
2493

2494
      do k = 1, size(this%sections)
137,130✔
2495

2496
         call this%sections(k)%check_section_for_illegal_keywords()
137,130✔
2497

2498
      enddo
2499

2500
   end subroutine check_for_errors
3,265✔
2501

2502

2503
   function is_section_recognized(this, section) result(allowed)
26,350✔
2504
      !!
2505
      !! Written by Sarai D. Folkestad and Eirik F. Kjønstad, 2019-2021
2506
      !!
2507
      implicit none
2508

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

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

2513
      logical :: allowed
2514

2515
      integer :: k
2516

2517
      allowed = .false.
2518

2519
      do k = 1, size(this%sections)
618,183✔
2520

2521
         if (this%sections(k)%name_ == trim(section)) then
618,183✔
2522
            allowed = .true.
2523
            return
2524
         end if
2525

2526
      enddo
2527

2528
   end function is_section_recognized
2529

2530

2531
   subroutine section_not_recognized(this, section)
×
2532
      !!
2533
      !! Written by Sara Angelico and Alexander C. Paul, 2023
2534
      !!
2535
      implicit none
2536

2537
      class(input_tool), intent(in) :: this
2538

2539
      character(len=*), intent(in) :: section
2540

2541
      call output%printf('m', 'Could not recognize section named "(a0)".', &
2542
                        chars=[trim(section)], fs='(/t3,a)')
×
2543
      call this%print_sections()
×
2544
      call output%error_msg('Something is wrong in the input file. See above.')
×
2545

2546
   end subroutine section_not_recognized
×
2547

2548

2549
   subroutine expect_set(string)
8,362✔
2550
      !!
2551
      !! Written by Alexander C. Paul, Mar 2023
2552
      !!
2553
      implicit none
2554

2555
      character(len=*), intent(in) :: string
2556
      integer :: opening, closing
2557

2558
      opening = index(string, '{')
8,362✔
2559
      if (opening == 0) call output%error_msg('Expected set, but no "{" found in string.')
8,362✔
2560

2561
      closing = index(string, '}')
8,362✔
2562
      if (closing == 0) call output%error_msg('Expected set, but no "}" found in string.')
8,362✔
2563

2564
      if (closing < opening) call output%error_msg('Expected set, but "}" found before "{".')
8,362✔
2565

2566
   end subroutine expect_set
8,362✔
2567

2568

2569
   subroutine expect_range(string)
396✔
2570
      !!
2571
      !! Written by Alexander C. Paul, Mar 2023
2572
      !!
2573
      implicit none
2574

2575
      character(len=*), intent(in) :: string
2576
      integer :: opening, closing, comma
2577

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

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

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

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

2590
   end subroutine expect_range
396✔
2591

2592

2593
   subroutine set_section_keywords(this, section, section_lines)
26,350✔
2594
      !!
2595
      !! Written by Sara Angelico and Alexander C. Paul, Apr 2023
2596
      !!
2597
      !! This routine removes empty lines and comment lines and
2598
      !! sets the keywords for the section
2599
      !!
2600
      implicit none
2601

2602
      class(input_tool),                intent(inout) :: this
2603
      character(len=*),                 intent(in)    :: section
2604
      character(len=200), dimension(:), intent(in)    :: section_lines
2605

2606
      character(len=200), dimension(:), allocatable :: keyword_lines
2607
      character(len=200) :: line
2608
      integer :: section_index, n_lines, l
2609

2610
      allocate(keyword_lines, mold=section_lines)
52,700✔
2611

2612
      n_lines = 0
2613
      do l = 1, size(section_lines)
105,077✔
2614

2615
         line = trim(adjustl(section_lines(l)))
78,727✔
2616

2617
         if (string_starts_with(line, "!")) cycle
78,727✔
2618
         if (is_empty(line)) cycle
78,607✔
2619

2620
         line = remove_substring_after_symbol(line,'!')
52,047✔
2621

2622
         n_lines = n_lines + 1
52,047✔
2623
         keyword_lines(n_lines) = adjustl(line)
105,077✔
2624

2625
      end do
2626

2627
      section_index = this%get_section_index(trim(section))
26,350✔
2628

2629
      call this%sections(section_index)%set_keyword_lines(keyword_lines(1:n_lines))
26,350✔
2630

2631
      deallocate(keyword_lines)
26,350✔
2632

2633
   end subroutine set_section_keywords
26,350✔
2634

2635

2636
   subroutine check_get_array_for_keyword(keyword, section, n_elements)
6,124✔
2637
      !!
2638
      !! Written by Alexander C. Paul, May 2023
2639
      !!
2640
      implicit none
2641

2642
      character(len=*), intent(in) :: keyword, section
2643
      integer,          intent(in) :: n_elements
2644

2645
      if (n_elements .le. 0) then
6,124✔
2646
         call output%error_msg("Get array for keyword called with n_elements=(i0). &
2647
                              &Keyword: (a0) Section: " // section, &
2648
                               ints=[n_elements], chars=[keyword])
×
2649
      end if
2650

2651
   end subroutine check_get_array_for_keyword
6,124✔
2652

2653

2654
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