| Home | Trees | Indices | Help |
|
|---|
|
|
1 # This program is public domain 2 """ 3 Data file reader for NCNR NG-1 data. 4 """ 5 6 import numpy,os 7 from numpy import inf,cos,pi,arctan2 8 from reflectometry.reduction import refldata, icpformat, properties 9 10 11 # Instrument parameters 12 # As instrument parameters change add additional lines to this file 13 # indicating the new value and the date of the change. The order of 14 # the entries does not matter. The timestamp on the file will 15 # determine which value will be used. 16 # The format of the entries should be: 17 # default.NAME = (VALUE, 'YYYY-MM-DD') # value in effect after DD/MM/YYYY 18 # default.NAME = (VALUE, '') # value in effect at commissioning 19 20 # ===================================================================== 21 # NG-1 defaults 22 ng1default = properties.DatedValues() 23 ng1default.wavelength = (4.76,'') # in case ICP records the wrong value 24 25 # Detector saturates at 15000 counts/s. The efficiency curve above 26 # 15000 has not been measured. 27 ng1default.saturation = (numpy.array([[1,15000,0]]),'') 28 ng1default.psd_saturation = (numpy.array([[1,8000,0]]),'') 29 30 # NG-1 detector closer than slit 4? 31 ng1default.detector_distance = (36*25.4, '') # mm 32 ng1default.pencil_size = ((100,20), '') # mm 33 ng1default.psd_size = ((200,170), '') # mm 34 ng1default.slit1_distance = (-75*25.4, '') # mm 35 ng1default.slit2_distance = (-14*25.4, '') # mm 36 ng1default.slit3_distance = (9*25.4, '') # mm 37 ng1default.slit4_distance = (42*25.4, '') # mm 38 ng1default.monitor_timestep = (60./100,'') # s ; ICP records 1/100ths of min 39 40 # ===================================================================== 41 # CG-1 defaults 42 cg1default = properties.DatedValues() 43 cg1default.wavelength = (5.0,'') # in case ICP records the wrong value 44 45 # Detector saturates at 15000 counts/s. The efficiency curve above 46 # 15000 has not been measured. 47 cg1default.saturation = (numpy.array([[1,15000,0]]),'') 48 cg1default.psd_saturation = (numpy.array([[1,8000,0]]),'') 49 50 # NG-1 detector closer than slit 4? 51 cg1default.detector_distance = (1600., '') # mm 52 cg1default.pencil_size = ((100,20), '') # mm 53 cg1default.psd_size = ((200,170), '') # mm 54 cg1default.slit1_distance = (-75*25.4, '') # mm 55 cg1default.slit2_distance = (-14*25.4, '') # mm 56 cg1default.slit3_distance = (9*25.4, '') # mm 57 cg1default.slit4_distance = (42*25.4, '') # mm 58 cg1default.monitor_timestep = (60./100,'') # s ; ICP records 1/100ths of min 59 60 # ===================================================================== 61 6466 probe = "neutron" 67 format = "NCNR ICP" 6820570 super(NG1Icp,self).__init__(*args, **kw) 71 self.path = os.path.abspath(path) 72 73 # Load file header 74 data = icpformat.summary(self.path) 75 if data.scantype != 'I': 76 raise TypeError, "Only I-Buffers supported for %s"%self.format 77 78 self.date = data.date 79 self.name = data.filename 80 self.description = data.comment 81 self.dataset = self.name[:5] 82 83 # Lookup defaults as of the current date 84 ext = os.path.splitext(data.filename)[1].lower() 85 if ext.startswith('c'): 86 self.instrument = "NCNR AND/R" 87 self.default = cg1default(str(data.date)) 88 else: 89 self.instrument = "NCNR NG-1" 90 self.default = ng1default(str(data.date)) 91 92 # Plug in instrument defaults 93 self.detector.distance = self.default.detector_distance 94 self.slit1.distance = self.default.slit1_distance 95 self.slit2.distance = self.default.slit2_distance 96 self.slit3.distance = self.default.slit3_distance 97 self.slit4.distance = self.default.slit4_distance 98 self.detector.rotation = 0 # degrees 99 self.monitor.time_step = self.default.monitor_timestep 100 101 # Initialize detector information 102 if data.PSD: 103 self.instrument += " PSD" 104 self.detector.saturation = self.default.psd_saturation 105 self.detector.size = self.default.psd_size 106 else: 107 self.detector.saturation = self.default.saturation 108 self.detector.size = self.default.pencil_size 109 self.display_monitor = data.monitor*data.prefactor 110 111 112 # Warn incorrect wavelength 113 if data.wavelength != self.default.wavelength: 114 self.warn("Unexpected wavelength: expected %g but got %g"\ 115 %(self.default.wavelength,data.wavelength)) 116 self.detector.wavelength = data.wavelength 117 118 # Callback for lazy data 119 self.detector.loadcounts = self.loadcounts 120 121 # Set initial Qz 122 self.resetQ()123 124126 # Load the counts from the data file 127 data = icpformat.read(self.path) 128 return data.counts129131 # Load the icp data 132 data = icpformat.read(self.path) 133 if data.counts.ndim == 1: 134 self.detector.dims = (1,1) 135 elif data.counts.ndim == 2: 136 self.detector.dims = (data.counts.shape[1],1) 137 elif data.counts.ndim == 3: 138 self.detector.dims = (data.counts.shape[1],data.counts.shape[2]) 139 else: 140 raise RuntimeError("Data has too many dimensions in "+self.path) 141 142 # Slits are either stored in the file or available from the 143 # motor information. For non-reflectometry scans they may 144 # not be available. 145 if 'a1' in data: self.slit1.x = data.column.a1 146 if 'a2' in data: self.slit2.x = data.column.a2 147 if 'a5' in data: self.slit3.x = data.column.a5 148 if 'a6' in data: self.slit4.x = data.column.a6 149 150 # Angles are either stored in the file or can be calculated 151 # from the motor details. For non-reflectometry scans they 152 # may not be available. 153 if 'a3' in data: self.sample.angle_x = data.column.a3 154 if 'a4' in data: self.detector.angle_x = data.column.a4 155 156 # Polarization was extracted from the comment line 157 self.polarization = data.polarization 158 159 # Monitor counts may be recorded or may be inferred from header 160 if 'monitor' in data: 161 # Prefer the monitor column if it exists 162 self.monitor.counts = data.column.monitor 163 elif data.count_type == 'NEUT': 164 # if count by neutron, the 'monitor' field stores counts 165 self.monitor.counts \ 166 = data.monitor*data.prefactor*numpy.ones(data.points,'i') 167 else: 168 # Need monitor rate for normalization; the application 169 # will have to provide the means of setting the rate 170 # and computing the counts based on that rate. 171 pass 172 173 # Counting time may be recorded or may be inferred from header 174 if data.count_type == 'TIME': 175 # Prefer the target value to the time column when counting by 176 # time because the time column is recorded in minutes rather 177 # than seconds and is not precise enough. 178 # if count by time, the 'monitor' field stores seconds 179 self.monitor.count_time \ 180 = data.monitor*data.prefactor*numpy.ones(data.points,'f') 181 elif 'time' in data: 182 self.monitor.count_time = data.column.time*60 183 else: 184 # Need monitor rate for normalization; the application 185 # will have to provide the means of setting the rate 186 # and computing the time based on that rate. 187 pass 188 189 # Set initial Qz 190 self.resetQ() 191 192 # TODO: if counts are huge we may want to make this lazy 193 self.detector.counts = data.counts194196 """ 197 Returns the default area correction that can be applied to the data. 198 """ 199 from reflectometry.reduction import areacor 200 nx,ny = self.detector.dims 201 Ax,Ay = self.detector.solid_angle 202 wx = (1+0.15*cos(2*pi*numpy.arange(nx)/32.))/nx * Ax 203 wy = (1+0.15*cos(2*pi*numpy.arange(ny)/32.))/ny * Ay 204 return areacor.AreaCorrection(wx,wy,source="15% * cos(2 pi k/32)")
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Tue Mar 17 14:22:23 2009 | http://epydoc.sourceforge.net |