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