LCOV - code coverage report
Current view: top level - src/xc - skala_torch_api.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 63.6 % 66 42
Test Date: 2026-10-15 00:55:44 Functions: 33.3 % 9 3

            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 Small CP2K wrapper around the SKALA TorchScript functional protocol.
      10              : ! **************************************************************************************************
      11              : MODULE skala_torch_api
      12              : #if defined (__HAS_IEEE_EXCEPTIONS)
      13              :    USE ieee_exceptions, ONLY: ieee_all, &
      14              :                               ieee_get_halting_mode, &
      15              :                               ieee_set_halting_mode
      16              : #endif
      17              :    USE kinds, ONLY: default_string_length, &
      18              :                     dp
      19              :    USE string_utilities, ONLY: uppercase
      20              :    USE torch_api, ONLY: &
      21              :       torch_dict_type, torch_model_disable_parameter_gradients, torch_model_forward_mol_tensor, &
      22              :       torch_model_freeze_preserving_method, torch_model_load_with_metadata, torch_model_release, &
      23              :       torch_model_remap_device_constants, torch_model_promote_float32, torch_model_type, &
      24              :       torch_tensor_item_double, torch_tensor_release, torch_tensor_type, &
      25              :       torch_tensor_weighted_sum
      26              : #include "../base/base_uses.f90"
      27              : 
      28              :    IMPLICIT NONE
      29              : 
      30              :    PRIVATE
      31              : 
      32              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'skala_torch_api'
      33              : 
      34              :    PUBLIC :: skala_torch_model_type, skala_torch_model_load, skala_torch_model_release
      35              :    PUBLIC :: skala_torch_model_get_exc, skala_torch_model_get_exc_density
      36              :    PUBLIC :: skala_torch_model_needs_feature, skala_torch_model_protocol_version
      37              : 
      38              :    TYPE skala_torch_model_type
      39              :       PRIVATE
      40              :       INTEGER                                            :: protocol_version = -1
      41              :       CHARACTER(len=default_string_length), ALLOCATABLE, &
      42              :          DIMENSION(:)                                    :: features
      43              :       TYPE(torch_model_type)                             :: torch_model
      44              :    END TYPE skala_torch_model_type
      45              : 
      46              : CONTAINS
      47              : 
      48              : ! **************************************************************************************************
      49              : !> \brief Load a SKALA TorchScript model and its feature metadata.
      50              : !> \param model ...
      51              : !> \param filename ...
      52              : !> \param fp64 Promote float32 numerical state and casts; default true for differential consistency.
      53              : ! **************************************************************************************************
      54           17 :    SUBROUTINE skala_torch_model_load(model, filename, fp64)
      55              :       TYPE(skala_torch_model_type), INTENT(INOUT)        :: model
      56              :       CHARACTER(len=*), INTENT(IN)                       :: filename
      57              :       LOGICAL, INTENT(IN), OPTIONAL                      :: fp64
      58              : 
      59           17 :       CHARACTER(:), ALLOCATABLE                          :: features_json, protocol_string
      60              :       INTEGER                                            :: ios
      61              :       LOGICAL                                            :: use_fp64
      62              : 
      63              :       CALL torch_model_load_with_metadata(model%torch_model, filename, &
      64              :                                           "protocol_version", protocol_string, &
      65           17 :                                           "features", features_json)
      66           17 :       CALL torch_model_remap_device_constants(model%torch_model)
      67           17 :       CALL torch_model_disable_parameter_gradients(model%torch_model)
      68           17 :       READ (protocol_string, *, IOSTAT=ios) model%protocol_version
      69           17 :       IF (ios /= 0) CPABORT("Could not parse SKALA TorchScript protocol_version metadata")
      70           17 :       IF (model%protocol_version /= 2) THEN
      71            0 :          CPABORT("Unsupported SKALA TorchScript protocol version")
      72              :       END IF
      73              : 
      74           17 :       CALL parse_feature_list(features_json, model%features)
      75           17 :       use_fp64 = .TRUE.
      76           17 :       IF (PRESENT(fp64)) use_fp64 = fp64
      77           17 :       IF (use_fp64) CALL torch_model_promote_float32(model%torch_model)
      78              :       ! Preserve the exported SKALA entry point while folding constant model state.
      79           17 :       CALL torch_model_freeze_preserving_method(model%torch_model, "get_exc_density")
      80              : 
      81           17 :    END SUBROUTINE skala_torch_model_load
      82              : 
      83              : ! **************************************************************************************************
      84              : !> \brief Release a loaded SKALA TorchScript model.
      85              : !> \param model ...
      86              : ! **************************************************************************************************
      87            0 :    SUBROUTINE skala_torch_model_release(model)
      88              :       TYPE(skala_torch_model_type), INTENT(INOUT)        :: model
      89              : 
      90            0 :       CALL torch_model_release(model%torch_model)
      91            0 :       IF (ALLOCATED(model%features)) DEALLOCATE (model%features)
      92            0 :       model%protocol_version = -1
      93              : 
      94            0 :    END SUBROUTINE skala_torch_model_release
      95              : 
      96              : ! **************************************************************************************************
      97              : !> \brief Check whether a loaded SKALA model requests a feature.
      98              : !> \param model ...
      99              : !> \param feature ...
     100              : !> \return ...
     101              : ! **************************************************************************************************
     102            0 :    FUNCTION skala_torch_model_needs_feature(model, feature) RESULT(needs_feature)
     103              :       TYPE(skala_torch_model_type), INTENT(IN)           :: model
     104              :       CHARACTER(len=*), INTENT(IN)                       :: feature
     105              :       LOGICAL                                            :: needs_feature
     106              : 
     107              :       CHARACTER(len=default_string_length)               :: feature_key, model_feature
     108              :       INTEGER                                            :: i
     109              : 
     110            0 :       feature_key = ADJUSTL(feature)
     111            0 :       CALL uppercase(feature_key)
     112              : 
     113            0 :       needs_feature = .FALSE.
     114            0 :       IF (.NOT. ALLOCATED(model%features)) RETURN
     115              : 
     116            0 :       DO i = 1, SIZE(model%features)
     117            0 :          model_feature = ADJUSTL(model%features(i))
     118            0 :          CALL uppercase(model_feature)
     119            0 :          IF (TRIM(model_feature) == TRIM(feature_key)) THEN
     120            0 :             needs_feature = .TRUE.
     121              :             RETURN
     122              :          END IF
     123              :       END DO
     124              : 
     125            0 :    END FUNCTION skala_torch_model_needs_feature
     126              : 
     127              : ! **************************************************************************************************
     128              : !> \brief Return the loaded SKALA TorchScript protocol version.
     129              : !> \param model ...
     130              : !> \return ...
     131              : ! **************************************************************************************************
     132            0 :    FUNCTION skala_torch_model_protocol_version(model) RESULT(protocol_version)
     133              :       TYPE(skala_torch_model_type), INTENT(IN)           :: model
     134              :       INTEGER                                            :: protocol_version
     135              : 
     136            0 :       protocol_version = model%protocol_version
     137              : 
     138            0 :    END FUNCTION skala_torch_model_protocol_version
     139              : 
     140              : ! **************************************************************************************************
     141              : !> \brief Evaluate the SKALA exchange-correlation energy density.
     142              : !> \param model ...
     143              : !> \param inputs ...
     144              : !> \param exc_density ...
     145              : ! **************************************************************************************************
     146            0 :    SUBROUTINE skala_torch_model_get_exc_density(model, inputs, exc_density)
     147              :       TYPE(skala_torch_model_type), INTENT(INOUT)        :: model
     148              :       TYPE(torch_dict_type), INTENT(IN)                  :: inputs
     149              :       TYPE(torch_tensor_type), INTENT(INOUT)             :: exc_density
     150              : 
     151              : #if defined (__HAS_IEEE_EXCEPTIONS)
     152              :       LOGICAL, DIMENSION(5)                              :: ieee_halt
     153              : 
     154              :       CALL ieee_get_halting_mode(IEEE_ALL, ieee_halt)
     155              :       CALL ieee_set_halting_mode(IEEE_ALL, .FALSE.)
     156              : #endif
     157            0 :       CALL torch_model_forward_mol_tensor(model%torch_model, "get_exc_density", inputs, exc_density)
     158              : #if defined (__HAS_IEEE_EXCEPTIONS)
     159              :       CALL ieee_set_halting_mode(IEEE_ALL, ieee_halt)
     160              : #endif
     161              : 
     162            0 :    END SUBROUTINE skala_torch_model_get_exc_density
     163              : 
     164              : ! **************************************************************************************************
     165              : !> \brief Evaluate the weighted SKALA exchange-correlation energy.
     166              : !> \param model ...
     167              : !> \param inputs ...
     168              : !> \param grid_weights ...
     169              : !> \param exc_tensor ...
     170              : !> \param exc ...
     171              : ! **************************************************************************************************
     172          284 :    SUBROUTINE skala_torch_model_get_exc(model, inputs, grid_weights, exc_tensor, exc)
     173              :       TYPE(skala_torch_model_type), INTENT(INOUT)        :: model
     174              :       TYPE(torch_dict_type), INTENT(IN)                  :: inputs
     175              :       TYPE(torch_tensor_type), INTENT(IN)                :: grid_weights
     176              :       TYPE(torch_tensor_type), INTENT(INOUT)             :: exc_tensor
     177              :       REAL(KIND=dp), INTENT(OUT)                         :: exc
     178              : 
     179              :       TYPE(torch_tensor_type)                            :: exc_density
     180              : 
     181              : #if defined (__HAS_IEEE_EXCEPTIONS)
     182              :       LOGICAL, DIMENSION(5)                              :: ieee_halt
     183              : 
     184              :       CALL ieee_get_halting_mode(IEEE_ALL, ieee_halt)
     185              :       CALL ieee_set_halting_mode(IEEE_ALL, .FALSE.)
     186              : #endif
     187          284 :       CALL torch_model_forward_mol_tensor(model%torch_model, "get_exc_density", inputs, exc_density)
     188          284 :       CALL torch_tensor_weighted_sum(exc_density, grid_weights, exc_tensor)
     189          284 :       CALL torch_tensor_release(exc_density)
     190          284 :       exc = torch_tensor_item_double(exc_tensor)
     191              : #if defined (__HAS_IEEE_EXCEPTIONS)
     192              :       CALL ieee_set_halting_mode(IEEE_ALL, ieee_halt)
     193              : #endif
     194              : 
     195          284 :    END SUBROUTINE skala_torch_model_get_exc
     196              : 
     197              : ! **************************************************************************************************
     198              : !> \brief Parse a TorchScript extra_files JSON list of feature names.
     199              : !> \param features_json ...
     200              : !> \param features ...
     201              : ! **************************************************************************************************
     202           17 :    SUBROUTINE parse_feature_list(features_json, features)
     203              :       CHARACTER(len=*), INTENT(IN)                       :: features_json
     204              :       CHARACTER(len=default_string_length), &
     205              :          ALLOCATABLE, DIMENSION(:), INTENT(OUT)          :: features
     206              : 
     207              :       INTEGER                                            :: end_pos, feature_count, i, pos, quote1, &
     208              :                                                             quote2, start_pos
     209              : 
     210           17 :       feature_count = 0
     211           17 :       pos = 1
     212          153 :       DO
     213          170 :          quote1 = INDEX(features_json(pos:), '"')
     214          170 :          IF (quote1 == 0) EXIT
     215          153 :          start_pos = pos + quote1
     216          153 :          quote2 = INDEX(features_json(start_pos:), '"')
     217          153 :          IF (quote2 == 0) EXIT
     218          153 :          feature_count = feature_count + 1
     219          153 :          pos = start_pos + quote2
     220              :       END DO
     221              : 
     222           17 :       IF (feature_count == 0) CPABORT("SKALA TorchScript model does not list any features")
     223           51 :       ALLOCATE (features(feature_count))
     224          170 :       features = ""
     225              : 
     226              :       pos = 1
     227          170 :       DO i = 1, feature_count
     228          153 :          quote1 = INDEX(features_json(pos:), '"')
     229          153 :          start_pos = pos + quote1
     230          153 :          quote2 = INDEX(features_json(start_pos:), '"')
     231          153 :          end_pos = start_pos + quote2 - 2
     232          153 :          features(i) = features_json(start_pos:end_pos)
     233          170 :          pos = start_pos + quote2
     234              :       END DO
     235              : 
     236           17 :    END SUBROUTINE parse_feature_list
     237              : 
     238            0 : END MODULE skala_torch_api
        

Generated by: LCOV version 2.0-1