file_hdf.F90 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238
  1. !
  2. !ProTeX: 1.14-AJS
  3. !
  4. !BOI
  5. !
  6. ! !TITLE: File_HDF - Interface to HDF4 files
  7. ! !AUTHORS: Arjo Segers, Roeland van Oss, Gijs van Soest, Jos van Geffen
  8. ! !AFFILIATION: KNMI
  9. ! !DATE: \today
  10. !
  11. ! !INTRODUCTION: Introduction
  12. !
  13. ! The routines facilitate reading/writing of integer or real arrays.
  14. ! The following type/kinds are possible:
  15. !
  16. ! \begin{tabular}{cc}
  17. ! integer(1) & \\
  18. ! integer(2) & \\
  19. ! integer(4) & real(4) \\
  20. ! integer(8) & real(8) \\
  21. ! \end{tabular}
  22. !
  23. ! Subroutines convert where possible between types and/or kinds:
  24. ! \begin{itemize}
  25. ! \item
  26. ! integer/real data from a hdf file is converted to the kind of
  27. ! the output array provided to reading routines;
  28. ! \item
  29. ! integer data might be read into a real array;
  30. ! \item
  31. ! integer/real arrays might be written in an other kind than that
  32. ! of the original array.
  33. ! \end{itemize}
  34. !
  35. !
  36. ! !INTRODUCTION: Compile and link
  37. !
  38. ! The module includes the file "hdf.f90" from the HDF4 distribution.
  39. ! The include directory with this file should be specified in an
  40. ! argument of the 'configure' script:
  41. ! \bv
  42. ! ./configure --includes=/usr/local/include
  43. ! \ev
  44. !
  45. ! The library should be linked together with the default hdf libraries.
  46. !
  47. !
  48. ! !INTRODUCTION: Usage
  49. !
  50. ! \bv
  51. !
  52. ! use file_hdf
  53. !
  54. ! HDF files
  55. ! ---------
  56. !
  57. ! type(THdfFile) :: hdf
  58. !
  59. ! call Init( hdf, '/data/test.hdf', 'read'|'create'|'write', status )
  60. !
  61. ! call GetInfo( hdf, status [,num_datasets=] [,num_global_attrs=] )
  62. !
  63. ! call Done( hdf, status )
  64. !
  65. !
  66. ! Scientific Data Sets
  67. ! --------------------
  68. !
  69. ! type(TSds) :: sds
  70. !
  71. !
  72. ! !
  73. ! ! *** basic access
  74. ! !
  75. !
  76. ! call Init( sds, status )
  77. !
  78. ! !
  79. ! ! select sds in hdf file;
  80. ! ! index : sets numbered 0,..,num_datasets-1
  81. ! !
  82. ! call Select( sds, hdf, index, status )
  83. !
  84. ! !
  85. ! ! extract properties
  86. ! !
  87. ! call GetInfo( sds, status [,name=] [,data_rank=] [,data_dims=] [,data_type=] [,num_attrs=] )
  88. !
  89. ! !
  90. ! ! check sds params:
  91. ! ! name : case independent
  92. ! !
  93. ! ! status : on input : if non-zero, do not print error messages
  94. ! ! on output : <0 check failed, =0 check success, >0 error
  95. ! !
  96. ! call CheckInfo( sds, status [,name=] [,data_rank=] [,data_dims=] [,data_type=] [,num_attrs=] )
  97. !
  98. ! call Done( sds, status )
  99. !
  100. !
  101. ! !
  102. ! ! *** init for reading
  103. ! !
  104. !
  105. ! call Init( sds, hdf, 'name', status )
  106. !
  107. ! call ReadData( sds, x(:,:,..), status [,start=(/0,0,../)] [,stride=(/1,1,../)] )
  108. !
  109. ! call Done( sds, status )
  110. !
  111. !
  112. ! !
  113. ! ! *** init for creation
  114. ! !
  115. !
  116. ! call Init( sds, hdf, 'name', shape(x), <typekey>, status [,knd=] [,bits=] )
  117. !
  118. ! ! The last value of the shape array might be the
  119. ! ! hdf constant 'SD_UNLIMITED' to specify an unlimited dimension.
  120. ! !
  121. ! ! The <typekey> with optional knd or bits specify
  122. ! ! how the data is storred:
  123. ! !
  124. ! ! 'int8' | 'integer(1)' | ('int' |'integer'), (bits=8 |knd=1)
  125. ! ! 'int16' | 'integer(2)' | ('int' |'integer'), (bits=16|knd=2)
  126. ! ! 'int32' | 'integer(4)' | ('int' |'integer'), (bits=32|knd=4)
  127. ! ! 'int64' | 'integer(8)' | ('int' |'integer'), (bits=64|knd=8)
  128. ! ! 'float32' | 'real(4)' | ('float'|'real' ), (bits=32|knd=4)
  129. ! ! 'float64' | 'real(8)' | ('float'|'real' ), (bits=64|knd=8)
  130. ! !
  131. ! ! 'char'
  132. ! !
  133. !
  134. ! call Compress( sds, 'none' , status )
  135. ! call Compress( sds, 'rle' , status )
  136. ! call Compress( sds, 'skphuff', status [,skip_size=1..] )
  137. ! call Compress( sds, 'deflate', status [,deflate_level=0..9] )
  138. !
  139. ! call WriteData( sds, x, status [,start=(/0,0,../)] [,stride=(/1,1,../)] )
  140. !
  141. ! call Done( sds, status )
  142. !
  143. !
  144. ! !
  145. ! ! *** init for creation with unlimited dimension
  146. ! !
  147. !
  148. ! call Init( sds, hdf, 'name', (/2,3,..,SD_UNLIMITED/), &
  149. ! <typekey>, status [,knd=] [,bits=] )
  150. !
  151. ! call WriteData( sds, x(:,:,..,1), status, start=(/0,0,..,0/) [,stride=(/1,1,../)] )
  152. ! call WriteData( sds, x(:,:,..,1), status, start=(/0,0,..,1/) [,stride=(/1,1,../)] )
  153. ! :
  154. !
  155. ! call Done( sds, status )
  156. !
  157. !
  158. ! SDS dimensions
  159. ! --------------
  160. !
  161. ! Simple usage:
  162. !
  163. ! call SetDim( sds, dim_index, 'name', 'unit', (/../), status [,knd=] )
  164. !
  165. ! or using the expert routines:
  166. !
  167. ! type(TSdsDim) :: dim
  168. ! call Init( dim, status )
  169. ! call Select( dim, sds, dim_index, status ) ! 0,..,n-1
  170. ! call SetName( dim, 'name'. status )
  171. ! call SetScale( dim, (/../), status [,knd=] )
  172. ! call Done( dim, status )
  173. !
  174. !
  175. ! Attributes
  176. ! ----------
  177. !
  178. ! !
  179. ! ! select attribute index of certain attribute;
  180. ! ! status /= 0 if not found
  181. ! !
  182. ! call FindAttribute( hdf|sds|dim, 'name', attr_index, status )
  183. !
  184. ! !
  185. ! ! get attribute params:
  186. ! ! attr_index : sets numbered 0,..,num_attrs-1
  187. ! ! data_type : internal hdf number, see hdf manual
  188. ! ! data_type_descr : 'i', 'r', 's'
  189. ! ! (no 'l', since logicals are storred as integers)
  190. ! !
  191. ! call GetAttributeInfo( hdf|sds|dim, attr_index, status &
  192. ! [,name=] &
  193. ! [,data_type=] [,data_type_descr=c] &
  194. ! [,n_values=] )
  195. !
  196. ! !
  197. ! ! check attribute params:
  198. ! ! name : case independent
  199. ! ! attr_index : sets numbered 0,..,num_attrs-1
  200. ! !
  201. ! ! status : on input : if zero, print error messages;
  202. ! ! on output : <0 check failed, =0 check success, >0 error
  203. ! !
  204. ! call CheckAttributeInfo( hdf|sds|dim, attr_index, status [,name=] [,data_type=] [,n_values=] )
  205. !
  206. ! call ReadAttribute( hdf|sds|dim, 'name', i, status )
  207. ! call ReadAttribute( hdf|sds|dim, 'name', r, status )
  208. ! call ReadAttribute( hdf|sds|dim, 'name', l, status )
  209. ! call ReadAttribute( hdf|sds|dim, 'name', s, status )
  210. !
  211. ! !
  212. ! ! status : on input : if non-zero, do not print error messages
  213. ! ! on output : <0 check failed, =0 check success, >0 error
  214. ! !
  215. ! call CheckAttribute( hdf|sds|dim, 'name', 1 ,status )
  216. ! call CheckAttribute( hdf|sds|dim, 'name', 1.0 ,status )
  217. ! call CheckAttribute( hdf|sds|dim, 'name', .true.,status )
  218. ! call CheckAttribute( hdf|sds|dim, 'name', 's' ,status )
  219. !
  220. ! call WriteAttribute( hdf|sds|dim, 'name', 1 ,status [,knd=] )
  221. ! call WriteAttribute( hdf|sds|dim, 'name', 1.0 ,status [,knd=] )
  222. ! call WriteAttribute( hdf|sds|dim, 'name', .true.,status )
  223. ! call WriteAttribute( hdf|sds|dim, 'name', 's' ,status )
  224. !
  225. !
  226. ! Time series
  227. ! -----------
  228. !
  229. ! Write time series of n-D arrays to a hdf file.
  230. !
  231. ! type(TTimeSeriesHDF) :: F
  232. !
  233. ! ! Open file, specify maximum number of data sets:
  234. ! call Init( F, 'test.hdf', 40, status )
  235. !
  236. ! ! Add new record for field.
  237. ! ! If field does not exist yet, it is created with the specified:
  238. ! ! o unit as attribute
  239. ! ! o type key : 'real(4)', 'integer(2)', etc
  240. ! ! o maximum shape
  241. ! ! For arrays, the maximum size should be provided.
  242. !
  243. ! ! first calls initialise the data sets and fill first temporal record:
  244. ! call AddRecord( F, 'psurf' , 'comment', 'hPa', 'real(4)', 1000.0, status )
  245. ! call AddRecord( F, 'press' , 'comment', 'hPa', 'real(4)', (/60/) , pp(:) , status )
  246. ! call AddRecord( F, 'kernel', 'comment', 'c/c', 'real(4)', (/20,20/), A(:,:), status )
  247. ! call AddRecord( F, 'key', 5, 'ab123', status )
  248. !
  249. ! ! extra calls add records:
  250. ! call AddRecord( F, 'press' , 'comment', 'hPa', 'real(4)', (/60/) , pp(:) , status )
  251. ! call AddRecord( F, 'press' , 'comment', 'hPa', 'real(4)', (/60/) , pp(:) , status )
  252. !
  253. ! ! Close file:
  254. ! call Done( F, status )
  255. !
  256. ! \ev
  257. !
  258. !
  259. ! !INTRODUCTION: Examples
  260. !
  261. ! \bv
  262. !
  263. ! ! Extract array from existing hdf file.
  264. ! ! Sds is identified by name 'aaa' .
  265. ! ! Attribute 'version' should be 'v1.23' .
  266. ! ! Error messages are issued in case of any error.
  267. ! type(THdfFile) :: hdf
  268. ! type(TSds) :: sds
  269. ! real :: x(10,20)
  270. ! call Init( hdf, 'test.hdf', 'read', status )
  271. ! call Init( sds, hdf, 'aaa', status )
  272. ! call CheckAttribute( sds, 'version', 'v1.23', status )
  273. ! call ReadData( sds, x, status )
  274. ! call Done( sds, status )
  275. ! call Done( hdf, status )
  276. !
  277. ! ! Extract array from existing hdf file.
  278. ! ! Sds is identified by name 'aaa' and a time attribure.
  279. ! ! Error messages are issued in case of any error.
  280. ! type(THdfFile) :: hdf
  281. ! type(TSds) :: sds
  282. ! real :: x(10,20)
  283. ! integer :: n, k
  284. ! integer :: status
  285. ! call Init( hdf, 'test.hdf', 'read', status )
  286. ! call Init( sds, status )
  287. ! call GetInfo( hdf, status, num_datasets=n )
  288. ! k = 0
  289. ! do
  290. ! k = k + 1
  291. ! if ( k > n ) stop 'sds not found'
  292. ! call Select( sds, hdf, k-1, status ) ! <-- sets numbered 0..n-1 !
  293. ! call CheckInfo( sds, name='aaa', status )
  294. ! if ( status /= 0 ) cycle
  295. ! call CheckAttribute( sds, 'time', (/2000,1,1,0,0,0/), status )
  296. ! if ( status /= 0 ) cycle
  297. ! call ReadData( sds, x, status )
  298. ! end do
  299. ! call Done( sds, status )
  300. ! call Done( hdf, status )
  301. !
  302. ! ! Write array to a hdf file.
  303. ! type(THdfFile) :: hdf
  304. ! type(TSds) :: sds
  305. ! real :: x(10,20)
  306. ! x = 0.0
  307. ! call Init( hdf, 'test.hdf', 'create', status )
  308. ! call Init( sds, hdf, 'aaa', shape(x), 'real(4)', status )
  309. ! call SetDim( sds, 0, 'lon', 'deg', lons, status )
  310. ! call SetDim( sds, 1, 'lat', 'deg', lats, status )
  311. ! call Compress( sds, 'deflate', status, deflate_level=6 )
  312. ! call WriteData( sds, x, status )
  313. ! call Done( sds, status )
  314. ! call Done( hdf, status )
  315. !
  316. !
  317. ! \ev
  318. !
  319. ! !INTRODUCTION: Source files
  320. !
  321. ! \bv
  322. !
  323. ! configure : script to generate source files and Makefile
  324. !
  325. ! file_hdf_base.f90 : definition of types, basic routines
  326. !
  327. ! file_hdf_iwp.F90.in : template for routines dealing with integer
  328. ! variables of different kinds in files named:
  329. ! file_hdf_i4.f90
  330. ! file_hdf_i8.f90
  331. ! etc; the template contains keys '<wp>' that are
  332. ! replaced by '4', '8' etc via a sed command in
  333. ! the makefile
  334. !
  335. ! file_hdf_rwp.F90.in : template for routines dealing with real
  336. ! variables of different kinds
  337. !
  338. ! file_hdf_l.f90 : routines dealing with logical variables
  339. !
  340. ! file_hdf_s.f90 : routines dealing with charcter string variables
  341. !
  342. ! file_hdf.f90.in : Template for the main module that collects all other;
  343. ! comments '!i<wp>!' etc are removed if the
  344. ! corresponding kind specific modules are generated
  345. ! Also contains types and routines for time series.
  346. !
  347. !
  348. ! \ev
  349. !
  350. ! !INTRODUCTION: See also
  351. !
  352. ! \begin{itemize}
  353. ! \item \htmladdnormallink{HDF Documentation}{http://hdf.ncsa.uiuc.edu/hdf4.html}
  354. ! \end{itemize}
  355. !
  356. !EOI
  357. module file_hdf
  358. use file_hdf_base, only : THdfFile, TSds, TSdsDim
  359. use file_hdf_base, only : SD_UNLIMITED
  360. use file_hdf_base, only : Init, Done
  361. use file_hdf_base, only : Select
  362. use file_hdf_base, only : GetInfo, CheckInfo
  363. use file_hdf_base, only : Compress
  364. use file_hdf_base, only : SetName
  365. use file_hdf_base, only : FindDataSet
  366. use file_hdf_base, only : FindAttribute, GetAttributeInfo, CheckAttributeInfo
  367. use file_hdf_i1, only : ReadAttribute, CheckAttribute, WriteAttribute, ReadData, WriteData, SetScale, SetDim
  368. use file_hdf_i2, only : ReadAttribute, CheckAttribute, WriteAttribute, ReadData, WriteData, SetScale, SetDim
  369. use file_hdf_i4, only : ReadAttribute, CheckAttribute, WriteAttribute, ReadData, WriteData, SetScale, SetDim
  370. use file_hdf_i8, only : ReadAttribute, CheckAttribute, WriteAttribute, ReadData, WriteData, SetScale, SetDim
  371. use file_hdf_r4, only : ReadAttribute, CheckAttribute, WriteAttribute, ReadData, WriteData, SetScale, SetDim
  372. use file_hdf_r8, only : ReadAttribute, CheckAttribute, WriteAttribute, ReadData, WriteData, SetScale, SetDim
  373. use file_hdf_l, only : ReadAttribute, CheckAttribute, WriteAttribute
  374. use file_hdf_s, only : ReadAttribute, CheckAttribute, WriteAttribute, ReadData, WriteData
  375. implicit none
  376. ! --- in/out --------------------------
  377. private
  378. public :: SD_UNLIMITED
  379. public :: THdfFile
  380. public :: TSds
  381. public :: TSdsDim
  382. public :: Init, Done
  383. public :: GetInfo, CheckInfo
  384. public :: Select
  385. public :: FindDataSet
  386. public :: ReadData
  387. public :: Compress, WriteData
  388. public :: SetName, SetScale, SetDim
  389. public :: FindAttribute
  390. public :: GetAttributeInfo, CheckAttributeInfo
  391. public :: ReadAttribute, CheckAttribute
  392. public :: WriteAttribute
  393. public :: TTimeSeriesHDF, TTimeSeriesSDS
  394. public :: AddRecord
  395. ! --- const ------------------------------
  396. ! module name
  397. character(len=*), parameter :: mname = 'file_hdf'
  398. ! default compression of hdf data sets
  399. character(len=*), parameter :: compression = 'none'
  400. !character(len=*), parameter :: compression = 'deflate' ! <--- errors ...
  401. ! --- types -------------------------------
  402. type TTimeSeriesSDS
  403. type(TSds) :: sds
  404. character(len=20) :: name
  405. integer, pointer :: shp(:)
  406. integer :: istart
  407. end type TTimeSeriesSDS
  408. type TTimeSeriesHDF
  409. character(len=256) :: fname
  410. type(THdfFile) :: hdf
  411. integer :: nfield
  412. integer :: mfield
  413. type(TTimeSeriesSDS), pointer :: tss(:)
  414. end type TTimeSeriesHDF
  415. ! --- interfaces -------------------------
  416. interface Init
  417. module procedure tsh_Init
  418. end interface
  419. interface Done
  420. module procedure tsh_Done
  421. end interface
  422. interface AddRecord
  423. module procedure tsh_AddRecord_i
  424. module procedure tsh_AddRecord_i1
  425. module procedure tsh_AddRecord_i2
  426. module procedure tsh_AddRecord_i3
  427. module procedure tsh_AddRecord_r
  428. module procedure tsh_AddRecord_r1
  429. module procedure tsh_AddRecord_r2
  430. module procedure tsh_AddRecord_r3
  431. module procedure tsh_AddRecord_r4
  432. module procedure tsh_AddRecord_s
  433. end interface
  434. contains
  435. ! ===========================================================
  436. subroutine tsh_Init( F, fname, mfield, status )
  437. ! --- in/out ------------------------------------
  438. type(TTimeSeriesHDF), intent(out) :: F
  439. character(len=*), intent(in) :: fname
  440. integer, intent(in) :: mfield
  441. integer, intent(out) :: status
  442. ! --- const ------------------------------------
  443. character(len=*), parameter :: rname = mname//'/tsh_Init'
  444. ! --- local ------------------------------------
  445. integer :: i
  446. ! --- begin -------------------------------------
  447. ! store file name
  448. F%fname = fname
  449. ! open new hdf file
  450. call Init( F%hdf, trim(F%fname), 'create', status )
  451. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  452. ! set maximum nuber of fields
  453. if ( mfield <= 0 ) then
  454. write (*,'("ERROR - strange argument for maximum number of fields:")')
  455. write (*,'("ERROR - mfield : ",i6)') mfield
  456. write (*,'("ERROR - file : ",a)') trim(F%fname)
  457. write (*,'("ERROR in ",a)') rname; status=1; return
  458. end if
  459. F%mfield = mfield
  460. ! init fields
  461. allocate( F%tss(F%mfield) )
  462. do i = 1, F%mfield
  463. nullify( F%tss(i)%shp )
  464. end do
  465. ! no fields defined yet
  466. F%nfield = 0
  467. ! ok
  468. status = 0
  469. end subroutine tsh_Init
  470. ! ***
  471. subroutine tsh_Done( F, status )
  472. ! --- in/out ------------------------------------
  473. type(TTimeSeriesHDF), intent(inout) :: F
  474. integer, intent(out) :: status
  475. ! --- const ------------------------------------
  476. character(len=*), parameter :: rname = mname//'/tsh_Done'
  477. ! --- local ------------------------------------
  478. integer :: i
  479. ! --- begin -------------------------------------
  480. ! close fields
  481. do i = 1, F%nfield
  482. ! close set
  483. call Done( F%tss(i)%sds, status )
  484. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  485. ! destroy arrays
  486. deallocate( F%tss(i)%shp )
  487. end do
  488. ! deallocate
  489. deallocate( F%tss )
  490. ! close hdf file
  491. call Done( F%hdf, status )
  492. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  493. ! ok
  494. status = 0
  495. end subroutine tsh_Done
  496. ! ***
  497. subroutine SearchField( F, name, comment, unit, shp, shp_x, typekey, k, status )
  498. ! --- in/out -----------------------
  499. type(TTimeSeriesHDF), intent(inout) :: F
  500. character(len=*), intent(in) :: name
  501. character(len=*), intent(in) :: comment
  502. character(len=*), intent(in) :: unit
  503. integer, intent(in) :: shp(:)
  504. integer, intent(in) :: shp_x(:)
  505. character(len=*), intent(in) :: typekey
  506. integer, intent(out) :: k
  507. integer, intent(out) :: status
  508. ! --- const --------------------------------------
  509. character(len=*), parameter :: rname = mname//'/SearchField'
  510. ! --- local --------------------------------------
  511. integer :: i
  512. ! --- local ---------------------------------------
  513. ! not found by default ...
  514. k = -1
  515. ! loop over current fields
  516. do i = 1, F%nfield
  517. ! this field ? then leave
  518. if ( F%tss(i)%name == name ) then
  519. k = i
  520. exit
  521. end if
  522. end do
  523. ! name ok ? then check shape
  524. if ( k > 0 ) then
  525. if ( size(shp_x) /= size(F%tss(k)%shp) ) then
  526. write (*,'("ERROR - rank of record is not the same as rank of open data set:")')
  527. write (*,'("ERROR - data set name : ",a)') F%tss(k)%name
  528. write (*,'("ERROR - data set shape : ",7i4)') F%tss(k)%shp
  529. write (*,'("ERROR - requested shape : ",7i4)') shp
  530. write (*,'("ERROR in ",a)') rname; status=1; return
  531. end if
  532. if ( any( shp_x > F%tss(k)%shp ) ) then
  533. write (*,'("ERROR - max shape of record exceeds shape of input array:")')
  534. write (*,'("ERROR - data set name : ",a)') F%tss(k)%name
  535. write (*,'("ERROR - data set shape : ",7i4)') F%tss(k)%shp
  536. write (*,'("ERROR - array shape : ",7i4)') shp_x
  537. write (*,'("ERROR in ",a)') rname; status=1; return
  538. end if
  539. ! found and ok
  540. status=0; return
  541. end if
  542. ! not found, thus new number
  543. if ( F%nfield == F%mfield ) then
  544. write (*,'("ERROR - unable to add new field after ",i4)') F%mfield
  545. write (*,'("ERROR - please increase argument `mfield` to Init procedure.")')
  546. write (*,'("ERROR in ",a)') rname; status=1; return
  547. end if
  548. F%nfield = F%nfield + 1
  549. k = F%nfield
  550. ! init new field
  551. ! * store name
  552. F%tss(k)%name = name
  553. ! * init data set
  554. call Init( F%tss(k)%sds, F%hdf, name, shp, typekey, status )
  555. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  556. !call Compress( F%tss(k)%sds, compression=compression )
  557. ! * comment
  558. if ( len_trim(comment) > 0 ) then
  559. call WriteAttribute( F%tss(k)%sds, 'comment', comment, status )
  560. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  561. end if
  562. ! * store unit ?
  563. if ( len_trim(unit) > 0 ) then
  564. call WriteAttribute( F%tss(k)%sds, 'unit', unit, status )
  565. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  566. end if
  567. ! * store shape
  568. allocate( F%tss(k)%shp(size(shp)) )
  569. F%tss(k)%shp = shp
  570. ! * init record counter
  571. F%tss(k)%istart = 0
  572. ! ok
  573. status = 0
  574. end subroutine SearchField
  575. ! ****************************************************************
  576. ! *** integer
  577. ! ****************************************************************
  578. subroutine tsh_AddRecord_i( F, name, comment, unit, typekey, x, status )
  579. ! --- in/out -----------------------
  580. type(TTimeSeriesHDF), intent(inout) :: F
  581. character(len=*), intent(in) :: name
  582. character(len=*), intent(in) :: comment
  583. character(len=*), intent(in) :: unit
  584. character(len=*), intent(in) :: typekey
  585. integer, intent(in) :: x
  586. integer, intent(out) :: status
  587. ! --- const --------------------------------------
  588. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_i'
  589. ! --- local --------------------------------------
  590. integer :: k
  591. integer :: start(1)
  592. ! --- local ---------------------------------------
  593. ! search index
  594. call SearchField( F, name, comment, unit, (/SD_UNLIMITED/), (/SD_UNLIMITED/), typekey, k, status )
  595. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  596. ! write record
  597. start = (/F%tss(k)%istart/)
  598. call WriteData( F%tss(k)%sds, (/x/), status, start=start )
  599. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  600. ! increase record base:
  601. F%tss(k)%istart = F%tss(k)%istart + 1
  602. ! ok
  603. status = 0
  604. end subroutine tsh_AddRecord_i
  605. ! ***
  606. subroutine tsh_AddRecord_i1( F, name, comment, unit, typekey, shp, x, status )
  607. use parray, only : pa_Init, pa_SetShape, pa_Done
  608. ! --- in/out -----------------------
  609. type(TTimeSeriesHDF), intent(inout) :: F
  610. character(len=*), intent(in) :: name
  611. character(len=*), intent(in) :: comment
  612. character(len=*), intent(in) :: unit
  613. character(len=*), intent(in) :: typekey
  614. integer, intent(in) :: shp(:)
  615. integer, intent(in) :: x(:)
  616. integer, intent(out) :: status
  617. ! --- const --------------------------------------
  618. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_i1'
  619. ! --- local --------------------------------------
  620. integer, pointer :: xa(:,:)
  621. integer :: k
  622. integer :: start(2)
  623. ! --- local ---------------------------------------
  624. ! search index
  625. call SearchField( F, name, comment, unit, &
  626. (/shp,SD_UNLIMITED/), (/shape(x),SD_UNLIMITED/), &
  627. typekey, k, status )
  628. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  629. ! write record
  630. call pa_Init( xa )
  631. call pa_SetShape( xa, (/shp,1/) )
  632. xa = 0
  633. xa(1:size(x),1) = x
  634. start = (/0,F%tss(k)%istart/)
  635. call WriteData( F%tss(k)%sds, xa, status, start=start )
  636. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  637. call pa_Done( xa )
  638. ! increase record base:
  639. F%tss(k)%istart = F%tss(k)%istart + 1
  640. ! ok
  641. status = 0
  642. end subroutine tsh_AddRecord_i1
  643. ! ***
  644. subroutine tsh_AddRecord_i2( F, name, comment, unit, typekey, shp, x, status )
  645. use parray, only : pa_Init, pa_SetShape, pa_Done
  646. ! --- in/out -----------------------
  647. type(TTimeSeriesHDF), intent(inout) :: F
  648. character(len=*), intent(in) :: name
  649. character(len=*), intent(in) :: comment
  650. character(len=*), intent(in) :: unit
  651. character(len=*), intent(in) :: typekey
  652. integer, intent(in) :: shp(:)
  653. integer, intent(in) :: x(:,:)
  654. integer, intent(out) :: status
  655. ! --- const --------------------------------------
  656. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_i2'
  657. ! --- local --------------------------------------
  658. integer, pointer :: xa(:,:,:)
  659. integer :: k
  660. integer :: start(3)
  661. ! --- local ---------------------------------------
  662. ! search index
  663. call SearchField( F, name, comment, unit, &
  664. (/shp,SD_UNLIMITED/), (/shape(x),SD_UNLIMITED/), &
  665. typekey, k, status )
  666. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  667. ! write record
  668. call pa_Init( xa )
  669. call pa_SetShape( xa, (/shp,1/) )
  670. xa = 0
  671. xa(1:size(x,1),1:size(x,2),1) = x
  672. start = (/0,0,F%tss(k)%istart/)
  673. call WriteData( F%tss(k)%sds, xa, status, start=start )
  674. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  675. call pa_Done( xa )
  676. ! increase record base:
  677. F%tss(k)%istart = F%tss(k)%istart + 1
  678. ! ok
  679. status = 0
  680. end subroutine tsh_AddRecord_i2
  681. ! ***
  682. subroutine tsh_AddRecord_i3( F, name, comment, unit, typekey, shp, x, status )
  683. use parray, only : pa_Init, pa_SetShape, pa_Done
  684. ! --- in/out -----------------------
  685. type(TTimeSeriesHDF), intent(inout) :: F
  686. character(len=*), intent(in) :: name
  687. character(len=*), intent(in) :: comment
  688. character(len=*), intent(in) :: unit
  689. character(len=*), intent(in) :: typekey
  690. integer, intent(in) :: shp(:)
  691. integer, intent(in) :: x(:,:,:)
  692. integer, intent(out) :: status
  693. ! --- const --------------------------------------
  694. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_i3'
  695. ! --- local --------------------------------------
  696. integer, pointer :: xa(:,:,:,:)
  697. integer :: k
  698. integer :: start(4)
  699. ! --- local ---------------------------------------
  700. ! search index
  701. call SearchField( F, name, comment, unit, &
  702. (/shp,SD_UNLIMITED/), (/shape(x),SD_UNLIMITED/), &
  703. typekey, k, status )
  704. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  705. ! write record
  706. call pa_Init( xa )
  707. call pa_SetShape( xa, (/shp,1/) )
  708. xa = 0
  709. xa(1:size(x,1),1:size(x,2),1:size(x,3),1) = x
  710. start = (/0,0,0,F%tss(k)%istart/)
  711. call WriteData( F%tss(k)%sds, xa, status, start=start )
  712. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  713. call pa_Done( xa )
  714. ! increase record base:
  715. F%tss(k)%istart = F%tss(k)%istart + 1
  716. ! ok
  717. status = 0
  718. end subroutine tsh_AddRecord_i3
  719. ! ****************************************************************
  720. ! *** real
  721. ! ****************************************************************
  722. subroutine tsh_AddRecord_r( F, name, comment, unit, typekey, x, status )
  723. ! --- in/out -----------------------
  724. type(TTimeSeriesHDF), intent(inout) :: F
  725. character(len=*), intent(in) :: name
  726. character(len=*), intent(in) :: comment
  727. character(len=*), intent(in) :: unit
  728. character(len=*), intent(in) :: typekey
  729. real, intent(in) :: x
  730. integer, intent(out) :: status
  731. ! --- const --------------------------------------
  732. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_r'
  733. ! --- local --------------------------------------
  734. integer :: k
  735. integer :: start(1)
  736. ! --- local ---------------------------------------
  737. ! search index
  738. call SearchField( F, name, comment, unit, &
  739. (/SD_UNLIMITED/), (/SD_UNLIMITED/), &
  740. typekey, k, status )
  741. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  742. ! write record
  743. start = (/F%tss(k)%istart/)
  744. call WriteData( F%tss(k)%sds, (/x/), status, start=start )
  745. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  746. ! increase record base:
  747. F%tss(k)%istart = F%tss(k)%istart + 1
  748. ! ok
  749. status = 0
  750. end subroutine tsh_AddRecord_r
  751. ! ***
  752. subroutine tsh_AddRecord_r1( F, name, comment, unit, typekey, shp, x, status )
  753. use parray, only : pa_Init, pa_SetShape, pa_Done
  754. ! --- in/out -----------------------
  755. type(TTimeSeriesHDF), intent(inout) :: F
  756. character(len=*), intent(in) :: name
  757. character(len=*), intent(in) :: comment
  758. character(len=*), intent(in) :: unit
  759. character(len=*), intent(in) :: typekey
  760. integer, intent(in) :: shp(:)
  761. real, intent(in) :: x(:)
  762. integer, intent(out) :: status
  763. ! --- const --------------------------------------
  764. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_r1'
  765. ! --- local --------------------------------------
  766. real, pointer :: xa(:,:)
  767. integer :: k
  768. integer :: start(2)
  769. ! --- local ---------------------------------------
  770. ! search index
  771. call SearchField( F, name, comment, unit, &
  772. (/shp,SD_UNLIMITED/), (/shape(x),SD_UNLIMITED/), &
  773. typekey, k, status )
  774. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  775. ! write record
  776. call pa_Init( xa )
  777. call pa_SetShape( xa, (/shp,1/) )
  778. xa = 0.0
  779. xa(1:size(x),1) = x
  780. start = (/0,F%tss(k)%istart/)
  781. call WriteData( F%tss(k)%sds, xa, status, start=start )
  782. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  783. call pa_Done( xa )
  784. ! increase record base:
  785. F%tss(k)%istart = F%tss(k)%istart + 1
  786. ! ok
  787. status = 0
  788. end subroutine tsh_AddRecord_r1
  789. ! ***
  790. subroutine tsh_AddRecord_r2( F, name, comment, unit, typekey, shp, x, status )
  791. use parray, only : pa_Init, pa_SetShape, pa_Done
  792. ! --- in/out -----------------------
  793. type(TTimeSeriesHDF), intent(inout) :: F
  794. character(len=*), intent(in) :: name
  795. character(len=*), intent(in) :: comment
  796. character(len=*), intent(in) :: unit
  797. character(len=*), intent(in) :: typekey
  798. integer, intent(in) :: shp(:)
  799. real, intent(in) :: x(:,:)
  800. integer, intent(out) :: status
  801. ! --- const --------------------------------------
  802. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_r2'
  803. ! --- local --------------------------------------
  804. real, pointer :: xa(:,:,:)
  805. integer :: k
  806. integer :: start(3)
  807. ! --- local ---------------------------------------
  808. ! search index
  809. call SearchField( F, name, comment, unit, &
  810. (/shp,SD_UNLIMITED/), (/shape(x),SD_UNLIMITED/), &
  811. typekey, k, status )
  812. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  813. ! write record
  814. call pa_Init( xa )
  815. call pa_SetShape( xa, (/shp,1/) )
  816. xa = 0.0
  817. xa(1:size(x,1),1:size(x,2),1) = x
  818. start = (/0,0,F%tss(k)%istart/)
  819. call WriteData( F%tss(k)%sds, xa, status, start=start )
  820. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  821. call pa_Done( xa )
  822. ! increase record base:
  823. F%tss(k)%istart = F%tss(k)%istart + 1
  824. ! ok
  825. status = 0
  826. end subroutine tsh_AddRecord_r2
  827. ! ***
  828. subroutine tsh_AddRecord_r3( F, name, comment, unit, typekey, shp, x, status )
  829. use parray, only : pa_Init, pa_SetShape, pa_Done
  830. ! --- in/out -----------------------
  831. type(TTimeSeriesHDF), intent(inout) :: F
  832. character(len=*), intent(in) :: name
  833. character(len=*), intent(in) :: comment
  834. character(len=*), intent(in) :: unit
  835. character(len=*), intent(in) :: typekey
  836. integer, intent(in) :: shp(:)
  837. real, intent(in) :: x(:,:,:)
  838. integer, intent(out) :: status
  839. ! --- const --------------------------------------
  840. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_r3'
  841. ! --- local --------------------------------------
  842. real, pointer :: xa(:,:,:,:)
  843. integer :: k
  844. integer :: start(4)
  845. ! --- local ---------------------------------------
  846. ! search index
  847. call SearchField( F, name, comment, unit, &
  848. (/shp,SD_UNLIMITED/), (/shape(x),SD_UNLIMITED/), &
  849. typekey, k, status )
  850. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  851. ! write record
  852. call pa_Init( xa )
  853. call pa_SetShape( xa, (/shp,1/) )
  854. xa = 0.0
  855. xa(1:size(x,1),1:size(x,2),1:size(x,3),1) = x
  856. start = (/0,0,0,F%tss(k)%istart/)
  857. call WriteData( F%tss(k)%sds, xa, status, start=start )
  858. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  859. call pa_Done( xa )
  860. ! increase record base:
  861. F%tss(k)%istart = F%tss(k)%istart + 1
  862. ! ok
  863. status = 0
  864. end subroutine tsh_AddRecord_r3
  865. ! ***
  866. subroutine tsh_AddRecord_r4( F, name, comment, unit, typekey, shp, x, status )
  867. use parray, only : pa_Init, pa_SetShape, pa_Done
  868. ! --- in/out -----------------------
  869. type(TTimeSeriesHDF), intent(inout) :: F
  870. character(len=*), intent(in) :: name
  871. character(len=*), intent(in) :: comment
  872. character(len=*), intent(in) :: unit
  873. character(len=*), intent(in) :: typekey
  874. integer, intent(in) :: shp(:)
  875. real, intent(in) :: x(:,:,:,:)
  876. integer, intent(out) :: status
  877. ! --- const --------------------------------------
  878. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_r4'
  879. ! --- local --------------------------------------
  880. real, pointer :: xa(:,:,:,:,:)
  881. integer :: k
  882. integer :: start(5)
  883. ! --- local ---------------------------------------
  884. ! search index
  885. call SearchField( F, name, comment, unit, &
  886. (/shp,SD_UNLIMITED/), (/shape(x),SD_UNLIMITED/), &
  887. typekey, k, status )
  888. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  889. ! write record
  890. call pa_Init( xa )
  891. call pa_SetShape( xa, (/shp,1/) )
  892. xa = 0.0
  893. xa(1:size(x,1),1:size(x,2),1:size(x,3),1:size(x,4),1) = x
  894. start = (/0,0,0,0,F%tss(k)%istart/)
  895. call WriteData( F%tss(k)%sds, xa, status, start=start )
  896. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  897. call pa_Done( xa )
  898. ! increase record base:
  899. F%tss(k)%istart = F%tss(k)%istart + 1
  900. ! ok
  901. status = 0
  902. end subroutine tsh_AddRecord_r4
  903. ! ****************************************************************
  904. ! *** char
  905. ! ****************************************************************
  906. subroutine tsh_AddRecord_s( F, name, comment, slen, s, status )
  907. ! --- in/out -----------------------
  908. type(TTimeSeriesHDF), intent(inout) :: F
  909. character(len=*), intent(in) :: name
  910. character(len=*), intent(in) :: comment
  911. integer, intent(in) :: slen
  912. character(len=*), intent(in) :: s
  913. integer, intent(out) :: status
  914. ! --- const --------------------------------------
  915. character(len=*), parameter :: rname = mname//'/tsh_AddRecord_s'
  916. ! --- local --------------------------------------
  917. integer :: k
  918. integer :: start(2)
  919. ! --- local ---------------------------------------
  920. ! search index
  921. call SearchField( F, name, comment, 'none', &
  922. (/slen,SD_UNLIMITED/), (/len(s),SD_UNLIMITED/), &
  923. 'char', k, status )
  924. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  925. ! write record
  926. start = (/0,F%tss(k)%istart/)
  927. call WriteData( F%tss(k)%sds, (/s/), status, start=start )
  928. if (status/=0) then; write (*,'("ERROR in ",a)') rname; status=1; return; end if
  929. ! increase record base:
  930. F%tss(k)%istart = F%tss(k)%istart + 1
  931. ! ok
  932. status = 0
  933. end subroutine tsh_AddRecord_s
  934. end module file_hdf
  935. ! ########################################################################
  936. ! ###
  937. ! ### test program
  938. ! ###
  939. ! ########################################################################
  940. !
  941. !program test
  942. !
  943. ! use file_TimeSeriesHDF
  944. !
  945. ! type(TTimeSeriesHDF) :: F
  946. ! integer :: status
  947. ! integer :: i
  948. ! real :: a(3,4)
  949. ! real :: p(4)
  950. !
  951. ! print *, 'test: begin'
  952. !
  953. ! print *, 'test: open file ...'
  954. ! call Init( F, 'test.hdf', 30, status )
  955. ! if (status/=0) stop 'ERROR'
  956. !
  957. ! do i = 1, 10
  958. ! call AddRecord( F, 'lon', 'longitude', 'deg', 'real(4)', 5.0*i, status )
  959. ! if (status/=0) stop 'ERROR'
  960. ! call AddRecord( F, 'lat', 'latitude', 'deg', 'real(4)', (/2/), (/2.0*i,3.0*i/), status )
  961. ! if (status/=0) stop 'ERROR'
  962. ! end do
  963. !
  964. ! !call AddRecord( F, 'lat', 'deg', 'real(4)', (/2.0*i,3.0*i,4.0/), status )
  965. ! !if (status/=0) stop 'ERROR'
  966. !
  967. ! do i = 1, 3
  968. ! call AddRecord( F, 'kernel', 'averaging kernel', 'c/c', 'real(4)', (/3,4/), a*0.0+i, status )
  969. ! if (status/=0) stop 'ERROR'
  970. ! end do
  971. !
  972. ! do i = 1, 3
  973. ! call AddRecord( F, 'p', 'pressure', 'hPa', 'real(4)', (/6/), p*0.0+i, status )
  974. ! if (status/=0) stop 'ERROR'
  975. ! end do
  976. !
  977. ! do i = 1, 4
  978. ! call AddRecord( F, 'key', 'record key', 5, 'abc', status )
  979. ! if (status/=0) stop 'ERROR'
  980. ! end do
  981. !
  982. ! print *, 'test: close file ...'
  983. ! call Done( F, status )
  984. ! if (status/=0) stop 'ERROR'
  985. !
  986. ! print *, 'test: end'
  987. !
  988. !end program test