def __init__(self, bolo_name, config): self.name = bolo_name self.config = Generic() bolo_config = importlib.import_module(config.bolo_config_file).bolo_config.bolos[bolo_name] self.config.__dict__.update(config.__dict__) self.config.__dict__.update(bolo_config.__dict__) if config.simulate_ts: self.calculate_params() self.beam = Beam(self.config, bolo_config) self.noise_class = Noise(self.config) if not config.sim_pol_type == "noise_only": self.get_sky_map() self.get_initial_axes() self.get_nsamples() self.set_bolo_dirs()
class Bolo: def __init__(self, bolo_name, config): self.name = bolo_name self.config = Generic() bolo_config = importlib.import_module(config.bolo_config_file).bolo_config.bolos[bolo_name] self.config.__dict__.update(config.__dict__) self.config.__dict__.update(bolo_config.__dict__) if config.simulate_ts: self.calculate_params() self.beam = Beam(self.config, bolo_config) self.noise_class = Noise(self.config) if not config.sim_pol_type == "noise_only": self.get_sky_map() self.get_initial_axes() self.get_nsamples() self.set_bolo_dirs() #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#* # Simulating the time-ordered data for a given bolo with any beam #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#* # def get_timestream(self, segment, read_list=["signal", "v", "pol_ang"]): # if config.simulate def read_timestream(self, segment, noise_only=False, read_list=["signal", "v", "pol_ang"]): segment_dir = self.get_segment_dir(segment) t_stream = {"signal" : None, "v" : None, "pol_ang" : None} if "signal" in read_list: if noise_only: t_stream["signal"] = np.load(os.path.join(segment_dir, "noise.npy")) else: t_stream["signal"] = np.load(os.path.join(segment_dir, "signal.npy")) if "v" in read_list: t_stream["v"] = np.load(os.path.join(segment_dir, "pointing_vec.npy")) if "pol_ang" in read_list: t_stream["pol_ang"] = np.load(os.path.join(segment_dir, "pol_ang.npy")) return t_stream def simulate_timestream(self, segment, return_field=["signal", "v", "pol_ang"]): if segment == 0: #self.display_params() #self.beam.display_beam_settings() if self.config.write_beam: self.beam.write_beam(self.bolo_dir) rot_qt = self.generate_quaternion(segment) t_stream = {"signal" : None, "v" : None, "pol_ang" : None, "noise" : None} prompter.prompt("0.0") #Simulating the scan along the centre of the FOV v_init = self.get_initial_vec(0.0) v_central = self.get_v_obv(v_init, rot_qt) t_stream['v'] = v_central pol_ang = self.get_pol_ang(rot_qt, v_central) t_stream['pol_ang'] = pol_ang if self.config.sim_pol_type == "T": cos2=None sin2=None else: cos2 = np.cos(2*pol_ang) sin2 = np.sin(2*pol_ang) if "timestream_data" in self.config.timestream_data_products: self.make_write_dir(segment) self.write_timestream_data(v_central, "pointing_vec", segment) self.write_timestream_data(pol_ang, "pol_ang", segment) if not self.config.pipe_with_map_maker: del pol_ang beam_kernel_row = self.beam.get_beam_row(0.0) #The input argument is the beam offset from the centre hit_pix = hp.vec2pix(self.config.nside_in, v_central[...,0], v_central[...,1], v_central[...,2]) signal = self.generate_signal(hit_pix, beam_kernel_row, cos2, sin2) for del_beta in self.beam.del_beta: if del_beta == 0.0: continue prompter.prompt(str(del_beta)) beam_kernel_row = self.beam.get_beam_row(del_beta) v_init = self.get_initial_vec(del_beta) v = quaternion.transform(rot_qt, v_init) hit_pix = hp.vec2pix(self.config.nside_in, v[...,0], v[...,1], v[...,2]) signal += self.generate_signal(hit_pix, beam_kernel_row, cos2, sin2) beam_sum = np.sum(self.beam.beam_kernel[0]) signal /= beam_sum if self.config.add_noise: noise = self.noise_class.simulate_timestream_noise_from_parameters() if "timestream_data" in self.config.timestream_data_products: self.write_timestream_data(noise, "noise", segment) signal[::self.config.oversampling_rate] += noise if "timestream_data" in self.config.timestream_data_products: self.write_timestream_data(signal, "signal", segment) if self.config.pipe_with_map_maker: if self.config.do_pencil_beam: t_stream["signal"] = signal t_stream["v"] = v_central t_stream["pol_ang"] = pol_ang return t_stream else: t_stream["signal"] = signal[::self.config.oversampling_rate] t_stream["v"] = v_central[self.pad:-self.pad][::self.config.oversampling_rate] t_stream["pol_ang"] = pol_ang[self.pad:-self.pad][::self.config.oversampling_rate] return t_stream if "hitmap" in self.config.timestream_data_products: del signal hit_pix = hp.vec2pix(self.config.nside_in, v_central[...,0], v_central[...,1], v_central[...,2]) hitmap = self.get_hitmap(hit_pix) return hitmap def generate_signal(self, hit_pix, beam_kernel_row, cos2, sin2): if self.config.sim_pol_type == "noise_only": signal = np.zeros(self.nsamples - 2*self.pad) elif self.config.sim_pol_type == "T": if self.config.do_pencil_beam: signal = 0.5*self.sky_map[hit_pix] else: signal = np.convolve(0.5*self.sky_map[hit_pix], beam_kernel_row[0], mode='valid') elif self.config.sim_pol_type in ["QU", "_QU"]: if self.config.do_pencil_beam: signal = 0.5*(self.sky_map[0][hit_pix]*cos2 + self.sky_map[1][hit_pix]*sin2) else: signal = np.convolve(0.5*(self.sky_map[0][hit_pix]*cos2 + self.sky_map[1][hit_pix]*sin2), -1.0*beam_kernel_row[1], mode='valid') signal += np.convolve(0.5*(self.sky_map[0][hit_pix]*sin2 + self.sky_map[1][hit_pix]*cos2), -1.0*beam_kernel_row[2], mode='valid') elif self.config.sim_pol_type == "pol_only": if self.config.do_pencil_beam: signal = 0.5*(self.sky_map[1][hit_pix]*cos2 + self.sky_map[2][hit_pix]*sin2) else: signal = np.convolve(0.5*(self.sky_map[1][hit_pix]*cos2 + self.sky_map[2][hit_pix]*sin2), -1.0*beam_kernel_row[1], mode='valid') signal += np.convolve(0.5*(self.sky_map[1][hit_pix]*sin2 + self.sky_map[2][hit_pix]*cos2), -1.0*beam_kernel_row[2], mode='valid') else: if self.config.do_pencil_beam: signal = 0.5*(self.sky_map[0][hit_pix] + self.sky_map[1][hit_pix]*cos2 + self.sky_map[2][hit_pix]*sin2) else: signal = np.convolve(0.5*self.sky_map[0][hit_pix], beam_kernel_row[0], mode='valid') signal += np.convolve(0.5*(self.sky_map[1][hit_pix]*cos2 + self.sky_map[2][hit_pix]*sin2), -1.0*beam_kernel_row[1], mode='valid') signal += np.convolve(0.5*(self.sky_map[1][hit_pix]*sin2 + self.sky_map[2][hit_pix]*cos2), -1.0*beam_kernel_row[2], mode='valid') return signal def get_nsamples(self): self.pad = self.beam.del_beta.size/2 self.nsamples = int(self.config.t_segment*self.config.sampling_rate)*self.config.oversampling_rate + 2*self.pad def calculate_params(self): self.config.theta_cross = 360.0*60.0*np.sin(np.radians(self.config.alpha))*self.config.t_spin/self.config.t_prec self.config.theta_co = 360*60*np.sin(np.radians(self.config.beta))/self.config.sampling_rate/self.config.t_spin self.config.scan_resolution = self.config.theta_co/self.config.oversampling_rate def get_initial_axes(self): alpha = np.deg2rad(self.config.alpha) #radians beta = np.deg2rad(self.config.beta) #radians self.axis_spin = np.array([np.cos(alpha), 0.0, np.sin(alpha)]) self.axis_prec = np.array([1.0, 0.0, 0.0]) self.axis_rev = np.array([0.0, 0.0, 1.0]) def get_initial_vec(self, del_beta): alpha = np.deg2rad(self.config.alpha) #radians beta = np.deg2rad(self.config.beta) #radians if self.config.do_pencil_beam: del_x = np.deg2rad(self.config.offset_x/60.0/60.0) #radians del_y = np.deg2rad(self.config.offset_y/60.0/60.0) #radians else: del_x = 0.0 del_y = 0.0 del_beta_rad = np.deg2rad(del_beta/60.0) #radians total_opening = alpha + beta + del_beta_rad u_view = np.array([np.cos(total_opening), 0.0, np.sin(total_opening)]) x_roll_axis = np.array([0.0, 1.0, 0.0]) y_roll_axis = np.array([-np.sin(total_opening), 0.0, np.cos(total_opening)]) q_x_roll = quaternion.make_quaternion(del_x, x_roll_axis) q_y_roll = quaternion.make_quaternion(del_y, y_roll_axis) q_offset = quaternion.multiply(q_x_roll, q_y_roll) u_view = quaternion.transform(q_offset, u_view) return u_view def generate_quaternion(self, segment): t_start = self.config.t_segment*segment t_steps = t_start + (1.0/self.config.sampling_rate/self.config.oversampling_rate)*np.arange(-self.pad, self.nsamples - self.pad) w_spin = -2*np.pi/self.config.t_spin w_prec = -2*np.pi/self.config.t_prec w_rev = -2*np.pi/self.config.t_year r_total = quaternion.multiply(quaternion.make_quaternion(w_rev*t_steps, self.axis_rev), quaternion.multiply(quaternion.make_quaternion(w_prec*t_steps, self.axis_prec), quaternion.make_quaternion(w_spin*t_steps, self.axis_spin))) #r_total = quaternion.multiply(quaternion.make_quaternion(w_prec*t_steps, self.axis_prec), quaternion.make_quaternion(w_spin*t_steps, self.axis_spin)) return r_total def get_v_obv(self, v_init, rot_qt): v = quaternion.transform(rot_qt, v_init) if self.config.gal_coords: v = self.transform_to_gal_coords(v) return v def transform_to_gal_coords(self, v): rot = hp.Rotator(coord=['E', 'G']) theta, phi = hp.vec2ang(v) theta_gal, phi_gal = rot(theta, phi) return hp.ang2vec(theta_gal, phi_gal) def get_pol_ang(self, rot_qt, v_dir): alpha = np.deg2rad(self.config.alpha) #radians beta = np.deg2rad(self.config.beta) #radians total_opening = alpha + beta pol_ini = np.deg2rad(self.config.pol_phase_ini) pol_vec_ini = np.array([0.0, 1.0, 0.0]) pol_vec = quaternion.transform(rot_qt, np.tile(pol_vec_ini, self.nsamples).reshape(-1,3)) if self.config.gal_coords: pol_vec = self.transform_to_gal_coords(pol_vec) theta, phi = hp.vec2ang(v_dir) x_local = np.array(zip(np.cos(theta)*np.cos(phi), np.cos(theta)*np.sin(phi), -np.sin(theta))) y_local = np.array(zip(-np.sin(phi), np.cos(phi), np.zeros(phi.size))) proj_x = np.sum(pol_vec*x_local, axis=-1) proj_y = np.sum(pol_vec*y_local, axis=-1) pol_ang = np.pi - (np.arctan2(proj_y, proj_x) + pol_ini) % np.pi return pol_ang def add_noise(self): if self.config.noise_type == "white": return np.random.normal(scale=self.config.noise_sigma, size=self.nsamples - 2*self.pad) def get_hitmap(self, hitpix): hitmap = np.bincount(hitpix, minlength=self.npix) return hitmap def get_sky_map(self): if self.config.sim_pol_type == "noise_only": self.sky_map = None elif self.config.sim_pol_type == "T": self.sky_map = hp.read_map(self.config.input_map, verbose=False) elif self.config.sim_pol_type == "QU": self.sky_map = hp.read_map(self.config.input_map, field=(0,1), verbose=False) elif self.config.sim_pol_type == "_QU": self.sky_map = hp.read_map(self.config.input_map, field=(1,2), verbose=False) else: self.sky_map = hp.read_map(self.config.input_map, field=(0,1,2), verbose=False) if not self.config.sim_pol_type == "noise_only": map_nside = hp.get_nside(self.sky_map) if map_nside != self.config.nside_in: prompter.prompt_warning("NSIDE of config does not match NSIDE of map") sys.exit() self.npix = hp.nside2npix(self.config.nside_in) def make_write_dir(self, segment): if not os.path.exists(self.bolo_dir): try: os.makedirs(self.bolo_dir) except OSError: pass segment_dir = self.get_segment_dir(segment) if os.path.exists(segment_dir): shutil.rmtree(segment_dir) os.makedirs(segment_dir) def set_bolo_dirs(self): self.sim_dir = os.path.join(self.config.general_data_dir, self.config.sim_tag) self.scan_dir = os.path.join(self.sim_dir, self.config.scan_tag) self.bolo_dir = os.path.join(self.scan_dir, self.name) def get_segment_dir(self, segment): segment_name = str(segment+1).zfill(4) return os.path.join(self.bolo_dir, segment_name) def write_timestream_data(self, ts_data, data_name, segment): write_dir = self.get_segment_dir(segment) if data_name == "signal": np.save(os.path.join(write_dir, data_name), ts_data[::self.config.oversampling_rate]) elif data_name == "noise": np.save(os.path.join(write_dir, data_name), ts_data) else: if self.config.do_pencil_beam: np.save(os.path.join(write_dir, data_name), ts_data) else: np.save(os.path.join(write_dir, data_name), ts_data[self.pad:-self.pad][::self.config.oversampling_rate]) def display_params(self): display_string = "" display_string += "Alpha : %f degrees\n" % (self.config.alpha) display_string += "Beta : %f degrees\n" % (self.config.beta) t_flight = self.config.t_segment*len(self.config.segment_list) display_string += "T flight : %f hours / %f days\n" % (t_flight/60.0/60.0, t_flight/60.0/60.0/24.0) display_string += "T segment : %f hours / %f days\n" % (self.config.t_segment/60.0/60.0, self.config.t_segment/60.0/60.0/24) display_string += "T precession : %f hours\n" % (self.config.t_prec/60.0/60.0) display_string += "T spin : %f seconds\n" % (self.config.t_spin) display_string += "Scan sampling rate : %f Hz\n" % (self.config.sampling_rate) display_string += "Theta co : %f arcmin\n" % (self.config.theta_co) display_string += "Theta cross : %f arcmin\n" % (self.config.theta_cross) display_string += "Oversampling rate : %d\n" % (self.config.oversampling_rate) display_string += "Scan resolution for beam integration : %f arcmin\n" % (self.config.scan_resolution) display_string += "Pixel size for NSIDE = %d : %f arcmin\n" % (self.config.nside_in, hp.nside2resol(self.config.nside_in, arcmin=True)) n_steps = int(self.config.t_segment*self.config.sampling_rate)*self.config.oversampling_rate display_string += "#Samples per segment : %d\n" %(n_steps) prompter.prompt(display_string, True)