source: sans/Dev/trunk/NCNR_User_Procedures/Reduction/VSANS/V_ReadWrite_HDF5.ipf @ 965

Last change on this file since 965 was 965, checked in by srkline, 7 years ago

intermediate changes to the VSANS r/w routines, a utility for processing ISO8601 dates, and some testing procedures for working with the banks of tubes.

File size: 18.0 KB
Line 
1#pragma rtGlobals=3             // Use modern global access method and strict wave access.
2
3
4// Start to build up and test the r/w accessors for VSANS
5// (SANS has a template, VSANS does not, so just start from scratch here, since the
6// file structure will be different)
7//
8//
9
10
11// thought this would be useful, but the file name (folder) is stuck in the middle...
12Strconstant ksPathPrefix = "root:(folder):entry:entry1:"
13
14
15
16// passing null file string presents a dialog
17Macro Read_HDF5_Raw_No_Attributes()
18        V_LoadHDF5Data("")
19End
20
21Proc V_LoadHDF5Data(file)
22        String file
23
24        SetDataFolder root:     
25        Variable err= V_LoadHDF5_NoAtt(file)    // reads into current folder
26        SetDataFolder root:
27End
28
29
30// This loads for speed, since loading the attributes takes a LOT of time.
31//
32// this will load in the whole HDF file all at once.
33// Attributes are NOT loaded at all.
34//
35// TODO: remove the P=home restriction top make this more generic
36// -- get rid of bits leftover here that I don't need
37// -- be sure I'm using all of the correct flags in the HDF5LoadGroup operation
38//
39Function V_LoadHDF5_NoAtt(fileName, [hdf5Path])
40        String fileName, hdf5Path
41        if ( ParamIsDefault(hdf5Path) )
42                hdf5Path = "/"
43        endif
44
45        String status = ""
46
47        Variable fileID = 0
48        HDF5OpenFile/R/P=home/Z fileID as fileName              //read file from home directory?
49//      HDF5OpenFile/R/P=catPathName/Z fileID as fileName
50        if (V_Flag != 0)
51                return 0
52        endif
53
54        String/G root:file_path = S_path
55        String/G root:file_name = S_FileName
56       
57        if ( fileID == 0 )
58                Print fileName + ": could not open as HDF5 file"
59                return (0)
60        endif
61       
62//s_tic()               //fast
63       
64        SVAR tmpStr=root:file_name
65        fileName=tmpStr         //SRK - in case the file was chosen from a dialog
66       
67        //   read the data (too bad that HDF5LoadGroup does not read the attributes)
68        String base_name = StringFromList(0,FileName,".")
69        HDF5LoadGroup/Z/L=7/O/R/T=$base_name  :, fileID, hdf5Path               //      recursive
70        if ( V_Flag != 0 )
71                Print fileName + ": could not open as HDF5 file"
72                setdatafolder root:
73                return (0)
74        endif
75
76        HDF5CloseFile fileID
77       
78//s_toc()
79        return(0)
80end     
81
82
83// read a single real value
84// - fname passed in is the full path to the file on disk
85// - path is the path to the value in the HDF tree
86//
87// check to see if the value exists (It will be a wave)
88// -- if it does, return the value from the local folder
89// -- if not, read the file in, then return the value
90//
91Function V_getRealValueFromHDF5(fname,path)
92        String fname,path
93
94        String folderStr=""
95        Variable valExists=0
96       
97        folderStr = V_RemoveDotExtension(V_GetFileNameFromPathNoSemi(fname))
98       
99        if(Exists("root:"+folderStr+":"+path))
100                valExists=1
101        endif
102       
103        if(!valExists)
104                //then read in the file
105                V_LoadHDF5_NoAtt(fname)
106        endif
107
108// this should exist now - if not, I need to see the error
109        Wave w = $("root:"+folderStr+":"+path)
110       
111        return(w[0])
112End
113
114// Returns a wave reference, not just a single value
115// ---then you pick what you need from the wave
116//
117// - fname passed in is the full path to the file on disk
118// - path is the path to the value in the HDF tree
119//
120// check to see if the value exists (It will be a wave)
121// -- if it does, return the value from the local folder
122// -- if not, read the file in, then return the value
123//
124Function/WAVE V_getRealWaveFromHDF5(fname,path)
125        String fname,path
126
127        String folderStr=""
128        Variable valExists=0
129       
130        folderStr = V_RemoveDotExtension(V_GetFileNameFromPathNoSemi(fname))
131       
132        if(Exists("root:"+folderStr+":"+path))
133                valExists=1
134        endif
135       
136        if(!valExists)
137                //then read in the file
138                V_LoadHDF5_NoAtt(fname)
139        endif
140
141// this should exist now - if not, I need to see the error
142        Wave wOut = $("root:"+folderStr+":"+path)
143       
144        return wOut
145       
146End
147
148//
149//   TODO
150// depricated? in HDF5 - store all of the values as real?
151// Igor sees no difference in real and integer variables (waves are different)
152// BUT-- Igor 7 will have integer variables
153//
154// truncate to integer before returning??
155//
156//////  integer values
157// reads 32 bit integer
158Function V_getIntegerFromHDF5(fname,path)
159        String fname                            //full path+name
160        String path                             //path to the hdf5 location
161       
162        Variable val = V_getRealValueFromHDF5(fname,path)
163       
164        val = round(val)
165        return(val)
166End
167
168
169// read a single string
170// - fname passed in is the full path to the file on disk
171// - path is the path to the value in the HDF tree
172// - num is the number of characters in the VAX string
173// check to see if the value exists (It will be a wave)
174// -- if it does, return the value from the local folder
175// -- if not, read the file in, then return the value
176//
177// TODO -- string could be checked for length, but returned right or wrong
178//
179Function/S V_getStringFromHDF5(fname,path,num)
180        String fname,path
181        Variable num
182
183        String folderStr=""
184        Variable valExists=0
185       
186        folderStr = V_RemoveDotExtension(V_GetFileNameFromPathNoSemi(fname))
187       
188        if(Exists("root:"+folderStr+":"+path))
189                valExists=1
190        endif
191       
192        if(!valExists)
193                //then read in the file
194                V_LoadHDF5_NoAtt(fname)
195        endif
196
197// this should exist now - if not, I need to see the error
198        Wave/T tw = $("root:"+folderStr+":"+path)
199       
200//      if(strlen(tw[0]) != num)
201//              Print "string is not the specified length"
202//      endif
203       
204        return(tw[0])
205End
206
207
208//
209//Write Wave 'wav' to hdf5 file 'fname'
210//Based on code from ANSTO (N. Hauser. nha 8/1/09)
211//
212// TODO:
213// -- figure out if this will write in the native format of the
214//     wave as passed in, or if it will only write as DP.
215// -- do I need to write separate functions for real, integer, etc.?
216//     
217// -- change the /P=home to the user-defined data path (which may be home)             
218//
219Function V_WriteWaveToHDF(fname, groupName, varName, wav)
220        String fname, groupName, varName
221        Wave wav
222       
223        variable err=0, fileID,groupID
224        String cDF = getDataFolder(1), temp
225        String NXentry_name
226       
227        try     
228                HDF5OpenFile/P=home /Z fileID  as fname  //open file read-write
229                if(!fileID)
230                        err = 1
231                        abort "HDF5 file does not exist"
232                endif
233               
234                //get the NXentry node name
235                HDF5ListGroup /TYPE=1 fileID, "/"
236                //remove trailing ; from S_HDF5ListGroup
237               
238                Print "S_HDF5ListGroup = ",S_HDF5ListGroup
239               
240                NXentry_name = S_HDF5ListGroup
241                NXentry_name = ReplaceString(";",NXentry_name,"")
242                if(strsearch(NXentry_name,":",0)!=-1) //more than one entry under the root node
243                        err = 1
244                        abort "More than one entry under the root node. Ambiguous"
245                endif
246                //concatenate NXentry node name and groupName   
247                groupName = "/" + NXentry_name + groupName
248                Print "groupName = ",groupName
249                HDF5OpenGroup /Z fileID , groupName, groupID
250
251                if(!groupID)
252                        HDF5CreateGroup /Z fileID, groupName, groupID
253                        //err = 1
254                        //abort "HDF5 group does not exist"
255                else
256                        // get attributes and save them
257                        //HDF5ListAttributes /Z fileID, groupName    this is returning null. expect it to return semicolon delimited list of attributes
258                        //Wave attributes = S_HDF5ListAttributes
259                endif
260       
261                HDF5SaveData /O /Z /IGOR=0 wav, groupID, varName
262                if (V_flag != 0)
263                        err = 1
264                        abort "Cannot save wave to HDF5 dataset " + varName
265                endif   
266               
267               
268                //attributes - something could be added here as optional parameters and flagged
269//              String attributes = "units"
270//              Make/O/T/N=1 tmp
271//              tmp[0] = "dimensionless"
272//              HDF5SaveData /O /Z /IGOR=0 /A=attributes tmp, groupID, varName
273//              if (V_flag != 0)
274//                      err = 1
275//                      abort "Cannot save attributes to HDF5 dataset"
276//              endif   
277        catch
278
279        endtry
280
281// it is not necessary to close the group here. HDF5CloseFile will close the group as well     
282        if(groupID)
283                HDF5CloseGroup /Z groupID
284        endif
285       
286        if(fileID)
287                HDF5CloseFile /Z fileID
288        endif
289
290        setDataFolder $cDF
291        return err
292end
293
294//Write Wave 'wav' to hdf5 file 'fname'
295//Based on code from ANSTO (N. Hauser. nha 8/1/09)
296Function V_WriteTextWaveToHDF(fname, groupName, varName, wav)
297        String fname, groupName, varName
298        Wave/T wav
299       
300        variable err=0, fileID,groupID
301        String cDF = getDataFolder(1), temp
302        String NXentry_name
303       
304        try     
305                HDF5OpenFile /Z fileID  as fname  //open file read-write
306                if(!fileID)
307                        err = 1
308                        abort "HDF5 file does not exist"
309                endif
310               
311                //get the NXentry node name
312                HDF5ListGroup /TYPE=1 fileID, "/"
313                //remove trailing ; from S_HDF5ListGroup
314               
315                Print "S_HDF5ListGroup = ",S_HDF5ListGroup
316               
317                NXentry_name = S_HDF5ListGroup
318                NXentry_name = ReplaceString(";",NXentry_name,"")
319                if(strsearch(NXentry_name,":",0)!=-1) //more than one entry under the root node
320                        err = 1
321                        abort "More than one entry under the root node. Ambiguous"
322                endif
323
324// TODO SRK -- ??? un-did this... skipping the concatenation of the NXentry_name - may add back in the future, but this
325//   prevents me from accessing the file name which I put on the top node (which may be incorrect style)
326//
327//              NOTE this is only for the texWaves - the writer for real waves does the concatenation , since everything is
328//     under the "entry" group (/Run1)
329//
330                //concatenate NXentry node name and groupName   
331                groupName = "/" + NXentry_name + groupName
332                Print "groupName = ",groupName
333
334                HDF5OpenGroup /Z fileID , groupName, groupID
335
336                if(!groupID)
337                        HDF5CreateGroup /Z fileID, groupName, groupID
338                        //err = 1
339                        //abort "HDF5 group does not exist"
340                else
341                        // get attributes and save them
342                        //HDF5ListAttributes /Z fileID, groupName    this is returning null. expect it to return semicolon delimited list of attributes
343                        //Wave attributes = S_HDF5ListAttributes
344                endif
345       
346                HDF5SaveData /O /Z /IGOR=0 wav, groupID, varName
347                if (V_flag != 0)
348                        err = 1
349                        abort "Cannot save wave to HDF5 dataset " + varName
350                endif   
351               
352               
353                //attributes - something could be added here as optional parameters and flagged
354//              String attributes = "units"
355//              Make/O/T/N=1 tmp
356//              tmp[0] = "dimensionless"
357//              HDF5SaveData /O /Z /IGOR=0 /A=attributes tmp, groupID, varName
358//              if (V_flag != 0)
359//                      err = 1
360//                      abort "Cannot save attributes to HDF5 dataset"
361//              endif   
362        catch
363
364        endtry
365       
366        if(groupID)
367                HDF5CloseGroup /Z groupID
368        endif
369       
370        if(fileID)
371                HDF5CloseFile /Z fileID
372        endif
373
374        setDataFolder $cDF
375        return err
376end
377
378
379//////////////////////////////////////////////
380//////////////////////////////////
381// for TESTING of the get functions - to quickly access and se if there are errors
382//
383// -- not sure how to test the string functions -- can't seem to get a FUNCREF to a string function
384// to work -- maybe it's not alllowed?
385//
386//      -- Not sure how to test the "write" functions. writing the wrong data type to the wrong data field will be a disaster
387//    Writing odd, dummy values will also be a mess - no way to know if I'm doing anything correctly
388//
389Function proto_V_get_FP(str)
390        String str
391        return(0)
392end
393
394//Function/S proto_V_get_STR(str)
395//      String str
396//      return("")
397//end
398
399Function Test_V_get_FP(str,fname)
400        String str,fname
401       
402        Variable ii,num
403        String list,item
404       
405       
406        list=FunctionList(str,";","NPARAMS:1") //,VALTYPE:1
407        Print list
408        num = ItemsInlist(list)
409       
410       
411        for(ii=0;ii<num;ii+=1)
412                item = StringFromList(ii, list , ";")
413                FUNCREF proto_V_get_FP f = $item
414                Print item ," = ", f(fname)
415        endfor
416       
417        return(0)
418end
419
420
421//Function Test_V_get_STR(str,fname)
422//      String str,fname
423//     
424//      Variable ii,num
425//      String list,item
426//     
427//     
428//      list=FunctionList(str,";","NPARAMS:1,VALTYPE:4")
429//      Print list
430//      num = ItemsInlist(list)
431//     
432//     
433//      for(ii=0;ii<num;ii+=1)
434//              item = StringFromList(ii, list , ";")
435//              FUNCREF proto_V_get_STR f = $item
436//              Print item ," = ", f(fname)
437//      endfor
438//     
439//      return(0)
440//end
441
442///////////////////////////////////////
443
444
445//////////////////////////////////////////////
446
447
448///////////////////////
449//
450// *These are the specific bits of information to retrieve (or write) to the data file
451// *These functions use the path to the file as input, and each has the specific
452//   path to the variable srting, or wave hard-coded into the access function
453// *They call the generic worker functions to get the values, either from the local copy if present,
454//   or the full file is loaded.
455//
456// *Since the path is the important bit, these are written as get/write pairs to make it easier to
457//   keep up with any changes in path
458//
459//
460// TODO -- verify the paths, and add more as needed
461//
462
463
464//////// TOP LEVEL
465//////// TOP LEVEL
466//////// TOP LEVEL
467
468
469
470//////// CONTROL
471//////// CONTROL
472//////// CONTROL
473
474//monitor count
475Function V_getMonitorCount(fname)
476        String fname
477       
478        String path = "entry:control:monitor_counts"   
479        return(V_getRealValueFromHDF5(fname,path))
480end
481
482
483//////// INSTRUMENT
484//////// INSTRUMENT
485//////// INSTRUMENT
486
487//wavelength
488Function V_getWavelength(fname)
489        String fname
490       
491        String path = "entry:instrument:beam:monochromator:wavelength" 
492        return(V_getRealValueFromHDF5(fname,path))
493end
494
495//wavelength spread
496Function V_getWavelengthSpread(fname)
497        String fname
498       
499        String path = "entry:instrument:beam:monochromator:wavelength_spread"   
500        return(V_getRealValueFromHDF5(fname,path))
501end
502
503// reactor power (MW)
504Function V_getReactorPower(fname)
505        String fname
506
507        String path = "entry:instrument:source:power"   
508        return(V_getRealValueFromHDF5(fname,path))
509end
510
511
512//////// SAMPLE
513//////// SAMPLE
514//////// SAMPLE
515
516
517// sample transmission
518Function V_getSampleTransmission(fname)
519        String fname
520       
521        String path = "entry:sample:transmission"       
522//      String path = "QKK0037737:data:Transmission"   
523        return(V_getRealValueFromHDF5(fname,path))
524end
525
526// sample transmission
527Function V_WriteTransmissionToHeader(fname,trans)
528        String fname
529        Variable trans
530       
531        Make/O/D/N=1 wTmpWrite
532        String groupName = "/sample"    //      skip "entry" - /entry/sample becomes groupName /entry/entry/sample
533        String varName = "transmission"
534//      Make/O/R/N=1 wTmpWrite
535//      String groupName = "/data"      //      skip "entry" - /entry/sample becomes groupName /entry/entry/sample
536//      String varName = "Transmission"
537        wTmpWrite[0] = trans //
538
539        variable err
540        err = V_WriteWaveToHDF(fname, groupName, varName, wTmpWrite)
541        if(err)
542                Print "HDF write err = ",err
543        endif
544        // now be sure to kill the data folder to force a re-read of the data next time this file is read in
545        err = V_KillNamedDataFolder(fname)
546        if(err)
547                Print "DataFolder kill err = ",err
548        endif
549        return(err)
550End
551
552
553//transmission error (one sigma)
554Function V_getSampleTransError(fname)
555        String fname
556       
557        String path = "entry:sample:transmission_error"
558        return(V_getRealValueFromHDF5(fname,path))
559end
560
561
562// sample label
563// TODO: value of num is currently not used
564//
565Function/S V_getSampleLabel(fname)
566        String fname
567
568        String path = "entry:sample:description"
569        Variable num=60
570        return(V_getStringFromHDF5(fname,path,num))
571End
572
573
574// sample label
575//
576// TODO
577// limit to 60 characters?? do I need to do this with HDF5?
578//
579// do I need to pad to 60 characters?
580//
581Function V_WriteSamLabelToHeader(fname,str)
582        String fname,str
583       
584        if(strlen(str) > 60)
585                str = str[0,59]
586        endif
587//      WriteTextToHeader(fname,str,98)
588       
589       
590        Make/O/T/N=1 tmpTW
591        String groupName = "/sample"    //      /entry is automatically prepended -- so just explicitly state the group
592        String varName = "description"
593        tmpTW[0] = str //
594
595        variable err
596        err = V_WriteTextWaveToHDF(fname, groupName, varName, tmpTW)
597        if(err)
598                Print "HDF write err = ",err
599        endif
600       
601        // now be sure to kill the data folder to force a re-read of the data next time this file is read in
602        err = V_KillNamedDataFolder(fname)
603        if(err)
604                Print "DataFolder kill err = ",err
605        endif
606               
607        return(err)
608End
609
610//Sample Thickness
611Function V_getSampleThickness(fname)
612        String fname
613       
614        String path = "entry:sample:thickness" 
615        return(V_getRealValueFromHDF5(fname,path))
616end
617
618//Sample Rotation Angle is at byte 170
619Function V_getSampleRotationAngle(fname)
620        String fname
621       
622        String path = "entry:sample:rotation_angle"     
623        return(V_getRealValueFromHDF5(fname,path))
624end
625
626//Sample position in changer
627Function V_getSamplePosition(fname)
628        String fname
629       
630        String path = "entry:sample:changer_position"   
631        return(V_getRealValueFromHDF5(fname,path))
632end
633
634
635
636
637
638///////// REDUCTION
639///////// REDUCTION
640///////// REDUCTION
641
642
643//box counts
644Function V_getBoxCounts(fname)
645        String fname
646       
647        String path = "entry:reduction:box_count"       
648        return(V_getRealValueFromHDF5(fname,path))
649end
650
651//box counts error
652Function V_getBoxCountsError(fname)
653        String fname
654       
655        String path = "entry:reduction:box_count_error"
656        return(V_getRealValueFromHDF5(fname,path))
657end
658
659
660//whole detector trasmission
661Function V_getSampleTransWholeDetector(fname)
662        String fname
663       
664        String path = "entry:reduction:whole_trans"     
665        return(V_getRealValueFromHDF5(fname,path))
666end
667
668//whole detector trasmission error
669Function V_getSampleTransWholeDetErr(fname)
670        String fname
671       
672        String path = "entry:reduction:whole_trans_error"       
673        return(V_getRealValueFromHDF5(fname,path))
674end
675
676
677
678// fname is the full path to the file
679// data is an empty 2D wave in RAW to hold the data
680//
681Function V_getDetectorData(fname,data)
682        String fname
683        Wave data
684       
685        // get a wave reference to the data
686        String path = "Run1:Detector:data"
687        WAVE w = V_getRealWaveFromHDF5(fname,path)
688
689        data = w
690
691        return(0)
692End
693
694
695
696//////////////////////////////
697//////////////////////////////
698//////////////////////////////
699
700Function V_KillNamedDataFolder(fname)
701        String fname
702       
703        Variable err=0
704       
705        String folderStr = V_GetFileNameFromPathNoSemi(fname)
706        folderStr = V_RemoveDotExtension(folderStr)
707       
708        KillDataFolder/Z $("root:"+folderStr)
709        err = V_flag
710       
711        return(err)
712end
713
714//given a filename of a SANS data filename of the form
715// name.anything
716//returns the name as a string without the ".fbdfasga" extension
717//
718// returns the input string if a"." can't be found (maybe it wasn't there"
719Function/S V_RemoveDotExtension(item)
720        String item
721        String invalid = item   //
722        Variable num=-1
723       
724        //find the "dot"
725        String runStr=""
726        Variable pos = strsearch(item,".",0)
727        if(pos == -1)
728                //"dot" not found
729                return (invalid)
730        else
731                //found, get all of the characters preceeding it
732                runStr = item[0,pos-1]
733                return (runStr)
734        Endif
735End
736
737//returns a string containing filename (WITHOUT the ;vers)
738//the input string is a full path to the file (Mac-style, still works on Win in IGOR)
739//with the folders separated by colons
740//
741// called by MaskUtils.ipf, ProtocolAsPanel.ipf, WriteQIS.ipf
742//
743Function/S V_GetFileNameFromPathNoSemi(fullPath)
744        String fullPath
745       
746        Variable offset1,offset2
747        String filename=""
748        //String PartialPath
749        offset1 = 0
750        do
751                offset2 = StrSearch(fullPath, ":", offset1)
752                if (offset2 == -1)                              // no more colons ?
753                        fileName = FullPath[offset1,strlen(FullPath) ]
754                        //PartialPath = FullPath[0, offset1-1]
755                        break
756                endif
757                offset1 = offset2+1
758        while (1)
759       
760        //remove version number from name, if it's there - format should be: filename;N
761        filename =  StringFromList(0,filename,";")              //returns null if error
762       
763        Return filename
764End
Note: See TracBrowser for help on using the repository browser.