Simulation Core
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

426 regels
21 KiB

  1. ! BSD 2-Clause License
  2. !
  3. ! Copyright (c) 2021-2022, Hewlett Packard Enterprise
  4. ! All rights reserved.
  5. !
  6. ! Redistribution and use in source and binary forms, with or without
  7. ! modification, are permitted provided that the following conditions are met:
  8. !
  9. ! 1. Redistributions of source code must retain the above copyright notice, this
  10. ! list of conditions and the following disclaimer.
  11. !
  12. ! 2. Redistributions in binary form must reproduce the above copyright notice,
  13. ! this list of conditions and the following disclaimer in the documentation
  14. ! and/or other materials provided with the distribution.
  15. !
  16. ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. ! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. ! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. ! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  20. ! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. ! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. ! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. ! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  25. ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. module smartredis_dataset
  27. use iso_c_binding, only : c_ptr, c_bool, c_null_ptr, c_char, c_int
  28. use iso_c_binding, only : c_int8_t, c_int16_t, c_int32_t, c_int64_t, c_float, c_double, c_size_t
  29. use iso_c_binding, only : c_loc, c_f_pointer
  30. use fortran_c_interop, only : enum_kind
  31. implicit none; private
  32. include 'enum_fortran.inc'
  33. include 'dataset/dataset_interfaces.inc'
  34. include 'dataset/add_tensor_interfaces.inc'
  35. include 'dataset/unpack_dataset_tensor_interfaces.inc'
  36. include 'dataset/metadata_interfaces.inc'
  37. public :: enum_kind !< The kind of integer equivalent to a C enum. According to C an Fortran
  38. !! standards this should be c_int, but is renamed here to ensure that
  39. !! users do not have to import the iso_c_binding module into their
  40. !! programs
  41. !> Contains multiple tensors and metadata used to describe an entire set of data
  42. type, public :: dataset_type
  43. type(c_ptr) :: dataset_ptr !< A pointer to the initialized dataset object
  44. contains
  45. !> Initialize a new dataset with a given name
  46. procedure :: initialize => initialize_dataset
  47. !> Add metadata to the dataset with a given field and string
  48. procedure :: add_meta_string
  49. ! procedure :: get_meta_strings ! Not supported currently
  50. !> Add a tensor to be included as part of the dataset
  51. generic :: add_tensor => add_tensor_i8, add_tensor_i16, add_tensor_i32, add_tensor_i64, &
  52. add_tensor_float, add_tensor_double
  53. !> Unpack a tensor that has previously been added to the dataset
  54. generic :: unpack_dataset_tensor => unpack_dataset_tensor_i8, unpack_dataset_tensor_i16, &
  55. unpack_dataset_tensor_i32, unpack_dataset_tensor_i64, &
  56. unpack_dataset_tensor_float, unpack_dataset_tensor_double
  57. !> Add metadata of type 'scalar' into a given field
  58. generic :: add_meta_scalar => add_meta_scalar_double, add_meta_scalar_float, add_meta_scalar_i32, add_meta_scalar_i64
  59. !> Retrieve scalar-type metadata as a vector
  60. generic :: get_meta_scalars => get_meta_scalars_double, get_meta_scalars_float, get_meta_scalars_i32, &
  61. get_meta_scalars_i64
  62. ! Private procedures
  63. procedure, private :: add_tensor_i8
  64. procedure, private :: add_tensor_i16
  65. procedure, private :: add_tensor_i32
  66. procedure, private :: add_tensor_i64
  67. procedure, private :: add_tensor_float
  68. procedure, private :: add_tensor_double
  69. procedure, private :: unpack_dataset_tensor_i8
  70. procedure, private :: unpack_dataset_tensor_i16
  71. procedure, private :: unpack_dataset_tensor_i32
  72. procedure, private :: unpack_dataset_tensor_i64
  73. procedure, private :: unpack_dataset_tensor_float
  74. procedure, private :: unpack_dataset_tensor_double
  75. procedure, private :: add_meta_scalar_double
  76. procedure, private :: add_meta_scalar_float
  77. procedure, private :: add_meta_scalar_i32
  78. procedure, private :: add_meta_scalar_i64
  79. procedure, private :: get_meta_scalars_double
  80. procedure, private :: get_meta_scalars_float
  81. procedure, private :: get_meta_scalars_i32
  82. procedure, private :: get_meta_scalars_i64
  83. end type dataset_type
  84. contains
  85. !> Initialize the dataset
  86. function initialize_dataset(self, name) result(code)
  87. class(dataset_type), intent(inout) :: self !< Receives the dataset
  88. character(len=*), intent(in) :: name !< Name of the dataset
  89. integer(kind=enum_kind) :: code !< Result of the operation
  90. ! Local variables
  91. integer(kind=c_size_t) :: name_length
  92. character(kind=c_char, len=len_trim(name)) :: c_name
  93. name_length = len_trim(name)
  94. c_name = trim(name)
  95. code = dataset_constructor(c_name, name_length, self%dataset_ptr)
  96. end function initialize_dataset
  97. !> Add a tensor to a dataset whose Fortran type is the equivalent 'int8' C-type
  98. function add_tensor_i8(self, name, data, dims) result(code)
  99. integer(kind=c_int8_t), dimension(..), target, intent(in) :: data !< Data to be sent
  100. class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset
  101. character(len=*), intent(in) :: name !< The unique name used to store in the database
  102. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  103. integer(kind=enum_kind) :: code !< Result of the operation
  104. include 'dataset/add_tensor_methods_common.inc'
  105. ! Define the type and call the C-interface
  106. data_type = tensor_int8
  107. code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, &
  108. c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous)
  109. end function add_tensor_i8
  110. !> Add a tensor to a dataset whose Fortran type is the equivalent 'int16' C-type
  111. function add_tensor_i16(self, name, data, dims) result(code)
  112. integer(kind=c_int16_t), dimension(..), target, intent(in) :: data !< Data to be sent
  113. class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset
  114. character(len=*), intent(in) :: name !< The unique name used to store in the database
  115. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  116. integer(kind=enum_kind) :: code !< Result of the operation
  117. include 'dataset/add_tensor_methods_common.inc'
  118. ! Define the type and call the C-interface
  119. data_type = tensor_int16
  120. code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, &
  121. c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous)
  122. end function add_tensor_i16
  123. !> Add a tensor to a dataset whose Fortran type is the equivalent 'int32' C-type
  124. function add_tensor_i32(self, name, data, dims) result(code)
  125. integer(kind=c_int32_t), dimension(..), target, intent(in) :: data !< Data to be sent
  126. class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset
  127. character(len=*), intent(in) :: name !< The unique name used to store in the database
  128. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  129. integer(kind=enum_kind) :: code !< Result of the operation
  130. include 'dataset/add_tensor_methods_common.inc'
  131. ! Define the type and call the C-interface
  132. data_type = tensor_int32
  133. code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, &
  134. c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous)
  135. end function add_tensor_i32
  136. !> Add a tensor to a dataset whose Fortran type is the equivalent 'int64' C-type
  137. function add_tensor_i64(self, name, data, dims) result(code)
  138. integer(kind=c_int64_t), dimension(..), target, intent(in) :: data !< Data to be sent
  139. class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset
  140. character(len=*), intent(in) :: name !< The unique name used to store in the database
  141. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  142. integer(kind=enum_kind) :: code !< Result of the operation
  143. include 'dataset/add_tensor_methods_common.inc'
  144. ! Define the type and call the C-interface
  145. data_type = tensor_int64
  146. code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, &
  147. c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous)
  148. end function add_tensor_i64
  149. !> Add a tensor to a dataset whose Fortran type is the equivalent 'float' C-type
  150. function add_tensor_float(self, name, data, dims) result(code)
  151. real(kind=c_float), dimension(..), target, intent(in) :: data !< Data to be sent
  152. class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset
  153. character(len=*), intent(in) :: name !< The unique name used to store in the database
  154. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  155. integer(kind=enum_kind) :: code !< Result of the operation
  156. include 'dataset/add_tensor_methods_common.inc'
  157. ! Define the type and call the C-interface
  158. data_type = tensor_flt
  159. code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, &
  160. c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous)
  161. end function add_tensor_float
  162. !> Add a tensor to a dataset whose Fortran type is the equivalent 'double' C-type
  163. function add_tensor_double(self, name, data, dims) result(code)
  164. real(kind=c_double), dimension(..), target, intent(in) :: data !< Data to be sent
  165. class(dataset_type), intent(in) :: self !< Fortran SmartRedis dataset
  166. character(len=*), intent(in) :: name !< The unique name used to store in the database
  167. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  168. integer(kind=enum_kind) :: code !< Result of the operation
  169. include 'dataset/add_tensor_methods_common.inc'
  170. ! Define the type and call the C-interface
  171. data_type = tensor_dbl
  172. code = add_tensor_c(self%dataset_ptr, c_name, name_length, data_ptr, &
  173. c_dims_ptr, c_n_dims, data_type, c_fortran_contiguous)
  174. end function add_tensor_double
  175. !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'int8' C-type
  176. function unpack_dataset_tensor_i8(self, name, result, dims) result(code)
  177. integer(kind=c_int8_t), dimension(..), target, intent(out) :: result !< Array to be populated with data
  178. class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset
  179. character(len=*), intent(in) :: name !< The name to use to place the tensor
  180. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  181. integer(kind=enum_kind) :: code
  182. include 'dataset/unpack_dataset_tensor_methods_common.inc'
  183. ! Define the type and call the C-interface
  184. data_type = tensor_int8
  185. code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, &
  186. data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout)
  187. end function unpack_dataset_tensor_i8
  188. !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'int16' C-type
  189. function unpack_dataset_tensor_i16(self, name, result, dims) result(code)
  190. integer(kind=c_int16_t), dimension(..), target, intent(out) :: result !< Array to be populated with data
  191. class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset
  192. character(len=*), intent(in) :: name !< The name to use to place the tensor
  193. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  194. integer(kind=enum_kind) :: code
  195. include 'dataset/unpack_dataset_tensor_methods_common.inc'
  196. ! Define the type and call the C-interface
  197. data_type = tensor_int16
  198. code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, &
  199. data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout)
  200. end function unpack_dataset_tensor_i16
  201. !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'int32' C-type
  202. function unpack_dataset_tensor_i32(self, name, result, dims) result(code)
  203. integer(kind=c_int32_t), dimension(..), target, intent(out) :: result !< Array to be populated with data
  204. class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset
  205. character(len=*), intent(in) :: name !< The name to use to place the tensor
  206. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  207. integer(kind=enum_kind) :: code
  208. include 'dataset/unpack_dataset_tensor_methods_common.inc'
  209. ! Define the type and call the C-interface
  210. data_type = tensor_int32
  211. code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, &
  212. data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout)
  213. end function unpack_dataset_tensor_i32
  214. !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'int64' C-type
  215. function unpack_dataset_tensor_i64(self, name, result, dims) result(code)
  216. integer(kind=c_int64_t), dimension(..), target, intent(out) :: result !< Array to be populated with data
  217. class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset
  218. character(len=*), intent(in) :: name !< The name to use to place the tensor
  219. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  220. integer(kind=enum_kind) :: code
  221. include 'dataset/unpack_dataset_tensor_methods_common.inc'
  222. ! Define the type and call the C-interface
  223. data_type = tensor_int64
  224. code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, &
  225. data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout)
  226. end function unpack_dataset_tensor_i64
  227. !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'float' C-type
  228. function unpack_dataset_tensor_float(self, name, result, dims) result(code)
  229. real(kind=c_float), dimension(..), target, intent(out) :: result !< Array to be populated with data
  230. class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset
  231. character(len=*), intent(in) :: name !< The name to use to place the tensor
  232. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  233. integer(kind=enum_kind) :: code
  234. include 'dataset/unpack_dataset_tensor_methods_common.inc'
  235. ! Define the type and call the C-interface
  236. data_type = tensor_flt
  237. code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, &
  238. data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout)
  239. end function unpack_dataset_tensor_float
  240. !> Unpack a tensor into already allocated memory whose Fortran type is the equivalent 'double' C-type
  241. function unpack_dataset_tensor_double(self, name, result, dims) result(code)
  242. real(kind=c_double), dimension(..), target, intent(out) :: result !< Array to be populated with data
  243. class(dataset_type), intent(in) :: self !< Pointer to the initialized dataset
  244. character(len=*), intent(in) :: name !< The name to use to place the tensor
  245. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  246. integer(kind=enum_kind) :: code
  247. include 'dataset/unpack_dataset_tensor_methods_common.inc'
  248. ! Define the type and call the C-interface
  249. data_type = tensor_dbl
  250. code = unpack_dataset_tensor_c(self%dataset_ptr, c_name, name_length, &
  251. data_ptr, c_dims_ptr, c_n_dims, data_type, mem_layout)
  252. end function unpack_dataset_tensor_double
  253. !> Get scalar metadata whose Fortran type is the equivalent 'int32' C-type
  254. function get_meta_scalars_i32(self, name, meta) result(code)
  255. class(dataset_type), intent(in) :: self !< The dataset
  256. character(len=*), intent(in) :: name !< The name of the metadata field
  257. integer(kind=c_int32_t), dimension(:), pointer :: meta !< The actual metadata
  258. integer(kind=enum_kind) :: code !< Result of the operation
  259. ! local variables
  260. integer(kind=enum_kind) :: expected_data_type = meta_int32
  261. include 'dataset/get_meta_scalars_common.inc'
  262. end function get_meta_scalars_i32
  263. !> Get scalar metadata whose Fortran type is the equivalent 'int64' C-type
  264. function get_meta_scalars_i64(self, name, meta) result(code)
  265. class(dataset_type), intent(in) :: self !< The dataset
  266. character(len=*), intent(in) :: name !< The name of the metadata field
  267. integer(kind=c_int64_t), dimension(:), pointer :: meta !< The actual metadata
  268. integer(kind=enum_kind) :: code !< Result of the operation
  269. ! local variables
  270. integer(kind=enum_kind) :: expected_data_type = meta_int64
  271. include 'dataset/get_meta_scalars_common.inc'
  272. end function get_meta_scalars_i64
  273. !> Get scalar metadata whose Fortran type is the equivalent 'float' C-type
  274. function get_meta_scalars_float(self, name, meta) result(code)
  275. class(dataset_type), intent(in) :: self !< The dataset
  276. character(len=*), intent(in) :: name !< The name of the metadata field
  277. real(kind=c_float), dimension(:), pointer :: meta !< The actual metadata
  278. integer(kind=enum_kind) :: code !< Result of the operation
  279. ! local variables
  280. integer(kind=enum_kind) :: expected_data_type = meta_flt
  281. include 'dataset/get_meta_scalars_common.inc'
  282. end function get_meta_scalars_float
  283. !> Get scalar metadata whose Fortran type is the equivalent 'double' C-type
  284. function get_meta_scalars_double(self, name, meta) result(code)
  285. class(dataset_type), intent(in) :: self !< The dataset
  286. character(len=*), intent(in) :: name !< The name of the metadata field
  287. real(kind=c_double), dimension(:), pointer :: meta !< The actual metadata
  288. integer(kind=enum_kind) :: code !< Result of the operation
  289. ! local variables
  290. integer(kind=enum_kind) :: expected_data_type = meta_dbl
  291. include 'dataset/get_meta_scalars_common.inc'
  292. end function get_meta_scalars_double
  293. !> Add scalar metadata whose Fortran type is the equivalent 'int32' C-type
  294. function add_meta_scalar_i32(self, name, meta) result(code)
  295. class(dataset_type), intent(in) :: self !< The dataset
  296. character(len=*), intent(in) :: name !< The name of the metadata field
  297. integer(kind=c_int32_t), target, intent(in) :: meta !< The actual metadata
  298. integer(kind=enum_kind) :: code !< Result of the operation
  299. ! local variables
  300. integer(kind=enum_kind), parameter :: meta_type = meta_int32
  301. include 'dataset/add_meta_scalar_common.inc'
  302. end function add_meta_scalar_i32
  303. !> Add scalar metadata whose Fortran type is the equivalent 'int64' C-type
  304. function add_meta_scalar_i64(self, name, meta) result(code)
  305. class(dataset_type), intent(in) :: self !< The dataset
  306. character(len=*), intent(in) :: name !< The name of the metadata field
  307. integer(kind=c_int64_t), target, intent(in) :: meta !< The actual metadata
  308. integer(kind=enum_kind) :: code !< Result of the operation
  309. ! local variables
  310. integer(kind=enum_kind), parameter :: meta_type = meta_int64
  311. include 'dataset/add_meta_scalar_common.inc'
  312. end function add_meta_scalar_i64
  313. !> Add scalar metadata whose Fortran type is the equivalent 'float' C-type
  314. function add_meta_scalar_float(self, name, meta) result(code)
  315. class(dataset_type), intent(in) :: self !< The dataset
  316. character(len=*), intent(in) :: name !< The name of the metadata field
  317. real(kind=c_float), target, intent(in) :: meta !< The actual metadata
  318. integer(kind=enum_kind) :: code !< Result of the operation
  319. ! local variables
  320. integer(kind=enum_kind), parameter :: meta_type = meta_flt
  321. include 'dataset/add_meta_scalar_common.inc'
  322. end function add_meta_scalar_float
  323. !> Add scalar metadata whose Fortran type is the equivalent 'double' C-type
  324. function add_meta_scalar_double(self, name, meta) result(code)
  325. class(dataset_type), intent(in) :: self !< The dataset
  326. character(len=*), intent(in) :: name !< The name of the metadata field
  327. real(kind=c_double), target, intent(in) :: meta !< The actual metadata
  328. integer(kind=enum_kind) :: code !< Result of the operation
  329. ! local variables
  330. integer(kind=enum_kind), parameter :: meta_type = meta_dbl
  331. include 'dataset/add_meta_scalar_common.inc'
  332. end function add_meta_scalar_double
  333. !> Add string-like metadata to the dataset
  334. function add_meta_string( self, name, meta) result(code)
  335. class(dataset_type), intent(in) :: self !< The dataset
  336. character(len=*), intent(in) :: name !< The name of the metadata field
  337. character(len=*), intent(in) :: meta !< The actual metadata
  338. integer(kind=enum_kind) :: code !< Result of the operation
  339. ! local variables
  340. character(kind=c_char, len=len_trim(meta)) :: c_meta
  341. character(kind=c_char, len=len_trim(name)) :: c_name
  342. integer(kind=c_size_t) :: meta_length, name_length
  343. c_name = trim(name)
  344. c_meta = trim(meta)
  345. meta_length = len_trim(c_meta)
  346. name_length = len_trim(c_name)
  347. code = add_meta_string_c(self%dataset_ptr, c_name, name_length, c_meta, meta_length)
  348. end function add_meta_string
  349. end module smartredis_dataset