LCOV - code coverage report
Current view: top level - src - nnp_environment.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:21ef868) Lines: 84.0 % 437 367
Test Date: 2026-08-14 07:04:57 Functions: 100.0 % 4 4

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

Generated by: LCOV version 2.0-1