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