PEARL Procedures  rev-distro-3.0.0-0-gfa24916-dirty
Igor procedures for the analysis of PEARL data
pearl-area-import.ipf
Go to the documentation of this file.
1 #pragma TextEncoding = "UTF-8"
2 #pragma rtGlobals=3 // Use modern global access method and strict wave access.
3 #pragma IgorVersion = 6.36
4 #pragma ModuleName = PearlAreaImport
5 #pragma version = 1.13
6 #if IgorVersion() < 9.00
7 #include <HDF5 Browser>
8 #endif
9 #include "pearl-compat"
10 #include "pearl-gui-tools"
11 
12 // copyright (c) 2013-21 Paul Scherrer Institut
13 //
14 // Licensed under the Apache License, Version 2.0 (the "License");
15 // you may not use this file except in compliance with the License.
16 // You may obtain a copy of the License at
17 // http:///www.apache.org/licenses/LICENSE-2.0
18 
38 
43 
46 static function BeforeFileOpenHook(refNum,fileName,path,type,creator,kind)
47  variable refNum, kind
48  string fileName, path, type, creator
49 
50  variable handledOpen = 0
51 
52  //PathInfo $path
53  //string FilePath = s_path + filename
54  string NickName = PearlCleanupName(ParseFilePath(3, FileName, ":", 0, 0))
55  string FileExt = LowerStr(ParseFilePath(4, FileName, ":", 0, 0))
56  string result = ""
57 
58  // override nickname with custom setting
59  svar /z cnn = gsCustomNickName
60  if (svar_exists(cnn))
61  if (exists("gvNickNameIndex") != 2)
62  variable/g gvNickNameIndex = 1
63  endif
64  nvar nni = gvNickNameIndex
65  NickName = cnn + num2str(nni)
66  nni += 1
67  endif
68 
69  if (stringmatch(FileExt, "h5") == 1)
70  result = adh5_load_complete(NickName, path, FileName)
71  endif
72 
73  string/g s_latest_datafile = result
74  string/g s_latest_nickname = nickname
75 
76  handledOpen = strlen(result) > 0
77  if (handledOpen)
78  close refnum
79  endif
80 
81  return handledOpen // 1 tells Igor not to open the file
82 End
83 
110 function /s ad_suggest_foldername(filename, [ignoredate,sourcename,unique])
111  string filename
112  variable ignoredate
113  string sourcename
114  variable unique
115 
116  if (ParamIsDefault(ignoredate))
117  ignoredate = 0
118  endif
119  if (ParamIsDefault(unique))
120  unique = 0
121  endif
122 
123  string basename = ParseFilePath(3, filename, ":", 0, 0)
124  string extension = ParseFilePath(4, filename, ":", 0, 0)
125  string nickname
126 
127  string autosource
128  if (strsearch(basename, "scienta", 0, 2) >= 0)
129  autosource = "sci"
130  elseif (strsearch(basename, "pshell", 0, 2) >= 0)
131  autosource = "psh"
132  elseif (strsearch(basename, "OP-SL", 0, 2) >= 0)
133  autosource = "sl"
134  elseif (strsearch(basename, "ES-PS", 0, 2) >= 0)
135  autosource = "es"
136  else
137  autosource = "xy"
138  endif
139  if (ParamIsDefault(sourcename))
140  sourcename = autosource
141  endif
142 
143  variable nparts = ItemsInList(basename, "-")
144  if (nparts >= 3)
145  string datepart = StringFromList(1, basename, "-")
146  variable l_datepart = strlen(datepart)
147  if (l_datepart == 8)
148  datepart = datepart[l_datepart-6, l_datepart-1]
149  endif
150  string indexpart = StringFromList(2, basename, "-")
151  if (ignoredate)
152  sprintf nickname, "%s_%s", sourcename, indexpart
153  else
154  sprintf nickname, "%s_%s_%s", sourcename, datepart, indexpart
155  endif
156  else
157  nickname = PearlCleanupName(basename)
158  endif
159 
160  if (unique && CheckName(nickname, 11))
161  nickname = UniqueName(nickname + "_", 11, 0)
162  endif
163 
164  return nickname
165 end
166 
171 function ad_load_dialog(APathName)
172  string APathName
173 
174  variable refNum
175  string message = "Select data files"
176  string filepaths
177  string filefilters = "Area Detector HDF5 Files (*.h5):.h5;"
178  filefilters += "All Files:.*;"
179 
180  PathInfo /S $APathName
181  Open /D /R /F=filefilters /M=message /MULT=1 refNum
182  filepaths = S_fileName
183 
184  dfref saveDF = GetDataFolderDFR()
185  setdatafolder root:
186 
187  if (strlen(filepaths) > 0)
188  variable nfiles = ItemsInList(filepaths, "\r")
189  variable ifile
190  for(ifile = 0; ifile < nfiles; ifile += 1)
191  String path = StringFromList(ifile, filepaths, "\r")
192  string nickname = ad_suggest_foldername(path)
193  adh5_load_complete(nickname, "", path)
194  endfor
195  endif
196 
197  setdatafolder saveDF
198 end
199 
211 function /s adh5_load_complete(ANickName, APathName, AFileName, [load_data, load_attr])
212  string ANickName
213  string APathName
214  string AFileName
215  variable load_data
216  variable load_attr
217 
218  if (ParamIsDefault(load_data))
219  load_data = 1
220  endif
221  if (ParamIsDefault(load_attr))
222  load_attr = 1
223  endif
224 
225  dfref saveDF = GetDataFolderDFR()
226  setdatafolder root:
227  newdatafolder /s/o $("root:" + ANickName)
228 
229  // open file
230  variable fileID
231  string instrumentpath = "/entry/instrument/"
232  string detectorpath = instrumentpath + "detector/"
233  string attributespath = instrumentpath + "NDAttributes/"
234  string datasetname
235  string datawavename
236 
237  // performance monitoring
238  variable timerRefNum
239  variable /g adh5_perf_secs
240  timerRefNum = startMSTimer
241 
242  // avoid compilation error if HDF5 XOP has not been loaded
243  #if Exists("HDF5OpenFile")
244  HDF5OpenFile /P=$APathName/R fileID as AFileName
245  if (v_flag == 0)
246  AFileName = s_path + s_filename
247  print "loading " + s_filename + "\r"
248 
249  if (load_data)
250  adh5_load_detector_slabs(fileID, detectorpath)
251  endif
252  if (load_attr)
253  newdatafolder /o/s attr
254  adh5_loadattr_all(fileID, attributespath)
255  setdatafolder ::
256  endif
257 
258  wave /z data
259  if (waveexists(data))
260  //adh5_redim(data) // not to be used with adh5_load_detector_slabs
261  adh5_scale(data)
262  endif
263 
264  HDF5CloseFile fileID
265  else
266  AFileName = ""
267  endif
268  #else
269  Abort "HDF5 XOP not loaded."
270  #endif
271 
272  if (timerRefNum >= 0)
273  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
274  endif
275 
276  setdatafolder saveDF
277  return AFileName
278 end
279 
306 function /s adh5_load_reduced(ANickName, APathName, AFileName, reduction_func, reduction_param, [load_data, load_attr, progress])
307  string ANickName
308  string APathName
309  string AFileName
310 
311  funcref adh5_default_reduction reduction_func
312  string reduction_param
313 
314  variable load_data
315  variable load_attr
316  variable progress
317 
318  if (ParamIsDefault(load_data))
319  load_data = 1
320  endif
321  if (ParamIsDefault(load_attr))
322  load_attr = 1
323  endif
324  if (ParamIsDefault(progress))
325  progress = 1
326  endif
327 
328  dfref saveDF = GetDataFolderDFR()
329  setdatafolder root:
330  newdatafolder /s/o $("root:" + ANickName)
331 
332  // open file
333  variable fileID
334  string instrumentpath = "/entry/instrument/"
335  string detectorpath = instrumentpath + "detector/"
336  string attributespath = instrumentpath + "NDAttributes/"
337  string datasetname
338  string datawavename
339 
340  // performance monitoring
341  variable timerRefNum
342  variable /g adh5_perf_secs
343  timerRefNum = startMSTimer
344 
345  // avoid compilation error if HDF5 XOP has not been loaded
346  #if Exists("HDF5OpenFile")
347  HDF5OpenFile /P=$APathName/R fileID as AFileName
348  if (v_flag == 0)
349  AFileName = s_path + s_filename
350  print "loading " + s_filename + "\r"
351 
352  if (load_attr)
353  newdatafolder /o/s attr
354  adh5_loadattr_all(fileID, attributespath)
355  setdatafolder ::
356  endif
357  if (load_data)
358  adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduction_param, progress=progress)
359  endif
360 
361  HDF5CloseFile fileID
362  else
363  AFileName = ""
364  endif
365  #else
366  Abort "HDF5 XOP not loaded."
367  #endif
368 
369  if (timerRefNum >= 0)
370  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
371  endif
372 
373  setdatafolder saveDF
374  return AFileName
375 end
376 
391 function /s adh5_load_preview(ANickName, APathName, AFileName, [load_data, load_attr])
392  string ANickName
393  string APathName
394  string AFileName
395  variable load_data
396  variable load_attr
397 
398  if (ParamIsDefault(load_data))
399  load_data = 1
400  endif
401  if (ParamIsDefault(load_attr))
402  load_attr = 1
403  endif
404 
405  dfref saveDF = GetDataFolderDFR()
406  setdatafolder root:
407  newdatafolder /o/s pearl_area
408  newdatafolder /o/s preview
409 
410  // open file
411  variable fileID
412  string instrumentpath = "/entry/instrument/"
413  string detectorpath = instrumentpath + "detector/"
414  string attributespath = instrumentpath + "NDAttributes/"
415  string datasetname
416  string datawavename
417 
418  // performance monitoring
419  variable timerRefNum
420  variable /g adh5_perf_secs
421  timerRefNum = startMSTimer
422 
423  // avoid compilation error if HDF5 XOP has not been loaded
424  #if Exists("HDF5OpenFile")
425  HDF5OpenFile /P=$APathName/R/Z fileID as AFileName
426  if (v_flag == 0)
427  AFileName = s_path + s_filename
428 
429  // detector data
430  datasetname = detectorpath + "data"
431  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
432  InitHDF5DataInfo(di)
433  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
434  if (err != 0)
435  print "error accessing detector/data"
436  return ""
437  endif
438  if (di.ndims < 2)
439  print "error: rank of dataset < 2"
440  return ""
441  endif
442 
443  variable dim2start = 0, dim2count = 1, dim3start = 0, dim3count = 1
444  if (di.ndims >= 3)
445  dim2start = floor(di.dims[di.ndims - 3] / 2)
446  dim2count = 1
447  endif
448  if (di.ndims >= 4)
449  dim3start = floor(di.dims[di.ndims - 4] / 2)
450  dim3count = 1
451  endif
452 
453  if (load_data)
454  adh5_load_detector_image(fileID, detectorpath, dim2start, dim2count, dim3start, dim3count)
455  wave /z data
456  string destpath = GetDataFolder(1, saveDF) + ANickName
457  if (waveexists(data))
458  duplicate /o data, $destpath
459  wave /z data = $destpath
460  endif
461  endif
462 
463  if (load_attr)
464  setdatafolder saveDF
465  newdatafolder /o/s attr
466  killwaves /a/z
467  adh5_loadattr_all(fileID, attributespath)
468  setdatafolder ::
469  if (waveexists(data))
470  adh5_scale(data)
471  endif
472  endif
473 
474  HDF5CloseFile fileID
475  else
476  print "error opening file " + AFileName
477  AFileName = ""
478  endif
479  #else
480  Abort "HDF5 XOP not loaded."
481  #endif
482 
483  if (timerRefNum >= 0)
484  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
485  endif
486 
487  setdatafolder saveDF
488  return AFileName
489 end
490 
501 function /s adh5_load_info(APathName, AFileName)
502  string APathName
503  string AFileName
504 
505  dfref saveDF = GetDataFolderDFR()
506 
507  // open file
508  variable fileID
509  string instrumentpath = "/entry/instrument/"
510  string detectorpath = instrumentpath + "detector/"
511  string attributespath = instrumentpath + "NDAttributes/"
512  string datasetname
513  string datawavename
514 
515  string s_info = ""
516  string s
517 
518  variable idim
519 
520  // avoid compilation error if HDF5 XOP has not been loaded
521  #if Exists("HDF5OpenFile")
522  HDF5OpenFile /P=$APathName/R/Z fileID as AFileName
523  if (v_flag == 0)
524  AFileName = s_path + s_filename
525 
526  // detector data
527  datasetname = detectorpath + "data"
528  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
529  InitHDF5DataInfo(di)
530  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
531  if (err != 0)
532  print "error accessing detector/data"
533  return ""
534  endif
535 
536  for (idim = 0; idim < di.ndims; idim += 1)
537  sprintf s, "dim %u: %u points", idim, di.dims[idim]
538  if (strlen(s_info) > 0)
539  s_info = s_info + "\r" + s
540  else
541  s_info = s
542  endif
543  endfor
544 
545  dfref df = NewFreeDataFolder()
546  setdatafolder df
547  adh5_loadattr_all(fileID, attributespath)
548 
549  for (idim = 1; idim < 5; idim += 1)
550  sprintf s, "Scan%uActive", idim
551  wave /z w = $s
552  if (waveexists(w) && (numpnts(w) > 0) && (w[0] > 0))
553  sprintf s, "Scan%uPositioner1", idim
554  wave /t wt = $s
555  sprintf s, "scan %u: %s", idim, wt[0]
556  if (strlen(s_info) > 0)
557  s_info = s_info + "\r" + s
558  else
559  s_info = s
560  endif
561  endif
562  endfor
563 
564  HDF5CloseFile fileID
565  else
566  print "error opening file " + AFileName
567  AFileName = ""
568  endif
569  #else
570  Abort "HDF5 XOP not loaded."
571  #endif
572 
573  setdatafolder saveDF
574  return s_info
575 end
576 
585 function adh5_load_detector(fileID, detectorpath)
586  variable fileID
587  string detectorpath
588 
589  // avoid compilation error if HDF5 XOP has not been loaded
590  #if Exists("HDF5LoadData")
591  string datasetname
592  string datawavename
593 
594  // detector data
595  datasetname = detectorpath + "data"
596  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
597  InitHDF5DataInfo(di)
598  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
599  if (err != 0)
600  print "error accessing detector/data"
601  return -1
602  endif
603  if (di.ndims < 2)
604  print "error: rank of dataset < 2"
605  return -2
606  endif
607 
608  HDF5LoadData /O /Q /Z fileID, datasetname
609  wave data
610 
611  #else
612  Abort "HDF5 XOP not loaded."
613  #endif
614 end
615 
630 function adh5_redim(data)
631  wave data
632 
633  duplicate /free data, tempdata
634  variable nd = wavedims(tempdata)
635  variable nx = dimsize(tempdata, nd - 1)
636  variable ny = dimsize(tempdata, nd - 2)
637  variable nz = dimsize(tempdata, nd - 3)
638  variable nt = dimsize(tempdata, nd - 4)
639 
640  switch (nd)
641  case 2:
642  if (nx <= 1)
643  redimension /n=(ny) data
644  setdimlabel 0, -1, AD_Dim1, data
645  data = tempdata[p][0]
646  elseif (ny <= 1)
647  redimension /n=(nx) data
648  setdimlabel 0, -1, AD_Dim0, data
649  data = tempdata[0][p]
650  else
651  redimension /n=(nx,ny) data
652  setdimlabel 0, -1, AD_Dim0, data
653  setdimlabel 1, -1, AD_Dim1, data
654  data = tempdata[q][p]
655  endif
656  break
657  case 3:
658  if (nx <= 1)
659  redimension /n=(ny,nz) data
660  setdimlabel 0, -1, AD_Dim1, data
661  setdimlabel 1, -1, AD_DimN, data
662  multithread data = tempdata[q][p][0]
663  elseif (ny <= 1)
664  redimension /n=(nx,nz) data
665  setdimlabel 0, -1, AD_Dim0, data
666  setdimlabel 1, -1, AD_DimN, data
667  multithread data = tempdata[q][0][p]
668  elseif (nz <= 1)
669  redimension /n=(nx,ny) data
670  setdimlabel 0, -1, AD_Dim0, data
671  setdimlabel 1, -1, AD_Dim1, data
672  multithread data = tempdata[0][q][p]
673  else
674  redimension /n=(nx,ny,nz) data
675  setdimlabel 0, -1, AD_Dim0, data
676  setdimlabel 1, -1, AD_Dim1, data
677  setdimlabel 2, -1, AD_DimN, data
678  multithread data = tempdata[r][q][p]
679  endif
680  break
681  case 4:
682  if (nz <= 1)
683  // singleton "frame number" dimension
684  redimension /n=(nx,ny,nt) data
685  setdimlabel 0, -1, AD_Dim0, data
686  setdimlabel 1, -1, AD_Dim1, data
687  setdimlabel 2, -1, AD_DimX, data
688  multithread data = tempdata[r][0][q][p]
689  else
690  redimension /n=(nx,ny,nz,nt) data
691  setdimlabel 0, -1, AD_Dim0, data
692  setdimlabel 1, -1, AD_Dim1, data
693  setdimlabel 2, -1, AD_DimN, data
694  setdimlabel 3, -1, AD_DimX, data
695  multithread data = tempdata[s][r][q][p]
696  endif
697  break
698  endswitch
699 end
700 
711 static function /DF GetAttrDataFolderDFR(data)
712  wave data
713 
714  dfref dataDF = GetWavesDataFolderDFR(data)
715  dfref attrDF = dataDF:attr
716  if (DataFolderRefStatus(attrDF) == 0)
717  attrDF = dataDF
718  endif
719 
720  return attrDF
721 end
722 
730 function adh5_scale(data,[source])
731  wave data
732  string source
733 
734  dfref saveDF = GetDataFolderDFR()
735  dfref dataDF = GetWavesDataFolderDFR(data)
736  dfref attrDF = GetAttrDataFolderDFR(data)
737 
738  if (ParamIsDefault(source))
739  // is the source a Scienta analyser?
740  wave /SDFR=attrDF /Z AcquisitionMode
741  wave /SDFR=attrDF /T /Z Manufacturer
742  source = "unknown"
743  if (waveexists(Manufacturer) && (numpnts(Manufacturer) >= 1))
744  strswitch(Manufacturer[0])
745  case "VG Scienta":
746  source = "scienta"
747  break
748  case "Prosilica":
749  source = "prosilica"
750  break
751  endswitch
752  elseif (waveexists(AcquisitionMode) && (numpnts(AcquisitionMode) >= 1))
753  if (stringmatch(note(AcquisitionMode), "*SCIENTA*"))
754  source = "scienta"
755  endif
756  endif
757  endif
758 
759  strswitch(source)
760  case "prosilica":
761  // pixel scale - nothing to do
762  break
763  case "scienta":
764  adh5_scale_scienta(data)
765  break
766  endswitch
767 
768  setdatafolder saveDF
769 end
770 
784 function adh5_load_detector_slabs(fileID, detectorpath, [progress])
785  variable fileID
786  string detectorpath
787  variable progress
788 
789  if (ParamIsDefault(progress))
790  progress = 1
791  endif
792  variable result = 0
793 
794  // avoid compilation error if HDF5 XOP has not been loaded
795  #if Exists("HDF5LoadData")
796  string datasetname
797  string datawavename
798 
799  // detector data
800  datasetname = detectorpath + "data"
801  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
802  InitHDF5DataInfo(di)
803  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
804  if (err != 0)
805  print "error accessing detector/data"
806  return -1
807  endif
808  if (di.ndims < 2)
809  print "error: rank of dataset < 2"
810  return -2
811  endif
812 
813  // nx and nz are the image dimensions
814  variable idx, idy, idz, idt, izt
815  idx = di.ndims - 1
816  idy = di.ndims - 2
817  idz = -1
818  idt = -1
819 
820  variable nx, ny, nz, nt, nzt
821  nx = di.dims[idx]
822  ny = di.dims[idy]
823  nz = 1
824  nt = 1
825 
826  make /n=(nx,ny,nz,nt) /o data
827  string dim_labels = "AD_Dim0;AD_Dim1;AD_DimN;AD_DimX;AD_DimY"
828  string dim_label
829  dim_label = StringFromList(0, dim_labels, ";")
830  setdimlabel 0, -1, $dim_label, data
831  dim_labels = RemoveFromList(dim_label, dim_labels, ";")
832  dim_label = StringFromList(0, dim_labels, ";")
833  setdimlabel 1, -1, $dim_label, data
834  dim_labels = RemoveFromList(dim_label, dim_labels, ";")
835 
836  // find additional dimensions, ignore singletons
837  variable id
838  for (id = idy - 1; (id >= 0) && (nz == 1); id -= 1)
839  if (di.dims[id] > 1)
840  idz = id
841  nz = di.dims[id]
842  dim_label = StringFromList(0, dim_labels, ";")
843  setdimlabel 2, -1, $dim_label, data
844  endif
845  dim_labels = RemoveListItem(0, dim_labels, ";")
846  endfor
847  for (id = idz - 1; (id >= 0) && (nt == 1); id -= 1)
848  if (di.dims[id] > 1)
849  idt = id
850  nt = di.dims[id]
851  dim_label = StringFromList(0, dim_labels, ";")
852  setdimlabel 3, -1, $dim_label, data
853  endif
854  dim_labels = RemoveListItem(0, dim_labels, ";")
855  endfor
856  redimension /n=(nx,ny,nz,nt) data
857 
858  // default values if dimensions are not present in dataset
859  if (idz < 0)
860  idz = idx + 1
861  idt = idz + 1
862  elseif (idt < 0)
863  idt = idx + 1
864  endif
865 
866  nzt = nz * nt
867  izt = 0
868  if (progress)
869  display_progress_panel("HDF5 Import", "Loading data...", nzt)
870  endif
871 
872  // load data image by image
873  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
874  wave slab
875  slab[][%Start] = 0
876  slab[][%Stride] = 1
877  slab[][%Count] = 1
878  slab[][%Block] = 1
879  slab[idx][%Block] = nx
880  slab[idy][%Block] = ny
881 
882  variable iz, it
883  for (iz = 0; iz < nz; iz += 1)
884  for (it = 0; it < nt; it += 1)
885  slab[idz][%Start] = iz
886  slab[idt][%Start] = it
887  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
888  wave slabdata // 2D, 3D, or 4D with singletons
889  switch (WaveDims(slabdata))
890  case 2:
891  data[][][iz][it] = slabdata[q][p]
892  break
893  case 3:
894  data[][][iz][it] = slabdata[0][q][p]
895  break
896  case 4:
897  data[][][iz][it] = slabdata[0][0][q][p]
898  break
899  endswitch
900  // progress window
901  izt += 1
902  if (progress)
903  if (update_progress_panel(izt))
904  result = -4 // user abort
905  break
906  endif
907  endif
908  endfor
909  if (result < 0)
910  break
911  endif
912  endfor
913 
914  if (nz == 1)
915  redimension /n=(nx,ny) data
916  elseif (nt == 1)
917  redimension /n=(nx,ny,nz) data
918  endif
919 
920  if (progress)
922  endif
923  #else
924  Abort "HDF5 XOP not loaded."
925  #endif
926 
927  return result
928 end
929 
949 function adh5_load_detector_image(fileID, detectorpath, dim2start, dim2count, dim3start, dim3count)
950  variable fileID
951  string detectorpath
952  variable dim2start
953  variable dim2count
954  variable dim3start
955  variable dim3count
956 
957  // avoid compilation error if HDF5 XOP has not been loaded
958  #if Exists("HDF5LoadData")
959  string datasetname
960  string datawavename
961 
962  // detector data
963  datasetname = detectorpath + "data"
964  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
965  InitHDF5DataInfo(di)
966  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
967  if (err != 0)
968  print "error accessing detector/data"
969  return -1
970  endif
971  if (di.ndims < 1)
972  print "error: rank of dataset < 1"
973  return -2
974  endif
975 
976  // nx and nz are the image dimensions
977  variable idx, idy, idz, idt
978  idx = di.ndims - 1
979  idy = di.ndims >= 2 ? di.ndims - 2 : 1
980  idz = di.ndims >= 3 ? di.ndims - 3 : 2
981  idt = di.ndims >= 4 ? di.ndims - 4 : 3
982 
983  variable nx, ny
984  nx = di.dims[idx]
985  ny = di.ndims >= 2 ? di.dims[idy] : 1
986 
987  variable dim2end = dim2start + dim2count - 1
988  variable dim3end = dim3start + dim3count - 1
989 
990  // the slab wave is at least 4-dimensional
991  // it will also load lower-dimensional datasets
992  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
993  wave slab
994  slab[][%Start] = 0
995  slab[][%Stride] = 1
996  slab[][%Count] = 1
997  slab[][%Block] = 1
998  slab[idx][%Block] = nx
999  slab[idy][%Block] = ny
1000 
1001  make /n=(nx,ny)/o/d data
1002  data = 0
1003  variable iz, it
1004  variable navg = 0
1005  for (iz = dim2start; iz <= dim2end; iz += 1)
1006  for (it = dim3start; it <= dim3end; it += 1)
1007  slab[idz][%Start] = iz
1008  slab[idt][%Start] = it
1009  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
1010  wave slabdata // 2D, 3D, or 4D with singletons
1011  switch (WaveDims(slabdata))
1012  case 1:
1013  data += slabdata[p]
1014  navg += 1
1015  break
1016  case 2:
1017  data += slabdata[q][p]
1018  navg += 1
1019  break
1020  case 3:
1021  data += slabdata[0][q][p]
1022  navg += 1
1023  break
1024  case 4:
1025  data += slabdata[0][0][q][p]
1026  navg += 1
1027  break
1028  endswitch
1029  endfor
1030  endfor
1031  data /= navg
1032  setdimlabel 0, -1, AD_Dim0, data
1033  setdimlabel 1, -1, AD_Dim1, data
1034 
1035  #else
1036  Abort "HDF5 XOP not loaded."
1037  #endif
1038 end
1039 
1046  string all_funcs = FunctionList("*", ";", "KIND:6,NPARAMS:2,VALTYPE:8")
1047  string result = ""
1048 
1049  variable ii
1050  variable nn = ItemsInList(all_funcs, ";")
1051 
1052  string funcname
1053  string info
1054  variable nparams
1055  variable accept
1056 
1057  for (ii = 0; ii < nn; ii += 1)
1058  funcname = StringFromList(ii, all_funcs, ";")
1059  info = FunctionInfo(funcname)
1060  accept = (NumberByKey("RETURNTYPE", info, ":", ";") == 0x4000)
1061  accept = accept && (cmpstr(StringByKey("THREADSAFE", info, ":", ";"), "yes") == 0)
1062  accept = accept && (NumberByKey("N_PARAMS", info, ":", ";") == 2)
1063  accept = accept && (NumberByKey("N_OPT_PARAMS", info, ":", ";") == 0)
1064  if (accept)
1065  // one numeric wave and one pass-by-reference string
1066  accept = accept && (NumberByKey("PARAM_0_TYPE", info, ":", ";") == 0x4002)
1067  accept = accept && (NumberByKey("PARAM_1_TYPE", info, ":", ";") == 0x3000)
1068  endif
1069  if (accept)
1070  result = AddListItem(funcname, result, ";")
1071  endif
1072  endfor
1073 
1074  result = SortList(result, ";", 4)
1075  return result
1076 end
1077 
1115 threadsafe function /wave adh5_default_reduction(source, param)
1116  wave source
1117  string &param
1118 
1119  // demo code
1120  // integrate along the dimensions
1121  make /n=0 /free dest1, dest2
1122  adh5_setup_profile(source, dest1, 0)
1123  ad_profile_x_w(source, 0, -1, dest1)
1124  adh5_setup_profile(source, dest2, 1)
1125  ad_profile_y_w(source, 0, -1, dest2)
1126 
1127  make /n=2 /free /wave results
1128  results[0] = dest1
1129  results[1] = dest2
1130  return results
1131 end
1132 
1138 threadsafe function adh5_setup_profile(image, profile, dim)
1139  wave image // prototype
1140  wave profile // destination wave
1141  variable dim // which dimension to keep: 0 = X, 1 = Y
1142 
1143  redimension /n=(dimsize(image, dim)) profile
1144  setscale /p x dimoffset(image, dim), dimdelta(image, dim), waveunits(image, dim), profile
1145  setscale d 0, 0, waveunits(image, -1), profile
1146  setdimlabel 0, -1, $getdimlabel(image, dim, -1), profile
1147 end
1148 
1171 function /s adh5_test_reduction_func(source, reduction_func, reduction_param, result_prefix)
1172  wave source
1173  funcref adh5_default_reduction reduction_func
1174  string reduction_param
1175  string result_prefix
1176 
1177  wave /wave results = reduction_func(source, reduction_param)
1178  adh5_get_result_waves(results, result_prefix, 1)
1179 
1180  return reduction_param
1181 end
1182 
1203 function adh5_reduce_brick(source, reduction_func, reduction_param, result_prefix, [progress, nthreads])
1204  wave source
1205  funcref adh5_default_reduction reduction_func
1206  string reduction_param
1207  string result_prefix
1208 
1209  variable progress
1210  variable nthreads
1211 
1212  if (ParamIsDefault(progress))
1213  progress = 1
1214  endif
1215  if (ParamIsDefault(nthreads))
1216  nthreads = -1
1217  endif
1218 
1219  dfref base_df = GetDataFolderDFR()
1220  variable result = 0
1221  string wavenames = ""
1222 
1223  // nx and nz are the image dimensions
1224  variable nx, ny, nz, nt
1225  nx = dimsize(source, 0)
1226  ny = dimsize(source, 1)
1227  nz = dimsize(source, 2)
1228  // force 4th dimension to singleton (ad_extract_slab handles 3 dimensions only)
1229  nt = 1
1230 
1231  variable nzt = max(nz, 1) * max(nt, 1)
1232 
1233  // set up multi threading
1234  if (nthreads < 0)
1235  nthreads = ThreadProcessorCount
1236  endif
1237  if (nthreads > 0)
1238  variable threadGroupID = ThreadGroupCreate(nthreads)
1239  variable ithread
1240  for (ithread = 0; ithread < nthreads; ithread += 1)
1241  ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
1242  endfor
1243  else
1244  make /n=(nzt) /df /free processing_folders
1245  endif
1246 
1247  if (progress)
1248  display_progress_panel("Reduction", "Processing data...", nzt)
1249  endif
1250 
1251  variable iz, it
1252  variable n_sent = 0
1253  variable n_recvd = 0
1254  variable tmo = 0
1255  string dfname
1256  dfref dfr
1257  variable iw, nw
1258  string sw
1259  make /n=0 /free /wave result_waves
1260 
1261  iz = 0
1262  it = 0
1263 
1264  do
1265  // fill the processing queue up to a maximum number of folders
1266  if (n_sent < max(1, nthreads) * 10 + n_recvd)
1267  if (iz < nz)
1268  if (it < nt)
1269  // load a slab into a temporary folder
1270  dfname = "processing_" + num2str(n_sent)
1271  NewDataFolder /s $dfname
1272  ad_extract_slab(source, nan, nan, nan, nan, iz, iz, "image", pscale=1)
1273  wave image
1274  variable /g r_index = iz
1275  variable /g s_index = it
1276  string /g func_param = reduction_param
1277 
1278  if (nthreads > 0)
1279  // send to thread group
1280  WaveClear image
1281  ThreadGroupPutDF threadGroupID, :
1282  else
1283  // process immediately in single-thread mode
1284  processing_folders[n_sent] = GetDataFolderDFR()
1285  string param = func_param
1286  wave /wave reduced_waves = reduction_func(image, param)
1287  variable /g func_result = numpnts(reduced_waves)
1288  adh5_get_result_waves(reduced_waves, "redw_", 0)
1289  WaveClear image, reduced_waves
1290  setdatafolder ::
1291  endif
1292 
1293  iz += 1
1294  n_sent += 1
1295  tmo = 0
1296  else
1297  iz += 1
1298  it = 0
1299  endif
1300  endif
1301  else
1302  // throttle the loop if processing is slow
1303  tmo = min(100, tmo + 10)
1304  endif
1305 
1306  // receive a slab from the processing queue
1307  if (n_recvd < nzt)
1308  if (nthreads > 0)
1309  dfr = ThreadGroupGetDFR(threadGroupID, tmo)
1310  else
1311  dfr = processing_folders[n_recvd]
1312  processing_folders[n_recvd] = $""
1313  endif
1314 
1315  if (DatafolderRefStatus(dfr) != 0)
1316  // access results folder
1317  nvar rr = dfr:r_index
1318  nvar ss = dfr:s_index
1319  nvar func_result = dfr:func_result
1320 
1321  if (func_result < 1)
1322  print "error during data reduction."
1323  result = -3
1324  break
1325  endif
1326 
1327  // initialize result waves just once
1328  if (numpnts(result_waves) == 0)
1329  redimension /n=(func_result) result_waves
1330  for (iw = 0; iw < func_result; iw += 1)
1331  sw = "redw_" + num2str(iw)
1332  wave profile = dfr:$sw
1333  sw = "ReducedData" + num2str(iw+1)
1334  make /n=(dimsize(profile, 0), nz, nt) /d /o $sw
1335  wave data = $sw
1336  setdimlabel 0, -1, $getdimlabel(profile, 0, -1), data
1337  setscale /p x dimoffset(profile, 0), dimdelta(profile, 0), waveunits(profile, 0), data
1338  setscale /p y dimoffset(source, 2), dimdelta(source, 2), waveunits(source, 2), data
1339  setscale /p z dimoffset(source, 3), dimdelta(source, 3), waveunits(source, 3), data
1340  setscale d 0, 0, waveunits(profile, -1), data
1341  note data, note(profile)
1342  result_waves[iw] = data
1343  endfor
1344  endif
1345 
1346  // copy results
1347  for (iw = 0; iw < func_result; iw += 1)
1348  sw = "redw_" + num2str(iw)
1349  wave profile = dfr:$sw
1350  wave data = result_waves[iw]
1351  data[][rr][ss] = profile[p]
1352  endfor
1353 
1354  n_recvd += 1
1355  KillDataFolder /Z dfr
1356  endif
1357  else
1358  // processing complete
1359  break
1360  endif
1361 
1362  // update progress window
1363  if (progress)
1364  if (update_progress_panel(n_recvd))
1365  print "user abort"
1366  result = -4
1367  break
1368  endif
1369  endif
1370  while ((n_recvd < nzt) && (result == 0))
1371 
1372  // clean up
1373  if (nthreads > 0)
1374  variable tstatus = ThreadGroupRelease(threadGroupID)
1375  if (tstatus == -2)
1376  print "error: thread did not terminate properly."
1377  result = -5
1378  endif
1379  endif
1380 
1381  // finalize results
1382  nw = numpnts(result_waves)
1383  wavenames = ""
1384  for (iw = 0; iw < nw; iw += 1)
1385  wave /z data = result_waves[iw]
1386  if (WaveExists(data))
1387  if (nz == 1)
1388  redimension /n=(-1, 0, 0) data
1389  elseif (nt == 1)
1390  redimension /n=(-1, nz, 0) data
1391  endif
1392  wavenames += nameofwave(data) + ";"
1393  endif
1394  endfor
1395 
1396  if (progress)
1398  endif
1399 
1400  setdatafolder base_df
1401  return result
1402 end
1403 
1410 threadsafe static function reduce_brick_worker(reduction_func)
1411  funcref adh5_default_reduction reduction_func
1412  do
1413  // wait for job from main thread
1414  do
1415  dfref dfr = ThreadGroupGetDFR(0, 1000)
1416  if (DataFolderRefStatus(dfr) == 0)
1417  if (GetRTError(2))
1418  return 0 // no more jobs
1419  endif
1420  else
1421  break
1422  endif
1423  while (1)
1424 
1425  // get input data
1426  wave image = dfr:image
1427  svar func_param = dfr:func_param
1428  nvar rr = dfr:r_index
1429  nvar ss = dfr:s_index
1430 
1431  // do the work
1432  newdatafolder /s outDF
1433  variable /g r_index = rr
1434  variable /g s_index = ss
1435  string param = func_param
1436  wave /wave reduced_waves = reduction_func(image, param)
1437  variable /g func_result = numpnts(reduced_waves)
1438 
1439  // send output to queue and clean up
1440  adh5_get_result_waves(reduced_waves, "redw_", 0)
1441  WaveClear image, reduced_waves
1442  ThreadGroupPutDF 0, :
1443  KillDataFolder dfr
1444  while (1)
1445 
1446  return 0
1447 end
1448 
1463 threadsafe function adh5_get_result_waves(results, result_prefix, start_index)
1464  wave /wave results
1465  string result_prefix
1466  variable start_index
1467 
1468  variable nw = numpnts(results)
1469  variable iw
1470  string sw
1471  for (iw = 0; iw < nw; iw += 1)
1472  sw = result_prefix + num2str(iw + start_index)
1473  duplicate /o results[iw], $sw
1474  endfor
1475 end
1476 
1499 function adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduction_param, [progress, nthreads])
1500  variable fileID
1501  string detectorpath
1502  funcref adh5_default_reduction reduction_func
1503  string reduction_param
1504  variable progress
1505  variable nthreads
1506 
1507  if (ParamIsDefault(progress))
1508  progress = 1
1509  endif
1510  if (ParamIsDefault(nthreads))
1511  nthreads = -1
1512  endif
1513  variable result = 0
1514 
1515  // avoid compilation error if HDF5 XOP has not been loaded
1516  #if Exists("HDF5LoadData")
1517  string datasetname
1518  string datawavename
1519 
1520  // detector data
1521  datasetname = detectorpath + "data"
1522  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
1523  InitHDF5DataInfo(di)
1524  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
1525  if (err != 0)
1526  print "error accessing detector/data"
1527  return -1
1528  endif
1529  if (di.ndims < 2)
1530  print "error: rank of dataset < 2"
1531  return -2
1532  endif
1533 
1534  // nx and nz are the image dimensions
1535  variable idx, idy, idz, idt
1536  idx = di.ndims - 1
1537  idy = di.ndims - 2
1538  idz = -1
1539  idt = -1
1540 
1541  variable nx, ny, nz, nt
1542  nx = di.dims[idx]
1543  ny = di.dims[idy]
1544  nz = 1
1545  nt = 1
1546 
1547  // find additional dimensions, ignore singletons
1548  variable id
1549  for (id = idy - 1; (id >= 0) && (nz == 1); id -= 1)
1550  if (di.dims[id] > 1)
1551  idz = id
1552  nz = di.dims[id]
1553  endif
1554  endfor
1555  for (id = idz - 1; (id >= 0) && (nt == 1); id -= 1)
1556  if (di.dims[id] > 1)
1557  idt = id
1558  nt = di.dims[id]
1559  endif
1560  endfor
1561  // default values if dimensions are not present in dataset
1562  if (idz < 0)
1563  idz = idx + 1
1564  idt = idz + 1
1565  elseif (idt < 0)
1566  idt = idx + 1
1567  endif
1568  variable nzt = nz * nt
1569  variable izt
1570 
1571  // load data image by image
1572  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
1573  wave slab
1574  slab[][%Start] = 0
1575  slab[][%Stride] = 1
1576  slab[][%Count] = 1
1577  slab[][%Block] = 1
1578  slab[idx][%Block] = nx
1579  slab[idy][%Block] = ny
1580 
1581  // set up multi threading
1582  if (nthreads < 0)
1583  nthreads = ThreadProcessorCount
1584  endif
1585  if (nthreads > 0)
1586  variable threadGroupID = ThreadGroupCreate(nthreads)
1587  variable ithread
1588  for (ithread = 0; ithread < nthreads; ithread += 1)
1589  ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
1590  endfor
1591  else
1592  make /n=(nzt) /df /free processing_folders
1593  endif
1594 
1595  if (progress)
1596  display_progress_panel("HDF5 Import", "Loading data (step 1 of 2)...", nzt)
1597  endif
1598 
1599  make /n=(nx,ny)/d image_template
1600  setdimlabel 0, -1, AD_Dim0, image_template
1601  setdimlabel 1, -1, AD_Dim1, image_template
1602  adh5_scale(image_template)
1603 
1604  variable iz, it
1605  string dfname
1606  variable iw, nw
1607  string sw
1608  make /n=0 /free /wave result_waves
1609 
1610  izt = 0
1611  for (iz = 0; iz < nz; iz += 1)
1612  for (it = 0; it < nt; it += 1)
1613  // load hyperslab
1614  slab[idz][%Start] = iz
1615  slab[idt][%Start] = it
1616  dfname = "processing_" + num2str(izt)
1617  newdatafolder /s $dfname
1618  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
1619 
1620  // send to processing queue
1621  duplicate image_template, image
1622  variable /g r_index = iz
1623  variable /g s_index = it
1624  string /g func_param = reduction_param
1625 
1626  if (nthreads > 0)
1627  WaveClear image
1628  ThreadGroupPutDF threadGroupID, :
1629  else
1630  processing_folders[izt] = GetDataFolderDFR()
1631  wave slabdata
1632  wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
1633  variable /g func_result = numpnts(reduced_waves)
1634  adh5_get_result_waves(reduced_waves, "redw_", 0)
1635  WaveClear slabdata, image, reduced_waves
1636  setdatafolder ::
1637  endif
1638 
1639  izt += 1
1640  // progress window
1641  if (progress)
1642  if (update_progress_panel(izt))
1643  result = -4 // user abort
1644  break
1645  endif
1646  endif
1647  endfor
1648  endfor
1649 
1650  killwaves /z slab, image_template
1651  if (progress)
1652  update_progress_panel(0, message="Processing data (step 2 of 2)...")
1653  endif
1654 
1655  dfref dfr
1656  for (izt = 0; (izt < nzt) && (result == 0); izt += 1)
1657  if (nthreads > 0)
1658  do
1659  dfr = ThreadGroupGetDFR(threadGroupID, 1000)
1660  if (DatafolderRefStatus(dfr) != 0)
1661  break
1662  endif
1663  if (progress)
1664  if (update_progress_panel(izt))
1665  result = -4 // user abort
1666  break
1667  endif
1668  endif
1669  while (1)
1670  else
1671  dfr = processing_folders[izt]
1672  if (progress)
1673  if (update_progress_panel(izt))
1674  result = -4 // user abort
1675  break
1676  endif
1677  endif
1678  endif
1679 
1680  if (result != 0)
1681  break
1682  endif
1683 
1684  nvar rr = dfr:r_index
1685  nvar ss = dfr:s_index
1686  nvar func_result = dfr:func_result
1687 
1688  if (func_result < 1)
1689  result = -3 // dimension reduction error
1690  break
1691  endif
1692 
1693  if (numpnts(result_waves) == 0)
1694  redimension /n=(func_result) result_waves
1695  for (iw = 0; iw < func_result; iw += 1)
1696  sw = "redw_" + num2str(iw)
1697  wave profile = dfr:$sw
1698  sw = "ReducedData" + num2str(iw+1)
1699  make /n=(dimsize(profile, 0), nz, nt) /d /o $sw
1700  wave data = $sw
1701  setdimlabel 0, -1, $getdimlabel(profile, 0, -1), data
1702  setscale /p x dimoffset(profile, 0), dimdelta(profile, 0), waveunits(profile, 0), data
1703  setscale d 0, 0, waveunits(profile, -1), data
1704  result_waves[iw] = data
1705  endfor
1706  endif
1707  for (iw = 0; iw < func_result; iw += 1)
1708  sw = "redw_" + num2str(iw)
1709  wave profile = dfr:$sw
1710  wave data = result_waves[iw]
1711  data[][rr][ss] = profile[p]
1712  endfor
1713  endfor
1714 
1715  if (nthreads > 0)
1716  variable tstatus = ThreadGroupRelease(threadGroupID)
1717  if (tstatus == -2)
1718  result = -5 // thread did not terminate properly
1719  endif
1720  else
1721  for (izt = 0; izt < nzt; izt += 1)
1722  KillDataFolder /Z processing_folders[izt]
1723  endfor
1724  endif
1725 
1726  if (result == 0)
1727  nw = numpnts(result_waves)
1728  for (iw = 0; iw < nw; iw += 1)
1729  wave data = result_waves[iw]
1730  if (nz == 1)
1731  redimension /n=(dimsize(data, 0)) data
1732  elseif (nt == 1)
1733  redimension /n=(dimsize(data, 0),nz) data
1734  setdimlabel 1, -1, AD_DimN, data
1735  else
1736  setdimlabel 1, -1, AD_DimN, data
1737  setdimlabel 2, -1, AD_DimX, data
1738  endif
1739  endfor
1740  endif
1741  if (progress)
1743  endif
1744 
1745  #else
1746  Abort "HDF5 XOP not loaded."
1747  #endif
1748  return result
1749 end
1750 
1751 threadsafe static function reduce_slab_worker(reduction_func)
1752  funcref adh5_default_reduction reduction_func
1753  do
1754  // wait for job from main thread
1755  do
1756  dfref dfr = ThreadGroupGetDFR(0, 1000)
1757  if (DataFolderRefStatus(dfr) == 0)
1758  if (GetRTError(2))
1759  return 0 // no more jobs
1760  endif
1761  else
1762  break
1763  endif
1764  while (1)
1765 
1766  // get input data
1767  wave slabdata = dfr:slabdata
1768  wave image = dfr:image
1769  svar func_param = dfr:func_param
1770  nvar rr = dfr:r_index
1771  nvar ss = dfr:s_index
1772 
1773  // do the work
1774  newdatafolder /s outDF
1775  variable /g r_index = rr
1776  variable /g s_index = ss
1777  wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
1778  variable /g func_result = numpnts(reduced_waves)
1779 
1780  // send output to queue and clean up
1781  adh5_get_result_waves(reduced_waves, "redw_", 0)
1782  WaveClear slabdata, image, reduced_waves
1783  ThreadGroupPutDF 0, :
1784  KillDataFolder dfr
1785  while (1)
1786 
1787  return 0
1788 end
1789 
1790 threadsafe static function /wave reduce_slab_image(slabdata, image, reduction_func, reduction_param)
1791  wave slabdata
1792  wave image
1793  funcref adh5_default_reduction reduction_func
1794  string reduction_param
1795 
1796  switch (WaveDims(slabdata))
1797  case 2:
1798  image = slabdata[q][p]
1799  break
1800  case 3:
1801  image = slabdata[0][q][p]
1802  break
1803  case 4:
1804  image = slabdata[0][0][q][p]
1805  break
1806  endswitch
1807 
1808  return reduction_func(image, reduction_param)
1809 end
1810 
1823 function adh5_loadattr_all(fileID, attributespath)
1824  variable fileID
1825  string attributespath
1826 
1827  string datasetname
1828  string datawavename
1829 
1830  // avoid compilation error if HDF5 XOP has not been loaded
1831  #if Exists("HDF5LoadData")
1832 
1833  // datasets in NDAttributes group
1834  HDF5ListGroup /F /TYPE=2 fileID, attributespath
1835  string h5datasets = S_HDF5ListGroup
1836  HDF5ListAttributes /TYPE=1 /Z fileID, attributespath
1837  string h5attributes = S_HDF5ListAttributes
1838 
1839  variable nds = ItemsInList(h5datasets, ";")
1840  variable na = ItemsInList(h5attributes, ";")
1841  variable ids
1842  variable idest = 0
1843  variable n_attr
1844  string s_attr
1845  string s_source
1846 
1847  make /n=(nds+na) /t /o IN, ID, IV, IU
1848 
1849  for (ids = 0; ids < nds; ids += 1)
1850  datasetname = StringFromList(ids, h5datasets, ";")
1851  HDF5LoadData /O/Q fileID, datasetname
1852  if (v_flag == 0)
1853  datawavename = StringFromList(0, s_wavenames)
1854  else
1855  datawavename = ""
1856  endif
1857  HDF5LoadData /A="source"/O/Q/TYPE=2 fileID, datasetname
1858  if (v_flag == 0)
1859  wave /t source
1860  s_source = source[0]
1861  else
1862  s_source = ""
1863  endif
1864  read_attribute_info(datawavename, s_source, idest)
1865  endfor
1866 
1867  // attributes of NDAttributes group
1868  if (v_flag == 0)
1869  nds = ItemsInList(h5attributes, ";")
1870  else
1871  nds = 0
1872  endif
1873  for (ids = 0; ids < nds; ids += 1)
1874  datasetname = StringFromList(ids, h5attributes, ";")
1875  HDF5LoadData /A=datasetname/O/Q/TYPE=1 fileID, attributespath
1876  if (v_flag == 0)
1877  datawavename = StringFromList(0, s_wavenames)
1878  read_attribute_info(datawavename, "", idest) // we don't get the source of these attributes
1879  endif
1880  endfor
1881 
1882  redimension /n=(idest) IN, ID, IV, IU
1883  sort {IN, ID}, IN, ID, IV, IU
1884 
1885  killwaves /z source
1886  #else
1887  Abort "HDF5 XOP not loaded."
1888  #endif
1889 
1890 end
1891 
1905 static function read_attribute_info(datawavename, source, idest)
1906  string datawavename // name of the attribute wave in the current folder.
1907  // can be text or numeric.
1908  string source
1909  // source identifier (EPICS name) of the attribute.
1910  variable &idest
1911  // destination index in IN, ID, IV, IU where the results are written.
1912  // the variable is incremented if data was written, otherwise it is left unchanged.
1913  // make sure IN, ID, IV, IU have at least idest + 1 elements.
1914 
1915  wave /t IN
1916  wave /t ID
1917  wave /t IV
1918  wave /t IU
1919 
1920  variable n_attr
1921  string s_attr
1922 
1923  if (exists(datawavename) == 1)
1924  if (strlen(source) > 0)
1925  Note $datawavename, "PV=" + source
1926  endif
1927  switch(WaveType($datawavename, 1))
1928  case 1: // numeric
1929  wave w_attr = $datawavename
1930  n_attr = numpnts(w_attr)
1931  sprintf s_attr, "%.12g", w_attr[0]
1932  break
1933  case 2: // text
1934  wave /t wt_attr = $datawavename
1935  n_attr = numpnts(wt_attr)
1936  s_attr = wt_attr[0]
1937  break
1938  default: // unknown
1939  n_attr = 0
1940  endswitch
1941  if (n_attr == 1)
1942  IN[idest] = source
1943  ID[idest] = datawavename
1944  IV[idest] = s_attr
1945  IU[idest] = "" // we don't get the units
1946  idest += 1
1947  endif
1948  endif
1949 end
1950 
1958 function adh5_scale_scienta(data)
1959  wave data
1960 
1961  dfref saveDF = GetDataFolderDFR()
1962 
1963  dfref dataDF = GetWavesDataFolderDFR(data)
1964  dfref attrDF = GetAttrDataFolderDFR(data)
1965 
1966  wave /SDFR=attrDF LensMode
1967  wave /SDFR=attrDF /Z ChannelBegin, ChannelEnd
1968  wave /SDFR=attrDF /Z SliceBegin, SliceEnd
1969 
1970  variable EDim, ADim
1971  variable ELow, EHigh, ALow, AHigh
1972  string EUnit, AUnit
1973 
1974  // which dimension is angle and which one is energy?
1975  strswitch(GetDimLabel(data, 0, -1))
1976  case "AD_Dim0":
1977  EDim = 0
1978  break
1979  case "AD_Dim1":
1980  EDim = 1
1981  break
1982  default:
1983  EDim = -1
1984  endswitch
1985  strswitch(GetDimLabel(data, 1, -1))
1986  case "AD_Dim0":
1987  ADim = 0
1988  break
1989  case "AD_Dim1":
1990  ADim = 1
1991  break
1992  default:
1993  ADim = -1
1994  endswitch
1995 
1996  // defaults (point scaling)
1997  if (EDim >= 0)
1998  ELow = dimoffset(data, EDim)
1999  EHigh = dimoffset(data, EDim) + dimdelta(data, EDim) * (dimsize(data, EDim) - 1)
2000  EUnit = "eV"
2001  endif
2002  if (ADim >= 0)
2003  ALow = dimoffset(data, ADim)
2004  AHigh = dimoffset(data, ADim) + dimdelta(data, ADim) * (dimsize(data, ADim) - 1)
2005  AUnit = "arb."
2006  endif
2007 
2008  // lens mode can give more detail
2009  if (waveexists(LensMode) && (numpnts(LensMode) >= 1))
2010  switch(LensMode[0])
2011  case 1: // Angular45
2012  ALow = -45/2
2013  AHigh = +45/2
2014  AUnit = "°"
2015  break
2016  case 2: // Angular60
2017  ALow = -60/2
2018  AHigh = +60/2
2019  AUnit = "°"
2020  break
2021  endswitch
2022  endif
2023 
2024  // best option if scales are explicit in separate waves
2025  if (waveexists(ChannelBegin) && waveexists(ChannelEnd) && (numpnts(ChannelBegin) >= 1) && (numpnts(ChannelEnd) >= 1))
2026  ELow = ChannelBegin[0]
2027  EHigh = ChannelEnd[0]
2028  endif
2029  if (waveexists(SliceBegin) && waveexists(SliceEnd) && (numpnts(SliceBegin) >= 1) && (numpnts(SliceEnd) >= 1))
2030  ALow = SliceBegin[0]
2031  AHigh = SliceEnd[0]
2032  endif
2033 
2034  // apply new scales
2035  switch(EDim)
2036  case 0:
2037  setscale /i x ELow, EHigh, EUnit, data
2038  break
2039  case 1:
2040  setscale /i y ELow, EHigh, EUnit, data
2041  break
2042  endswitch
2043  switch(ADim)
2044  case 0:
2045  setscale /i x ALow, AHigh, AUnit, data
2046  break
2047  case 1:
2048  setscale /i y ALow, AHigh, AUnit, data
2049  break
2050  endswitch
2051 
2052  setscale d 0, 0, "arb.", data
2053 
2054  setdatafolder saveDF
2055 end
2056 
2063 function adh5_scale_scan(data)
2064  wave data
2065 
2066  dfref saveDF = GetDataFolderDFR()
2067 
2068  dfref dataDF = GetWavesDataFolderDFR(data)
2069  wave /SDFR=dataDF AcquisitionMode, DetectorMode, EnergyMode
2070 
2071  wave /SDFR=dataDF /z Scan1Active, Scan2Active
2072  wave /SDFR=dataDF /t /z Scan1Positioner1, Scan1Readback1
2073  wave /SDFR=dataDF /t /z Scan1Positioner2, Scan1Readback2
2074  wave /SDFR=dataDF /t /z Scan2Positioner1, Scan2Readback1
2075  wave /SDFR=dataDF /t /z Scan2Positioner2, Scan2Readback2
2076 
2077  // TODO : search the data folder for positioner waves,
2078  // i.e. waves with the PV name corresponding to Scan1Positioner1 in their wave note.
2079  wave /z zscale
2080 
2081  strswitch(GetDimLabel(data, 0, -1))
2082  case "AD_DimN":
2083  setscale /i x zscale[0], zscale[numpnts(zscale)-1], "", data
2084  break
2085  endswitch
2086  strswitch(GetDimLabel(data, 1, -1))
2087  case "AD_DimN":
2088  setscale /i y zscale[0], zscale[numpnts(zscale)-1], "", data
2089  break
2090  endswitch
2091  strswitch(GetDimLabel(data, 2, -1))
2092  case "AD_DimN":
2093  setscale /i z zscale[0], zscale[numpnts(zscale)-1], "", data
2094  break
2095  endswitch
2096 
2097  setdatafolder saveDF
2098 end
adh5_list_reduction_funcs
string adh5_list_reduction_funcs()
get a list of functions which can be used as reduction functions.
Definition: pearl-area-import.ipf:1045
reduce_slab_worker
static threadsafe variable reduce_slab_worker(funcref reduction_func)
Definition: pearl-area-import.ipf:1751
adh5_load_preview
string adh5_load_preview(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
load a single image from a HDF5 file created by the Area Detector software.
Definition: pearl-area-import.ipf:391
kill_progress_panel
variable kill_progress_panel()
Definition: pearl-gui-tools.ipf:51
adh5_load_info
string adh5_load_info(string APathName, string AFileName)
load descriptive info from a HDF5 file created by the Area Detector software.
Definition: pearl-area-import.ipf:501
display_progress_panel
variable display_progress_panel(string title, string message, variable progress_max)
Definition: pearl-gui-tools.ipf:19
update_progress_panel
variable update_progress_panel(variable progress, string message=defaultValue, variable progress_max=defaultValue)
Definition: pearl-gui-tools.ipf:33
ad_load_dialog
variable ad_load_dialog(string APathName)
load area detector data files selected in a file dialog window
Definition: pearl-area-import.ipf:171
adh5_get_result_waves
threadsafe variable adh5_get_result_waves(wave results, string result_prefix, variable start_index)
copy waves from wave reference wave into current data folder
Definition: pearl-area-import.ipf:1463
read_attribute_info
static variable read_attribute_info(string datawavename, string source, variable *idest)
sub-function of adh5_loadattr_all.
Definition: pearl-area-import.ipf:1905
ad_profile_x_w
threadsafe wave ad_profile_x_w(wave dataset, variable q1, variable q2, wave destwave, variable noavg=defaultValue)
1D cut through 2D dataset along X dimension, existing destination wave.
Definition: pearl-area-profiles.ipf:505
adh5_scale_scienta
variable adh5_scale_scienta(wave data)
set the energy and angle scales of an area detector dataset from the Scienta analyser.
Definition: pearl-area-import.ipf:1958
adh5_test_reduction_func
string adh5_test_reduction_func(wave source, funcref reduction_func, string reduction_param, string result_prefix)
wrapper function for testing reduction functions from the command line.
Definition: pearl-area-import.ipf:1171
GetAttrDataFolderDFR
static dfr GetAttrDataFolderDFR(wave data)
find the attributes data folder of an area detector dataset.
Definition: pearl-area-import.ipf:711
adh5_setup_profile
threadsafe variable adh5_setup_profile(wave image, wave profile, variable dim)
set up a one-dimensional wave for a line profile based on a 2D original wave.
Definition: pearl-area-import.ipf:1138
adh5_loadattr_all
variable adh5_loadattr_all(variable fileID, string attributespath)
load an NDAttributes group from an open HDF5 file into the current data folder.
Definition: pearl-area-import.ipf:1823
adh5_scale_scan
variable adh5_scale_scan(wave data)
scales the extra dimensions of an area detector dataset according to the EPICS scan
Definition: pearl-area-import.ipf:2063
adh5_reduce_brick
variable adh5_reduce_brick(wave source, funcref reduction_func, string reduction_param, string result_prefix, variable progress=defaultValue, variable nthreads=defaultValue)
reduce a three-dimensional intensity distribution
Definition: pearl-area-import.ipf:1203
reduce_brick_worker
static threadsafe variable reduce_brick_worker(funcref reduction_func)
thread worker for adh5_reduce_brick
Definition: pearl-area-import.ipf:1410
ad_suggest_foldername
string ad_suggest_foldername(string filename, variable ignoredate=defaultValue, string sourcename=defaultValue, variable unique=defaultValue)
generate the name of a data folder based on a file name.
Definition: pearl-area-import.ipf:110
adh5_load_complete
string adh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
import everything from a HDF5 file created by the Area Detector software.
Definition: pearl-area-import.ipf:211
ad_profile_y_w
threadsafe wave ad_profile_y_w(wave dataset, variable p1, variable p2, wave destwave, variable noavg=defaultValue)
1D cut through 2D dataset along X dimension, existing destination wave.
Definition: pearl-area-profiles.ipf:568
adh5_default_reduction
threadsafe wave adh5_default_reduction(wave source, string *param)
function prototype for adh5_load_reduced_detector
Definition: pearl-area-import.ipf:1115
ad_extract_slab
threadsafe wave ad_extract_slab(wave dataset, variable x1, variable x2, variable y1, variable y2, variable z1, variable z2, string destname, variable noavg=defaultValue, variable pscale=defaultValue)
2D cut through 3D dataset, integrate in normal dimension
Definition: pearl-area-profiles.ipf:314
adh5_redim
variable adh5_redim(wave data)
redimension a multi-dimensional area detector array loaded from HDF5.
Definition: pearl-area-import.ipf:630
adh5_load_detector_slabs
variable adh5_load_detector_slabs(variable fileID, string detectorpath, variable progress=defaultValue)
load the detector dataset from the open HDF5 file.
Definition: pearl-area-import.ipf:784
adh5_load_reduced
string adh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable load_data=defaultValue, variable load_attr=defaultValue, variable progress=defaultValue)
load and reduce a dataset from a HDF5 file created by the Area Detector software.
Definition: pearl-area-import.ipf:306
adh5_load_reduced_detector
variable adh5_load_reduced_detector(variable fileID, string detectorpath, funcref reduction_func, string reduction_param, variable progress=defaultValue, variable nthreads=defaultValue)
load a reduced detector dataset from the open HDF5 file.
Definition: pearl-area-import.ipf:1499
PearlCleanupName
string PearlCleanupName(string name)
Definition: pearl-compat.ipf:48
adh5_load_detector
variable adh5_load_detector(variable fileID, string detectorpath)
load the detector dataset from the open HDF5 file.
Definition: pearl-area-import.ipf:585
adh5_scale
variable adh5_scale(wave data, string source=defaultValue)
set the dimension scales of an area detector dataset.
Definition: pearl-area-import.ipf:730
BeforeFileOpenHook
static variable BeforeFileOpenHook(variable refNum, string fileName, string path, string type, string creator, variable kind)
callback function for drag&drop of HDF5 files into Igor.
Definition: pearl-area-import.ipf:46
reduce_slab_image
static threadsafe wave reduce_slab_image(wave slabdata, wave image, funcref reduction_func, string reduction_param)
Definition: pearl-area-import.ipf:1790
adh5_load_detector_image
variable adh5_load_detector_image(variable fileID, string detectorpath, variable dim2start, variable dim2count, variable dim3start, variable dim3count)
load a single image from the detector dataset of the open HDF5 file
Definition: pearl-area-import.ipf:949