def __init__(self, odrange=None, channels=None, nside=1024, ordering='RING', coord='E', outmap='outmap.fits', exchange_folder=None, fpdb=None, output_xml='toastrun.xml', ahf_folder=None, components='IQU', obtmask=None, flagmask=None, log_level=l.INFO, remote_exchange_folder=None, remote_ahf_folder=None, calibration_file=None, dipole_removal=False, noise_tod=False, noise_tod_weight=None, efftype=None, flag_HFI_bad_rings=None, include_preFLS=False, ptcorfile=None, include_repointings=False, psd=None, deaberrate=True, extend_857=False, no_wobble=False, eff_is_for_flags=False, exchange_weights=None, beamsky=None, beamsky_weight=None, interp_order=5, horn_noise_tod=None, horn_noise_weight=None, horn_noise_psd=None, observation_is_interval=False, lfi_ring_range=None, hfi_ring_range=None, wobble_high=False): """TOAST configuration: odrange: list of start and end OD, AHF ODS, i.e. with whole pointing periods as the DPC is using lfi_ring_range: first and last LFI pointing ID to include hfi_ring_range: first and last HFI ring number to include channels: one of integer frequency, channel string, list of channel strings obtmask and flagmask: default LFI 1,255 HFI 1,1 exchange_folder: either a string or a container or strings listing locations for Exchange Format data exchange_weights: list of scaling factors to apply to Exchange data prior to coadding eff_is_for_flags : only use Exchange data for flags remote_exchange_folder, remote_ahf_folder: they allow to run toast.py in one environment using ahf_folder and exchange_folder and then replace the path with the remote folders calibration_file: path to a fits calibration file, with first extension OBT, then one extension per channel with the calibration factors dipole_removal: dipole removal is performed ONLY if calibration is specified noise_tod: Add simulated noise TODs noise_tod_weight: scaling factor to apply to noise_tod flag_HFI_bad_rings: if None, flagged just for HFI. If a valid file, use that as input. include_preFLS : if None, True for LFI include_repointings : Construct intervals with the 4 minute repointing maneuvers: 10% dataset increase, continuous time stamps psd : templated name of an ASCII PSD files. Tag CHANNEL will be replaced with the appropriate channel identifier. horn_noise_tod : False horn_noise_weight : None horn_noise_psd : templated name of an ASCII PSD files. Tag HORN will be replaced with the appropriate identifier. deaberrate : Correct pointing for aberration extend_857 : Whether or not to include the RTS bolometer, 857-4 in processing no_wobble : Disable all flavors of wobble angle correction wobble_high : Use 8Hz wobble correction rather than per ring beamsky : templated name of the beamsky files for OTF sky convolution. Tag CHANNEL will be replaced with the appropriate channel identifier. beamsky_weight : scaling factor to apply to the beamsky interp_order : beamsky interpolation order defines number of cartesian pixels to interpolate over observation_is_interval : If True, do not split operational days into pointing period intervals additional configuration options are available modifying: .config and Data Selector configuration: .data_selector.config dictionaries before running .run() """ l.root.level = log_level self.extend_857 = extend_857 if self.extend_857: if '857-4' in EXCLUDED_CH: EXCLUDED_CH.remove('857-4') if sum([odrange!=None, lfi_ring_range!=None, hfi_ring_range!=None]) != 1: raise Exception('Must specify exactly one type of data span: OD, LFI PID or HFI ring') self.odrange = odrange self.lfi_ring_range = lfi_ring_range self.hfi_ring_range = hfi_ring_range self.nside = nside self.coord = coord self.ordering = ordering self.outmap = outmap if channels == None: raise Exception('Must define which channels to include') self.channels = parse_channels(channels) self.f = self.channels[0].f self.output_xml = output_xml self.ptcorfile = ptcorfile if no_wobble and wobble_high: raise Exception('no_wobble and wobble_high are mutually exclusive') self.no_wobble = no_wobble self.wobble_high = wobble_high self.include_repointings = include_repointings self.deaberrate = deaberrate self.noise_tod = noise_tod self.noise_tod_weight = noise_tod_weight self.psd = psd self.horn_noise_tod = horn_noise_tod self.horn_noise_weight = horn_noise_weight self.horn_noise_psd = horn_noise_psd if self.horn_noise_tod and not self.horn_noise_psd: raise Exception('Must specify horn_noise_psd template name when enabling horn_noise') self.fpdb = fpdb or private.rimo[self.f.inst.name] self.beamsky = beamsky self.beamsky_weight = beamsky_weight self.interp_order = interp_order self.observation_is_interval = observation_is_interval self.rngorder = { 'LFI18M' : 0, 'LFI18S' : 1, 'LFI19M' : 2, 'LFI19S' : 3, 'LFI20M' : 4, 'LFI20S' : 5, 'LFI21M' : 6, 'LFI21S' : 7, 'LFI22M' : 8, 'LFI22S' : 9, 'LFI23M' : 10, 'LFI23S' : 11, 'LFI24M' : 12, 'LFI24S' : 13, 'LFI25M' : 14, 'LFI25S' : 15, 'LFI26M' : 16, 'LFI26S' : 17, 'LFI27M' : 18, 'LFI27S' : 19, 'LFI28M' : 20, 'LFI28S' : 21, '100-1a' : 22, '100-1b' : 23, '100-2a' : 24, '100-2b' : 25, '100-3a' : 26, '100-3b' : 27, '100-4a' : 28, '100-4b' : 29, '143-1a' : 30, '143-1b' : 31, '143-2a' : 32, '143-2b' : 33, '143-3a' : 34, '143-3b' : 35, '143-4a' : 36, '143-4b' : 37, '143-5' : 38, '143-6' : 39, '143-7' : 40, '143-8' : 41, '217-5a' : 42, '217-5b' : 43, '217-6a' : 44, '217-6b' : 45, '217-7a' : 46, '217-7b' : 47, '217-8a' : 48, '217-8b' : 49, '217-1' : 50, '217-2' : 51, '217-3' : 52, '217-4' : 53, '353-3a' : 54, '353-3b' : 55, '353-4a' : 56, '353-4b' : 57, '353-5a' : 58, '353-5b' : 59, '353-6a' : 60, '353-6b' : 61, '353-1' : 62, '353-2' : 63, '353-7' : 64, '353-8' : 65, '545-1' : 66, '545-2' : 67, '545-3' : 68, '545-4' : 69, '857-1' : 70, '857-2' : 71, '857-3' : 72, '857-4' : 73, 'LFI18' : 74, 'LFI19' : 75, 'LFI20' : 76, 'LFI21' : 77, 'LFI22' : 78, 'LFI23' : 79, 'LFI24' : 80, 'LFI25' : 81, 'LFI26' : 82, 'LFI27' : 83, 'LFI28' : 84, '100-1' : 85, '100-2' : 86, '100-3' : 87, '100-4' : 88, '143-1' : 89, '143-2' : 90, '143-3' : 91, '143-4' : 92, '217-5' : 93, '217-6' : 94, '217-7' : 95, '217-8' : 96, '353-3' : 97, '353-4' : 98, '353-5' : 99, '353-6' : 100, } self.config = {} if self.f.inst.name == 'LFI': self.config['pairflags'] = True else: self.config['pairflags'] = False if efftype is None: efftype ='R' if self.f.inst.name == 'LFI' and (not calibration_file is None): efftype ='C' self.data_selector = DataSelector(channels=self.channels, efftype=efftype, include_preFLS=include_preFLS) self.exchange_weights = exchange_weights if remote_exchange_folder: if isinstance(remote_exchange_folder, str): remote_exchange_folder = [remote_exchange_folder] if remote_exchange_folder[-1] != '/': remote_exchange_folder += '/' self.remote_exchange_folder = remote_exchange_folder if remote_ahf_folder: if remote_ahf_folder[-1] != '/': remote_ahf_folder += '/' self.remote_ahf_folder = remote_ahf_folder if exchange_folder: if isinstance(exchange_folder, str): exchange_folder = [exchange_folder] self.exchange_folder = exchange_folder self.data_selector.config[ 'exchangefolder' ] = exchange_folder[0] if ahf_folder: self.data_selector.config['ahf_folder'] = ahf_folder if self.odrange: self.data_selector.by_od_range(self.odrange) elif self.lfi_ring_range: self.data_selector.by_lfi_rings(self.lfi_ring_range) elif self.hfi_ring_range: self.data_selector.by_hfi_rings(self.hfi_ring_range) else: raise Exception('Must specify one type of data span') self.wobble = private.WOBBLE self.components = components self.obtmask = obtmask or DEFAULT_OBTMASK[self.f.inst.name] self.flagmask = flagmask or DEFAULT_FLAGMASK[self.f.inst.name] self.calibration_file = calibration_file self.dipole_removal = dipole_removal if flag_HFI_bad_rings is None: if self.f.inst.name == 'HFI': flag_HFI_bad_rings = True else: flag_HFI_bad_rings = False if flag_HFI_bad_rings: if ( os.path.isfile(str(flag_HFI_bad_rings)) ): self.bad_rings = flag_HFI_bad_rings else: self.bad_rings = private.HFI_badrings else: self.bad_rings = None self.eff_is_for_flags = eff_is_for_flags self.fptab = None
class ToastConfig(object): """Toast configuration class""" def __init__(self, odrange=None, channels=None, nside=1024, ordering='RING', coord='E', outmap='outmap.fits', exchange_folder=None, fpdb=None, output_xml='toastrun.xml', ahf_folder=None, components='IQU', obtmask=None, flagmask=None, log_level=l.INFO, remote_exchange_folder=None, remote_ahf_folder=None, calibration_file=None, dipole_removal=False, noise_tod=False, noise_tod_weight=None, efftype=None, flag_HFI_bad_rings=None, include_preFLS=False, ptcorfile=None, include_repointings=False, psd=None, deaberrate=True, extend_857=False, no_wobble=False, eff_is_for_flags=False, exchange_weights=None, beamsky=None, beamsky_weight=None, interp_order=5, horn_noise_tod=None, horn_noise_weight=None, horn_noise_psd=None, observation_is_interval=False, lfi_ring_range=None, hfi_ring_range=None, wobble_high=False): """TOAST configuration: odrange: list of start and end OD, AHF ODS, i.e. with whole pointing periods as the DPC is using lfi_ring_range: first and last LFI pointing ID to include hfi_ring_range: first and last HFI ring number to include channels: one of integer frequency, channel string, list of channel strings obtmask and flagmask: default LFI 1,255 HFI 1,1 exchange_folder: either a string or a container or strings listing locations for Exchange Format data exchange_weights: list of scaling factors to apply to Exchange data prior to coadding eff_is_for_flags : only use Exchange data for flags remote_exchange_folder, remote_ahf_folder: they allow to run toast.py in one environment using ahf_folder and exchange_folder and then replace the path with the remote folders calibration_file: path to a fits calibration file, with first extension OBT, then one extension per channel with the calibration factors dipole_removal: dipole removal is performed ONLY if calibration is specified noise_tod: Add simulated noise TODs noise_tod_weight: scaling factor to apply to noise_tod flag_HFI_bad_rings: if None, flagged just for HFI. If a valid file, use that as input. include_preFLS : if None, True for LFI include_repointings : Construct intervals with the 4 minute repointing maneuvers: 10% dataset increase, continuous time stamps psd : templated name of an ASCII PSD files. Tag CHANNEL will be replaced with the appropriate channel identifier. horn_noise_tod : False horn_noise_weight : None horn_noise_psd : templated name of an ASCII PSD files. Tag HORN will be replaced with the appropriate identifier. deaberrate : Correct pointing for aberration extend_857 : Whether or not to include the RTS bolometer, 857-4 in processing no_wobble : Disable all flavors of wobble angle correction wobble_high : Use 8Hz wobble correction rather than per ring beamsky : templated name of the beamsky files for OTF sky convolution. Tag CHANNEL will be replaced with the appropriate channel identifier. beamsky_weight : scaling factor to apply to the beamsky interp_order : beamsky interpolation order defines number of cartesian pixels to interpolate over observation_is_interval : If True, do not split operational days into pointing period intervals additional configuration options are available modifying: .config and Data Selector configuration: .data_selector.config dictionaries before running .run() """ l.root.level = log_level self.extend_857 = extend_857 if self.extend_857: if '857-4' in EXCLUDED_CH: EXCLUDED_CH.remove('857-4') if sum([odrange!=None, lfi_ring_range!=None, hfi_ring_range!=None]) != 1: raise Exception('Must specify exactly one type of data span: OD, LFI PID or HFI ring') self.odrange = odrange self.lfi_ring_range = lfi_ring_range self.hfi_ring_range = hfi_ring_range self.nside = nside self.coord = coord self.ordering = ordering self.outmap = outmap if channels == None: raise Exception('Must define which channels to include') self.channels = parse_channels(channels) self.f = self.channels[0].f self.output_xml = output_xml self.ptcorfile = ptcorfile if no_wobble and wobble_high: raise Exception('no_wobble and wobble_high are mutually exclusive') self.no_wobble = no_wobble self.wobble_high = wobble_high self.include_repointings = include_repointings self.deaberrate = deaberrate self.noise_tod = noise_tod self.noise_tod_weight = noise_tod_weight self.psd = psd self.horn_noise_tod = horn_noise_tod self.horn_noise_weight = horn_noise_weight self.horn_noise_psd = horn_noise_psd if self.horn_noise_tod and not self.horn_noise_psd: raise Exception('Must specify horn_noise_psd template name when enabling horn_noise') self.fpdb = fpdb or private.rimo[self.f.inst.name] self.beamsky = beamsky self.beamsky_weight = beamsky_weight self.interp_order = interp_order self.observation_is_interval = observation_is_interval self.rngorder = { 'LFI18M' : 0, 'LFI18S' : 1, 'LFI19M' : 2, 'LFI19S' : 3, 'LFI20M' : 4, 'LFI20S' : 5, 'LFI21M' : 6, 'LFI21S' : 7, 'LFI22M' : 8, 'LFI22S' : 9, 'LFI23M' : 10, 'LFI23S' : 11, 'LFI24M' : 12, 'LFI24S' : 13, 'LFI25M' : 14, 'LFI25S' : 15, 'LFI26M' : 16, 'LFI26S' : 17, 'LFI27M' : 18, 'LFI27S' : 19, 'LFI28M' : 20, 'LFI28S' : 21, '100-1a' : 22, '100-1b' : 23, '100-2a' : 24, '100-2b' : 25, '100-3a' : 26, '100-3b' : 27, '100-4a' : 28, '100-4b' : 29, '143-1a' : 30, '143-1b' : 31, '143-2a' : 32, '143-2b' : 33, '143-3a' : 34, '143-3b' : 35, '143-4a' : 36, '143-4b' : 37, '143-5' : 38, '143-6' : 39, '143-7' : 40, '143-8' : 41, '217-5a' : 42, '217-5b' : 43, '217-6a' : 44, '217-6b' : 45, '217-7a' : 46, '217-7b' : 47, '217-8a' : 48, '217-8b' : 49, '217-1' : 50, '217-2' : 51, '217-3' : 52, '217-4' : 53, '353-3a' : 54, '353-3b' : 55, '353-4a' : 56, '353-4b' : 57, '353-5a' : 58, '353-5b' : 59, '353-6a' : 60, '353-6b' : 61, '353-1' : 62, '353-2' : 63, '353-7' : 64, '353-8' : 65, '545-1' : 66, '545-2' : 67, '545-3' : 68, '545-4' : 69, '857-1' : 70, '857-2' : 71, '857-3' : 72, '857-4' : 73, 'LFI18' : 74, 'LFI19' : 75, 'LFI20' : 76, 'LFI21' : 77, 'LFI22' : 78, 'LFI23' : 79, 'LFI24' : 80, 'LFI25' : 81, 'LFI26' : 82, 'LFI27' : 83, 'LFI28' : 84, '100-1' : 85, '100-2' : 86, '100-3' : 87, '100-4' : 88, '143-1' : 89, '143-2' : 90, '143-3' : 91, '143-4' : 92, '217-5' : 93, '217-6' : 94, '217-7' : 95, '217-8' : 96, '353-3' : 97, '353-4' : 98, '353-5' : 99, '353-6' : 100, } self.config = {} if self.f.inst.name == 'LFI': self.config['pairflags'] = True else: self.config['pairflags'] = False if efftype is None: efftype ='R' if self.f.inst.name == 'LFI' and (not calibration_file is None): efftype ='C' self.data_selector = DataSelector(channels=self.channels, efftype=efftype, include_preFLS=include_preFLS) self.exchange_weights = exchange_weights if remote_exchange_folder: if isinstance(remote_exchange_folder, str): remote_exchange_folder = [remote_exchange_folder] if remote_exchange_folder[-1] != '/': remote_exchange_folder += '/' self.remote_exchange_folder = remote_exchange_folder if remote_ahf_folder: if remote_ahf_folder[-1] != '/': remote_ahf_folder += '/' self.remote_ahf_folder = remote_ahf_folder if exchange_folder: if isinstance(exchange_folder, str): exchange_folder = [exchange_folder] self.exchange_folder = exchange_folder self.data_selector.config[ 'exchangefolder' ] = exchange_folder[0] if ahf_folder: self.data_selector.config['ahf_folder'] = ahf_folder if self.odrange: self.data_selector.by_od_range(self.odrange) elif self.lfi_ring_range: self.data_selector.by_lfi_rings(self.lfi_ring_range) elif self.hfi_ring_range: self.data_selector.by_hfi_rings(self.hfi_ring_range) else: raise Exception('Must specify one type of data span') self.wobble = private.WOBBLE self.components = components self.obtmask = obtmask or DEFAULT_OBTMASK[self.f.inst.name] self.flagmask = flagmask or DEFAULT_FLAGMASK[self.f.inst.name] self.calibration_file = calibration_file self.dipole_removal = dipole_removal if flag_HFI_bad_rings is None: if self.f.inst.name == 'HFI': flag_HFI_bad_rings = True else: flag_HFI_bad_rings = False if flag_HFI_bad_rings: if ( os.path.isfile(str(flag_HFI_bad_rings)) ): self.bad_rings = flag_HFI_bad_rings else: self.bad_rings = private.HFI_badrings else: self.bad_rings = None self.eff_is_for_flags = eff_is_for_flags self.fptab = None def parse_fpdb(self, channel, key): if self.fptab == None: fptab = pyfits.getdata(self.fpdb, 1) ind = (fptab.field('DETECTOR') == channel).ravel() if np.sum(ind) != 1: raise Exception('Error matching {} in {}: {} matches.'.format(channel, self.fpdb, np.sum(ind))) return fptab.field(key)[ind][0] def run(self, write=True): """Call the python-toast bindings to create the xml configuration file""" self.conf = Run() if self.noise_tod or self.horn_noise_tod: self.conf.variable_add ( "rngbase", "native", Params({"default":"0"}) ) sky = self.conf.sky_add ( "sky", "native", ParMap() ) mapset = sky.mapset_add ( '_'.join(['healpix',self.components, self.ordering]), "healpix", Params({ "path" : self.outmap, "fullsky" : "TRUE", "stokes" : self.components, "order" : self.ordering, "coord" : self.coord, "nside" : str(self.nside), "units" : "micro-K" })) #if self.f.inst.name == 'LFI': # wobble_offset = 0; #else: # wobble_offset = self.wobble["psi2_offset"] if self.no_wobble: teleparams = { "wobble_ahf_high":"FALSE", "wobble_ahf_obs":"FALSE", "wobblepsi2dir":"" } else: if self.wobble_high: wobble_obs = 'FALSE' wobble_high = 'TRUE' else: wobble_obs = 'TRUE' wobble_high = 'FALSE' teleparams = { #"wobblepsi2dir":self.wobble["psi2_dir"], "wobblepsi2_ref":self.wobble["psi2_ref"], "wobblepsi1_ref":self.wobble["psi1_ref"], "wobble_ahf_obs":wobble_obs, "wobble_ahf_high":wobble_high #"wobblepsi2_offset":wobble_offset } if self.ptcorfile: teleparams['ptcorfile'] = self.ptcorfile if self.deaberrate != None: if self.deaberrate: teleparams['deaberrate'] = 'TRUE' else: teleparams['deaberrate'] = 'FALSE' tele = self.conf.telescope_add ( "planck", "planck", Params(teleparams)) fp = tele.focalplane_add ( "FP_%s" % self.f.inst.name, "planck_rimo", Params({"path":self.fpdb}) ) self.add_pointing(tele) self.add_observations(tele) self.add_streams() self.add_eff_tods() self.add_noise() self.add_channels(tele) if write: self.write() def write(self): # write out XML self.conf.write ( self.output_xml ) def add_pointing(self, telescope): # Add pointing files for i,ahf in enumerate(self.data_selector.get_AHF()): path = str(ahf[0]) if self.remote_ahf_folder: path = path.replace(self.data_selector.config['ahf_folder'], self.remote_ahf_folder) telescope.pointing_add ( "%04d" % i, "planck_ahf", Params({"path": path})) @property def observations(self): try: return self._observations except: self._observations = self.data_selector.get_OBS() return self.observations def add_observations(self, telescope): """Each observation is an OD as specified in the AHF files""" # Add streamset self.strset = telescope.streamset_add ( self.f.inst.name, "native", Params() ) # Add observations # For Planck, each observation must cache the timestamps for all days included # in the observation, which is very expensive. For this reason, the number of # ODs in a single observation should be the minimum necessary for the size of # the interval being considered. For applications which do not care about noise # stationarity or which are only dealing with ring-by-ring quantities, one OD # per observation is fine. If you wish to consider intervals longer than a day # as a single stationary interval, then each observation will need to include # multiple ODs. # For "planck_exchange" format, if no "start" or "stop" times are specified, # then the observation will span the time range of the EFF data specified in # the "times1", "times2", "times3", etc parameters. broken_od = defaultdict(None) # Observations are same for all datasets but now there may be # several exchange folders and raw streams to add. Therefore # tod_name_list and tod_par_list are lists of dictionaries. self.tod_name_list = [] self.tod_par_list = [] for i in range(len(self.exchange_folder)): self.tod_name_list.append( defaultdict(list) ) self.tod_par_list.append( defaultdict(list) ) # Add observations for iobs, observation in enumerate(self.observations): params = {"start":observation.start, "stop":observation.stop} for i, eff in enumerate(observation.EFF): if self.remote_exchange_folder: params[ "times%d" % (i+1) ] = eff.replace(self.exchange_folder[0], self.remote_exchange_folder[0]) else: params[ "times%d" % (i+1) ] = eff obs = self.strset.observation_add ( "%04d%s" % (observation.od, observation.tag) , "planck_exchange", Params(params) ) if self.observation_is_interval: # intervals are observations obs.interval_add( '{:04}'.format(iobs), "native", Params({"start":observation.start, "stop":observation.stop}) ) else: pointing_periods = observation.PP if self.include_repointings: # First interval begins with the operational day, last one ends with it. New interval begins when the old stable pointing ends. # First and last included samples remain the same. for ipp, pp in enumerate(pointing_periods): if ipp == 0: # Remove the comments in this section to include period between OD and ring start #if iobs == 0: obs.interval_add( "%05d-%d" % (pp.number, pp.splitnumber), "native", Params({"start":pp.start, "stop":pointing_periods[ipp+1].start}) ) #else: # obs.interval_add( "%05d-%d" % (pp.number, pp.splitnumber), "native", Params({"start":observation.start, "stop":pointing_periods[ipp+1].start}) ) elif ipp == len(pointing_periods) - 1: if iobs == len(self.observations) - 1: obs.interval_add( "%05d-%d" % (pp.number, pp.splitnumber), "native", Params({"start":pp.start, "stop":pp.stop}) ) else: obs.interval_add( "%05d-%d" % (pp.number, pp.splitnumber), "native", Params({"start":pp.start, "stop":observation.stop}) ) else: obs.interval_add( "%05d-%d" % (pp.number, pp.splitnumber), "native", Params({"start":pp.start, "stop":pointing_periods[ipp+1].start}) ) else: # Intervals are the stable pointing periods for pp in pointing_periods: obs.interval_add( "%05d-%d" % (pp.number, pp.splitnumber), "native", Params({"start":pp.start, "stop":pp.stop}) ) for ch in self.channels: print("Observation %d%s, EFF ODs:%s" % (observation.od, observation.tag, str(map(get_eff_od, observation.EFF)))) for ix, fx in enumerate(self.exchange_folder): for i, file_path in enumerate(observation.EFF): eff_od = get_eff_od(file_path) # Add TODs for this stream params = {} params[ "flagmask" ] = self.flagmask params[ "obtmask" ] = self.obtmask params[ "hdu" ] = ch.eff_tag if self.config['pairflags']: params[ "pairflags" ] = 'TRUE' if self.remote_exchange_folder: params[ "path" ] = file_path.replace(self.exchange_folder[0], self.remote_exchange_folder[ix]) else: params[ "path" ] = file_path.replace(self.exchange_folder[0], self.exchange_folder[ix]) tag = '' if i==(len(observation.EFF)-1) and not observation.break_startrow is None: params['rows'] = observation.break_startrow + 1 tag = 'a' broken_od[ch.tag] = eff_od if not observation.break_stoprow is None and broken_od[ch.tag]==eff_od: params['startrow'] = observation.break_stoprow tag = 'b' broken_od[ch.tag] = None name = "%s_%d%s" % (ch.tag, eff_od, tag) if name not in self.tod_name_list[ix][ch.tag]: print('add ' + name) self.tod_name_list[ix][ch.tag].append(name) self.tod_par_list[ix][ch.tag].append(params) else: print("skip " + name) def add_streams(self): # Add streams for data components basename = "@rngbase@" self.strm = {} for ch in self.channels: stack_elements = [] # add simulated noise stream if self.noise_tod: rngstream = self.rngorder[ ch.tag ] * 100000 noisename = "/planck/" + self.f.inst.name + "/noise_" + ch.tag self.strm["simnoise_" + ch.tag] = self.strset.stream_add( "simnoise_" + ch.tag, "native", Params( ) ) suffix = '' if self.noise_tod_weight: suffix += ',PUSH:$' + strconv(self.noise_tod_weight) + ',MUL' stack_elements.append( "PUSH:simnoise_" + ch.tag + suffix) if self.observation_is_interval: # one noise tod per observation. # # FIXME: this code will not work. the start and stop times # must be the *detector* start and stop times inside # the observation boundaries (which are set by the AHF). # so you must iterate over self.pp_boundaries and find # the first and last valid detector times inside this observation. # for iobs, observation in enumerate(self.observations): self.strm["simnoise_" + ch.tag].tod_add ( "nse_%s_%05d" % (ch.tag, iobs), "sim_noise", Params({ "noise" : noisename, "base" : basename, "start" : observation.start, "stop" : observation.stop, "offset" : rngstream + iobs })) else: # one noise tod per pointing period self.pp_boundaries = PPBoundaries(self.f.freq, self.data_selector.config['database']) for row, pp_boundaries in enumerate(self.pp_boundaries.ppf): if pp_boundaries[1] < self.observations[0].start or pp_boundaries[0] > self.observations[-1].stop: continue self.strm["simnoise_" + ch.tag].tod_add ( "nse_%s_%05d" % (ch.tag, row), "sim_noise", Params({ "noise" : noisename, "base" : basename, "start" : pp_boundaries[0], "stop" : pp_boundaries[1], "offset" : rngstream + row })) # add simulated noise stream common to each horn if self.horn_noise_tod and ch.tag[-1] in 'MSab': horn = ch.tag[:-1] rngstream = self.rngorder[ horn ] * 100000 noisename = "/planck/" + self.f.inst.name + "/noise_" + horn self.strm["simnoise_" + horn] = self.strset.stream_add( "simnoise_" + horn, "native", Params( ) ) suffix = '' if self.horn_noise_weight: suffix += ',PUSH:$' + strconv(self.horn_noise_weight) + ',MUL' if len(stack_elements) != 0: suffix += ',ADD' stack_elements.append( "PUSH:simnoise_" + horn + suffix) if self.observation_is_interval: # one noise tod per observation for iobs, observation in enumerate(self.observations): self.strm["simnoise_" + horn].tod_add ( "nse_%s_%05d" % (horn, iobs), "sim_noise", Params({ "noise" : noisename, "base" : basename, "start" : observation.start, "stop" : observation.stop, "offset" : rngstream + iobs })) else: # one noise tod per pointing period self.pp_boundaries = PPBoundaries(self.f.freq) for row, pp_boundaries in enumerate(self.pp_boundaries.ppf): if pp_boundaries[1] < self.observations[0].start or pp_boundaries[0] > self.observations[-1].stop: continue self.strm["simnoise_" + horn].tod_add ( "nse_%s_%05d" % (horn, row), "sim_noise", Params({ "noise" : noisename, "base" : basename, "start" : pp_boundaries[0], "stop" : pp_boundaries[1], "offset" : rngstream + row })) # add the beam sky if self.beamsky: epsilon = self.parse_fpdb(ch.tag, 'epsilon') #beamskyname = '/planck/' + self.f.inst.name + '/' + ch.tag beamskyname = '/planck/' + ch.tag self.strm["beamsky_" + ch.tag] = self.strset.stream_add( "beamsky_" + ch.tag, "planck_beamsky", Params({ 'path' : self.beamsky.replace('CHANNEL', ch.tag), 'epsilon' : str(epsilon), 'interp_order' : str(self.interp_order), 'coord' : self.coord, 'channel' : beamskyname }) ) suffix = '' if self.beamsky_weight: suffix += ',PUSH:$' + strconv(self.beamsky_weight) + ',MUL' if len(stack_elements) != 0: suffix += ',ADD' stack_elements.append( "PUSH:beamsky_" + ch.tag + suffix) # add real data streams, either for flags or data plus flags for i, x in enumerate(self.exchange_folder): self.strm[ 'raw{}_{}'.format(i, ch.tag) ] = self.strset.stream_add( "raw{}_{}".format(i, ch.tag), "native", Params() ) if self.eff_is_for_flags: suffix = ',FLG' else: suffix = '' if self.exchange_weights: suffix = ',PUSH:$' + strconv(self.exchange_weights[i]) + ',MUL' if len(stack_elements) != 0: suffix += ',ADD' stack_elements.append( "PUSH:raw{}_{}{}".format(i, ch.tag, suffix) ) # add calibration stream if (not self.calibration_file is None): self.strm["cal_" + ch.tag] = self.strset.stream_add( "cal_" + ch.tag, "planck_cal", Params( {"hdu":ch.tag, "path":self.calibration_file } ) ) stack_elements.append("PUSH:cal_" + ch.tag + ",MUL") # dipole subtract if self.dipole_removal: self.strm["dipole_" + ch.tag] = self.strset.stream_add( "dipole_" + ch.tag, "dipole", Params( {"channel":ch.tag, "coord":"E"} ) ) stack_elements.append("PUSH:dipole_" + ch.tag + ",SUB") # bad rings if not self.bad_rings is None: self.strm["bad_" + ch.tag] = self.strset.stream_add ( "bad_" + ch.tag, "planck_bad", Params({'detector':ch.tag, 'path':self.bad_rings}) ) stack_elements.append("PUSH:bad_" + ch.tag + ",FLG") # stack expr = ','.join([el for el in stack_elements]) self.strm["stack_" + ch.tag] = self.strset.stream_add ( "stack_" + ch.tag, "stack", Params( {"expr":expr} ) ) def add_eff_tods(self): """Add TOD files already included in tod_name_list and tod_par_list to the streamset""" for ix in range(len(self.exchange_folder)): # remove duplicate files on breaks for ch in self.channels: for name in [n for n in self.tod_name_list[ix][ch.tag] if n.endswith('a')]: try: delindex = self.tod_name_list[ix][ch.tag].index(name.rstrip('a')) print('Removing %s because of breaks' % self.tod_name_list[ix][ch.tag][delindex]) del self.tod_name_list[ix][ch.tag][delindex] del self.tod_par_list[ix][ch.tag][delindex] except exceptions.ValueError: pass # add EFF to stream for ch in self.channels: for name, par in zip(self.tod_name_list[ix][ch.tag], self.tod_par_list[ix][ch.tag]): self.strm[ "raw{}_{}".format(ix, ch.tag) ].tod_add ( name, "planck_exchange", Params(par) ) def add_noise(self): # Add RIMO noise model (LFI) or mission average PSD (HFI) for ch in self.channels: noise = self.strset.noise_add ( "noise_" + ch.tag, "native", Params() ) # add PSD if self.psd: psdname = self.psd.replace('CHANNEL', ch.tag) noise.psd_add ( "psd", "ascii", Params({ "start" : self.strset.observations()[0].start(), "stop" : self.strset.observations()[-1].stop(), "path": psdname })) else: noise.psd_add ( "psd", "planck_rimo", Params({ "start" : self.strset.observations()[0].start(), "stop" : self.strset.observations()[-1].stop(), "path": self.fpdb, "detector": ch.tag })) # add horn noise psd if self.horn_noise_tod and ch.tag[-1] in 'aM': horn = ch.tag[:-1] noise = self.strset.noise_add ( "noise_" + horn, "native", Params() ) psdname = self.horn_noise_psd.replace('HORN', horn) noise.psd_add ( "psd", "ascii", Params({ "start" : self.strset.observations()[0].start(), "stop" : self.strset.observations()[-1].stop(), "path": psdname })) def add_channels(self, telescope): params = ParMap() params[ "focalplane" ] = self.conf.telescopes()[0].focalplanes()[0].name() for ch in self.channels: params[ "detector" ] = ch.tag params[ "stream" ] = "/planck/%s/stack_%s" % (self.f.inst.name, ch.tag) params[ "noise" ] = "/planck/%s/noise_%s" % (self.f.inst.name, ch.tag) telescope.channel_add ( ch.tag, "native", params )