LCOV - code coverage report
Current view: top level - src - nnp_environment.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:42dac4a) Lines: 87.7 % 406 356
Test Date: 2025-07-25 12:55:17 Functions: 100.0 % 3 3

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief  Methods dealing with Neural Network potentials
      10              : !> \author Christoph Schran (christoph.schran@rub.de)
      11              : !> \date   2020-10-10
      12              : ! **************************************************************************************************
      13              : MODULE nnp_environment
      14              : 
      15              :    USE atomic_kind_types,               ONLY: atomic_kind_type
      16              :    USE bibliography,                    ONLY: Behler2007,&
      17              :                                               Behler2011,&
      18              :                                               Schran2020a,&
      19              :                                               Schran2020b,&
      20              :                                               cite_reference
      21              :    USE cell_methods,                    ONLY: read_cell,&
      22              :                                               write_cell
      23              :    USE cell_types,                      ONLY: cell_release,&
      24              :                                               cell_type,&
      25              :                                               get_cell
      26              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      27              :                                               cp_logger_get_default_unit_nr,&
      28              :                                               cp_logger_type
      29              :    USE cp_parser_methods,               ONLY: parser_read_line,&
      30              :                                               parser_search_string
      31              :    USE cp_parser_types,                 ONLY: cp_parser_type,&
      32              :                                               parser_create,&
      33              :                                               parser_release,&
      34              :                                               parser_reset
      35              :    USE cp_subsys_methods,               ONLY: cp_subsys_create
      36              :    USE cp_subsys_types,                 ONLY: cp_subsys_set,&
      37              :                                               cp_subsys_type
      38              :    USE distribution_1d_types,           ONLY: distribution_1d_release,&
      39              :                                               distribution_1d_type
      40              :    USE distribution_methods,            ONLY: distribute_molecules_1d
      41              :    USE input_section_types,             ONLY: section_vals_get,&
      42              :                                               section_vals_get_subs_vals,&
      43              :                                               section_vals_type,&
      44              :                                               section_vals_val_get
      45              :    USE kinds,                           ONLY: default_path_length,&
      46              :                                               dp
      47              :    USE message_passing,                 ONLY: mp_para_env_type
      48              :    USE molecule_kind_types,             ONLY: molecule_kind_type,&
      49              :                                               write_molecule_kind_set
      50              :    USE molecule_types,                  ONLY: molecule_type
      51              :    USE nnp_acsf,                        ONLY: nnp_init_acsf_groups,&
      52              :                                               nnp_sort_acsf,&
      53              :                                               nnp_sort_ele,&
      54              :                                               nnp_write_acsf
      55              :    USE nnp_environment_types,           ONLY: &
      56              :         nnp_actfnct_cos, nnp_actfnct_exp, nnp_actfnct_gaus, nnp_actfnct_invsig, nnp_actfnct_lin, &
      57              :         nnp_actfnct_quad, nnp_actfnct_sig, nnp_actfnct_softplus, nnp_actfnct_tanh, nnp_env_set, &
      58              :         nnp_type
      59              :    USE nnp_model,                       ONLY: nnp_write_arc
      60              :    USE particle_methods,                ONLY: write_fist_particle_coordinates,&
      61              :                                               write_particle_distances,&
      62              :                                               write_structure_data
      63              :    USE particle_types,                  ONLY: particle_type
      64              :    USE periodic_table,                  ONLY: get_ptable_info
      65              : #include "./base/base_uses.f90"
      66              : 
      67              :    IMPLICIT NONE
      68              : 
      69              :    PRIVATE
      70              : 
      71              :    LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .TRUE.
      72              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'nnp_environment'
      73              : 
      74              :    PUBLIC :: nnp_init
      75              :    PUBLIC :: nnp_init_model
      76              : 
      77              : CONTAINS
      78              : 
      79              : ! **************************************************************************************************
      80              : !> \brief Read and initialize all the information for neural network potentials
      81              : !> \param nnp_env ...
      82              : !> \param root_section ...
      83              : !> \param para_env ...
      84              : !> \param force_env_section ...
      85              : !> \param subsys_section ...
      86              : !> \param use_motion_section ...
      87              : !> \date   2020-10-10
      88              : !> \author Christoph Schran (christoph.schran@rub.de)
      89              : ! **************************************************************************************************
      90           28 :    SUBROUTINE nnp_init(nnp_env, root_section, para_env, force_env_section, subsys_section, &
      91              :                        use_motion_section)
      92              :       TYPE(nnp_type), INTENT(INOUT), POINTER             :: nnp_env
      93              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: root_section
      94              :       TYPE(mp_para_env_type), INTENT(IN), POINTER        :: para_env
      95              :       TYPE(section_vals_type), INTENT(INOUT), POINTER    :: force_env_section, subsys_section
      96              :       LOGICAL, INTENT(IN)                                :: use_motion_section
      97              : 
      98              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'nnp_init'
      99              : 
     100              :       INTEGER                                            :: handle
     101              :       LOGICAL                                            :: explicit, use_ref_cell
     102              :       REAL(KIND=dp), DIMENSION(3)                        :: abc
     103              :       TYPE(cell_type), POINTER                           :: cell, cell_ref
     104              :       TYPE(cp_subsys_type), POINTER                      :: subsys
     105              :       TYPE(section_vals_type), POINTER                   :: cell_section, nnp_section
     106              : 
     107           14 :       CALL timeset(routineN, handle)
     108           14 :       CALL cite_reference(Behler2007)
     109           14 :       CALL cite_reference(Behler2011)
     110           14 :       CALL cite_reference(Schran2020a)
     111           14 :       CALL cite_reference(Schran2020b)
     112              : 
     113           14 :       CPASSERT(ASSOCIATED(nnp_env))
     114              : 
     115           14 :       NULLIFY (cell_section, nnp_section, cell, cell_ref, subsys)
     116              : 
     117           14 :       IF (.NOT. ASSOCIATED(subsys_section)) THEN
     118            0 :          subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
     119              :       END IF
     120           14 :       cell_section => section_vals_get_subs_vals(subsys_section, "CELL")
     121           14 :       nnp_section => section_vals_get_subs_vals(force_env_section, "NNP")
     122           14 :       CALL section_vals_get(nnp_section, explicit=explicit)
     123           14 :       IF (.NOT. explicit) THEN
     124            0 :          CPWARN("NNP section not explicitly stated. Using default file names.")
     125              :       END IF
     126              : 
     127              :       CALL nnp_env_set(nnp_env=nnp_env, nnp_input=nnp_section, &
     128           14 :                        force_env_input=force_env_section)
     129              : 
     130              :       CALL read_cell(cell=cell, cell_ref=cell_ref, use_ref_cell=use_ref_cell, cell_section=cell_section, &
     131           14 :                      para_env=para_env)
     132           14 :       CALL get_cell(cell=cell, abc=abc)
     133           14 :       CALL write_cell(cell=cell, subsys_section=subsys_section)
     134              : 
     135              :       CALL cp_subsys_create(subsys, para_env, root_section, &
     136              :                             force_env_section=force_env_section, subsys_section=subsys_section, &
     137           14 :                             use_motion_section=use_motion_section)
     138              : 
     139              :       CALL nnp_init_subsys(nnp_env=nnp_env, subsys=subsys, cell=cell, &
     140              :                            cell_ref=cell_ref, use_ref_cell=use_ref_cell, &
     141           14 :                            subsys_section=subsys_section)
     142              : 
     143           14 :       CALL cell_release(cell)
     144           14 :       CALL cell_release(cell_ref)
     145              : 
     146           14 :       CALL timestop(handle)
     147              : 
     148           14 :    END SUBROUTINE nnp_init
     149              : 
     150              : ! **************************************************************************************************
     151              : !> \brief Read and initialize all the information for neural network potentials
     152              : !> \param nnp_env ...
     153              : !> \param subsys ...
     154              : !> \param cell ...
     155              : !> \param cell_ref ...
     156              : !> \param use_ref_cell ...
     157              : !> \param subsys_section ...
     158              : !> \date   2020-10-10
     159              : !> \author Christoph Schran (christoph.schran@rub.de)
     160              : ! **************************************************************************************************
     161           14 :    SUBROUTINE nnp_init_subsys(nnp_env, subsys, cell, cell_ref, use_ref_cell, subsys_section)
     162              :       TYPE(nnp_type), INTENT(INOUT), POINTER             :: nnp_env
     163              :       TYPE(cp_subsys_type), INTENT(IN), POINTER          :: subsys
     164              :       TYPE(cell_type), INTENT(INOUT), POINTER            :: cell, cell_ref
     165              :       LOGICAL, INTENT(IN)                                :: use_ref_cell
     166              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: subsys_section
     167              : 
     168              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'nnp_init_subsys'
     169              : 
     170              :       INTEGER                                            :: handle, natom
     171           14 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     172              :       TYPE(distribution_1d_type), POINTER                :: local_molecules, local_particles
     173           14 :       TYPE(molecule_kind_type), DIMENSION(:), POINTER    :: molecule_kind_set
     174           14 :       TYPE(molecule_type), DIMENSION(:), POINTER         :: molecule_set
     175           14 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     176              : 
     177           14 :       CALL timeset(routineN, handle)
     178              : 
     179              :       NULLIFY (atomic_kind_set, molecule_kind_set, particle_set, molecule_set, &
     180           14 :                local_molecules, local_particles)
     181              : 
     182           14 :       particle_set => subsys%particles%els
     183           14 :       atomic_kind_set => subsys%atomic_kinds%els
     184           14 :       molecule_kind_set => subsys%molecule_kinds%els
     185           14 :       molecule_set => subsys%molecules%els
     186              : 
     187              :       !Print the molecule kind set
     188           14 :       CALL write_molecule_kind_set(molecule_kind_set, subsys_section)
     189              : 
     190              :       !Print the atomic coordinates
     191           14 :       CALL write_fist_particle_coordinates(particle_set, subsys_section)
     192              :       CALL write_particle_distances(particle_set, cell=cell, &
     193           14 :                                     subsys_section=subsys_section)
     194              :       CALL write_structure_data(particle_set, cell=cell, &
     195           14 :                                 input_section=subsys_section)
     196              : 
     197              :       !Distribute molecules and atoms using the new data structures
     198              :       CALL distribute_molecules_1d(atomic_kind_set=atomic_kind_set, &
     199              :                                    particle_set=particle_set, &
     200              :                                    local_particles=local_particles, &
     201              :                                    molecule_kind_set=molecule_kind_set, &
     202              :                                    molecule_set=molecule_set, &
     203              :                                    local_molecules=local_molecules, &
     204           14 :                                    force_env_section=nnp_env%force_env_input)
     205              : 
     206           14 :       natom = SIZE(particle_set)
     207              : 
     208           42 :       ALLOCATE (nnp_env%nnp_forces(3, natom))
     209              : 
     210         9254 :       nnp_env%nnp_forces(:, :) = 0.0_dp
     211              : 
     212           14 :       nnp_env%nnp_potential_energy = 0.0_dp
     213              : 
     214              :       ! Set up arrays for calculation:
     215           14 :       nnp_env%num_atoms = natom
     216           42 :       ALLOCATE (nnp_env%ele_ind(natom))
     217           42 :       ALLOCATE (nnp_env%nuc_atoms(natom))
     218           42 :       ALLOCATE (nnp_env%coord(3, natom))
     219           42 :       ALLOCATE (nnp_env%atoms(natom))
     220           42 :       ALLOCATE (nnp_env%sort(natom))
     221           42 :       ALLOCATE (nnp_env%sort_inv(natom))
     222              : 
     223           14 :       CALL cp_subsys_set(subsys, cell=cell)
     224              : 
     225              :       CALL nnp_env_set(nnp_env=nnp_env, subsys=subsys, &
     226              :                        cell_ref=cell_ref, use_ref_cell=use_ref_cell, &
     227              :                        local_molecules=local_molecules, &
     228           14 :                        local_particles=local_particles)
     229              : 
     230           14 :       CALL distribution_1d_release(local_particles)
     231           14 :       CALL distribution_1d_release(local_molecules)
     232              : 
     233           14 :       CALL nnp_init_model(nnp_env=nnp_env, printtag="NNP")
     234              : 
     235           14 :       CALL timestop(handle)
     236              : 
     237           14 :    END SUBROUTINE nnp_init_subsys
     238              : 
     239              : ! **************************************************************************************************
     240              : !> \brief Initialize the Neural Network Potential
     241              : !> \param nnp_env ...
     242              : !> \param printtag ...
     243              : !> \date   2020-10-10
     244              : !> \author Christoph Schran (christoph.schran@rub.de)
     245              : ! **************************************************************************************************
     246           15 :    SUBROUTINE nnp_init_model(nnp_env, printtag)
     247              :       TYPE(nnp_type), INTENT(INOUT), POINTER             :: nnp_env
     248              :       CHARACTER(LEN=*), INTENT(IN)                       :: printtag
     249              : 
     250              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'nnp_init_model'
     251              :       INTEGER, PARAMETER                                 :: def_str_len = 256, &
     252              :                                                             default_path_length = 256
     253              : 
     254           15 :       CHARACTER(len=1), ALLOCATABLE, DIMENSION(:)        :: cactfnct
     255              :       CHARACTER(len=2)                                   :: ele
     256              :       CHARACTER(len=def_str_len)                         :: dummy, line
     257              :       CHARACTER(len=default_path_length)                 :: base_name, file_name
     258              :       INTEGER                                            :: handle, i, i_com, io, iweight, j, k, l, &
     259              :                                                             n_weight, nele, nuc_ele, symfnct_type, &
     260              :                                                             unit_nr
     261              :       LOGICAL                                            :: at_end, atom_e_found, explicit, first, &
     262              :                                                             found
     263              :       REAL(KIND=dp)                                      :: energy
     264           15 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: weights
     265              :       REAL(KIND=dp), DIMENSION(7)                        :: test_array
     266           15 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: work
     267              :       TYPE(cp_logger_type), POINTER                      :: logger
     268              :       TYPE(cp_parser_type)                               :: parser
     269              :       TYPE(section_vals_type), POINTER                   :: bias_section, model_section
     270              : 
     271           15 :       CALL timeset(routineN, handle)
     272              : 
     273           15 :       NULLIFY (logger)
     274              : 
     275           15 :       logger => cp_get_default_logger()
     276              : 
     277           15 :       IF (logger%para_env%is_source()) THEN
     278            8 :          unit_nr = cp_logger_get_default_unit_nr(logger)
     279            8 :          WRITE (unit_nr, *) ""
     280            8 :          WRITE (unit_nr, *) TRIM(printtag)//"| Neural Network Potential Force Environment"
     281              :       END IF
     282              : 
     283           15 :       model_section => section_vals_get_subs_vals(nnp_env%nnp_input, "MODEL")
     284           15 :       CALL section_vals_get(model_section, n_repetition=nnp_env%n_committee)
     285           60 :       ALLOCATE (nnp_env%atomic_energy(nnp_env%num_atoms, nnp_env%n_committee))
     286           45 :       ALLOCATE (nnp_env%committee_energy(nnp_env%n_committee))
     287           60 :       ALLOCATE (nnp_env%myforce(3, nnp_env%num_atoms, nnp_env%n_committee))
     288           60 :       ALLOCATE (nnp_env%committee_forces(3, nnp_env%num_atoms, nnp_env%n_committee))
     289           45 :       ALLOCATE (nnp_env%committee_stress(3, 3, nnp_env%n_committee))
     290              : 
     291           15 :       CALL section_vals_val_get(nnp_env%nnp_input, "NNP_INPUT_FILE_NAME", c_val=file_name)
     292           15 :       CALL parser_create(parser, file_name, para_env=logger%para_env)
     293              : 
     294              :       ! read number of elements and cut_type and check for scale and center
     295           15 :       nnp_env%scale_acsf = .FALSE.
     296           15 :       nnp_env%scale_sigma_acsf = .FALSE.
     297              :       ! Defaults for scale min and max:
     298           15 :       nnp_env%scmin = 0.0_dp
     299           15 :       nnp_env%scmax = 1.0_dp
     300           15 :       nnp_env%center_acsf = .FALSE.
     301           15 :       nnp_env%normnodes = .FALSE.
     302           15 :       nnp_env%n_hlayer = 0
     303              : 
     304           15 :       IF (logger%para_env%is_source()) THEN
     305            8 :          unit_nr = cp_logger_get_default_unit_nr(logger)
     306            8 :          WRITE (unit_nr, *) TRIM(printtag)//"| Reading NNP input from file: ", TRIM(file_name)
     307              :       END IF
     308              : 
     309              :       CALL parser_search_string(parser, "number_of_elements", .TRUE., found, line, &
     310           15 :                                 search_from_begin_of_file=.TRUE.)
     311           15 :       IF (found) THEN
     312           15 :          READ (line, *) dummy, nnp_env%n_ele
     313              :       ELSE
     314              :          CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     315            0 :                        "| number of elements missing in NNP_INPUT_FILE")
     316              :       END IF
     317              : 
     318              :       CALL parser_search_string(parser, "scale_symmetry_functions_sigma", .TRUE., found, &
     319           15 :                                 search_from_begin_of_file=.TRUE.)
     320           15 :       nnp_env%scale_sigma_acsf = found
     321              : 
     322              :       CALL parser_search_string(parser, "scale_symmetry_functions", .TRUE., found, &
     323           15 :                                 search_from_begin_of_file=.TRUE.)
     324           15 :       nnp_env%scale_acsf = found
     325              : 
     326              :       ! Test if there are two keywords of this:
     327           15 :       CALL parser_search_string(parser, "scale_symmetry_functions", .TRUE., found)
     328           15 :       IF (found .AND. nnp_env%scale_sigma_acsf) THEN
     329            0 :          CPWARN('Two scaling keywords in the input, we will ignore sigma scaling in this case')
     330            0 :          nnp_env%scale_sigma_acsf = .FALSE.
     331           15 :       ELSE IF (.NOT. found .AND. nnp_env%scale_sigma_acsf) THEN
     332            0 :          nnp_env%scale_acsf = .FALSE.
     333              :       END IF
     334              : 
     335              :       CALL parser_search_string(parser, "scale_min_short_atomic", .TRUE., found, line, &
     336           15 :                                 search_from_begin_of_file=.TRUE.)
     337           15 :       IF (found) READ (line, *) dummy, nnp_env%scmin
     338              : 
     339              :       CALL parser_search_string(parser, "scale_max_short_atomic", .TRUE., found, line, &
     340           15 :                                 search_from_begin_of_file=.TRUE.)
     341           15 :       IF (found) READ (line, *) dummy, nnp_env%scmax
     342              : 
     343              :       CALL parser_search_string(parser, "center_symmetry_functions", .TRUE., found, &
     344           15 :                                 search_from_begin_of_file=.TRUE.)
     345           15 :       nnp_env%center_acsf = found
     346              :       ! n2p2 overwrites sigma scaling, if centering is requested:
     347           15 :       IF (nnp_env%scale_sigma_acsf .AND. nnp_env%center_acsf) THEN
     348            0 :          nnp_env%scale_sigma_acsf = .FALSE.
     349              :       END IF
     350              :       ! Print warning if centering and scaling is requested:
     351           15 :       IF (nnp_env%center_acsf .AND. nnp_env%scale_acsf) THEN
     352           15 :          IF ((ABS(nnp_env%scmin) > EPSILON(0.0_dp)*1.0E+4_dp) .OR. (ABS(nnp_env%scmax - 1.0_dp) > EPSILON(0.0_dp)*1.0E+4_dp)) THEN
     353              :             CALL cp_warn(__LOCATION__, &
     354              :                          "Centering and scaling of symmetry functions requested while scale_min_short_atomic != 0 and/or "// &
     355              :                          "scale_max_short_atomic != 1. Make sure that scaling and centering of symmetry functions in CP2K "// &
     356              :                          "is consistent with your training code. "// &
     357            0 :                          "In CP2K: G* = (G - ave(G)) / (max(G) - min(G)) * (Smax - Smin) + Smin")
     358              :          END IF
     359              :       END IF
     360              : 
     361              :       CALL parser_search_string(parser, "normalize_nodes", .TRUE., found, &
     362           15 :                                 search_from_begin_of_file=.TRUE.)
     363           15 :       nnp_env%normnodes = found
     364              : 
     365              :       CALL parser_search_string(parser, "cutoff_type", .TRUE., found, line, &
     366           15 :                                 search_from_begin_of_file=.TRUE.)
     367           15 :       IF (found) THEN
     368           15 :          READ (line, *) dummy, nnp_env%cut_type
     369              :       ELSE
     370              :          CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     371            0 :                        "| no cutoff type specified in NNP_INPUT_FILE")
     372              :       END IF
     373              : 
     374              :       CALL parser_search_string(parser, "global_hidden_layers_short", .TRUE., found, line, &
     375           15 :                                 search_from_begin_of_file=.TRUE.)
     376           15 :       IF (found) THEN
     377           15 :          READ (line, *) dummy, nnp_env%n_hlayer
     378              :       ELSE
     379              :          CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     380            0 :                        "| number of hidden layers missing in NNP_INPUT_FILE")
     381              :       END IF
     382           15 :       nnp_env%n_layer = nnp_env%n_hlayer + 2
     383              : 
     384           15 :       nele = nnp_env%n_ele
     385           76 :       ALLOCATE (nnp_env%rad(nele))
     386           76 :       ALLOCATE (nnp_env%ang(nele))
     387           45 :       ALLOCATE (nnp_env%n_rad(nele))
     388           30 :       ALLOCATE (nnp_env%n_ang(nele))
     389           45 :       ALLOCATE (nnp_env%actfnct(nnp_env%n_hlayer + 1))
     390           45 :       ALLOCATE (cactfnct(nnp_env%n_hlayer + 1))
     391           30 :       ALLOCATE (nnp_env%ele(nele))
     392           30 :       ALLOCATE (nnp_env%nuc_ele(nele))
     393           76 :       ALLOCATE (nnp_env%arc(nele))
     394           46 :       DO i = 1, nele
     395          217 :          ALLOCATE (nnp_env%arc(i)%layer(nnp_env%n_layer))
     396          108 :          ALLOCATE (nnp_env%arc(i)%n_nodes(nnp_env%n_layer))
     397              :       END DO
     398           45 :       ALLOCATE (nnp_env%n_hnodes(nnp_env%n_hlayer))
     399           45 :       ALLOCATE (nnp_env%atom_energies(nele))
     400           46 :       nnp_env%atom_energies = 0.0_dp
     401              : 
     402              :       ! read elements, broadcast and sort
     403           15 :       CALL parser_reset(parser)
     404              :       DO
     405           30 :          CALL parser_search_string(parser, "elements", .TRUE., found, line)
     406           30 :          IF (found) THEN
     407           30 :             READ (line, *) dummy
     408           30 :             IF (TRIM(ADJUSTL(dummy)) == "elements") THEN
     409           15 :                READ (line, *) dummy, nnp_env%ele(:)
     410           15 :                CALL nnp_sort_ele(nnp_env%ele, nnp_env%nuc_ele)
     411           15 :                EXIT
     412              :             END IF
     413              :          ELSE
     414              :             CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     415            0 :                           "| elements not specified in NNP_INPUT_FILE")
     416              :          END IF
     417              :       END DO
     418              : 
     419              :       CALL parser_search_string(parser, "remove_atom_energies", .TRUE., atom_e_found, &
     420           15 :                                 search_from_begin_of_file=.TRUE.)
     421              : 
     422           15 :       IF (atom_e_found) THEN
     423            0 :          CALL parser_reset(parser)
     424            0 :          i = 0
     425              :          DO
     426            0 :             CALL parser_search_string(parser, "atom_energy", .TRUE., found, line)
     427            0 :             IF (found) THEN
     428            0 :                READ (line, *) dummy, ele, energy
     429            0 :                DO j = 1, nele
     430            0 :                   IF (nnp_env%ele(j) == TRIM(ele)) THEN
     431            0 :                      i = i + 1
     432            0 :                      nnp_env%atom_energies(j) = energy
     433              :                   END IF
     434              :                END DO
     435            0 :                IF (i == nele) EXIT
     436              :             ELSE
     437              :                CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     438            0 :                              "| atom energies are not specified")
     439              :             END IF
     440              :          END DO
     441              :       END IF
     442              : 
     443              :       CALL parser_search_string(parser, "global_nodes_short", .TRUE., found, line, &
     444           15 :                                 search_from_begin_of_file=.TRUE.)
     445           15 :       IF (found) THEN
     446           15 :          READ (line, *) dummy, nnp_env%n_hnodes(:)
     447              :       ELSE
     448              :          CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     449            0 :                        "NNP| global_nodes_short not specified in NNP_INPUT_FILE")
     450              :       END IF
     451              : 
     452              :       CALL parser_search_string(parser, "global_activation_short", .TRUE., found, line, &
     453           15 :                                 search_from_begin_of_file=.TRUE.)
     454           15 :       IF (found) THEN
     455           15 :          READ (line, *) dummy, cactfnct(:)
     456              :       ELSE
     457              :          CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     458            0 :                        "| global_activation_short not specified in NNP_INPUT_FILE")
     459              :       END IF
     460              : 
     461           60 :       DO i = 1, nnp_env%n_hlayer + 1
     462           15 :          SELECT CASE (cactfnct(i))
     463              :          CASE ("t")
     464           30 :             nnp_env%actfnct(i) = nnp_actfnct_tanh
     465              :          CASE ("g")
     466            0 :             nnp_env%actfnct(i) = nnp_actfnct_gaus
     467              :          CASE ("l")
     468           15 :             nnp_env%actfnct(i) = nnp_actfnct_lin
     469              :          CASE ("c")
     470            0 :             nnp_env%actfnct(i) = nnp_actfnct_cos
     471              :          CASE ("s")
     472            0 :             nnp_env%actfnct(i) = nnp_actfnct_sig
     473              :          CASE ("S")
     474            0 :             nnp_env%actfnct(i) = nnp_actfnct_invsig
     475              :          CASE ("e")
     476            0 :             nnp_env%actfnct(i) = nnp_actfnct_exp
     477              :          CASE ("p")
     478            0 :             nnp_env%actfnct(i) = nnp_actfnct_softplus
     479              :          CASE ("h")
     480            0 :             nnp_env%actfnct(i) = nnp_actfnct_quad
     481              :          CASE DEFAULT
     482              :             CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     483           45 :                           "| Activation function unkown")
     484              :          END SELECT
     485              :       END DO
     486              : 
     487              :       ! determine n_rad and n_ang
     488           46 :       DO i = 1, nele
     489           31 :          nnp_env%n_rad(i) = 0
     490           46 :          nnp_env%n_ang(i) = 0
     491              :       END DO
     492              : 
     493              :       ! count symfunctions
     494           15 :       CALL parser_reset(parser)
     495           15 :       first = .TRUE.
     496              :       DO
     497          871 :          CALL parser_search_string(parser, "symfunction_short", .TRUE., found, line)
     498          871 :          IF (found) THEN
     499          856 :             READ (line, *) dummy, ele, symfnct_type
     500         2626 :             DO i = 1, nele
     501         2626 :                IF (TRIM(ele) .EQ. nnp_env%ele(i)) THEN
     502          856 :                   IF (symfnct_type .EQ. 2) THEN
     503          486 :                      nnp_env%n_rad(i) = nnp_env%n_rad(i) + 1
     504          370 :                   ELSE IF (symfnct_type .EQ. 3) THEN
     505          370 :                      nnp_env%n_ang(i) = nnp_env%n_ang(i) + 1
     506              :                   ELSE
     507              :                      CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     508            0 :                                    "| Symmetry function type not supported")
     509              :                   END IF
     510              :                END IF
     511              :             END DO
     512              :             first = .FALSE.
     513              :          ELSE
     514           15 :             IF (first) CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     515            0 :                                      "| no symfunction_short specified in NNP_INPUT_FILE")
     516              :             ! no additional symfnct found
     517              :             EXIT
     518              :          END IF
     519              :       END DO
     520              : 
     521           46 :       DO i = 1, nele
     522           93 :          ALLOCATE (nnp_env%rad(i)%y(nnp_env%n_rad(i)))
     523           93 :          ALLOCATE (nnp_env%rad(i)%funccut(nnp_env%n_rad(i)))
     524           93 :          ALLOCATE (nnp_env%rad(i)%eta(nnp_env%n_rad(i)))
     525           93 :          ALLOCATE (nnp_env%rad(i)%rs(nnp_env%n_rad(i)))
     526           93 :          ALLOCATE (nnp_env%rad(i)%loc_min(nnp_env%n_rad(i)))
     527           93 :          ALLOCATE (nnp_env%rad(i)%loc_max(nnp_env%n_rad(i)))
     528           93 :          ALLOCATE (nnp_env%rad(i)%loc_av(nnp_env%n_rad(i)))
     529           93 :          ALLOCATE (nnp_env%rad(i)%sigma(nnp_env%n_rad(i)))
     530           62 :          ALLOCATE (nnp_env%rad(i)%ele(nnp_env%n_rad(i)))
     531           93 :          ALLOCATE (nnp_env%rad(i)%nuc_ele(nnp_env%n_rad(i)))
     532          517 :          nnp_env%rad(i)%funccut = 0.0_dp
     533          517 :          nnp_env%rad(i)%eta = 0.0_dp
     534          517 :          nnp_env%rad(i)%rs = 0.0_dp
     535          517 :          nnp_env%rad(i)%ele = 'X'
     536          517 :          nnp_env%rad(i)%nuc_ele = 0
     537              : 
     538           93 :          ALLOCATE (nnp_env%ang(i)%y(nnp_env%n_ang(i)))
     539           93 :          ALLOCATE (nnp_env%ang(i)%funccut(nnp_env%n_ang(i)))
     540           93 :          ALLOCATE (nnp_env%ang(i)%eta(nnp_env%n_ang(i)))
     541           93 :          ALLOCATE (nnp_env%ang(i)%zeta(nnp_env%n_ang(i)))
     542           93 :          ALLOCATE (nnp_env%ang(i)%prefzeta(nnp_env%n_ang(i)))
     543           93 :          ALLOCATE (nnp_env%ang(i)%lam(nnp_env%n_ang(i)))
     544           93 :          ALLOCATE (nnp_env%ang(i)%loc_min(nnp_env%n_ang(i)))
     545           93 :          ALLOCATE (nnp_env%ang(i)%loc_max(nnp_env%n_ang(i)))
     546           93 :          ALLOCATE (nnp_env%ang(i)%loc_av(nnp_env%n_ang(i)))
     547           93 :          ALLOCATE (nnp_env%ang(i)%sigma(nnp_env%n_ang(i)))
     548           62 :          ALLOCATE (nnp_env%ang(i)%ele1(nnp_env%n_ang(i)))
     549           62 :          ALLOCATE (nnp_env%ang(i)%ele2(nnp_env%n_ang(i)))
     550           93 :          ALLOCATE (nnp_env%ang(i)%nuc_ele1(nnp_env%n_ang(i)))
     551           93 :          ALLOCATE (nnp_env%ang(i)%nuc_ele2(nnp_env%n_ang(i)))
     552          401 :          nnp_env%ang(i)%funccut = 0.0_dp
     553          401 :          nnp_env%ang(i)%eta = 0.0_dp
     554          401 :          nnp_env%ang(i)%zeta = 0.0_dp
     555          401 :          nnp_env%ang(i)%prefzeta = 1.0_dp
     556          401 :          nnp_env%ang(i)%lam = 0.0_dp
     557          401 :          nnp_env%ang(i)%ele1 = 'X'
     558          401 :          nnp_env%ang(i)%ele2 = 'X'
     559          401 :          nnp_env%ang(i)%nuc_ele1 = 0
     560          401 :          nnp_env%ang(i)%nuc_ele2 = 0
     561              : 
     562              :          ! set number of nodes
     563           31 :          nnp_env%arc(i)%n_nodes(1) = nnp_env%n_rad(i) + nnp_env%n_ang(i)
     564           93 :          nnp_env%arc(i)%n_nodes(2:nnp_env%n_layer - 1) = nnp_env%n_hnodes
     565           31 :          nnp_env%arc(i)%n_nodes(nnp_env%n_layer) = 1
     566          170 :          DO j = 1, nnp_env%n_layer
     567          372 :             ALLOCATE (nnp_env%arc(i)%layer(j)%node(nnp_env%arc(i)%n_nodes(j)))
     568          372 :             ALLOCATE (nnp_env%arc(i)%layer(j)%node_grad(nnp_env%arc(i)%n_nodes(j)))
     569          527 :             ALLOCATE (nnp_env%arc(i)%layer(j)%tmp_der(nnp_env%arc(i)%n_nodes(1), nnp_env%arc(i)%n_nodes(j)))
     570              :          END DO
     571              :       END DO
     572              : 
     573              :       ! read, bcast and sort symfnct parameters
     574           46 :       DO i = 1, nele
     575           31 :          nnp_env%n_rad(i) = 0
     576           46 :          nnp_env%n_ang(i) = 0
     577              :       END DO
     578           15 :       CALL parser_reset(parser)
     579           15 :       first = .TRUE.
     580           15 :       nnp_env%max_cut = 0.0_dp
     581              :       DO
     582          871 :          CALL parser_search_string(parser, "symfunction_short", .TRUE., found, line)
     583          871 :          IF (found) THEN
     584          856 :             READ (line, *) dummy, ele, symfnct_type
     585         2626 :             DO i = 1, nele
     586         2626 :                IF (TRIM(ele) .EQ. nnp_env%ele(i)) THEN
     587          856 :                   IF (symfnct_type .EQ. 2) THEN
     588          486 :                      nnp_env%n_rad(i) = nnp_env%n_rad(i) + 1
     589          486 :                      READ (line, *) dummy, ele, symfnct_type, &
     590          486 :                         nnp_env%rad(i)%ele(nnp_env%n_rad(i)), &
     591          486 :                         nnp_env%rad(i)%eta(nnp_env%n_rad(i)), &
     592          486 :                         nnp_env%rad(i)%rs(nnp_env%n_rad(i)), &
     593          972 :                         nnp_env%rad(i)%funccut(nnp_env%n_rad(i))
     594          486 :                      IF (nnp_env%max_cut < nnp_env%rad(i)%funccut(nnp_env%n_rad(i))) THEN
     595           16 :                         nnp_env%max_cut = nnp_env%rad(i)%funccut(nnp_env%n_rad(i))
     596              :                      END IF
     597          370 :                   ELSE IF (symfnct_type .EQ. 3) THEN
     598          370 :                      nnp_env%n_ang(i) = nnp_env%n_ang(i) + 1
     599          370 :                      READ (line, *) dummy, ele, symfnct_type, &
     600          370 :                         nnp_env%ang(i)%ele1(nnp_env%n_ang(i)), &
     601          370 :                         nnp_env%ang(i)%ele2(nnp_env%n_ang(i)), &
     602          370 :                         nnp_env%ang(i)%eta(nnp_env%n_ang(i)), &
     603          370 :                         nnp_env%ang(i)%lam(nnp_env%n_ang(i)), &
     604          370 :                         nnp_env%ang(i)%zeta(nnp_env%n_ang(i)), &
     605          740 :                         nnp_env%ang(i)%funccut(nnp_env%n_ang(i))
     606              :                      nnp_env%ang(i)%prefzeta(nnp_env%n_ang(i)) = &
     607          370 :                         2.0_dp**(1.0_dp - nnp_env%ang(i)%zeta(nnp_env%n_ang(i)))
     608          370 :                      IF (nnp_env%max_cut < nnp_env%ang(i)%funccut(nnp_env%n_ang(i))) THEN
     609            0 :                         nnp_env%max_cut = nnp_env%ang(i)%funccut(nnp_env%n_ang(i))
     610              :                      END IF
     611              :                   ELSE
     612              :                      CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     613            0 :                                    "| Symmetry function type not supported")
     614              :                   END IF
     615              :                END IF
     616              :             END DO
     617              :             first = .FALSE.
     618              :          ELSE
     619           15 :             IF (first) CALL cp_abort(__LOCATION__, TRIM(printtag)// &
     620            0 :                                      "| no symfunction_short specified in NNP_INPUT_FILE")
     621              :             ! no additional symfnct found
     622              :             EXIT
     623              :          END IF
     624              :       END DO
     625              : 
     626           46 :       DO i = 1, nele
     627          517 :          DO j = 1, nnp_env%n_rad(i)
     628          517 :             CALL get_ptable_info(nnp_env%rad(i)%ele(j), number=nnp_env%rad(i)%nuc_ele(j))
     629              :          END DO
     630          416 :          DO j = 1, nnp_env%n_ang(i)
     631          370 :             CALL get_ptable_info(nnp_env%ang(i)%ele1(j), number=nnp_env%ang(i)%nuc_ele1(j))
     632          370 :             CALL get_ptable_info(nnp_env%ang(i)%ele2(j), number=nnp_env%ang(i)%nuc_ele2(j))
     633              :             ! sort ele1 and ele2
     634          401 :             IF (nnp_env%ang(i)%nuc_ele1(j) .GT. nnp_env%ang(i)%nuc_ele2(j)) THEN
     635          164 :                ele = nnp_env%ang(i)%ele1(j)
     636          164 :                nnp_env%ang(i)%ele1(j) = nnp_env%ang(i)%ele2(j)
     637          164 :                nnp_env%ang(i)%ele2(j) = ele
     638          164 :                nuc_ele = nnp_env%ang(i)%nuc_ele1(j)
     639          164 :                nnp_env%ang(i)%nuc_ele1(j) = nnp_env%ang(i)%nuc_ele2(j)
     640          164 :                nnp_env%ang(i)%nuc_ele2(j) = nuc_ele
     641              :             END IF
     642              :          END DO
     643              :       END DO
     644              :       ! Done with input.nn file
     645           15 :       CALL parser_release(parser)
     646              : 
     647              :       ! sort symmetry functions and output information
     648           15 :       CALL nnp_sort_acsf(nnp_env)
     649           15 :       CALL nnp_write_acsf(nnp_env, logger%para_env, printtag)
     650           15 :       CALL nnp_write_arc(nnp_env, logger%para_env, printtag)
     651              : 
     652              :       ! read scaling information from file
     653           15 :       IF (nnp_env%scale_acsf .OR. nnp_env%center_acsf .OR. nnp_env%scale_sigma_acsf) THEN
     654           15 :          IF (logger%para_env%is_source()) THEN
     655            8 :             WRITE (unit_nr, *) TRIM(printtag)//"| Reading scaling information from file: ", TRIM(file_name)
     656              :          END IF
     657              :          CALL section_vals_val_get(nnp_env%nnp_input, "SCALE_FILE_NAME", &
     658           15 :                                    c_val=file_name)
     659           15 :          CALL parser_create(parser, file_name, para_env=logger%para_env)
     660              : 
     661              :          ! Get number of elements in scaling file
     662           15 :          CALL parser_read_line(parser, 1)
     663           15 :          k = 0
     664          119 :          DO WHILE (k < 7)
     665          105 :             READ (parser%input_line, *, IOSTAT=io) test_array(1:k)
     666          105 :             IF (io == -1) EXIT
     667          105 :             k = k + 1
     668              :          END DO
     669           15 :          k = k - 1
     670              : 
     671           15 :          IF (k == 5 .AND. nnp_env%scale_sigma_acsf) THEN
     672            0 :             CPABORT("Sigma scaling requested, but scaling.data does not contain sigma.")
     673              :          END IF
     674              : 
     675           15 :          CALL parser_reset(parser)
     676           46 :          DO i = 1, nnp_env%n_ele
     677          517 :             DO j = 1, nnp_env%n_rad(i)
     678          486 :                CALL parser_read_line(parser, 1)
     679          517 :                IF (nnp_env%scale_sigma_acsf) THEN
     680            0 :                   READ (parser%input_line, *) dummy, dummy, &
     681            0 :                      nnp_env%rad(i)%loc_min(j), &
     682            0 :                      nnp_env%rad(i)%loc_max(j), &
     683            0 :                      nnp_env%rad(i)%loc_av(j), &
     684            0 :                      nnp_env%rad(i)%sigma(j)
     685              :                ELSE
     686          486 :                   READ (parser%input_line, *) dummy, dummy, &
     687          486 :                      nnp_env%rad(i)%loc_min(j), &
     688          486 :                      nnp_env%rad(i)%loc_max(j), &
     689          972 :                      nnp_env%rad(i)%loc_av(j)
     690              :                END IF
     691              :             END DO
     692          416 :             DO j = 1, nnp_env%n_ang(i)
     693          370 :                CALL parser_read_line(parser, 1)
     694          401 :                IF (nnp_env%scale_sigma_acsf) THEN
     695            0 :                   READ (parser%input_line, *) dummy, dummy, &
     696            0 :                      nnp_env%ang(i)%loc_min(j), &
     697            0 :                      nnp_env%ang(i)%loc_max(j), &
     698            0 :                      nnp_env%ang(i)%loc_av(j), &
     699            0 :                      nnp_env%ang(i)%sigma(j)
     700              :                ELSE
     701          370 :                   READ (parser%input_line, *) dummy, dummy, &
     702          370 :                      nnp_env%ang(i)%loc_min(j), &
     703          370 :                      nnp_env%ang(i)%loc_max(j), &
     704          740 :                      nnp_env%ang(i)%loc_av(j)
     705              :                END IF
     706              :             END DO
     707              :          END DO
     708           15 :          CALL parser_release(parser)
     709              :       END IF
     710              : 
     711           15 :       CALL nnp_init_acsf_groups(nnp_env)
     712              : 
     713              :       ! read weights from file
     714           46 :       DO i = 1, nnp_env%n_ele
     715          139 :          DO j = 2, nnp_env%n_layer
     716            0 :             ALLOCATE (nnp_env%arc(i)%layer(j)%weights(nnp_env%arc(i)%n_nodes(j - 1), &
     717          465 :                                                       nnp_env%arc(i)%n_nodes(j), nnp_env%n_committee))
     718          403 :             ALLOCATE (nnp_env%arc(i)%layer(j)%bweights(nnp_env%arc(i)%n_nodes(j), nnp_env%n_committee))
     719              :          END DO
     720              :       END DO
     721          114 :       DO i_com = 1, nnp_env%n_committee
     722           99 :          CALL section_vals_val_get(model_section, "WEIGHTS", c_val=base_name, i_rep_section=i_com)
     723           99 :          IF (logger%para_env%is_source()) THEN
     724           50 :             WRITE (unit_nr, *) TRIM(printtag)//"| Initializing weights for model: ", i_com
     725              :          END IF
     726          313 :          DO i = 1, nnp_env%n_ele
     727          199 :             WRITE (file_name, '(A,I0.3,A)') TRIM(base_name)//".", nnp_env%nuc_ele(i), ".data"
     728          199 :             IF (logger%para_env%is_source()) THEN
     729          101 :                WRITE (unit_nr, *) TRIM(printtag)//"| Reading weights from file: ", TRIM(file_name)
     730              :             END IF
     731          199 :             CALL parser_create(parser, file_name, para_env=logger%para_env)
     732          199 :             n_weight = 0
     733       205629 :             DO WHILE (.TRUE.)
     734       205828 :                CALL parser_read_line(parser, 1, at_end)
     735       205828 :                IF (at_end) EXIT
     736       205629 :                n_weight = n_weight + 1
     737              :             END DO
     738              : 
     739          597 :             ALLOCATE (weights(n_weight))
     740              : 
     741          199 :             CALL parser_reset(parser)
     742       205828 :             DO j = 1, n_weight
     743       205629 :                CALL parser_read_line(parser, 1)
     744       205828 :                READ (parser%input_line, *) weights(j)
     745              :             END DO
     746          199 :             CALL parser_release(parser)
     747              : 
     748              :             ! sort weights into corresponding arrays
     749          199 :             iweight = 0
     750          796 :             DO j = 2, nnp_env%n_layer
     751        14231 :                DO k = 1, nnp_env%arc(i)%n_nodes(j - 1)
     752       211671 :                   DO l = 1, nnp_env%arc(i)%n_nodes(j)
     753       197440 :                      iweight = iweight + 1
     754       211074 :                      nnp_env%arc(i)%layer(j)%weights(k, l, i_com) = weights(iweight)
     755              :                   END DO
     756              :                END DO
     757              : 
     758         8985 :                DO k = 1, nnp_env%arc(i)%n_nodes(j)
     759         8189 :                   iweight = iweight + 1
     760         8786 :                   nnp_env%arc(i)%layer(j)%bweights(k, i_com) = weights(iweight)
     761              :                END DO
     762              :             END DO
     763              : 
     764          497 :             DEALLOCATE (weights)
     765              :          END DO
     766              :       END DO
     767              : 
     768              :       !Initialize extrapolation counter
     769           15 :       nnp_env%expol = 0
     770              : 
     771              :       ! Bias the standard deviation of committee disagreement
     772           15 :       NULLIFY (bias_section)
     773           15 :       explicit = .FALSE.
     774              :       !HELIUM NNP does atm not allow for bias (not even defined)
     775           15 :       bias_section => section_vals_get_subs_vals(nnp_env%nnp_input, "BIAS", can_return_null=.TRUE.)
     776           15 :       IF (ASSOCIATED(bias_section)) CALL section_vals_get(bias_section, explicit=explicit)
     777           15 :       nnp_env%bias = .FALSE.
     778           15 :       IF (explicit) THEN
     779            4 :          IF (nnp_env%n_committee > 1) THEN
     780            4 :             IF (logger%para_env%is_source()) THEN
     781            2 :                WRITE (unit_nr, *) "NNP| Biasing of committee disagreement enabled"
     782              :             END IF
     783            4 :             nnp_env%bias = .TRUE.
     784           12 :             ALLOCATE (nnp_env%bias_forces(3, nnp_env%num_atoms))
     785           12 :             ALLOCATE (nnp_env%bias_e_avrg(nnp_env%n_committee))
     786            4 :             CALL section_vals_val_get(bias_section, "SIGMA_0", r_val=nnp_env%bias_sigma0)
     787            4 :             CALL section_vals_val_get(bias_section, "K_B", r_val=nnp_env%bias_kb)
     788           36 :             nnp_env%bias_e_avrg(:) = 0.0_dp
     789            4 :             CALL section_vals_val_get(bias_section, "ALIGN_NNP_ENERGIES", explicit=explicit)
     790            4 :             nnp_env%bias_align = explicit
     791            4 :             IF (explicit) THEN
     792            4 :                NULLIFY (work)
     793            4 :                CALL section_vals_val_get(bias_section, "ALIGN_NNP_ENERGIES", r_vals=work)
     794            4 :                IF (SIZE(work) .NE. nnp_env%n_committee) THEN
     795            0 :                   CPABORT("ALIGN_NNP_ENERGIES size mismatch wrt committee size.")
     796              :                END IF
     797           68 :                nnp_env%bias_e_avrg(:) = work
     798            4 :                IF (logger%para_env%is_source()) THEN
     799            2 :                   WRITE (unit_nr, *) TRIM(printtag)//"| Biasing is aligned by shifting the energy prediction of the C-NNP members"
     800              :                END IF
     801              :             END IF
     802              :          ELSE
     803            0 :             CPWARN("NNP committee size is 1, BIAS section is ignored.")
     804              :          END IF
     805              :       END IF
     806              : 
     807           15 :       IF (logger%para_env%is_source()) THEN
     808            8 :          WRITE (unit_nr, *) TRIM(printtag)//"| NNP force environment initialized"
     809              :       END IF
     810              : 
     811           15 :       CALL timestop(handle)
     812              : 
     813           75 :    END SUBROUTINE nnp_init_model
     814              : 
     815              : END MODULE nnp_environment
        

Generated by: LCOV version 2.0-1