PEARL Procedures rev-distro-3.1.0-0-gea838b3-dirty
Igor procedures for the analysis of PEARL data
Loading...
Searching...
No Matches
pearl-pshell-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 = 8.00
4#pragma ModuleName = PearlPShellImport
5#pragma version = 2.2
6#if IgorVersion() < 9.00
7#include <HDF5 Browser>
8#endif
9#include "pearl-compat"
10#include "pearl-gui-tools"
11#include "pearl-area-import"
12
13// copyright (c) 2013-25 Paul Scherrer Institut
14//
15// Licensed under the Apache License, Version 2.0 (the "License");
16// you may not use this file except in compliance with the License.
17// You may obtain a copy of the License at
18// http:///www.apache.org/licenses/LICENSE-2.0
19
43
48
50strconstant kEnergyDimLabel = "energy"
51
53strconstant kAngleDimLabel = "angle"
54
56strconstant kScanDimLabel = "scan"
57
60strconstant kDataDimLabel = "data"
61
63strconstant kPreviewDatasets = "ImageEnergyDistribution;ScientaSpectrum;ScientaImage;Counts;SampleCurrent;"
64
66strconstant kScientaScalingDatasets = "LensMode;ScientaChannelBegin;ScientaChannelEnd;ScientaSliceBegin;ScientaSliceEnd;Eph;ScientaHighEnergy;ScientaHighThetaX;ScientaLowEnergy;ScientaLowThetaX;"
67
69strconstant kEssentialDiagnostics = "ManipulatorX;ManipulatorY;ManipulatorZ;ManipulatorTheta;ManipulatorTilt;ManipulatorPhi;MonoEnergy;"
70
72strconstant kTransposedDatasets = "ScientaImage;"
73
74constant kDSCPositioners = 0x0001
75constant kDSCDetectors = 0x0002
76constant kDSCScientaScaling = 0x0004
77constant kDSCPreview = 0x0008
78constant kDSCEssentialDiags = 0x0010
79constant kDSCAttrs = 0x0020
80constant kDSCDiags = 0x0040
81constant kDSCSnaps = 0x0080
82constant kDSCMeta = 0x0100
83constant kDSCMonitors = 0x0200
84constant kDSCRegions = 0x0400
85constant kDSCOther = 0x8000
86constant kDSCAll = 0xffff
87
88
89// ====== main import functions ======
90
158function /df psh5_load(path_name, file_name, scans, regions, datasets, [classes, max_rank, reduction_func, reduction_params, dest_df])
159 string path_name
160 string file_name
161 string scans
162 string regions
163 string datasets
164 variable classes
165 variable max_rank
166 string reduction_func
167 string reduction_params
168 dfref dest_df
169
170 dfref save_df = GetDataFolderDFR()
171 variable timerRefNum = startMSTimer
172
173 if (ParamIsDefault(classes) || (classes == 0))
175 endif
176 variable essential_classes = kDSCPositioners | kDSCScientaScaling | kDSCEssentialDiags
177
178 if (ParamIsDefault(dest_df) || !DataFolderRefStatus(dest_df))
179 dest_df = psh5_open_file(path_name, file_name)
180 else
181 dest_df = psh5_open_file(path_name, file_name, dest_df=dest_df)
182 endif
183 if (ParamIsDefault(reduction_func))
184 reduction_func = ""
185 endif
186 if (ParamIsDefault(reduction_params))
187 reduction_params = ""
188 endif
189
190 if (DataFolderRefStatus(dest_df))
191 setdatafolder dest_df
193
194 // datasets contained in file
195 svar /sdfr=dest_df file_datasets = s_datasets
196
197 // datasets contained in file up to allowed rank
198 string ranked_datasets = ""
199 if (ParamIsDefault(max_rank))
200 ranked_datasets = file_datasets
201 else
202 svar /sdfr=dest_df file_ranks = s_datasets_ranks
203 ranked_datasets = psh5_filter_datasets_rank(file_datasets, file_ranks, 0, max_rank)
204 endif
205
206 string matching_datasets = ""
207 string matching_essentials = ""
208 string scan_datasets = ""
209 string region_datasets = ""
210 string free_datasets = ""
211 string selected_datasets = ""
212 string essential_datasets = ""
213
214 variable i_item
215 variable n_items
216 string item
217
218 // select datasets belonging to selected scans
219 n_items = ItemsInList(scans, ";")
220 for (i_item = 0; i_item < n_items; i_item += 1)
221 item = StringFromList(i_item, scans, ";")
222 if (cmpstr(item[0,3], "scan") == 0)
223 item = "/" + item
224 endif
225 item = ReplaceString("//", item + "/*", "/")
226 matching_datasets = psh5_match_datasets(ranked_datasets, item)
227 scan_datasets = scan_datasets + matching_datasets
228 endfor
229
230 // select datasets belonging to selected regions
231 n_items = ItemsInList(regions, ";")
232 for (i_item = 0; i_item < n_items; i_item += 1)
233 item = StringFromList(i_item, regions, ";")
234 if (cmpstr(item[0,3], "scan") == 0)
235 item = "/" + item
236 endif
237 item = ReplaceString("//", item + "/*", "/")
238 matching_datasets = psh5_match_datasets(ranked_datasets, item)
239 region_datasets = region_datasets + matching_datasets
240 endfor
241
242 // free select datasets
243 n_items = ItemsInList(datasets, ";")
244 for (i_item = 0; i_item < n_items; i_item += 1)
245 item = StringFromList(i_item, datasets, ";")
246 if (cmpstr(item[0,3], "scan") == 0)
247 item = "/" + item
248 endif
249 matching_datasets = psh5_match_datasets(ranked_datasets, item)
250 free_datasets = free_datasets + matching_datasets
251 endfor
252
253 selected_datasets = scan_datasets + region_datasets + free_datasets
254
255 string filtered_datasets = ""
256 string diag_datasets = ""
257 string selected_scans = psh5_extract_scan_paths(selected_datasets)
258 variable i_scan
259 variable n_scans = ItemsInList(selected_scans)
260 string scan
261 string selected_regions = psh5_extract_region_paths(selected_datasets)
262 variable i_region
263 variable n_regions = ItemsInList(selected_regions)
264 string region
265 string positioners
266 string detectors
267
268 // datasets directly under one of the selected regions
269 region_datasets = ""
270 for (i_region = 0; i_region < n_regions; i_region += 1)
271 region = StringFromList(i_region, selected_regions, ";")
272 region_datasets = region_datasets + GrepList(file_datasets, "(?i)^" + region + "[[:alpha:]]+$")
273 endfor
274
275 // filter selected datasets by class and add essential dependencies
276 // each scan may have specific positioners and detectors
277 for (i_scan = 0; i_scan < n_scans; i_scan += 1)
278 scan = StringFromList(i_scan, selected_scans, ";")
279
280 // potentially interesting diagnostics of current scan and selected regions
281 diag_datasets = psh5_match_datasets(file_datasets, scan + "*")
282 diag_datasets = psh5_match_dataset_classes(diag_datasets, kDSCAttrs | kDSCDiags | kDSCSnaps)
283 diag_datasets = diag_datasets + GrepList(file_datasets, "(?i)^" + scan + "[[:alpha:]]+$")
284 diag_datasets = diag_datasets + psh5_match_datasets(region_datasets, scan + "*")
285
286 // explicit positioners and detectors set by pshell
287 setdatafolder dest_df
288 dfref scan_df = psh5_create_folders(scan)
289 setdatafolder scan_df
290 psh5_load_scan_meta(dest_df, scan)
291 wave /t /z ScanWritables
292 wave /t /z ScanReadables
293 if (WaveExists(ScanWritables))
294 positioners = twave2list(ScanWritables, ";")
295 else
296 positioners = ""
297 endif
298 if (WaveExists(ScanReadables))
299 detectors = twave2list(ScanReadables, ";")
300 else
301 detectors = ""
302 endif
303
304 // filtering by classes
305 matching_datasets = psh5_match_dataset_classes(selected_datasets, classes, positioners=positioners, detectors=detectors)
306
307 // add essential diags
308 if (strlen(matching_datasets) > 1)
309 essential_datasets = psh5_match_dataset_classes(diag_datasets, essential_classes, positioners=positioners, detectors=detectors)
310 endif
311
312 // scaling datasets before detectors because data reduction needs the scales
313 filtered_datasets = essential_datasets + filtered_datasets + matching_datasets
314 endfor
315
316 // load the datasets
317 setdatafolder dest_df
318 string /g s_loaded_datasets = ""
319 s_loaded_datasets = psh5_load_datasets(dest_df, filtered_datasets, reduction_func=reduction_func, reduction_params=reduction_params)
320
321 // apply scaling by scan
322 for (i_scan = 0; i_scan < n_scans; i_scan += 1)
323 scan = StringFromList(i_scan, selected_scans, ";")
325 endfor
326
327 psh5_close_file(dest_df)
328
329 // performance reporting
330 if (timerRefNum >= 0)
331 setdatafolder dest_df
332 variable /g psh5_perf_secs
333 psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
334 endif
335 endif
336
337 setdatafolder save_df
338 return dest_df
339end
340
345function /df psh5_preview(path_name, file_name, [dest_df, preview_datasets])
346 string path_name
347 string file_name
348 dfref dest_df
349 string preview_datasets
350
351 dfref save_df = GetDataFolderDFR()
352
353 if (ParamIsDefault(dest_df))
354 dest_df = psh5_open_file(path_name, file_name)
355 else
356 dest_df = psh5_open_file(path_name, file_name, dest_df=dest_df)
357 endif
358 if (ParamIsDefault(preview_datasets))
359 preview_datasets = kPreviewDatasets
360 endif
361 variable essential_classes = kDSCPositioners | kDSCScientaScaling
362
363 if (DataFolderRefStatus(dest_df))
364 setdatafolder dest_df
366
367 // select dataset based on preference
368 svar /sdfr=dest_df file_datasets = s_datasets
369 svar /sdfr=dest_df file_datasets_ranks = s_datasets_ranks
370 string selected_datasets = ""
371 string essential_datasets = ""
372 string scan_datasets = ""
373 string filtered_datasets = ""
374
375 variable nds = ItemsInList(preview_datasets, ";")
376 variable ids
377 string ds
378 for (ids = 0; ids < nds; ids += 1)
379 ds = StringFromList(ids, preview_datasets, ";")
380 selected_datasets = psh5_filter_datasets_rank(file_datasets, file_datasets_ranks, 1, 2)
381 selected_datasets = psh5_match_datasets(selected_datasets, "/scan*" + ds)
382 if (strlen(selected_datasets) > 1)
383 selected_datasets = StringFromList(0, selected_datasets, ";")
384 break
385 endif
386 endfor
387
388 // add essential dependencies
389 if (strlen(selected_datasets) > 1)
390 string selected_scans = psh5_extract_scan_paths(selected_datasets)
391 string scan
392 string positioners
393
394 scan = StringFromList(0, selected_scans, ";")
395 scan_datasets = psh5_match_datasets(file_datasets, scan + "*")
396
397 psh5_load_scan_meta(dest_df, scan)
398 wave /t /z ScanWritables
399 if (WaveExists(ScanWritables))
400 positioners = twave2list(ScanWritables, ";")
401 else
402 positioners = ""
403 endif
404
405 essential_datasets = psh5_match_dataset_classes(scan_datasets, essential_classes, positioners=positioners)
406 filtered_datasets = essential_datasets + selected_datasets
407
408 // load the datasets
409 psh5_load_datasets(dest_df, filtered_datasets, create_folders=0)
410 ps_scale_datasets(dest_df)
411 string /g s_preview_dataset = StringFromList(0, selected_datasets, ";")
412 string /g s_preview_wave = StringFromList(ItemsInList(s_preview_dataset, "/") - 1, s_preview_dataset, "/")
413 endif
414
415 psh5_close_file(dest_df)
416 endif
417
418 setdatafolder save_df
419 return dest_df
420end
421
450function /df psh5_open_file(path_name, file_name, [dest_df])
451 string path_name
452 string file_name
453 dfref dest_df
454
455 dfref save_df = GetDataFolderDFR()
456
457 variable fid
458 HDF5OpenFile /P=$path_name /R fid as file_name
459 if (v_flag == 0)
460 if (!ParamIsDefault(dest_df))
461 setdatafolder dest_df
462 else
463 string dest_name = ad_suggest_foldername(s_filename, sourcename="psh")
464 setdatafolder root:
465 newdatafolder /s /o $("root:" + dest_name)
466 endif
467 dfref file_df = GetDataFolderDFR()
468
469 variable /g file_id = fid
470 string /g s_filepath
471 string /g s_scanpaths
472 string /g s_datasets
473 string datatypes
474 string ranks
475 string dimensions
476 s_filepath = s_path + s_filename
477 s_scanpaths = psh5_list_scans(file_id)
478 s_datasets = psh5_list_all_datasets(file_id)
479 [datatypes, ranks, dimensions] = psh5_list_dataset_info(file_id, s_datasets)
480 string /g s_datasets_datatypes = datatypes
481 string /g s_datasets_ranks = ranks
482 string /g s_datasets_dimensions = dimensions
483 else
484 dfref file_df = $""
485 endif
486
487 setdatafolder save_df
488 return file_df
489end
490
509function psh5_close_file(file_df)
510 dfref file_df
511
512 if (DataFolderRefStatus(file_df))
513 nvar /sdfr=file_df /z file_id
514 if (nvar_Exists(file_id))
515 HDF5CloseFile /z file_id
516 file_id = 0
517 KillVariables /z file_id
518 else
519 dfref parent_df = $(GetDataFolder(1, file_df) + ":")
520 if (DataFolderRefStatus(parent_df))
521 psh5_close_file(parent_df)
522 endif
523 endif
524 endif
525end
526
527// === datasets and paths ===
528
532static function /s twave2list(wt, sep)
533 wave /t wt
534 string sep
535
536 string list = ""
537 variable n = numpnts(wt)
538 variable i
539 for (i = 0; i < n; i += 1)
540 list = AddListItem(wt[i], list, sep, inf)
541 endfor
542
543 return list
544end
545
549static function /s wave2list(w, format, sep)
550 wave w
551 string format
552 string sep
553
554 string list = ""
555 variable n = numpnts(w)
556 variable i
557 string s
558 for (i = 0; i < n; i += 1)
559 sprintf s, format, w[i]
560 list = AddListItem(s, list, sep, inf)
561 endfor
562
563 return list
564end
565
574function /s psh5_list_scans(file_id)
575 variable file_id
576
577 HDF5ListGroup /F /TYPE=1 file_id, "/"
578
579 variable ig
580 variable ng = ItemsInList(S_HDF5ListGroup, ";")
581 string sg
582 string scans = ""
583
584 for (ig = 0; ig < ng; ig += 1)
585 sg = StringFromList(ig, S_HDF5ListGroup, ";")
586 if (cmpstr(sg[1,4], "scan") == 0)
587 scans = AddListItem(sg, scans, ";", inf)
588 endif
589 endfor
590
591 return scans
592end
593
605function /s psh5_list_all_datasets(file_id)
606 variable file_id
607
608 HDF5ListGroup /F /R /TYPE=2 /Z file_id, "/"
609 if (!v_flag)
610 return S_HDF5ListGroup
611 else
612 return ""
613 endif
614end
615
631function [string datatypes, string ranks, string dimensions] psh5_list_dataset_info(variable file_id, string datasets)
632 variable nds = ItemsInList(datasets, ";")
633 variable ids
634 string sds
635 STRUCT HDF5DataInfo di
636 InitHDF5DataInfo(di)
637 variable err
638 variable idim
639 string sdims
640 datatypes = ""
641 ranks = ""
642 dimensions = ""
643
644 for (ids = 0; ids < nds; ids += 1)
645 sds = StringFromList(ids, datasets, ";")
646 err = HDF5DatasetInfo(file_id, sds, 0, di)
647 if (err == 0)
648 switch (di.datatype_class)
649 case H5T_INTEGER:
650 datatypes = AddListItem("i", datatypes, ";", ids)
651 break
652 case H5T_FLOAT:
653 datatypes = AddListItem("f", datatypes, ";", ids)
654 break
655 case H5T_STRING:
656 datatypes = AddListItem("s", datatypes, ";", ids)
657 break
658 default:
659 datatypes = AddListItem("?", datatypes, ";", ids)
660 break
661 endswitch
662
663 ranks = AddListItem(num2str(di.ndims), ranks, ";", ids)
664
665 sdims = ""
666 for (idim = 0; idim < di.ndims; idim += 1)
667 sdims = AddListItem(num2str(di.dims[idim]), sdims, ",", idim)
668 endfor
669 if (strlen(sdims) > 1)
670 sdims = sdims[0, strlen(sdims)-2]
671 endif
672 dimensions = AddListItem(sdims, dimensions, ";", ids)
673 endif
674 endfor
675end
676
692function /s psh5_match_datasets(datasets, match)
693 string datasets
694 string match
695
696 string result = ""
697
698 string spaceless_datasets = ReplaceString(" ", datasets, "")
699 string spaceless_match = ReplaceString(" ", match, "")
700
701 string sep = ";"
702 variable seplen = strlen(sep)
703 variable nds = ItemsInList(spaceless_datasets, sep)
704 variable ids
705 string ds
706 variable offset = 0
707
708 for (ids = 0; ids < nds; ids += 1)
709 ds = StringFromList(0, spaceless_datasets, sep, offset)
710 offset += strlen(ds) + seplen
711 if (StringMatch(ds, spaceless_match))
712 ds = StringFromList(ids, datasets, sep, 0)
713 result = AddListItem(ds, result, sep, inf)
714 endif
715 endfor
716
717 return result
718end
719
728function /s psh5_filter_datasets_rank(datasets, ranks, min_rank, max_rank)
729 string datasets
730 string ranks
731 variable min_rank
732 variable max_rank
733
734 string result = ""
735 string sep = ";"
736 variable seplen = strlen(sep)
737 variable nds = ItemsInList(datasets, sep)
738 variable ids
739 string ds
740 variable offset = 0
741 variable rank
742
743 for (ids = 0; ids < nds; ids += 1)
744 ds = StringFromList(0, datasets, sep, offset)
745 offset += strlen(ds) + seplen
746 rank = str2num(StringFromList(ids, ranks, sep))
747 if ((rank >= min_rank) && (rank <= max_rank))
748 result = AddListItem(ds, result, sep, inf)
749 endif
750 endfor
751
752 return result
753end
754
764static function /s unique_strings(list)
765 string list
766
767 string result = ""
768
769 string sep = ";"
770 variable seplen = strlen(sep)
771 variable nn = ItemsInList(list, sep)
772 variable ii
773 string item
774 variable offset = 0
775
776 make /n=(nn) /t /free wt_in
777 for (ii = 0; ii < nn; ii += 1)
778 item = StringFromList(0, list, sep, offset)
779 offset += strlen(item) + seplen
780 wt_in[ii] = item
781 endfor
782
783 FindDuplicates /Z /FREE /RT=wt_out wt_in
784
785 return twave2list(wt_out, ";")
786end
787
803function /s psh5_extract_scan_paths(datasets)
804 string datasets
805
806 string result = ""
807 string sep = ";"
808 variable seplen = strlen(sep)
809 variable nds = ItemsInList(datasets, sep)
810 variable ids
811 string ds
812 string scan
813 string item
814 variable offset = 0
815
816 for (ids = 0; ids < nds; ids += 1)
817 ds = StringFromList(0, datasets, sep, offset)
818 offset += strlen(ds) + seplen
819 if (cmpstr(ds[0], "/") != 0)
820 ds = "/" + ds
821 endif
822
823 scan = StringFromList(1, ds, "/")
824 if (StringMatch(scan, "scan*"))
825 item = "/" + scan + "/"
826 else
827 item = ""
828 endif
829
830 if ((strlen(item) > 0) && (WhichListItem(item, result, ";", 0, 0) < 0))
831 result = AddListItem(item, result, ";", inf)
832 endif
833 endfor
834
835 return result
836end
837
853function /s psh5_extract_region_paths(datasets)
854 string datasets
855
856 string result = ""
857 string sep = ";"
858 variable seplen = strlen(sep)
859 variable nds = ItemsInList(datasets, sep)
860 variable ids
861 string ds
862 string scan
863 string region
864 string item
865 variable offset = 0
866
867 for (ids = 0; ids < nds; ids += 1)
868 ds = StringFromList(0, datasets, sep, offset)
869 offset += strlen(ds) + seplen
870 if (cmpstr(ds[0], "/") != 0)
871 ds = "/" + ds
872 endif
873
874 scan = StringFromList(1, ds, "/")
875 region = StringFromList(2, ds, "/")
876 if (StringMatch(scan, "scan*") && StringMatch(region, "region*"))
877 item = "/" + scan + "/" + region + "/"
878 else
879 item = ""
880 endif
881
882 if ((strlen(item) > 0) && (WhichListItem(item, result, ";", 0, 0) < 0))
883 result = AddListItem(item, result, ";", inf)
884 endif
885 endfor
886
887 return result
888end
889
899function /s psh5_match_dataset_classes(datasets, classes, [positioners, detectors])
900 string datasets
901 variable classes
902 string positioners
903 string detectors
904
905 if (ParamIsDefault(positioners))
906 positioners = ""
907 endif
908 if (ParamIsDefault(detectors) || (strlen(detectors) == 0))
909 detectors = kPreviewDatasets
910 endif
911
912 string result = ""
913 string sep = ";"
914 variable seplen = strlen(sep)
915 variable nds = ItemsInList(datasets, sep)
916 variable ids
917 variable offset = 0
918 string ds
919 variable nparts
920 string ds_parent
921 string ds_name
922 string ds_scan_rel
923 variable ds_class
924
925 for (ids = 0; ids < nds; ids += 1)
926 ds = StringFromList(0, datasets, sep, offset)
927 offset += strlen(ds) + seplen
928 nparts = ItemsInList(ds, "/")
929 ds_parent = StringFromList(nparts - 2, ds, "/")
930 ds_name = StringFromList(nparts - 1, ds, "/")
931 if (cmpstr(ds[0,4], "/scan") == 0)
932 ds_scan_rel = RemoveListItem(0, ds[1, strlen(ds) - 1], "/")
933 else
934 ds_scan_rel = ds
935 endif
936 ds_class = 0
937
938 if (strlen(ds_parent) > 0)
939 ds_class = ds_class | (cmpstr(ds_parent, "attr") == 0 ? kDSCAttrs : 0)
940 ds_class = ds_class | (cmpstr(ds_parent, "attrs") == 0 ? kDSCAttrs : 0)
941 ds_class = ds_class | (cmpstr(ds_parent, "diags") == 0 ? kDSCDiags : 0)
942 ds_class = ds_class | (cmpstr(ds_parent, "snaps") == 0 ? kDSCSnaps : 0)
943 ds_class = ds_class | (cmpstr(ds_parent, "meta") == 0 ? kDSCMeta : 0)
944 ds_class = ds_class | (cmpstr(ds_parent, "monitors") == 0 ? kDSCMonitors : 0)
945 ds_class = ds_class | (cmpstr(ds_parent[0,5], "region") == 0 ? kDSCRegions : 0)
946 endif
947
948 if (strlen(ds_name) > 0)
949 ds_class = ds_class | (WhichListItem(ds_scan_rel, positioners, sep, 0, 0) >= 0 ? kDSCPositioners : 0)
950 ds_class = ds_class | (WhichListItem(ds_scan_rel, detectors, sep, 0, 0) >= 0 ? kDSCDetectors : 0)
951 ds_class = ds_class | (WhichListItem(ds_name, kPreviewDatasets, sep, 0, 0) >= 0 ? kDSCPreview : 0)
952 ds_class = ds_class | (WhichListItem(ds_name, kScientaScalingDatasets, sep, 0, 0) >= 0 ? kDSCScientaScaling : 0)
953 ds_class = ds_class | (WhichListItem(ds_name, kEssentialDiagnostics, sep, 0, 0) >= 0 ? kDSCEssentialDiags : 0)
954 endif
955
956 if (ds_class == 0)
957 ds_class = kDSCOther
958 endif
959
960 if (ds_class & classes)
961 result = AddListItem(ds, result, sep, inf)
962 endif
963 endfor
964
965 return result
966end
967
990function /df psh5_create_folders(datasetpath)
991 string datasetpath
992
993 if (cmpstr(datasetpath[0], "/") == 0)
994 datasetpath = datasetpath[1, strlen(datasetpath)-1]
995 endif
996 if (cmpstr(datasetpath[strlen(datasetpath)-1], "/") == 0)
997 datasetpath += "dummy"
998 endif
999
1000 variable nfolders = ItemsInList(datasetpath, "/") - 1
1001 variable ifolder
1002 string folder
1003 string inc_path = "/"
1004
1005 for (ifolder = 0; ifolder < nfolders; ifolder += 1)
1006 folder = StringFromList(ifolder, datasetpath, "/")
1007 folder = ps_fix_folder_name(folder)
1008 NewDataFolder /o/s $folder
1009 inc_path += folder
1010 inc_path += "/"
1011 string /g s_hdf5_group = inc_path
1012 endfor
1013
1014 return GetDataFolderDFR()
1015end
1016
1034function /df psh5_dataset_to_folder(parent_df, datasetpath)
1035 dfref parent_df
1036 string datasetpath
1037
1038 if (cmpstr(datasetpath[0], "/") == 0)
1039 datasetpath = datasetpath[1, strlen(datasetpath)-1]
1040 endif
1041 if (cmpstr(datasetpath[strlen(datasetpath)-1], "/") == 0)
1042 datasetpath += "dummy"
1043 endif
1044
1045 variable nfolders = ItemsInList(datasetpath, "/") - 1
1046 variable ifolder
1047 string folder
1048 string inc_path = ""
1049
1050 for (ifolder = 0; ifolder < nfolders; ifolder += 1)
1051 folder = StringFromList(ifolder, datasetpath, "/")
1052 folder = ps_fix_folder_name(folder)
1053 if (ifolder)
1054 inc_path += ":"
1055 endif
1056 inc_path += folder
1057 endfor
1058
1059 dfref out_df = parent_df:$inc_path
1060 return out_df
1061end
1062
1065function /s ps_fix_folder_name(group_name)
1066 string group_name
1067 string folder_name
1068
1069 folder_name = ReplaceString(" ", group_name, "")
1070 if (cmpstr(folder_name, "attrs") == 0)
1071 folder_name = "attr"
1072 endif
1073 folder_name = PearlCleanupName(folder_name)
1074
1075 return folder_name
1076end
1077
1078// ====== import functions ======
1079
1098function /s psh5_load_datasets(file_df, datasets, [create_folders, reduction_func, reduction_params])
1099 dfref file_df
1100 string datasets
1101 variable create_folders
1102 string reduction_func
1103 string reduction_params
1104
1105 if (!DataFolderRefStatus(file_df))
1106 dfref file_df = GetDataFolderDFR()
1107 endif
1108 if (ParamIsDefault(create_folders))
1109 create_folders = 1
1110 endif
1111 if (ParamIsDefault(reduction_func))
1112 reduction_func = ""
1113 endif
1114 if (ParamIsDefault(reduction_params))
1115 reduction_params = ""
1116 endif
1117
1118 dfref save_df = GetdataFolderDFR()
1119
1120 datasets = unique_strings(datasets)
1121 variable nds = ItemsInList(datasets, ";")
1122 variable ids
1123 string ds
1124 string loaded_datasets = ""
1125 string loaded_waves = ""
1126
1127 for (ids = 0; ids < nds; ids += 1)
1128 SetDataFolder file_df
1129 ds = StringFromList(ids, datasets, ";")
1130 loaded_waves = psh5_load_dataset(file_df, ds, create_folders=create_folders, reduction_func=reduction_func, reduction_params=reduction_params)
1131 if (strlen(loaded_waves) > 1)
1132 loaded_datasets = loaded_datasets + ds + ";"
1133 endif
1134 endfor
1135
1136 setdatafolder save_df
1137 return loaded_datasets
1138end
1139
1176function /s psh5_load_dataset(file_df, datasetpath, [create_folders, reduction_func, reduction_params])
1177 dfref file_df
1178 string datasetpath
1179 variable create_folders
1180 string reduction_func
1181 string reduction_params
1182
1183 dfref base_df = GetDataFolderDFR()
1184 if (!DataFolderRefStatus(file_df))
1185 dfref file_df = GetDataFolderDFR()
1186 endif
1187 nvar /sdfr=file_df file_id
1188
1189 if (ParamIsDefault(create_folders))
1190 create_folders = 1
1191 endif
1192 if (create_folders)
1193 psh5_create_folders(datasetpath)
1194 endif
1195 if (ParamIsDefault(reduction_func))
1196 reduction_func = ""
1197 endif
1198 if (ParamIsDefault(reduction_params))
1199 reduction_params = ""
1200 endif
1201
1202 STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
1203 InitHDF5DataInfo(di)
1204 variable err = HDF5DatasetInfo(file_id, datasetpath, 0, di)
1205 if (err != 0)
1206 // error accessing data
1207 return ""
1208 endif
1209
1210 variable numeric = 0
1211 variable compound = 0
1212
1213 switch (di.datatype_class)
1214 case H5T_INTEGER:
1215 case H5T_FLOAT:
1216 numeric = 1
1217 break
1218 case H5T_STRING:
1219 numeric = 0
1220 break
1221 case H5T_COMPOUND:
1222 compound = 1
1223 break
1224 case H5T_TIME:
1225 case H5T_BITFIELD:
1226 case H5T_OPAQUE:
1227 case H5T_REFERENCE:
1228 case H5T_ENUM:
1229 case H5T_VLEN:
1230 case H5T_ARRAY:
1231 default:
1232 // unsupported data type
1233 return ""
1234 endswitch
1235
1236 string wave_names = ""
1237 if (di.ndims <= 2)
1238 string datasetname = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
1239 variable transpose = WhichListItem(datasetname, kTransposedDatasets) >= 0
1240 HDF5LoadData /O /Q /Z /TRAN=(transpose) file_id, datasetpath
1241 wave_names = S_waveNames
1242 elseif (numeric)
1243 if (exists(reduction_func) == 6)
1244 wave_names = psh5_load_dataset_reduced(file_df, datasetpath, $reduction_func, reduction_params, create_folders=0)
1245 else
1246 wave_names = psh5_load_dataset_slabs(file_df, datasetpath, create_folders=0)
1247 endif
1248 endif
1249
1250 variable nw = ItemsInList(wave_names, ";")
1251 variable iw
1252 string sw
1253 string loaded_waves = ""
1254 for (iw = 0; iw < nw; iw += 1)
1255 sw = StringFromList(iw, wave_names)
1256 wave /z w = $sw
1257 if (WaveExists(w))
1258 loaded_waves = loaded_waves + sw + ";"
1260 psh5_load_dataset_meta(file_df, datasetpath, w)
1261 endif
1262 endfor
1263
1264 setdatafolder base_df
1265 return loaded_waves
1266end
1267
1289function /s psh5_load_dataset_slabs(file_df, datasetpath, [create_folders, progress])
1290 dfref file_df
1291 string datasetpath
1292 variable create_folders
1293 variable progress
1294
1295 if (ParamIsDefault(create_folders))
1296 create_folders = 1
1297 endif
1298 if (ParamIsDefault(progress))
1299 progress = 1
1300 endif
1301
1302 if (!DataFolderRefStatus(file_df))
1303 dfref file_df = GetDataFolderDFR()
1304 endif
1305 nvar /sdfr=file_df file_id
1306
1307 variable result = 0
1308 string datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
1309
1310 if (create_folders)
1311 psh5_create_folders(datasetpath)
1312 endif
1313
1314 STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
1315 InitHDF5DataInfo(di)
1316 variable err = HDF5DatasetInfo(file_id, datasetpath, 0, di)
1317 if (err != 0)
1318 print "error accessing dataset", datasetpath
1319 return ""
1320 endif
1321 if (di.ndims < 2)
1322 print "error: rank of dataset < 2", datasetpath
1323 return ""
1324 elseif (di.ndims < 3)
1325 progress = 0
1326 endif
1327 if ((di.datatype_class != H5T_INTEGER) && (di.datatype_class != H5T_FLOAT))
1328 print "error: unsupported datatype", datasetpath
1329 return ""
1330 endif
1331
1332 variable idx, idy, idz, idt, izt
1333 variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
1334 if (transpose)
1335 idx = 1
1336 idy = 0
1337 else
1338 idx = 0
1339 idy = 1
1340 endif
1341 idz = 2
1342 idt = 3
1343
1344 variable nx, ny, nz, nt, nzt
1345 nx = di.dims[idx]
1346 ny = di.dims[idy]
1347 nz = di.dims[idz]
1348 nt = di.dims[idt]
1349 make /n=(nx,ny,nz,nt) /o $datawavename
1350 wave data = $datawavename
1351
1352 nz = max(nz, 1)
1353 nt = max(nt, 1)
1354 nzt = nz * nt
1355 izt = 0
1356 if (progress)
1357 display_progress_panel("HDF5 Import", "Loading " + datasetpath + "...", nzt)
1358 endif
1359
1360 // load data image by image
1361 HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
1362 wave slab
1363 slab[][%Start] = 0
1364 slab[][%Stride] = 1
1365 slab[][%Count] = 1
1366 slab[][%Block] = 1
1367 slab[idx][%Block] = nx
1368 slab[idy][%Block] = ny
1369
1370 variable iz, it
1371 for (iz = 0; iz < nz; iz += 1)
1372 for (it = 0; it < nt; it += 1)
1373 slab[idz][%Start] = iz
1374 slab[idt][%Start] = it
1375 HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata file_id, datasetpath
1376 wave slabdata // 2D, 3D, or 4D with singletons
1377 if (transpose)
1378 data[][][iz][it] = slabdata[q][p][0][0]
1379 else
1380 data[][][iz][it] = slabdata[p][q][0][0]
1381 endif
1382
1383 // progress window
1384 izt += 1
1385 if (progress)
1386 if (update_progress_panel(izt))
1387 result = -4 // user abort
1388 break
1389 endif
1390 endif
1391 endfor
1392 if (result < 0)
1393 break
1394 endif
1395 endfor
1396
1397 if (progress)
1399 endif
1400
1401 killwaves /z slab, slabdata
1402 if (!result)
1403 ps_set_dimlabels(data)
1404 return NameOfWave(data) + ";"
1405 else
1406 killwaves /z data
1407 return ""
1408 endif
1409end
1410
1411// ====== data reduction ======
1412
1472function /s psh5_load_dataset_reduced(file_df, datasetpath, reduction_func, reduction_params, [create_folders, progress, nthreads])
1473 dfref file_df
1474 string datasetpath
1475 funcref adh5_default_reduction reduction_func
1476 string reduction_params
1477 variable create_folders
1478 variable progress
1479 variable nthreads
1480
1481 if (ParamIsDefault(create_folders))
1482 create_folders = 1
1483 endif
1484 if (ParamIsDefault(progress))
1485 progress = 1
1486 endif
1487 if (ParamIsDefault(nthreads))
1488 nthreads = -1
1489 endif
1490
1491 dfref base_df = GetDataFolderDFR()
1492 if (!DataFolderRefStatus(file_df))
1493 dfref file_df = GetDataFolderDFR()
1494 endif
1495 nvar /sdfr=file_df file_id
1496
1497 variable result = 0
1498 string datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
1499 string wavenames = ""
1500
1501 if (create_folders)
1502 psh5_create_folders(datasetpath)
1503 endif
1504
1505 STRUCT HDF5DataInfo di // Defined in HDF5 Browser.ipf.
1506 InitHDF5DataInfo(di)
1507 variable err = HDF5DatasetInfo(file_id, datasetpath, 0, di)
1508 if (err != 0)
1509 print "error accessing detector/data"
1510 result = -1
1511 return wavenames
1512 endif
1513 if (di.ndims < 2)
1514 print "error: rank of dataset < 2"
1515 result = -2
1516 return wavenames
1517 elseif (di.ndims < 3)
1518 progress = 0
1519 endif
1520
1521 variable idx, idy, idz, idt
1522 variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
1523 if (transpose)
1524 idx = 1
1525 idy = 0
1526 else
1527 idx = 0
1528 idy = 1
1529 endif
1530 idz = 2
1531 idt = 3
1532
1533 variable nx, ny, nz, nt, nzt
1534 nx = di.dims[idx]
1535 ny = di.dims[idy]
1536 nz = di.dims[idz]
1537 nt = di.dims[idt]
1538 // adjust singleton dimensions
1539 nz = max(nz, 1)
1540 nt = max(nt, 1)
1541 nzt = nz * nt
1542
1543 // load data image by image
1544 HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
1545 wave slab
1546 slab[][%Start] = 0
1547 slab[][%Stride] = 1
1548 slab[][%Count] = 1
1549 slab[][%Block] = 1
1550 slab[idx][%Block] = nx
1551 slab[idy][%Block] = ny
1552
1553 // set up multi threading
1554 if (nthreads < 0)
1555 nthreads = ThreadProcessorCount
1556 endif
1557 if (nthreads > 0)
1558 variable threadGroupID = ThreadGroupCreate(nthreads)
1559 variable ithread
1560 for (ithread = 0; ithread < nthreads; ithread += 1)
1561 ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
1562 endfor
1563 else
1564 make /n=(nzt) /df /free processing_folders
1565 endif
1566
1567 if (progress)
1568 display_progress_panel("PShell Import", "Reducing " + datasetpath + "...", nzt)
1569 endif
1570
1571 // create a template wave with the correct scales and labels
1572 make /n=(nx,ny) /d /o $datawavename
1573 wave template = $datawavename
1574 ps_set_dimlabels2(template, datawavename)
1575 ps_scale_dataset(template)
1576
1577 variable iz, it, izt
1578 variable n_sent = 0
1579 variable n_recvd = 0
1580 variable tmo = 0
1581 string dfname
1582 dfref dfr
1583 variable iw, nw
1584 string sw
1585 make /n=0 /free /wave result_waves
1586
1587 iz = 0
1588 it = 0
1589
1590 do
1591 // fill the processing queue up to a maximum number of folders
1592 if (n_sent < max(1, nthreads) * 10 + n_recvd)
1593 if (iz < nz)
1594 if (it < nt)
1595 // load a slab into a temporary folder
1596 slab[idz][%Start] = iz
1597 slab[idt][%Start] = it
1598 dfname = "processing_" + num2str(n_sent)
1599 NewDataFolder /s $dfname
1600 HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata file_id, datasetpath
1601
1602 duplicate template, image
1603 variable /g r_index = iz
1604 variable /g s_index = it
1605 string /g func_param = reduction_params
1606
1607 if (nthreads > 0)
1608 // send to thread group
1609 WaveClear image
1610 ThreadGroupPutDF threadGroupID, :
1611 else
1612 // process immediately in single-thread mode
1613 processing_folders[n_sent] = GetDataFolderDFR()
1614 make /n=1/d profile1, profile2
1615 wave slabdata
1616 wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
1617 variable /g func_result = numpnts(reduced_waves)
1618 adh5_get_result_waves(reduced_waves, "redw_", 0)
1619 WaveClear slabdata, image, reduced_waves
1620 setdatafolder ::
1621 endif
1622
1623 iz += 1
1624 n_sent += 1
1625 tmo = 0
1626 else
1627 iz += 1
1628 it = 0
1629 endif
1630 endif
1631 else
1632 // throttle the loop if processing is slow
1633 tmo = min(100, tmo + 10)
1634 endif
1635
1636 // receive a slab from the processing queue
1637 if (n_recvd < nzt)
1638 if (nthreads > 0)
1639 dfr = ThreadGroupGetDFR(threadGroupID, tmo)
1640 else
1641 dfr = processing_folders[n_recvd]
1642 processing_folders[n_recvd] = $""
1643 endif
1644
1645 if (DatafolderRefStatus(dfr) != 0)
1646 // access results folder
1647 nvar rr = dfr:r_index
1648 nvar ss = dfr:s_index
1649 nvar func_result = dfr:func_result
1650
1651 if (func_result < 1)
1652 print "error during data reduction."
1653 result = -3
1654 break
1655 endif
1656
1657 // initialize result waves just once
1658 if (numpnts(result_waves) == 0)
1659 redimension /n=(func_result) result_waves
1660 for (iw = 0; iw < func_result; iw += 1)
1661 sw = "redw_" + num2str(iw)
1662 wave profile = dfr:$sw
1663 sw = "ReducedData" + num2str(iw+1)
1664 make /n=(dimsize(profile, 0), nz, nt) /d /o $sw
1665 wave data = $sw
1666 setdimlabel 0, -1, $getdimlabel(profile, 0, -1), data
1667 setdimlabel 1, -1, $kScanDimLabel, data
1668 note data, note(profile)
1669 ps_scale_dataset(data)
1670 setscale /p x dimoffset(profile, 0), dimdelta(profile, 0), waveunits(profile, 0), data
1671 setscale d 0, 0, waveunits(profile, -1), data
1672 result_waves[iw] = data
1673 endfor
1674 endif
1675
1676 // copy results
1677 for (iw = 0; iw < func_result; iw += 1)
1678 sw = "redw_" + num2str(iw)
1679 wave profile = dfr:$sw
1680 wave data = result_waves[iw]
1681 data[][rr][ss] = profile[p]
1682 endfor
1683
1684 n_recvd += 1
1685 KillDataFolder /Z dfr
1686 endif
1687 else
1688 // processing complete
1689 break
1690 endif
1691
1692 // update progress window
1693 if (progress)
1694 if (update_progress_panel(n_recvd))
1695 print "user abort"
1696 result = -4
1697 break
1698 endif
1699 endif
1700 while ((n_recvd < nzt) && (result == 0))
1701
1702 // clean up
1703 killwaves /z slab, slabdata, template
1704
1705 if (nthreads > 0)
1706 variable tstatus = ThreadGroupRelease(threadGroupID)
1707 if (tstatus == -2)
1708 print "error: thread did not terminate properly."
1709 result = -5
1710 endif
1711 endif
1712
1713 // finalize results
1714 nw = numpnts(result_waves)
1715 wavenames = ""
1716 for (iw = 0; iw < nw; iw += 1)
1717 wave /z data = result_waves[iw]
1718 if (WaveExists(data))
1719 if (nz == 1)
1720 redimension /n=(-1, 0, 0) data
1721 elseif (nt == 1)
1722 redimension /n=(-1, nz, 0) data
1723 endif
1724 wavenames += nameofwave(data) + ";"
1725 endif
1726 endfor
1727
1728 if (progress)
1730 endif
1731
1732 setdatafolder base_df
1733 return wavenames
1734end
1735
1736
1737threadsafe static function reduce_slab_worker(reduction_func)
1738 funcref adh5_default_reduction reduction_func
1739 do
1740 // wait for job from main thread
1741 do
1742 dfref dfr = ThreadGroupGetDFR(0, 1000)
1743 if (DataFolderRefStatus(dfr) == 0)
1744 if (GetRTError(2))
1745 return 0 // no more jobs
1746 endif
1747 else
1748 break
1749 endif
1750 while (1)
1751
1752 // get input data
1753 wave slabdata = dfr:slabdata
1754 wave image = dfr:image
1755 svar func_param = dfr:func_param
1756 nvar rr = dfr:r_index
1757 nvar ss = dfr:s_index
1758
1759 // do the work
1760 newdatafolder /s out_df
1761 variable /g r_index = rr
1762 variable /g s_index = ss
1763 wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
1764 variable /g func_result = numpnts(reduced_waves)
1765
1766 // send output to queue and clean up
1767 adh5_get_result_waves(reduced_waves, "redw_", 0)
1768 WaveClear slabdata, image, reduced_waves
1769 ThreadGroupPutDF 0, :
1770 KillDataFolder dfr
1771 while (1)
1772
1773 return 0
1774end
1775
1776threadsafe static function /wave reduce_slab_image(slabdata, image, reduction_func, reduction_params)
1777 wave slabdata
1778 wave image
1779 funcref adh5_default_reduction reduction_func
1780 string reduction_params
1781
1782 image = slabdata[q][p][0][0]
1783
1784 return reduction_func(image, reduction_params)
1785end
1786
1787// ====== meta and auxiliary data ======
1788
1803function /s psh5_load_general_group(file_df)
1804 dfref file_df
1805
1806 if (!DataFolderRefStatus(file_df))
1807 dfref file_df = GetDataFolderDFR()
1808 endif
1809 nvar /sdfr=file_df file_id
1810
1811 string obj_names = "authors;pgroup;proposal;proposer;sample;"
1812 variable nn = ItemsInList(obj_names, ";")
1813 variable ii
1814 string name
1815
1816 for (ii = 0; ii < nn; ii += 1)
1817 name = StringFromList(ii, obj_names, ";")
1818 psh_load_general_string(file_df, name)
1819 endfor
1820
1821 return obj_names
1822end
1823
1838function /s psh_load_general_string(file_df, name)
1839 dfref file_df
1840 string name
1841
1842 if (!DataFolderRefStatus(file_df))
1843 dfref file_df = GetDataFolderDFR()
1844 endif
1845 nvar /sdfr=file_df file_id
1846
1847 string path = "/general/" + name
1848 HDF5LoadData /O /Q /Z /N=wt_load_general /TYPE=1 file_id, path
1849 string values = ""
1850 if (!v_flag)
1851 wave /t wt_load_general
1852 variable nn = numpnts(wt_load_general)
1853 variable ii
1854 for (ii = 0; ii < nn; ii += 1)
1855 values = AddListItem(wt_load_general[ii], values, ",", inf)
1856 endfor
1857 killwaves /z wt_load_general
1858 if (strlen(values) >= 1)
1859 values = values[0,strlen(values)-2]
1860 endif
1861 endif
1862 string /g $name = values
1863 return values
1864end
1865
1887function psh5_load_dataset_meta(file_df, datasetpath, datawave)
1888 dfref file_df
1889 string datasetpath
1890 wave datawave
1891
1892 if (!DataFolderRefStatus(file_df))
1893 dfref file_df = GetDataFolderDFR()
1894 endif
1895 nvar /sdfr=file_df file_id
1896
1897 dfref save_df = GetDataFolderDFR()
1898 SetDataFolder NewFreeDataFolder()
1899
1900 string wnote
1901
1902 HDF5LoadData /O /Q /Z /A="Writable Dimension" /N=WriteDim file_id, datasetpath
1903 if (!v_flag)
1904 wave WriteDim
1905 // scan dimension starts at 1
1906 sprintf wnote, "ScanDimension=%u", WriteDim[0]
1907 Note datawave, wnote
1908 endif
1909
1910 HDF5LoadData /O /Q /Z /A="Writable Index" /N=WriteIndex file_id, datasetpath
1911 if (!v_flag)
1912 wave WriteIndex
1913 sprintf wnote, "WriteableIndex=%u", WriteIndex[0]
1914 Note datawave, wnote
1915 endif
1916
1917 HDF5LoadData /O /Q /Z /A="Readable Index" /N=ReadIndex file_id, datasetpath
1918 if (!v_flag)
1919 wave ReadIndex
1920 sprintf wnote, "ReadableIndex=%u", ReadIndex[0]
1921 Note datawave, wnote
1922 endif
1923
1924 setdatafolder save_df
1925 return 0
1926end
1927
1954function /s psh5_load_scan_meta(file_df, scanpath)
1955 // todo: convert to variables/strings
1956 dfref file_df
1957 string scanpath
1958 string wavenames = ""
1959
1960 if (!DataFolderRefStatus(file_df))
1961 dfref file_df = GetDataFolderDFR()
1962 endif
1963 nvar /sdfr=file_df file_id
1964
1965 HDF5LoadData /O /Q /Z /A="Dimensions" /N=ScanDimensions /TYPE=1 file_id, scanpath
1966 if (!v_flag)
1967 wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
1968 else
1969 make /n=1 /o ScanDimensions
1970 ScanDimensions = 0
1971 wavenames = AddListItem("ScanDimensions", wavenames, ";", inf)
1972 endif
1973 HDF5LoadData /O /Q /Z /A="Readables" /N=ScanReadables /TYPE=1 file_id, scanpath
1974 if (!v_flag)
1975 wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
1976 else
1977 make /n=1 /o /t ScanReadables
1978 ScanReadables[0] = "ScientaSpectrum"
1979 wavenames = AddListItem("ScanReadables", wavenames, ";", inf)
1980 endif
1981 HDF5LoadData /O /Q /Z /A="Writables" /N=ScanWritables /TYPE=1 file_id, scanpath
1982 if (!v_flag)
1983 wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
1984 else
1985 // OTF script
1986 HDF5LoadData /O /Q /Z /A="PlotDomain" /N=ScanWritables /TYPE=1 file_id, scanpath
1987 if (!v_flag)
1988 wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
1989 endif
1990 endif
1991 HDF5LoadData /O /Q /Z /A="Steps" /N=ScanSteps /TYPE=1 file_id, scanpath
1992 if (!v_flag)
1993 wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
1994 endif
1995 wavenames = ReplaceString(";;", wavenames, ";")
1996
1997 // additional attributes from XPSSpectrum.py
1998 HDF5LoadData /O /Q /Z /A="Iterations" /N=ScanIterations /TYPE=1 file_id, scanpath
1999 if (!v_flag)
2000 wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
2001 endif
2002 HDF5LoadData /O /Q /Z /A="Step Size" /N=ScanStepSize /TYPE=1 file_id, scanpath
2003 if (!v_flag)
2004 wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
2005 endif
2006 HDF5LoadData /O /Q /Z /A="Step Time" /N=ScanStepTime /TYPE=1 file_id, scanpath
2007 if (!v_flag)
2008 wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
2009 endif
2010
2011 return wavenames
2012end
2013
2014// ====== dimension scaling ======
2015
2031function ps_set_dimlabels(data)
2032 wave data
2033
2034 ps_set_dimlabels2(data, NameOfWave(data))
2035end
2036
2050function ps_set_dimlabels2(data, name)
2051 wave data
2052 string name
2053
2054 variable dummy
2055 try
2056 // intrinsic dimensions
2057 strswitch(name)
2058 case "ScientaImage":
2059 setdimlabel 0, -1, $kEnergyDimLabel, data
2060 setdimlabel 1, -1, $kAngleDimLabel, data
2061 if (WaveDims(data) >= 3)
2062 setdimlabel 2, -1, $kScanDimLabel, data
2063 endif
2064 AbortOnRTE
2065 break
2066 case "ImageAngleDistribution":
2067 case "ScientaAngleDistribution":
2068 if (WaveDims(data) >= 2)
2069 setdimlabel 0, -1, $kScanDimLabel, data
2070 setdimlabel 1, -1, $kAngleDimLabel, data
2071 else
2072 setdimlabel 0, -1, $kAngleDimLabel, data
2073 endif
2074 AbortOnRTE
2075 break
2076 case "ScientaSpectrum":
2077 case "ImageEnergyDistribution":
2078 case "ScientaEnergyDistribution":
2079 if (WaveDims(data) >= 2)
2080 setdimlabel 0, -1, $kScanDimLabel, data
2081 setdimlabel 1, -1, $kEnergyDimLabel, data
2082 else
2083 setdimlabel 0, -1, $kEnergyDimLabel, data
2084 endif
2085 AbortOnRTE
2086 break
2087 default:
2088 if (WaveDims(data) == 1)
2089 setdimlabel 0, -1, $kScanDimLabel, data
2090 AbortOnRTE
2091 else
2092 return 1
2093 endif
2094 endswitch
2095 catch
2096 dummy = GetRTError(1)
2097 return 2
2098 endtry
2099 return 0
2100end
2101
2111function /df ps_find_scan_folder(data_df)
2112 dfref data_df
2113
2114 wave /z /t /sdfr=data_df ScanWritables=::ScanWritables
2115 if (WaveExists(ScanWritables))
2116 string sdf = GetDataFolder(1, data_df)
2117 dfref parent_df = $(sdf + ":")
2118 return parent_df
2119 else
2120 return data_df
2121 endif
2122end
2123
2134function /df ps_find_attr_folder(scan_df)
2135 dfref scan_df
2136
2137 dfref diags_df = data_df:diags
2138 dfref attrs_df = scan_df:attrs
2139 dfref attr_df = scan_df:attr
2140 if (DataFolderRefStatus(diags_df))
2141 return diags_df
2142 elseif (DataFolderRefStatus(attrs_df))
2143 return attrs_df
2144 elseif (DataFolderRefStatus(attr_df))
2145 return attr_df
2146 else
2147 return $""
2148 endif
2149end
2150
2161function /wave ps_find_scale_wave(name, df1, df2, df3)
2162 string name
2163 dfref df1
2164 dfref df2
2165 dfref df3
2166
2167 variable idf
2168 variable ndf=3
2169 make /n=(ndf) /df /free dfs
2170 dfs[0] = {df1, df2, df3}
2171 for (idf = 0; idf < ndf; idf += 1)
2172 if (DataFolderRefStatus(dfs[idf]))
2173 wave /SDFR=dfs[idf] /Z w = $name
2174 if (WaveExists(w))
2175 return w
2176 endif
2177 endif
2178 endfor
2179
2180 return $""
2181end
2182
2229function ps_detect_scale(data_df, ax, lo, hi, un)
2230 dfref data_df
2231 wave /t ax
2232 wave lo
2233 wave hi
2234 wave /t un
2235
2236 dfref scan_df = ps_find_scan_folder(data_df)
2237 dfref attr_df = ps_find_attr_folder(scan_df)
2238
2239 redimension /n=4 lo, hi, un, ax
2240 setdimlabel 0, 0, $kEnergyDimLabel, lo, hi, un, ax
2241 setdimlabel 0, 1, $kAngleDimLabel, lo, hi, un, ax
2242 setdimlabel 0, 2, $kScanDimLabel, lo, hi, un, ax
2243 setdimlabel 0, 3, $kDataDimLabel, lo, hi, un, ax
2244
2245 // default values
2246 lo[%$kEnergyDimLabel] = 0
2247 hi[%$kEnergyDimLabel] = 1
2248 un[%$kEnergyDimLabel] = "eV"
2249 ax[%$kEnergyDimLabel] = "Ekin"
2250
2251 lo[%$kAngleDimLabel] = -1
2252 hi[%$kAngleDimLabel] = 1
2253 un[%$kAngleDimLabel] = "arb."
2254 un[%$kAngleDimLabel] = "slice"
2255
2256 lo[%$kScanDimLabel] = 0
2257 hi[%$kScanDimLabel] = 1
2258 un[%$kScanDimLabel] = "arb."
2259 ax[%$kScanDimLabel] = "scan"
2260
2261 lo[%$kDataDimLabel] = 0
2262 hi[%$kDataDimLabel] = 0
2263 un[%$kDataDimLabel] = "arb."
2264 ax[%$kDataDimLabel] = "value"
2265
2266 wave /T /Z LensMode = ps_find_scale_wave("LensMode", data_df, scan_df, attr_df)
2267 wave /Z LowEnergy = ps_find_scale_wave("ScientaLowEnergy", data_df, scan_df, attr_df)
2268 wave /Z HighEnergy = ps_find_scale_wave("ScientaHighEnergy", data_df, scan_df, attr_df)
2269 wave /Z LowThetaX = ps_find_scale_wave("ScientaLowThetaX", data_df, scan_df, attr_df)
2270 wave /Z HighThetaX = ps_find_scale_wave("ScientaHighThetaX", data_df, scan_df, attr_df)
2271 wave /Z ChannelBegin = ps_find_scale_wave("ScientaChannelBegin", data_df, scan_df, attr_df)
2272 wave /Z ChannelEnd = ps_find_scale_wave("ScientaChannelEnd", data_df, scan_df, attr_df)
2273 wave /Z SliceBegin = ps_find_scale_wave("ScientaSliceBegin", data_df, scan_df, attr_df)
2274 wave /Z SliceEnd = ps_find_scale_wave("ScientaSliceEnd", data_df, scan_df, attr_df)
2275 wave /Z ScientaChannels = ps_find_scale_wave("ScientaChannels", data_df, scan_df, attr_df)
2276
2277 // lens mode can give more detail
2278 if (waveexists(LensMode) && (numpnts(LensMode) >= 1))
2279 if (stringmatch(LensMode[0], "*Transmission*"))
2280 un[%$kAngleDimLabel] = "mm"
2281 ax[%$kAngleDimLabel] = "position"
2282 else
2283 un[%$kAngleDimLabel] = "°"
2284 ax[%$kAngleDimLabel] = "angle"
2285 endif
2286 endif
2287
2288 // best option if scales are explicit in separate waves
2289 if (waveexists(LowEnergy) && waveexists(HighEnergy) && (numpnts(LowEnergy) >= 1) && (numpnts(HighEnergy) >= 1))
2290 lo[%$kEnergyDimLabel] = LowEnergy[0]
2291 hi[%$kEnergyDimLabel] = HighEnergy[0]
2292 elseif (waveexists(ChannelBegin) && waveexists(ChannelEnd) && (numpnts(ChannelBegin) >= 1) && (numpnts(ChannelEnd) >= 1))
2293 lo[%$kEnergyDimLabel] = ChannelBegin[0]
2294 hi[%$kEnergyDimLabel] = ChannelEnd[0]
2295 elseif (waveexists(ScientaChannels) && (numpnts(ScientaChannels) >= 1))
2296 lo[%$kEnergyDimLabel] = ScientaChannels[0]
2297 hi[%$kEnergyDimLabel] = ScientaChannels[numpnts(ScientaChannels)-1]
2298 endif
2299 if (waveexists(LowThetaX) && waveexists(HighThetaX) && (numpnts(LowThetaX) >= 1) && (numpnts(HighThetaX) >= 1))
2300 lo[%$kAngleDimLabel] = LowThetaX[0]
2301 hi[%$kAngleDimLabel] = HighThetaX[0]
2302 elseif (waveexists(SliceBegin) && waveexists(SliceEnd) && (numpnts(SliceBegin) >= 1) && (numpnts(SliceEnd) >= 1))
2303 lo[%$kAngleDimLabel] = SliceBegin[0]
2304 hi[%$kAngleDimLabel] = SliceEnd[0]
2305 endif
2306
2307 wave /z /t /SDFR=scan_df ScanWritables
2308 if (WaveExists(ScanWritables))
2309 wave /z /SDFR=scan_df scanner = $ScanWritables[0]
2310 if (!WaveExists(scanner))
2311 wave /z /SDFR=attr_df scanner = $ScanWritables[0]
2312 endif
2313 if (WaveExists(scanner) && (numpnts(scanner) >= 1))
2314 lo[%$kScanDimLabel] = scanner[0]
2315 hi[%$kScanDimLabel] = scanner[numpnts(scanner)-1]
2316 ax[%$kScanDimLabel] = NameOfWave(scanner)
2317 strswitch(NameOfWave(scanner))
2318 case "Eph":
2319 ax[%$kScanDimLabel] = "photon energy"
2320 un[%$kScanDimLabel] = "eV"
2321 break
2322 case "ManipulatorX":
2323 case "ManipulatorY":
2324 case "ManipulatorZ":
2325 case "FocusYTrans":
2326 case "FocusZTrans":
2327 case "RefocusYTrans":
2328 case "RefocusZTrans":
2329 case "ExitSlitY":
2330 un[%$kScanDimLabel] = "mm"
2331 break
2332 case "ExitSlit":
2333 un[%$kScanDimLabel] = "µm"
2334 break
2335 case "ManipulatorTheta":
2336 case "ManipulatorTilt":
2337 case "ManipulatorPhi":
2338 un[%$kScanDimLabel] = "°"
2339 break
2340 case "FocusXRot":
2341 case "FocusYRot":
2342 case "FocusZRot":
2343 case "RefocusXRot":
2344 case "RefocusYRot":
2345 case "RefocusZRot":
2346 un[%$kScanDimLabel] = "mrad"
2347 break
2348 endswitch
2349 endif
2350 endif
2351end
2352
2392function ps_scale_dataset_2(data, ax, lo, hi, un)
2393 wave data
2394 wave /t ax
2395 wave lo
2396 wave hi
2397 wave /t un
2398
2399 string snote = note(data)
2400 string sdim
2401 sdim = GetDimLabel(data, 0, -1)
2402 if (strlen(sdim))
2403 setscale /i x lo[%$sdim], hi[%$sdim], un[%$sdim], data
2404 snote = ReplaceStringByKey("AxisLabelX", snote, ax[%$sdim], "=", "\r")
2405 endif
2406
2407 sdim = GetDimLabel(data, 1, -1)
2408 if (strlen(sdim))
2409 setscale /i y lo[%$sdim], hi[%$sdim], un[%$sdim], data
2410 snote = ReplaceStringByKey("AxisLabelY", snote, ax[%$sdim], "=", "\r")
2411 endif
2412
2413 sdim = GetDimLabel(data, 2, -1)
2414 if (strlen(sdim))
2415 setscale /i z lo[%$sdim], hi[%$sdim], un[%$sdim], data
2416 snote = ReplaceStringByKey("AxisLabelZ", snote, ax[%$sdim], "=", "\r")
2417 endif
2418
2419 string data_unit = un[%$kDataDimLabel]
2420 string data_label = ax[%$kDataDimLabel]
2421 string s
2422 variable def = (cmpstr(data_unit, "arb.") == 0) && (cmpstr(data_label, "value") == 0)
2423
2424 if (def)
2425 s = StringByKey("AxisLabelD", snote, "=", "\r")
2426 if (strlen(s) > 0)
2427 data_label = s
2428 def = 0
2429 endif
2430 s = StringByKey("AxisUnitD", snote, "=", "\r")
2431 if (strlen(s) > 0)
2432 data_unit = s
2433 def = 0
2434 endif
2435 endif
2436
2437 if (def)
2438 strswitch(NameOfWave(data))
2439 case "ScientaImage":
2440 case "ImageAngleDistribution":
2441 case "ScientaAngleDistribution":
2442 case "ScientaSpectrum":
2443 case "ImageEnergyDistribution":
2444 case "ScientaEnergyDistribution":
2445 data_unit = "arb."
2446 data_label = "intensity"
2447 def = 0
2448 break
2449 case "SampleCurrent":
2450 case "RefCurrent":
2451 case "AuxCurrent":
2452 data_unit = "A"
2453 data_label = "current"
2454 def = 0
2455 break
2456 case "MachineCurrent":
2457 data_unit = "mA"
2458 data_label = "current"
2459 def = 0
2460 break
2461 endswitch
2462 endif
2463
2464 setscale d 0, 0, data_unit, data
2465 snote = ReplaceStringByKey("AxisLabelD", snote, data_label, "=", "\r")
2466 snote = ReplaceStringByKey("AxisUnitD", snote, data_unit, "=", "\r")
2467 snote = ReplaceStringByKey("Dataset", snote, NameOfWave(data), "=", "\r")
2468 note /k data, snote
2469end
2470
2486function ps_scale_datasets(scan_df)
2487 dfref scan_df
2488
2489 make /n=3 /free lo, hi
2490 make /n=3 /t /free ax, un
2491 wave /t /z /SDFR=scan_df ScanReadables
2492 if (WaveExists(ScanReadables))
2493 variable isr
2494 variable nsr = numpnts(ScanReadables)
2495 variable nel
2496 string ssr
2497 string sds
2498 for (isr = 0; isr < nsr; isr += 1)
2499 ssr = ScanReadables[isr]
2500 dfref data_df = psh5_dataset_to_folder(scan_df, ssr)
2501 if (!DataFolderRefStatus(data_df))
2502 dfref data_df = scan_df
2503 endif
2504 nel = ItemsInList(ssr, "/")
2505 sds = StringFromList(nel - 1, ssr, "/")
2506 wave /z /sdfr=data_df wsr=$sds
2507 if (WaveExists(wsr))
2508 ps_detect_scale(data_df, ax, lo, hi, un)
2509 ps_scale_dataset_2(wsr, ax, lo, hi, un)
2510 endif
2511 endfor
2512 endif
2513end
2514
2531function ps_scale_dataset(data)
2532 wave data
2533
2534 dfref save_df = GetDataFolderDFR()
2535 dfref data_df = GetWavesDataFolderDFR(data)
2536
2537 setdatafolder data_df
2538 make /n=3 /free lo, hi
2539 make /n=3 /t /free ax, un
2540 ps_detect_scale(data_df, ax, lo, hi, un)
2541 ps_scale_dataset_2(data, ax, lo, hi, un)
2542 setdatafolder save_df
2543end
2544
2545
2546// ====== miscellaneous functions ======
2547
2557function /s kill_matching_waves(dfr, pattern, recurse, [killed])
2558 DFREF dfr
2559 string pattern
2560 variable recurse
2561 string killed
2562
2563 if (ParamIsDefault(killed))
2564 killed = ""
2565 endif
2566
2567 string s
2568 string r
2569 variable index = 0
2570 do
2571 Wave/Z w = WaveRefIndexedDFR(dfr, index)
2572 if (!WaveExists(w))
2573 break
2574 endif
2575
2576 s = NameOfWave(w)
2577 if (stringmatch(s, pattern))
2578 killwaves /z w
2579 killed = AddListItem(s, killed, ";", Inf)
2580 endif
2581
2582 index += 1
2583 while(1)
2584
2585 if (recurse)
2586 Variable numChildDataFolders = CountObjectsDFR(dfr, 4)
2587 Variable i
2588 for(i=0; i<numChildDataFolders; i+=1)
2589 String childDFName = GetIndexedObjNameDFR(dfr, 4, i)
2590 DFREF childDFR = dfr:$childDFName
2591 killed = kill_matching_waves(childDFR, pattern, 1, killed=killed)
2592 endfor
2593 endif
2594
2595 return killed
2596End
threadsafe variable adh5_get_result_waves(wave results, string result_prefix, variable start_index)
copy waves from wave reference wave into current data folder
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
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()
const string kScientaScalingDatasets
List of datasets that must be loaded to determine the axis scaling of a Scienta image.
const string kTransposedDatasets
List of datasets that must be transposed upon loading.
const variable kDSCAttrs
string psh5_list_all_datasets(variable file_id)
list all datasets in a file
variable[string datatypes, string ranks, string dimensions] psh5_list_dataset_info(string variable, string file_id, variable string, sds datasets)
list data types and dimensions of datasets
const variable kDSCAll
string psh5_load_scan_meta(dfref file_df, string scanpath)
load metadata of a PShell scan group.
dfr psh5_preview(string path_name, string file_name, dfref dest_df=defaultValue, string preview_datasets=defaultValue)
load preview
const string kDataDimLabel
Dimension label for the data dimension.
variable ps_scale_dataset_2(wave data, wave ax, wave lo, wave hi, wave un)
set the dimension scales of a dataset.
wave ps_find_scale_wave(string name, dfref df1, dfref df2, dfref df3)
find a wave in scan and attr data folders
const variable kDSCMonitors
const variable kDSCSnaps
static threadsafe variable reduce_slab_worker(funcref reduction_func)
const string kPreviewDatasets
List of preferred datasets to load for preview.
const string kScanDimLabel
Dimension label for the scan dimension of multi-dimensional datasets.
variable psh5_close_file(dfref file_df)
close a HDF5 file opened by psh5_open_file.
dfr ps_find_attr_folder(dfref scan_df)
find the attributes data folder
const variable kDSCRegions
string psh5_extract_region_paths(string datasets)
trim dataset paths to the scan/region part
dfr ps_find_scan_folder(dfref data_df)
find the scan folder of current data
variable ps_scale_datasets(dfref scan_df)
set the dimension scales of loaded PShell Scienta datasets according to attributes.
const string kEnergyDimLabel
Dimension label for the energy dispersive dimension of multi-dimensional datasets.
const variable kDSCPreview
const variable kDSCMeta
string psh_load_general_string(dfref file_df, string name)
load a string from the general group.
string psh5_filter_datasets_rank(string datasets, string ranks, variable min_rank, variable max_rank)
filter datasets by rank
const variable kDSCDetectors
string ps_fix_folder_name(string group_name)
convert HDF5 group name to data folder name and fix compatibility issues
static threadsafe wave reduce_slab_image(wave slabdata, wave image, funcref reduction_func, string reduction_params)
const string kAngleDimLabel
Dimension label for the angle dispersive dimension of multi-dimensional datasets.
string psh5_list_scans(variable file_id)
list scan groups of a PShell data file.
variable ps_set_dimlabels2(wave data, string name)
set dimension labels according to the axis type
static string twave2list(wave wt, string sep)
convert text wave to list.
string kill_matching_waves(dfref dfr, string pattern, variable recurse, string killed=defaultValue)
kill any waves matching a pattern in the experiment
static string wave2list(wave w, string format, string sep)
convert numeric wave to list.
dfr psh5_create_folders(string datasetpath)
create all data folders along a dataset path
const string kEssentialDiagnostics
List of diagnostic datasets that are normally loaded with a scan.
dfr psh5_load(string path_name, string file_name, string scans, string regions, string datasets, variable classes=defaultValue, variable max_rank=defaultValue, string reduction_func=defaultValue, string reduction_params=defaultValue, dfref dest_df=defaultValue)
main data loading function
dfr psh5_open_file(string path_name, string file_name, dfref dest_df=defaultValue)
open a HDF5 file created by the PShell data acquisition program and prepare the data folder.
const variable kDSCScientaScaling
string psh5_extract_scan_paths(string datasets)
trim dataset paths to the scan part
variable ps_set_dimlabels(wave data)
set dimension labels according to the axis type
variable psh5_load_dataset_meta(dfref file_df, string datasetpath, wave datawave)
load metadata of a PShell dataset.
string psh5_load_general_group(dfref file_df)
load organizational metadata from the general group.
const variable kDSCOther
dfr psh5_dataset_to_folder(dfref parent_df, string datasetpath)
map dataset path to datafolder path
variable ps_detect_scale(dfref data_df, wave ax, wave lo, wave hi, wave un)
detect the dimension scales from attributes.
variable ps_scale_dataset(wave data)
set the dimension scales of a loaded PShell Scienta dataset according to attributes.
const variable kDSCDiags
static string unique_strings(string list)
remove duplicate items from list
string psh5_load_datasets(dfref file_df, string datasets, variable create_folders=defaultValue, string reduction_func=defaultValue, string reduction_params=defaultValue)
load multiple datasets from open file
const variable kDSCPositioners
const variable kDSCEssentialDiags
string psh5_match_dataset_classes(string datasets, variable classes, string positioners=defaultValue, string detectors=defaultValue)
filter a list of datasets by classification
string psh5_load_dataset_reduced(dfref file_df, string datasetpath, funcref reduction_func, string reduction_params, variable create_folders=defaultValue, variable progress=defaultValue, variable nthreads=defaultValue)
load a dataset with reduced dimensionality
string psh5_load_dataset(dfref file_df, string datasetpath, variable create_folders=defaultValue, string reduction_func=defaultValue, string reduction_params=defaultValue)
load a dataset from an open PShell HDF5 file.
string psh5_load_dataset_slabs(dfref file_df, string datasetpath, variable create_folders=defaultValue, variable progress=defaultValue)
load a dataset slab-wise from the open PShell HDF5 file.