PEARL Procedures  rev-distro-2.1.1-1-gf419e92-dirty
Igor procedures for the analysis of PEARL data
pearl-pshell-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.36
3 #pragma ModuleName = PearlPShellImport
4 #include <HDF5 Browser>
5 #include "pearl-compat"
6 #include "pearl-gui-tools"
7 #include "pearl-area-import"
8 
9 // copyright (c) 2013-18 Paul Scherrer Institut
10 //
11 // Licensed under the Apache License, Version 2.0 (the "License");
12 // you may not use this file except in compliance with the License.
13 // You may obtain a copy of the License at
14 // http:///www.apache.org/licenses/LICENSE-2.0
15 
58 
63 
65 strconstant kEnergyDimLabel = "energy"
66 
68 strconstant kAngleDimLabel = "angle"
69 
71 strconstant kScanDimLabel = "scan"
72 
75 strconstant kDataDimLabel = "data"
76 
78 strconstant kPreviewDatasets = "ScientaImage;ScientaSpectrum;ImageAngleDistribution;ImageEnergyDistribution;Counts;SampleCurrent;"
79 
81 strconstant kScientaScalingDatasets = "LensMode;ScientaChannelBegin;ScientaChannelEnd;ScientaSliceBegin;ScientaSliceEnd;"
82 
84 strconstant kTransposedDatasets = "ScientaImage;"
85 
88 
110 function psh5_open_file(ANickName, APathName, AFileName)
111  string ANickName
112  string APathName
113  string AFileName
114 
115  setdatafolder root:
116  newdatafolder /s /o $("root:" + ANickName)
117  dfref fileDF = GetDataFolderDFR()
118 
119  variable fileID
120  HDF5OpenFile /P=$APathName /R fileID as AFileName
121  if (v_flag == 0)
122  string /g s_filepath
123  string /g s_scanpaths
124  s_filepath = s_path + s_filename
125  s_scanpaths = psh5_list_scans(fileID)
126  else
127  fileID = 0
128  endif
129 
130  return fileID
131 end
132 
140 function psh5_close_file(fileID)
141  variable fileID
142 
143  HDF5CloseFile fileID
144 end
145 
170 function /s psh5_load_complete(ANickName, APathName, AFileName, [load_data, load_attr])
171  string ANickName
172  string APathName
173  string AFileName
174  variable load_data
175  variable load_attr
176 
177  if (ParamIsDefault(load_data))
178  load_data = 1
179  endif
180  if (ParamIsDefault(load_attr))
181  load_attr = 1
182  endif
183 
184  dfref saveDF = GetDataFolderDFR()
185 
186  // performance monitoring
187  variable timerRefNum
188  variable /g psh5_perf_secs
189  timerRefNum = startMSTimer
190 
191  variable fileID = psh5_open_file(ANickName, APathName, AFileName)
192  if (fileID)
193  dfref fileDF = GetDataFolderDFR()
194  svar s_filepath
195  svar s_scanpaths
196  AFileName = s_filepath
197  print "loading " + s_filepath + "\r"
198 
199  variable ig
200  variable ng = ItemsInList(s_scanpaths, ";")
201  string sg
202  string folder
203 
204  for (ig = 0; ig < ng; ig += 1)
205  sg = StringFromList(ig, s_scanpaths, ";")
206  folder = ReplaceString("/", sg, "")
207  folder = ReplaceString(" ", folder, "")
208  folder = PearlCleanupName(folder)
209  setdatafolder fileDF
210  newdatafolder /s /o $folder
211  psh5_load_scan_complete(fileID, sg, load_data=load_data, load_attr=load_attr)
212  endfor
213 
214  psh5_close_file(fileID)
215  else
216  AFileName = ""
217  endif
218 
219  psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
220 
221  setdatafolder saveDF
222  return AFileName
223 end
224 
251 function /s psh5_load_preview(APathName, AFileName, [load_data, load_attr, pref_scans, pref_datasets])
252  string APathName
253  string AFileName
254  variable load_data
255  variable load_attr
256  string pref_scans
257  string pref_datasets
258 
259  if (ParamIsDefault(load_data))
260  load_data = 1
261  endif
262  if (ParamIsDefault(load_attr))
263  load_attr = 1
264  endif
265  if (ParamIsDefault(pref_scans))
266  pref_scans = "*scan1*;"
267  endif
268  if (ParamIsDefault(pref_datasets))
269  pref_datasets = ""
270  endif
271 
272  dfref saveDF = GetDataFolderDFR()
273 
274  variable fileID
275  string scanpaths = ""
276  string dataname = ""
277 
278  // performance monitoring
279  variable timerRefNum
280  variable /g adh5_perf_secs
281  timerRefNum = startMSTimer
282 
283  HDF5OpenFile /P=$APathName /R /Z fileID as AFileName
284  if (v_flag == 0)
285  AFileName = s_path + s_filename
286  dfref fileDF = GetDataFolderDFR()
287 
288  scanpaths = psh5_list_scans(fileID)
289  variable ng = ItemsInList(scanpaths)
290  variable ig
291  string sg
292  variable np = ItemsInList(pref_scans)
293  variable ip
294  string sp
295  variable found = 0
296  if (ng > 0)
297  for (ip = 0; ip < np; ip += 1)
298  for (ig = 0; ig < ng; ig += 1)
299  sg = StringFromList(ig, scanpaths)
300  sp = StringFromList(ip, pref_scans)
301  if (StringMatch(sg, sp))
302  found = 1
303  break
304  endif
305  endfor
306  if (found)
307  break
308  endif
309  endfor
310  if (!found)
311  ig = 0
312  endif
313  sg = StringFromList(ig, scanpaths)
314 
315  if (load_attr)
316  setdatafolder fileDF
317  newdatafolder /o/s attr
318  killwaves /a/z
319  psh5_load_scan_attrs(fileID, sg)
320  endif
321 
322  setdatafolder fileDF
323  dataname = psh5_load_scan_preview(fileID, sg, set_scale=load_attr, pref_datasets=pref_datasets)
324  else
325  print "no scans found in file " + AFileName
326  endif
327 
328  HDF5CloseFile fileID
329  endif
330 
331  if (timerRefNum >= 0)
332  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
333  endif
334 
335  setdatafolder saveDF
336  return dataname
337 end
338 
361 function /s psh5_load_scan_complete(fileID, scanpath, [load_data, load_attr])
362  variable fileID
363  string scanpath
364  variable load_data
365  variable load_attr
366 
367  if (ParamIsDefault(load_data))
368  load_data = 1
369  endif
370  if (ParamIsDefault(load_attr))
371  load_attr = 1
372  endif
373 
374  dfref saveDF = GetDataFolderDFR()
375 
376  dfref dataDF = GetDataFolderDFR()
377  string wavenames
378  string attrnames
379  psh5_load_scan_meta(fileID, scanpath)
380  if (load_attr)
381  newdatafolder /s /o attr
382  attrnames = psh5_load_scan_attrs(fileID, scanpath)
383  endif
384  if (load_data)
385  setdatafolder dataDF
386  wavenames = psh5_load_scan_data(fileID, scanpath)
387  endif
388  if (load_data && load_attr)
389  setdatafolder dataDF
391  endif
392 
393  setdatafolder saveDF
394  return wavenames
395 end
396 
405 function /s psh5_list_scans(fileID)
406  variable fileID
407 
408  HDF5ListGroup /F /TYPE=1 fileID, "/"
409 
410  variable ig
411  variable ng = ItemsInList(S_HDF5ListGroup, ";")
412  string sg
413  string scans = ""
414 
415  for (ig = 0; ig < ng; ig += 1)
416  sg = StringFromList(ig, S_HDF5ListGroup, ";")
417  if (cmpstr(sg[1,4], "scan") == 0)
418  scans = AddListItem(sg, scans, ";", inf)
419  endif
420  endfor
421 
422  return scans
423 end
424 
440 function /s psh5_list_scan_datasets(fileID, scanpath, [include_regions])
441  variable fileID
442  string scanpath
443  variable include_regions
444 
445  if (ParamIsDefault(include_regions))
446  include_regions = 0
447  endif
448  string result
449 
450  HDF5ListGroup /TYPE=2 /Z fileID, scanpath
451  result = S_HDF5ListGroup
452 
453  if (include_regions)
454  HDF5ListGroup /R /TYPE=2 /Z fileID, scanpath
455  variable n = ItemsInList(S_HDF5ListGroup)
456  variable i
457  string ds
458  string region_datasets
459  for (i = 0; i < n; i += 1)
460  ds = StringFromList(i, S_HDF5ListGroup)
461  if (StringMatch(ds, "region*/*"))
462  //region_datasets = psh5_list_scan_datasets(fileID, ReplaceString("//", scanpath + "/" + region, "/"), include_regions=0)
463  result = AddListItem(ds, result, ";", inf)
464  endif
465  endfor
466  endif
467 
468  return result
469 end
470 
481 function /s psh5_list_scan_regions(fileID, scanpath)
482  variable fileID
483  string scanpath
484 
485  HDF5ListGroup /TYPE=1 /Z fileID, scanpath
486  variable n = ItemsInList(S_HDF5ListGroup)
487  variable i
488  string result = ""
489  string s
490  for (i = 0; i < n; i += 1)
491  s = StringFromList(i, S_HDF5ListGroup)
492  if (StringMatch(s, "region*"))
493  result = AddListItem(s, result, ";", inf)
494  endif
495  endfor
496 
497  return result
498 end
499 
514 function /s psh5_load_scan_data(fileID, scanpath)
515  variable fileID
516  string scanpath
517 
518  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
519  variable nds = ItemsInList(datasets)
520  variable ids
521  string sds
522  string sw
523  string wavenames = ""
524  for (ids = 0; ids < nds; ids += 1)
525  sds = StringFromList(ids, datasets)
526  sw = psh5_load_dataset(fileID, scanpath, sds, set_scale=0)
527  wavenames = AddListItem(sw, wavenames, ";", inf)
528  endfor
529 
530  return wavenames
531 end
532 
554 function /s psh5_load_scan_attrs(fileID, scanpath, [attr_sets])
555  variable fileID
556  string scanpath
557  variable attr_sets
558 
559  if (ParamIsDefault(attr_sets))
560  attr_sets = 1
561  endif
562 
563  string attr_path = ReplaceString("//", scanpath + "/attrs", "/")
564  string attr_list = ""
565  if (attr_sets & 1)
566  HDF5ListGroup /TYPE=2 /Z fileID, attr_path
567  if (!v_flag)
568  attr_list = S_HDF5ListGroup
569  endif
570  endif
571 
572  variable ids
573  variable nds
574  string sds
575 
576  if (attr_sets & 2)
577  nds = ItemsInList(kScientaScalingDatasets, ";")
578  for (ids = 0; ids < nds; ids += 1)
579  sds = StringFromList(ids, kScientaScalingDatasets)
580  if (WhichListItem(sds, attr_list) < 0)
581  attr_list = AddListItem(sds, attr_list, ";", inf)
582  endif
583  endfor
584  endif
585 
586  nds = ItemsInList(attr_list, ";")
587  string wavenames = ""
588  for (ids = 0; ids < nds; ids += 1)
589  sds = StringFromList(ids, attr_list, ";")
590  HDF5LoadData /O /Q /Z fileID, attr_path + "/" + sds
591  if (!v_flag)
592  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
593  endif
594  endfor
595  wavenames = ReplaceString(";;", wavenames, ";")
596 
597  return wavenames
598 end
599 
625 function /s psh5_load_scan_meta(fileID, scanpath)
626  variable fileID
627  string scanpath
628  string wavenames = ""
629 
630  HDF5LoadData /O /Q /Z /A="Dimensions" /N=ScanDimensions /TYPE=1 fileID, scanpath
631  if (!v_flag)
632  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
633  else
634  make /n=1 /o ScanDimensions
635  ScanDimensions = 0
636  wavenames = AddListItem("ScanDimensions", wavenames, ";", inf)
637  endif
638  HDF5LoadData /O /Q /Z /A="Readables" /N=ScanReadables /TYPE=1 fileID, scanpath
639  if (!v_flag)
640  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
641  else
642  make /n=1 /o /t ScanReadables
643  ScanReadables[0] = "ScientaSpectrum"
644  wavenames = AddListItem("ScanReadables", wavenames, ";", inf)
645  endif
646  HDF5LoadData /O /Q /Z /A="Writables" /N=ScanWritables /TYPE=1 fileID, scanpath
647  if (!v_flag)
648  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
649  endif
650  HDF5LoadData /O /Q /Z /A="Steps" /N=ScanSteps /TYPE=1 fileID, scanpath
651  if (!v_flag)
652  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
653  endif
654  wavenames = ReplaceString(";;", wavenames, ";")
655 
656  // additional attributes from XPSSpectrum.py
657  HDF5LoadData /O /Q /Z /A="Iterations" /N=ScanIterations /TYPE=1 fileID, scanpath
658  if (!v_flag)
659  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
660  endif
661  HDF5LoadData /O /Q /Z /A="Step Size" /N=ScanStepSize /TYPE=1 fileID, scanpath
662  if (!v_flag)
663  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
664  endif
665  HDF5LoadData /O /Q /Z /A="Step Time" /N=ScanStepTime /TYPE=1 fileID, scanpath
666  if (!v_flag)
667  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
668  endif
669 
670  return wavenames
671 end
672 
706 function /s psh5_load_dataset(fileID, scanpath, datasetname, [set_scale])
707  variable fileID
708  string scanpath
709  string datasetname
710  variable set_scale
711 
712  if (ParamIsDefault(set_scale))
713  set_scale = 1
714  endif
715 
716  dfref base_df = GetDataFolderDFR()
717 
718  string datasetpath
719  datasetpath = scanpath + "/" + datasetname
720  datasetpath = ReplaceString("//", datasetpath, "/")
721 
722  string regionname
723  string regionpath
724  if (ItemsInList(datasetname, "/") >= 2)
725  regionname = StringFromList(0, datasetname, "/")
726  regionpath = ReplaceString("//", scanpath + "/" + regionname, "/")
727  datasetname = RemoveListItem(0, datasetname, "/")
728  NewDataFolder /o/s $regionname
729  else
730  regionname = ""
731  regionpath = scanpath
732  endif
733 
734  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
735  InitHDF5DataInfo(di)
736  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
737  if (err != 0)
738  print "error accessing detector/data"
739  return ""
740  endif
741 
742  string dataname
743  if (di.ndims < 2)
744  HDF5LoadData /O /Q /Z fileID, datasetpath
745  dataname = StringFromList(0, S_waveNames)
746  else
747  dataname = psh5_load_dataset_slabs(fileID, regionpath, datasetname)
748  endif
749 
750  wave /z data = $dataname
751  if (waveexists(data))
752  psh5_load_dataset_meta(fileID, regionpath, datasetname, data)
753  ps_set_dimlabels(data)
754  if (set_scale)
755  ps_scale_dataset(data)
756  endif
757  else
758  dataname = ""
759  endif
760 
761  setdatafolder base_df
762  return dataname
763 end
764 
778 static function /s select_dataset(file_datasets, pref_datasets)
779  string file_datasets
780  string pref_datasets
781 
782  variable index
783  variable nds = ItemsInList(file_datasets)
784  variable ids
785  string sds = ""
786  string mds = ""
787  variable np = ItemsInList(pref_datasets)
788  variable ip
789  string sp
790  variable found = 0
791  if (nds > 0)
792  for (ip = 0; ip < np; ip += 1)
793  for (ids = 0; ids < nds; ids += 1)
794  sds = StringFromList(ids, file_datasets)
795  index = ItemsInList(sds, "/") - 1
796  mds = StringFromList(index, sds, "/")
797  sp = StringFromList(ip, pref_datasets)
798  if (StringMatch(mds, sp))
799  found = 1
800  break
801  endif
802  endfor
803  if (found)
804  break
805  endif
806  endfor
807  if (!found)
808  ids = 0
809  sds = StringFromList(ids, file_datasets)
810  endif
811  endif
812 
813  return sds
814 end
815 
840 function /s psh5_load_scan_preview(fileID, scanpath, [set_scale, pref_datasets])
841  variable fileID
842  string scanpath
843  variable set_scale
844  string pref_datasets
845 
846  if (ParamIsDefault(set_scale))
847  set_scale = 1
848  endif
849  if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0))
850  pref_datasets = kPreviewDatasets
851  endif
852 
853  dfref saveDF = GetDataFolderDFR()
854  dfref dataDF = saveDF
855 
856  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
857  string datasetname = select_dataset(datasets, pref_datasets)
858  string datasetpath
859  datasetpath = scanpath + "/" + datasetname
860  datasetpath = ReplaceString("//", datasetpath, "/")
861 
862  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
863  InitHDF5DataInfo(di)
864  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
865  if (err != 0)
866  print "error accessing detector/data"
867  return ""
868  endif
869 
870  string dataname
871  if (di.ndims < 2)
872  HDF5LoadData /O /Q /Z fileID, datasetpath
873  dataname = StringFromList(0, S_waveNames)
874  wave /z data = $dataname
875  if (waveexists(data))
876  ps_set_dimlabels(data)
877  endif
878  else
879  variable dim2start = 0
880  variable dim2count = 1
881  variable dim3start = 0
882  variable dim3count = 1
883  if (di.ndims >= 3)
884  dim2start = floor(di.dims[2] / 2)
885  dim2count = 1
886  endif
887  if (di.ndims >= 4)
888  dim3start = floor(di.dims[3] / 2)
889  dim3count = 1
890  endif
891 
892  dataname = psh5_load_dataset_slab(fileID, scanpath, datasetname, dim2start, dim2count, dim3start, dim3count)
893  endif
894 
895  wave /z data = $dataname
896  if (waveexists(data))
897  if (set_scale)
898  setdatafolder dataDF
899  string positioners
900  string positioner
901  string positionerpath
902  positioners = psh5_load_scan_meta(fileID, scanpath)
903  wave /t /z ScanWritables
904  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
905  positioner = ScanWritables[0]
906  if (strlen(positioner) > 0)
907  positionerpath = scanpath + "/" + positioner
908  positionerpath = ReplaceString("//", positionerpath, "/")
909  HDF5LoadData /O /Q /Z fileID, positionerpath
910  endif
911  endif
912 
913  setdatafolder dataDF
914  newdatafolder /o/s attr
915  psh5_load_scan_attrs(fileID, scanpath, attr_sets=2)
916  setdatafolder dataDF
917  ps_scale_dataset(data)
918  endif
919  else
920  dataname = ""
921  endif
922 
923  return dataname
924 end
925 
953 function /s psh5_load_scan_section(fileID, scanpath, dim, [set_scale, pref_datasets])
954  variable fileID
955  string scanpath
956  variable dim
957  variable set_scale
958  string pref_datasets
959 
960  // select first dimension (future argument)
961  // 0 = first dimension is x axis (energy of scienta image)
962  dim = 0
963 
964  if (ParamIsDefault(set_scale))
965  set_scale = 1
966  endif
967  if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0))
968  pref_datasets = kPreviewDatasets
969  endif
970 
971  dfref saveDF = GetDataFolderDFR()
972  dfref dataDF = saveDF
973 
974  string datasets = psh5_list_scan_datasets(fileID, scanpath)
975  string datasetname = select_dataset(datasets, pref_datasets)
976  string datasetpath
977  datasetpath = scanpath + "/" + datasetname
978  datasetpath = ReplaceString("//", datasetpath, "/")
979  string dataname = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
980  string destname = dataname[0,29] + num2str(dim)
981 
982  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
983  InitHDF5DataInfo(di)
984  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
985  if (err != 0)
986  print "error accessing detector/data"
987  return ""
988  elseif (di.ndims != 3)
989  print "error: rank of dataset != 3"
990  return ""
991  endif
992 
993  variable idx, idy, idz, idt
994  variable transpose = WhichListItem(dataname, kTransposedDatasets) >= 0
995  if (transpose)
996  idx = 1
997  idy = 0
998  else
999  idx = 0
1000  idy = 1
1001  endif
1002  idz = 2
1003  idt = 3
1004 
1005  variable nx, ny, nz
1006  nx = di.dims[idx]
1007  ny = di.dims[idy]
1008  nz = di.dims[idz]
1009 
1010  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
1011  wave slab
1012  slab[][%Start] = 0
1013  slab[][%Stride] = 1
1014  slab[][%Count] = 1
1015  slab[][%Block] = 1
1016 
1017  if (dim == 0)
1018  slab[idy][%Start] = floor(ny / 2)
1019  slab[idx][%Block] = nx
1020  make /n=(nx,nz) /o $destname
1021  else
1022  slab[idx][%Start] = floor(nx / 2)
1023  slab[idy][%Block] = ny
1024  make /n=(ny,nz) /o $destname
1025  endif
1026  slab[idz][%Block] = nz
1027  wave data = $destname
1028  data = 0
1029 
1030  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
1031  if (!v_flag)
1032  wave slabdata
1033  if (transpose)
1034  data += slabdata[0][p][q][0]
1035  else
1036  data += slabdata[p][0][q][0]
1037  endif
1038  endif
1039  killwaves /z slab, slabdata
1040 
1041  if (set_scale)
1042  make /n=(1,1,1) /free dummy
1043  ps_set_dimlabels2(dummy, dataname)
1044  setdimlabel 0, -1, $GetDimLabel(dummy, dim, -1), data
1045  setdimlabel 1, -1, $kScanDimLabel, data
1046 
1047  setdatafolder dataDF
1048  string positioners
1049  string positioner
1050  string positionerpath
1051  positioners = psh5_load_scan_meta(fileID, scanpath)
1052  wave /t /z ScanWritables
1053  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
1054  positioner = ScanWritables[0]
1055  if (strlen(positioner) > 0)
1056  positionerpath = scanpath + "/" + positioner
1057  positionerpath = ReplaceString("//", positionerpath, "/")
1058  HDF5LoadData /O /Q /Z fileID, positionerpath
1059  endif
1060  endif
1061 
1062  setdatafolder dataDF
1063  newdatafolder /o/s attr
1064  killwaves /a/z
1065  psh5_load_scan_attrs(fileID, scanpath, attr_sets=2)
1066  setdatafolder dataDF
1067  ps_scale_dataset(data)
1068  endif
1069 
1070  return destname
1071 end
1072 
1091 function psh5_load_dataset_meta(fileID, datapath, datasetname, datawave)
1092  variable fileID
1093  string datapath
1094  string datasetname
1095  wave datawave
1096 
1097  dfref saveDF = GetDataFolderDFR()
1098  SetDataFolder NewFreeDataFolder()
1099 
1100  string datasetpath = datapath + "/" + datasetname
1101  datasetpath = ReplaceString("//", datasetpath, "/")
1102  string wnote
1103 
1104  HDF5LoadData /O /Q /Z /A="Writable Dimension" /N=WriteDim fileID, datasetpath
1105  if (!v_flag)
1106  wave WriteDim
1107  // scan dimension starts at 1
1108  sprintf wnote, "ScanDimension=%u", WriteDim[0]
1109  Note datawave, wnote
1110  endif
1111 
1112  HDF5LoadData /O /Q /Z /A="Writable Index" /N=WriteIndex fileID, datasetpath
1113  if (!v_flag)
1114  wave WriteIndex
1115  sprintf wnote, "WriteableIndex=%u", WriteIndex[0]
1116  Note datawave, wnote
1117  endif
1118 
1119  HDF5LoadData /O /Q /Z /A="Readable Index" /N=ReadIndex fileID, datasetpath
1120  if (!v_flag)
1121  wave ReadIndex
1122  sprintf wnote, "ReadableIndex=%u", ReadIndex[0]
1123  Note datawave, wnote
1124  endif
1125 
1126  setdatafolder saveDF
1127  return 0
1128 end
1129 
1148 function /s psh5_load_dataset_slabs(fileID, datapath, datasetname, [progress])
1149  variable fileID
1150  string datapath
1151  string datasetname
1152  variable progress
1153 
1154  if (ParamIsDefault(progress))
1155  progress = 1
1156  endif
1157 
1158  variable result = 0
1159  string datasetpath
1160  string datawavename
1161  datasetpath = datapath + "/" + datasetname
1162  datasetpath = ReplaceString("//", datasetpath, "/")
1163  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
1164 
1165  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
1166  InitHDF5DataInfo(di)
1167  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
1168  if (err != 0)
1169  print "error accessing detector/data"
1170  return ""
1171  endif
1172  if (di.ndims < 2)
1173  print "error: rank of dataset < 2"
1174  return ""
1175  elseif (di.ndims < 3)
1176  progress = 0
1177  endif
1178 
1179  variable idx, idy, idz, idt, izt
1180  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
1181  if (transpose)
1182  idx = 1
1183  idy = 0
1184  else
1185  idx = 0
1186  idy = 1
1187  endif
1188  idz = 2
1189  idt = 3
1190 
1191  variable nx, ny, nz, nt, nzt
1192  nx = di.dims[idx]
1193  ny = di.dims[idy]
1194  nz = di.dims[idz]
1195  nt = di.dims[idt]
1196  make /n=(nx,ny,nz,nt) /o $datawavename
1197  wave data = $datawavename
1198 
1199  nz = max(nz, 1)
1200  nt = max(nt, 1)
1201  nzt = nz * nt
1202  izt = 0
1203  if (progress)
1204  display_progress_panel("HDF5 Import", "Loading data...", nzt)
1205  endif
1206 
1207  // load data image by image
1208  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
1209  wave slab
1210  slab[][%Start] = 0
1211  slab[][%Stride] = 1
1212  slab[][%Count] = 1
1213  slab[][%Block] = 1
1214  slab[idx][%Block] = nx
1215  slab[idy][%Block] = ny
1216 
1217  variable iz, it
1218  for (iz = 0; iz < nz; iz += 1)
1219  for (it = 0; it < nt; it += 1)
1220  slab[idz][%Start] = iz
1221  slab[idt][%Start] = it
1222  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
1223  wave slabdata // 2D, 3D, or 4D with singletons
1224  if (transpose)
1225  data[][][iz][it] = slabdata[q][p][0][0]
1226  else
1227  data[][][iz][it] = slabdata[p][q][0][0]
1228  endif
1229 
1230  // progress window
1231  izt += 1
1232  if (progress)
1233  if (update_progress_panel(izt))
1234  result = -4 // user abort
1235  break
1236  endif
1237  endif
1238  endfor
1239  if (result < 0)
1240  break
1241  endif
1242  endfor
1243 
1244  if (progress)
1245  kill_progress_panel()
1246  endif
1247 
1248  killwaves /z slab, slabdata
1249  if (!result)
1250  ps_set_dimlabels(data)
1251  return datawavename
1252  else
1253  killwaves /z data
1254  return ""
1255  endif
1256 end
1257 
1284 function /s psh5_load_dataset_slab(fileID, datapath, datasetname, dim2start, dim2count, dim3start, dim3count)
1285  variable fileID
1286  string datapath
1287  string datasetname
1288  variable dim2start
1289  variable dim2count
1290  variable dim3start
1291  variable dim3count
1292 
1293  string datasetpath
1294  string datawavename
1295  datasetpath = datapath + "/" + datasetname
1296  datasetpath = ReplaceString("//", datasetpath, "/")
1297  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
1298 
1299  STRUCT HDF5DataInfo di
1300  InitHDF5DataInfo(di)
1301  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
1302  if (err != 0)
1303  print "error accessing detector/data"
1304  return ""
1305  endif
1306  if (di.ndims < 2)
1307  print "error: rank of dataset < 2"
1308  return ""
1309  endif
1310 
1311  variable idx, idy, idz, idt
1312  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
1313  if (transpose)
1314  idx = 1
1315  idy = 0
1316  else
1317  idx = 0
1318  idy = 1
1319  endif
1320  idz = 2
1321  idt = 3
1322 
1323  variable nx, ny
1324  nx = di.dims[idx]
1325  ny = di.dims[idy]
1326  make /n=(nx,ny) /o $datawavename
1327  wave data = $datawavename
1328  data = 0
1329 
1330  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
1331  wave slab
1332  slab[][%Start] = 0
1333  slab[][%Stride] = 1
1334  slab[][%Count] = 1
1335  slab[][%Block] = 1
1336  slab[idx][%Block] = nx
1337  slab[idy][%Block] = ny
1338 
1339  variable iz, it
1340  variable navg = 0
1341  variable dim2end = dim2start + dim2count - 1
1342  variable dim3end = dim3start + dim3count - 1
1343  for (iz = dim2start; iz <= dim2end; iz += 1)
1344  for (it = dim3start; it <= dim3end; it += 1)
1345  slab[idz][%Start] = iz
1346  slab[idt][%Start] = it
1347  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
1348  if (!v_flag)
1349  wave slabdata
1350  if (transpose)
1351  data += slabdata[q][p][0][0]
1352  else
1353  data += slabdata[p][q][0][0]
1354  endif
1355  navg += 1
1356  endif
1357  endfor
1358  endfor
1359  if (navg)
1360  data /= navg
1361  endif
1362 
1363  killwaves /z slab, slabdata
1364  ps_set_dimlabels(data)
1365  return datawavename
1366 end
1367 
1383 function ps_set_dimlabels(data)
1384  wave data
1385 
1386  ps_set_dimlabels2(data, NameOfWave(data))
1387 end
1388 
1402 function ps_set_dimlabels2(data, name)
1403  wave data
1404  string name
1405 
1406  variable dummy
1407  try
1408  // intrinsic dimensions
1409  strswitch(name)
1410  case "ScientaImage":
1411  setdimlabel 0, -1, $kEnergyDimLabel, data
1412  setdimlabel 1, -1, $kAngleDimLabel, data
1413  if (WaveDims(data) >= 3)
1414  setdimlabel 2, -1, $kScanDimLabel, data
1415  endif
1416  AbortOnRTE
1417  break
1418  case "ImageAngleDistribution":
1419  case "ScientaAngleDistribution":
1420  if (WaveDims(data) >= 2)
1421  setdimlabel 0, -1, $kScanDimLabel, data
1422  setdimlabel 1, -1, $kAngleDimLabel, data
1423  else
1424  setdimlabel 0, -1, $kAngleDimLabel, data
1425  endif
1426  AbortOnRTE
1427  break
1428  case "ScientaSpectrum":
1429  case "ImageEnergyDistribution":
1430  case "ScientaEnergyDistribution":
1431  if (WaveDims(data) >= 2)
1432  setdimlabel 0, -1, $kScanDimLabel, data
1433  setdimlabel 1, -1, $kEnergyDimLabel, data
1434  else
1435  setdimlabel 0, -1, $kEnergyDimLabel, data
1436  endif
1437  AbortOnRTE
1438  break
1439  default:
1440  if (WaveDims(data) == 1)
1441  setdimlabel 0, -1, $kScanDimLabel, data
1442  AbortOnRTE
1443  else
1444  return 1
1445  endif
1446  endswitch
1447  catch
1448  dummy = GetRTError(1)
1449  return 2
1450  endtry
1451  return 0
1452 end
1453 
1459 static function /df find_scan_folder(dataDF)
1460  dfref dataDF
1461 
1462  dfref attrDF = dataDF:attr
1463  if (!DataFolderRefStatus(attrDF))
1464  string df = GetDataFolder(1, dataDF) + ":"
1465  dfref scanDF = $df
1466  else
1467  dfref scanDF = dataDF
1468  endif
1469  return scanDF
1470 end
1471 
1476 static function /df find_attr_folder(dataDF)
1477  dfref dataDF
1478 
1479  dfref attrDF = dataDF:attr
1480  if (!DataFolderRefStatus(attrDF))
1481  string df = GetDataFolder(1, dataDF) + ":"
1482  dfref scanDF = $df
1483  dfref attrDF = scanDF:attr
1484  endif
1485  return attrDF
1486 end
1487 
1504 function ps_scale_datasets()
1505  dfref scanDF = GetDataFolderDFR()
1506  dfref attrDF = find_attr_folder(scanDF)
1507 
1508  make /n=3 /free lo, hi
1509  make /n=3 /t /free ax, un
1510  wave /t /z /SDFR=scanDF ScanReadables
1511  if (WaveExists(ScanReadables))
1512  variable isr
1513  variable nsr = numpnts(ScanReadables)
1514  string ssr
1515  string sdf
1516  for (isr = 0; isr < nsr; isr += 1)
1517  setdatafolder scanDF
1518  ssr = ScanReadables[isr]
1519  if (ItemsInList(ssr, "/") >= 2)
1520  sdf = StringFromList(0, ssr, "/")
1521  ssr = RemoveListItem(0, ssr, "/")
1522  setdatafolder $sdf
1523  endif
1524  wave /z wsr=$ssr
1525  if (WaveExists(wsr))
1526  ps_detect_scale(ax, lo, hi, un)
1527  ps_scale_dataset_2(wsr, ax, lo, hi, un)
1528  endif
1529  endfor
1530  endif
1531  setdatafolder scanDF
1532 end
1533 
1550 function ps_scale_dataset(data)
1551  wave data
1552 
1553  dfref saveDF = GetDataFolderDFR()
1554  dfref dataDF = GetWavesDataFolderDFR(data)
1555 
1556  setdatafolder dataDF
1557  make /n=3 /free lo, hi
1558  make /n=3 /t /free ax, un
1559  ps_detect_scale(ax, lo, hi, un)
1560  ps_scale_dataset_2(data, ax, lo, hi, un)
1561  setdatafolder saveDF
1562 end
1563 
1564 static function /wave find_scale_wave(name, dataDF, scanDF, attrDF)
1565  string name
1566  dfref dataDF
1567  dfref scanDF
1568  dfref attrDF
1569 
1570  wave /SDFR=dataDF /Z w = $name
1571  if (!WaveExists(w))
1572  wave /SDFR=scanDF /Z w = $name
1573  if (!WaveExists(w))
1574  wave /SDFR=attrDF /Z w = $name
1575  endif
1576  endif
1577  return w
1578 end
1579 
1621 function ps_detect_scale(ax, lo, hi, un)
1622  wave /t ax
1623  wave lo
1624  wave hi
1625  wave /t un
1626 
1627  dfref dataDF = GetDataFolderDFR()
1628  dfref scanDF = find_scan_folder(dataDF)
1629  dfref attrDF = find_attr_folder(dataDF)
1630 
1631  redimension /n=4 lo, hi, un, ax
1632  setdimlabel 0, 0, $kEnergyDimLabel, lo, hi, un, ax
1633  setdimlabel 0, 1, $kAngleDimLabel, lo, hi, un, ax
1634  setdimlabel 0, 2, $kScanDimLabel, lo, hi, un, ax
1635  setdimlabel 0, 3, $kDataDimLabel, lo, hi, un, ax
1636 
1637  // default values
1638  lo[%$kEnergyDimLabel] = 0
1639  hi[%$kEnergyDimLabel] = 1
1640  un[%$kEnergyDimLabel] = "eV"
1641  ax[%$kEnergyDimLabel] = "Ekin"
1642 
1643  lo[%$kAngleDimLabel] = -1
1644  hi[%$kAngleDimLabel] = 1
1645  un[%$kAngleDimLabel] = "arb."
1646  un[%$kAngleDimLabel] = "slice"
1647 
1648  lo[%$kScanDimLabel] = 0
1649  hi[%$kScanDimLabel] = 1
1650  un[%$kScanDimLabel] = "arb."
1651  ax[%$kScanDimLabel] = "scan"
1652 
1653  lo[%$kDataDimLabel] = 0
1654  hi[%$kDataDimLabel] = 0
1655  un[%$kDataDimLabel] = "arb."
1656  ax[%$kDataDimLabel] = "value"
1657 
1658  wave /SDFR=attrDF /T /Z LensMode
1659  wave /Z ChannelBegin = find_scale_wave("ScientaChannelBegin", dataDF, scanDF, attrDF)
1660  wave /Z ChannelEnd = find_scale_wave("ScientaChannelEnd", dataDF, scanDF, attrDF)
1661  wave /Z SliceBegin = find_scale_wave("ScientaSliceBegin", dataDF, scanDF, attrDF)
1662  wave /Z SliceEnd = find_scale_wave("ScientaSliceEnd", dataDF, scanDF, attrDF)
1663 
1664  // lens mode can give more detail
1665  if (waveexists(LensMode) && (numpnts(LensMode) >= 1))
1666  strswitch(LensMode[0])
1667  case "Angular45":
1668  lo[%$kAngleDimLabel] = -45/2
1669  hi[%$kAngleDimLabel] = +45/2
1670  un[%$kAngleDimLabel] = "°"
1671  ax[%$kAngleDimLabel] = "angle"
1672  break
1673  case "Angular60":
1674  lo[%$kAngleDimLabel] = -60/2
1675  hi[%$kAngleDimLabel] = +60/2
1676  un[%$kAngleDimLabel] = "°"
1677  ax[%$kAngleDimLabel] = "angle"
1678  break
1679  case "Transmission":
1680  un[%$kAngleDimLabel] = "arb."
1681  ax[%$kAngleDimLabel] = "offset"
1682  break
1683  endswitch
1684  endif
1685 
1686  // best option if scales are explicit in separate waves
1687  if (waveexists(ChannelBegin) && waveexists(ChannelEnd) && (numpnts(ChannelBegin) >= 1) && (numpnts(ChannelEnd) >= 1))
1688  lo[%$kEnergyDimLabel] = ChannelBegin[0]
1689  hi[%$kEnergyDimLabel] = ChannelEnd[0]
1690  endif
1691  if (waveexists(SliceBegin) && waveexists(SliceEnd) && (numpnts(SliceBegin) >= 1) && (numpnts(SliceEnd) >= 1))
1692  lo[%$kAngleDimLabel] = SliceBegin[0]
1693  hi[%$kAngleDimLabel] = SliceEnd[0]
1694  endif
1695 
1696  wave /z /t /SDFR=scanDF ScanWritables
1697  if (WaveExists(ScanWritables))
1698  wave /z /SDFR=scanDF scanner = $ScanWritables[0]
1699  if (!WaveExists(scanner))
1700  wave /z /SDFR=attrDF scanner = $ScanWritables[0]
1701  endif
1702  if (WaveExists(scanner) && (numpnts(scanner) >= 1))
1703  lo[%$kScanDimLabel] = scanner[0]
1704  hi[%$kScanDimLabel] = scanner[numpnts(scanner)-1]
1705  ax[%$kScanDimLabel] = NameOfWave(scanner)
1706  strswitch(NameOfWave(scanner))
1707  case "Eph":
1708  ax[%$kScanDimLabel] = "photon energy"
1709  un[%$kScanDimLabel] = "eV"
1710  break
1711  case "ManipulatorX":
1712  case "ManipulatorY":
1713  case "ManipulatorZ":
1714  case "FocusYTrans":
1715  case "FocusZTrans":
1716  case "RefocusYTrans":
1717  case "RefocusZTrans":
1718  case "ExitSlitY":
1719  un[%$kScanDimLabel] = "mm"
1720  break
1721  case "ExitSlit":
1722  un[%$kScanDimLabel] = "µm"
1723  break
1724  case "ManipulatorTheta":
1725  case "ManipulatorTilt":
1726  case "ManipulatorPhi":
1727  un[%$kScanDimLabel] = "°"
1728  break
1729  case "FocusXRot":
1730  case "FocusYRot":
1731  case "FocusZRot":
1732  case "RefocusXRot":
1733  case "RefocusYRot":
1734  case "RefocusZRot":
1735  un[%$kScanDimLabel] = "mrad"
1736  break
1737  endswitch
1738  endif
1739  endif
1740 end
1741 
1781 function ps_scale_dataset_2(data, ax, lo, hi, un)
1782  wave data
1783  wave /t ax
1784  wave lo
1785  wave hi
1786  wave /t un
1787 
1788  string snote = note(data)
1789  string sdim
1790  sdim = GetDimLabel(data, 0, -1)
1791  if (strlen(sdim))
1792  setscale /i x lo[%$sdim], hi[%$sdim], un[%$sdim], data
1793  snote = ReplaceStringByKey("AxisLabelX", snote, ax[%$sdim], "=", "\r")
1794  endif
1795 
1796  sdim = GetDimLabel(data, 1, -1)
1797  if (strlen(sdim))
1798  setscale /i y lo[%$sdim], hi[%$sdim], un[%$sdim], data
1799  snote = ReplaceStringByKey("AxisLabelY", snote, ax[%$sdim], "=", "\r")
1800  endif
1801 
1802  sdim = GetDimLabel(data, 2, -1)
1803  if (strlen(sdim))
1804  setscale /i z lo[%$sdim], hi[%$sdim], un[%$sdim], data
1805  snote = ReplaceStringByKey("AxisLabelZ", snote, ax[%$sdim], "=", "\r")
1806  endif
1807 
1808  string data_unit = un[%$kDataDimLabel]
1809  string data_label = ax[%$kDataDimLabel]
1810  string s
1811  variable def = (cmpstr(data_unit, "arb.") == 0) && (cmpstr(data_label, "value") == 0)
1812 
1813  if (def)
1814  s = StringByKey("AxisLabelD", snote, "=", "\r")
1815  if (strlen(s) > 0)
1816  data_label = s
1817  def = 0
1818  endif
1819  s = StringByKey("AxisUnitD", snote, "=", "\r")
1820  if (strlen(s) > 0)
1821  data_unit = s
1822  def = 0
1823  endif
1824  endif
1825 
1826  if (def)
1827  strswitch(NameOfWave(data))
1828  case "ScientaImage":
1829  case "ImageAngleDistribution":
1830  case "ScientaAngleDistribution":
1831  case "ScientaSpectrum":
1832  case "ImageEnergyDistribution":
1833  case "ScientaEnergyDistribution":
1834  data *= kDetectorSensitivity
1835  data_unit = "counts"
1836  data_label = "intensity"
1837  def = 0
1838  break
1839  case "SampleCurrent":
1840  case "RefCurrent":
1841  case "AuxCurrent":
1842  data_unit = "A"
1843  data_label = "current"
1844  def = 0
1845  break
1846  case "MachineCurrent":
1847  data_unit = "mA"
1848  data_label = "current"
1849  def = 0
1850  break
1851  endswitch
1852  endif
1853 
1854  setscale d 0, 0, data_unit, data
1855  snote = ReplaceStringByKey("AxisLabelD", snote, data_label, "=", "\r")
1856  snote = ReplaceStringByKey("AxisUnitD", snote, data_unit, "=", "\r")
1857  snote = ReplaceStringByKey("Dataset", snote, NameOfWave(data), "=", "\r")
1858  note /k data, snote
1859 end
1860 
1911 function /s psh5_load_reduced(ANickName, APathName, AFileName, reduction_func, reduction_param, [progress, nthreads])
1912  string ANickName
1913  string APathName
1914  string AFileName
1915  funcref adh5_default_reduction reduction_func
1916  string reduction_param
1917  variable progress
1918  variable nthreads
1919 
1920  if (ParamIsDefault(progress))
1921  progress = 1
1922  endif
1923  if (ParamIsDefault(nthreads))
1924  nthreads = -1
1925  endif
1926 
1927  dfref saveDF = GetDataFolderDFR()
1928 
1929  // performance monitoring
1930  variable timerRefNum
1931  variable /g psh5_perf_secs
1932  timerRefNum = startMSTimer
1933 
1934  variable fileID = psh5_open_file(ANickName, APathName, AFileName)
1935  string wavenames = ""
1936  if (fileID)
1937  dfref fileDF = GetDataFolderDFR()
1938  svar s_filepath
1939  svar s_scanpaths
1940  AFileName = s_filepath
1941  print "loading " + s_filepath + "\r"
1942 
1943  variable ig = 0
1944  variable ng = ItemsInList(s_scanpaths)
1945  string scanpath
1946  string folder
1947  string positioners
1948  string positioner
1949  string positionerpath
1950 
1951  scanpath = StringFromList(ig, s_scanpaths)
1952  folder = ReplaceString("/", scanpath, "")
1953  folder = ReplaceString(" ", folder, "")
1954  folder = PearlCleanupName(folder)
1955  setdatafolder fileDF
1956  newdatafolder /s /o $folder
1957  dfref dataDF = GetDataFolderDFR()
1958  positioners = psh5_load_scan_meta(fileID, scanpath)
1959  newdatafolder /s /o attr
1960  killwaves /a/z
1961  psh5_load_scan_attrs(fileID, scanpath)
1962  setdatafolder dataDF
1963  wave /t /z ScanWritables
1964  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
1965  positioner = ScanWritables[0]
1966  if (strlen(positioner) > 0)
1967  positionerpath = scanpath + "/" + positioner
1968  positionerpath = ReplaceString("//", positionerpath, "/")
1969  HDF5LoadData /O /Q /Z fileID, positionerpath
1970  endif
1971  endif
1972 
1973  setdatafolder dataDF
1974  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
1975  string dataset = select_dataset(datasets, "ScientaImage")
1976  wavenames = psh5_load_dataset_reduced(fileID, scanpath, dataset, reduction_func, reduction_param, progress=progress, nthreads=nthreads)
1977 
1978  psh5_close_file(fileID)
1979  endif
1980 
1981  if (timerRefNum >= 0)
1982  psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
1983  endif
1984 
1985  setdatafolder saveDF
1986  return wavenames
1987 end
1988 
1989 
2040 function /s psh5_load_dataset_reduced(fileID, scanpath, datasetname, reduction_func, reduction_param, [progress, nthreads])
2041  variable fileID
2042  string scanpath
2043  string datasetname
2044  funcref adh5_default_reduction reduction_func
2045  string reduction_param
2046  variable progress
2047  variable nthreads
2048 
2049  if (ParamIsDefault(progress))
2050  progress = 1
2051  endif
2052  if (ParamIsDefault(nthreads))
2053  nthreads = -1
2054  endif
2055 
2056  dfref base_df = GetDataFolderDFR()
2057  variable result = 0
2058  string datasetpath
2059  string datawavename
2060  string wavenames = ""
2061 
2062  datasetpath = scanpath + "/" + datasetname
2063  datasetpath = ReplaceString("//", datasetpath, "/")
2064  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
2065 
2066  string regionname
2067  string regionpath
2068  if (ItemsInList(datasetname, "/") >= 2)
2069  regionname = StringFromList(0, datasetname, "/")
2070  regionpath = ReplaceString("//", scanpath + "/" + regionname, "/")
2071  datasetname = RemoveListItem(0, datasetname, "/")
2072  NewDataFolder /o/s $regionname
2073  else
2074  regionname = ""
2075  regionpath = scanpath
2076  endif
2077 
2078  STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
2079  InitHDF5DataInfo(di)
2080  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
2081  if (err != 0)
2082  print "error accessing detector/data"
2083  result = -1
2084  return wavenames
2085  endif
2086  if (di.ndims < 2)
2087  print "error: rank of dataset < 2"
2088  result = -2
2089  return wavenames
2090  elseif (di.ndims < 3)
2091  progress = 0
2092  endif
2093 
2094  variable idx, idy, idz, idt
2095  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
2096  if (transpose)
2097  idx = 1
2098  idy = 0
2099  else
2100  idx = 0
2101  idy = 1
2102  endif
2103  idz = 2
2104  idt = 3
2105 
2106  variable nx, ny, nz, nt, nzt
2107  nx = di.dims[idx]
2108  ny = di.dims[idy]
2109  nz = di.dims[idz]
2110  nt = di.dims[idt]
2111  // adjust singleton dimensions
2112  nz = max(nz, 1)
2113  nt = max(nt, 1)
2114  nzt = nz * nt
2115 
2116  // load data image by image
2117  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
2118  wave slab
2119  slab[][%Start] = 0
2120  slab[][%Stride] = 1
2121  slab[][%Count] = 1
2122  slab[][%Block] = 1
2123  slab[idx][%Block] = nx
2124  slab[idy][%Block] = ny
2125 
2126  // set up multi threading
2127  if (nthreads < 0)
2128  nthreads = ThreadProcessorCount
2129  endif
2130  if (nthreads > 0)
2131  variable threadGroupID = ThreadGroupCreate(nthreads)
2132  variable ithread
2133  for (ithread = 0; ithread < nthreads; ithread += 1)
2134  ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
2135  endfor
2136  else
2137  make /n=(nzt) /df /free processing_folders
2138  endif
2139 
2140  if (progress)
2141  display_progress_panel("HDF5 Import", "Loading data (step 1 of 2)...", nzt)
2142  endif
2143 
2144  // create a template wave with the correct scales and labels
2145  make /n=(nx,ny) /d /o $datawavename
2146  wave template = $datawavename
2147  ps_set_dimlabels2(template, datawavename)
2148  ps_scale_dataset(template)
2149 
2150  variable iz, it, izt
2151  string dfname
2152  variable iw, nw
2153  string sw
2154  make /n=0 /free /wave result_waves
2155 
2156  izt = 0
2157  for (iz = 0; iz < nz; iz += 1)
2158  for (it = 0; it < nt; it += 1)
2159  // load hyperslab
2160  slab[idz][%Start] = iz
2161  slab[idt][%Start] = it
2162  dfname = "processing_" + num2str(izt)
2163  newdatafolder /s $dfname
2164  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
2165 
2166  // send to processing queue
2167  duplicate template, image
2168  variable /g r_index = iz
2169  variable /g s_index = it
2170  string /g func_param = reduction_param
2171 
2172  if (nthreads > 0)
2173  WaveClear image
2174  ThreadGroupPutDF threadGroupID, :
2175  else
2176  processing_folders[izt] = GetDataFolderDFR()
2177  make /n=1/d profile1, profile2
2178  wave slabdata
2179  wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
2180  variable /g func_result = numpnts(reduced_waves)
2181  adh5_get_result_waves(reduced_waves, "redw_", 0)
2182  WaveClear slabdata, image, reduced_waves
2183  setdatafolder ::
2184  endif
2185 
2186  izt += 1
2187  // progress window
2188  if (progress)
2189  if (update_progress_panel(izt))
2190  print "user abort"
2191  result = -4
2192  break
2193  endif
2194  endif
2195  endfor
2196  endfor
2197 
2198  killwaves /z slab, slabdata, template
2199  if (progress)
2200  update_progress_panel(0, message="Processing data (step 2 of 2)...")
2201  endif
2202 
2203  dfref dfr
2204  for (izt = 0; (izt < nzt) && (result == 0); izt += 1)
2205  if (nthreads > 0)
2206  do
2207  if (progress)
2208  if (update_progress_panel(izt))
2209  print "user abort"
2210  result = -4
2211  break
2212  endif
2213  endif
2214  dfr = ThreadGroupGetDFR(threadGroupID, 1000)
2215  if (DatafolderRefStatus(dfr) != 0)
2216  break
2217  endif
2218  while (1)
2219  else
2220  if (progress)
2221  if (update_progress_panel(izt))
2222  print "user abort"
2223  result = -4
2224  break
2225  endif
2226  endif
2227  dfr = processing_folders[izt]
2228  endif
2229 
2230  if (result != 0)
2231  break
2232  endif
2233 
2234  nvar rr = dfr:r_index
2235  nvar ss = dfr:s_index
2236  nvar func_result = dfr:func_result
2237 
2238  if (func_result < 1)
2239  print "error during data reduction."
2240  result = -3
2241  break
2242  endif
2243 
2244  if (numpnts(result_waves) == 0)
2245  redimension /n=(func_result) result_waves
2246  for (iw = 0; iw < func_result; iw += 1)
2247  sw = "redw_" + num2str(iw)
2248  wave profile = dfr:$sw
2249  sw = "ReducedData" + num2str(iw+1)
2250  make /n=(dimsize(profile, 0), nz, nt) /d /o $sw
2251  wave data = $sw
2252  setdimlabel 0, -1, $getdimlabel(profile, 0, -1), data
2253  setdimlabel 1, -1, $kScanDimLabel, data
2254  note data, note(profile)
2255  ps_scale_dataset(data)
2256  setscale /p x dimoffset(profile, 0), dimdelta(profile, 0), waveunits(profile, 0), data
2257  setscale d 0, 0, waveunits(profile, -1), data
2258  result_waves[iw] = data
2259  endfor
2260  endif
2261  for (iw = 0; iw < func_result; iw += 1)
2262  sw = "redw_" + num2str(iw)
2263  wave profile = dfr:$sw
2264  wave data = result_waves[iw]
2265  data[][rr][ss] = profile[p]
2266  endfor
2267  endfor
2268 
2269  if (nthreads > 0)
2270  variable tstatus = ThreadGroupRelease(threadGroupID)
2271  if (tstatus == -2)
2272  print "error: thread did not terminate properly."
2273  result = -5
2274  endif
2275  else
2276  for (izt = 0; izt < nzt; izt += 1)
2277  KillDataFolder /Z processing_folders[izt]
2278  endfor
2279  endif
2280 
2281  if (result == 0)
2282  nw = numpnts(result_waves)
2283  wavenames = ""
2284  for (iw = 0; iw < nw; iw += 1)
2285  wave data = result_waves[iw]
2286  if (nz == 1)
2287  redimension /n=(-1, 0, 0) data
2288  elseif (nt == 1)
2289  redimension /n=(-1, nz, 0) data
2290  endif
2291  wavenames += nameofwave(data) + ";"
2292  endfor
2293  endif
2294  if (progress)
2295  kill_progress_panel()
2296  endif
2297 
2298  setdatafolder base_df
2299  return wavenames
2300 end
2301 
2302 threadsafe static function reduce_slab_worker(reduction_func)
2303  funcref adh5_default_reduction reduction_func
2304  do
2305  // wait for job from main thread
2306  do
2307  dfref dfr = ThreadGroupGetDFR(0, 1000)
2308  if (DataFolderRefStatus(dfr) == 0)
2309  if (GetRTError(2))
2310  return 0 // no more jobs
2311  endif
2312  else
2313  break
2314  endif
2315  while (1)
2316 
2317  // get input data
2318  wave slabdata = dfr:slabdata
2319  wave image = dfr:image
2320  svar func_param = dfr:func_param
2321  nvar rr = dfr:r_index
2322  nvar ss = dfr:s_index
2323 
2324  // do the work
2325  newdatafolder /s outDF
2326  variable /g r_index = rr
2327  variable /g s_index = ss
2328  wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
2329  variable /g func_result = numpnts(reduced_waves)
2330 
2331  // send output to queue and clean up
2332  adh5_get_result_waves(reduced_waves, "redw_", 0)
2333  WaveClear slabdata, image, reduced_waves
2334  ThreadGroupPutDF 0, :
2335  KillDataFolder dfr
2336  while (1)
2337 
2338  return 0
2339 end
2340 
2341 threadsafe static function /wave reduce_slab_image(slabdata, image, reduction_func, reduction_param)
2342  wave slabdata
2343  wave image
2344  funcref adh5_default_reduction reduction_func
2345  string reduction_param
2346 
2347  // the multiplication by detector sensitivity assumes that we are loading a ScientaImage.
2348  image = slabdata[q][p][0][0] * kDetectorSensitivity
2349 
2350  return reduction_func(image, reduction_param)
2351 end
2352 
2367 function /s psh5_load_info(APathName, AFileName)
2368  string APathName
2369  string AFileName
2370 
2371  dfref saveDF = GetDataFolderDFR()
2372  dfref fileDF = NewFreeDataFolder()
2373  setdatafolder fileDF
2374 
2375  variable fileID
2376  string filepath
2377  string scanpaths
2378  variable nscans
2379  variable iscan
2380  string scanpath
2381  string info = ""
2382 
2383  HDF5OpenFile /P=$APathName /R fileID as AFileName
2384  if (v_flag == 0)
2385  filepath = s_path + s_filename
2386  scanpaths = psh5_list_scans(fileID)
2387  nscans = ItemsInList(scanpaths)
2388  for (iscan = 0; iscan < nscans; iscan += 1)
2389  scanpath = StringFromList(iscan, scanpaths)
2390  info = info + scanpath + "\r"
2391  info = info + psh5_load_scan_info(fileID, scanpath)
2392  endfor
2393  HDF5CloseFile fileID
2394  endif
2395 
2396  setdatafolder saveDF
2397  return info
2398 end
2399 
2414 function /s psh5_load_scan_info(fileID, scanpath)
2415  variable fileID
2416  string scanpath
2417 
2418  string info = ""
2419  string positions = ""
2420  string positioners = ""
2421  string readables = ""
2422  string detectors = ""
2423  string regions = ""
2424 
2425  psh5_load_scan_meta(fileID, scanpath)
2426 
2427  wave /z ScanDimensions
2428  wave /t /z ScanWritables
2429  wave /t /z ScanReadables
2430  wave /z ScanSteps
2431 
2432  if (WaveExists(ScanSteps) && (numpnts(ScanSteps) >= 1))
2433  ScanSteps += 1
2434  positions = "positions = (" + wave2list(ScanSteps, "%u", ",") + ")"
2435  info = AddListItem(positions, info, "\r", inf)
2436  endif
2437  if (WaveExists(ScanWritables) && (numpnts(ScanWritables) >= 1))
2438  positioners = "positioners = " + twave2list(ScanWritables, ",")
2439  info = AddListItem(positioners, info, "\r", inf)
2440  endif
2441 
2442  variable i, m, n
2443  string s
2444  if (WaveExists(ScanReadables) && (numpnts(ScanReadables) >= 1))
2445  readables = twave2list(ScanReadables, ",")
2446  n = ItemsInList(readables, ",")
2447  for (i = 0; i < n; i += 1)
2448  s = StringFromList(i, readables, ",")
2449  m = ItemsInList(s, "/")
2450  if (m > 1)
2451  s = StringFromList(m - 1, s, "/")
2452  endif
2453  if (WhichListItem(s, detectors, ",") < 0)
2454  detectors = AddListItem(s, detectors, ",", inf)
2455  endif
2456  endfor
2457  detectors = "detectors = " + detectors
2458  info = AddListItem(detectors, info, "\r", inf)
2459  endif
2460 
2461  regions = psh5_list_scan_regions(fileID, scanpath)
2462  if (strlen(regions) > 0)
2463  regions = "regions = " + regions
2464  info = AddListItem(regions, info, "\r", inf)
2465  endif
2466 
2467  return info
2468 end
2469 
2473 static function /s twave2list(wt, sep)
2474  wave /t wt
2475  string sep
2476 
2477  string list = ""
2478  variable n = numpnts(wt)
2479  variable i
2480  for (i = 0; i < n; i += 1)
2481  list = AddListItem(wt[i], list, sep, inf)
2482  endfor
2483 
2484  return list
2485 end
2486 
2490 static function /s wave2list(w, format, sep)
2491  wave w
2492  string format
2493  string sep
2494 
2495  string list = ""
2496  variable n = numpnts(w)
2497  variable i
2498  string s
2499  for (i = 0; i < n; i += 1)
2500  sprintf s, format, w[i]
2501  list = AddListItem(s, list, sep, inf)
2502  endfor
2503 
2504  return list
2505 end
const string kEnergyDimLabel
Dimension label for the energy dispersive dimension of multi-dimensional datasets.
string psh5_load_scan_preview(variable fileID, string scanpath, variable set_scale=defaultValue, string pref_datasets=defaultValue)
load a preview dataset from an open PShell HDF5 file.
string psh5_load_scan_attrs(variable fileID, string scanpath, variable attr_sets=defaultValue)
load attributes of a PShell scan group.
const string kTransposedDatasets
List of datasets that should be transposed upon loading.
string psh5_load_scan_complete(variable fileID, string scanpath, variable load_data=defaultValue, variable load_attr=defaultValue)
load all data of a selected scan from a PShell data file.
const string kScanDimLabel
Dimension label for the scan dimension of multi-dimensional datasets.
string PearlCleanupName(string name)
const string kAngleDimLabel
Dimension label for the angle dispersive dimension of multi-dimensional datasets. ...
const string kDataDimLabel
Dimension label for the data dimension.
string psh5_load_preview(string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue, string pref_scans=defaultValue, string pref_datasets=defaultValue)
load a preview image from a PShell data file.
variable psh5_open_file(string ANickName, string APathName, string AFileName)
open a HDF5 file created by the PShell data acquisition program and prepare the data folder...
variable ps_scale_datasets()
set the dimension scales of loaded PShell Scienta datasets according to attributes.
string psh5_load_scan_meta(variable fileID, string scanpath)
load metadata of a PShell scan group.
const string kScientaScalingDatasets
List of datasets that must be loaded to determine the axis scaling of a Scienta image.
string psh5_list_scan_datasets(variable fileID, string scanpath, variable include_regions=defaultValue)
list datasets of a PShell scan group.
string psh5_load_scan_data(variable fileID, string scanpath)
load all datasets of a PShell scan group.
const variable kDetectorSensitivity
multiply scienta detector intensity by this value to get actual counts.
string psh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
load everything from a PShell data file.
string psh5_list_scans(variable fileID)
list scan groups of a PShell data file.
variable psh5_close_file(variable fileID)
close a HDF5 file opened by psh5_open_file.
const string kPreviewDatasets
List of preferred datasets to load for preview.