Skip to content
ObservationSim.py 16 KiB
Newer Older
Fang Yuedong's avatar
Fang Yuedong committed
import numpy as np
import mpi4py.MPI as MPI
import galsim
import logging
import psutil
from astropy.io import fits
from datetime import datetime

from ObservationSim.Config import config_dir, ChipOutput
from ObservationSim.Config.Header import generatePrimaryHeader, generateExtensionHeader
from ObservationSim.Instrument import Telescope, Filter, FilterParam, FocalPlane, Chip
from ObservationSim.Instrument.Chip import Effects
from ObservationSim.MockObject import calculateSkyMap_split_g
from ObservationSim.PSF import PSFGauss, FieldDistortion, PSFInterp
from ObservationSim._util import get_shear_field, makeSubDir_PointingList
Fang Yuedong's avatar
Fang Yuedong committed

class Observation(object):
    def __init__(self, config, Catalog, work_dir=None, data_dir=None):
        self.path_dict = config_dir(config=config, work_dir=work_dir, data_dir=data_dir)
Fang Yuedong's avatar
Fang Yuedong committed
        self.config = config
        self.tel = Telescope(optEffCurve_path=self.path_dict["mirror_file"]) 
        self.focal_plane = FocalPlane(survey_type=self.config["obs_setting"]["survey_type"]) 
        self.filter_param = FilterParam(filter_dir=self.path_dict["filter_dir"]) 
Fang Yuedong's avatar
Fang Yuedong committed
        self.chip_list = []
        self.filter_list = []
        self.Catalog = Catalog
Fang Yuedong's avatar
Fang Yuedong committed

        # if we want to apply field distortion?
Fang Yuedong's avatar
Fang Yuedong committed
        if self.config["ins_effects"]["field_dist"] == True:
Fang Yuedong's avatar
Fang Yuedong committed
            self.fd_model = FieldDistortion(fdModel_path=self.path_dict["fd_path"])
Fang Yuedong's avatar
Fang Yuedong committed
        else:
            self.fd_model = None

        # Construct chips & filters:
        nchips = self.focal_plane.nchip_x*self.focal_plane.nchip_y
        for i in range(nchips):
            chipID = i + 1
            if self.focal_plane.isIgnored(chipID=chipID):
                continue

            # Make Chip & Filter lists
            chip = Chip(
                chipID=chipID, 
                ccdEffCurve_dir=self.path_dict["ccd_dir"], 
                CRdata_dir=self.path_dict["CRdata_dir"], 
                normalize_dir=self.path_dict["normalize_dir"], 
                sls_dir=self.path_dict["sls_dir"], config=self.config)
Fang Yuedong's avatar
Fang Yuedong committed
            filter_id, filter_type = chip.getChipFilter()
            filt = Filter(filter_id=filter_id, 
                filter_type=filter_type, 
                filter_param=self.filter_param, 
                ccd_bandpass=chip.effCurve)
Fang Yuedong's avatar
Fang Yuedong committed
            self.chip_list.append(chip)
            self.filter_list.append(filt)

        # Read catalog and shear(s)
        self.g1_field, self.g2_field, self.nshear = get_shear_field(config=self.config)
Fang Yuedong's avatar
Fang Yuedong committed

    def run_one_chip(self, chip, filt, pointing, chip_output, wcs_fp=None, psf_model=None, shear_cat_file=None, cat_dir=None, sed_dir=None):
Fang Yuedong's avatar
Fang Yuedong committed

        print(':::::::::::::::::::Current Pointing Information::::::::::::::::::')
        print("RA: %f, DEC; %f" % (pointing.ra, pointing.dec))
        print("Time: %s" % datetime.fromtimestamp(pointing.timestamp).isoformat())
        print("Exposure time: %f" % pointing.exp_time)
        print("Satellite Position (x, y, z): (%f, %f, %f)" % (pointing.sat_x, pointing.sat_y, pointing.sat_z))
        print("Satellite Velocity (x, y, z): (%f, %f, %f)" % (pointing.sat_vx, pointing.sat_vy, pointing.sat_vz))
        print("Position Angle: %f" % pointing.img_pa.deg)
        print('Chip : %d' % chip.chipID)
        print(':::::::::::::::::::::::::::END:::::::::::::::::::::::::::::::::::')
Fang Yuedong's avatar
Fang Yuedong committed

Fang Yuedong's avatar
Fang Yuedong committed
        if self.config["psf_setting"]["psf_model"] == "Gauss":
Fang Yuedong's avatar
Fang Yuedong committed
            psf_model = PSFGauss(chip=chip)
Fang Yuedong's avatar
Fang Yuedong committed
        elif self.config["psf_setting"]["psf_model"] == "Interp":
Fang Yuedong's avatar
Fang Yuedong committed
            psf_model = PSFInterp(chip=chip, PSF_data_file=self.path_dict["psf_dir"])
Fang Yuedong's avatar
Fang Yuedong committed
        else:
            print("unrecognized PSF model type!!", flush=True)

        # Get (extra) shear fields
        if shear_cat_file is not None:
            self.g1_field, self.g2_field, self.nshear = get_shear_field(config=self.config, shear_cat_file=shear_cat_file)
Fang Yuedong's avatar
Fang Yuedong committed

        # Get WCS for the focal plane
        if wcs_fp == None:
            wcs_fp = self.focal_plane.getTanWCS(pointing.ra, pointing.dec, pointing.img_pa, chip.pix_scale)
Fang Yuedong's avatar
Fang Yuedong committed

        # Create chip Image
        chip.img = galsim.ImageF(chip.npix_x, chip.npix_y)
        chip.img.setOrigin(chip.bound.xmin, chip.bound.ymin)
        chip.img.wcs = wcs_fp
        if chip.survey_type == "photometric":
            sky_map = None
        # elif chip.survey_type == "spectroscopic":
        #     sky_map = calculateSkyMap_split_g(xLen=chip.npix_x, yLen=chip.npix_y, blueLimit=filt.blue_limit, redLimit=filt.red_limit, skyfn=self.path_dict["sky_file"], conf=chip.sls_conf, pixelSize=chip.pix_scale, isAlongY=0)
Fang Yuedong's avatar
Fang Yuedong committed
        elif chip.survey_type == "spectroscopic":
            flat_normal = np.ones_like(chip.img.array)
            if self.config["ins_effects"]["flat_fielding"] == True:
                print("SLS flat preprocess,CHIP %d : Creating and applying Flat-Fielding"%chip.chipID, flush=True)
                print(chip.img.bounds, flush=True)
                flat_img = Effects.MakeFlatSmooth(
                    chip.img.bounds,
                    int(self.config["random_seeds"]["seed_flat"]))
                flat_normal = flat_normal * flat_img.array / np.mean(flat_img.array)
            if self.config["ins_effects"]["shutter_effect"] == True:
                print("SLS flat preprocess,CHIP %d : Apply shutter effect"%chip.chipID, flush=True)
                shuttimg = Effects.ShutterEffectArr(chip.img, t_shutter=1.3, dist_bearing=735,
                                                    dt=1E-3)  # shutter effect normalized image for this chip
                flat_normal = flat_normal*shuttimg
                flat_normal = np.array(flat_normal,dtype='float32')
            sky_map = calculateSkyMap_split_g(skyMap=flat_normal, blueLimit=filt.blue_limit, redLimit=filt.red_limit, skyfn=self.path_dict["sky_file"], conf=chip.sls_conf, pixelSize=chip.pix_scale, isAlongY=0)
            del flat_normal
Fang Yuedong's avatar
Fang Yuedong committed

        if pointing.pointing_type == 'MS':
Fang Yuedong's avatar
Fang Yuedong committed
            # Load catalogues and templates
            self.cat = self.Catalog(config=self.config, chip=chip, pointing=pointing, cat_dir=cat_dir, sed_dir=sed_dir)
Fang Yuedong's avatar
Fang Yuedong committed
            self.nobj = len(self.cat.objs)

            # Loop over objects
            missed_obj = 0
            bright_obj = 0
            dim_obj = 0
            for j in range(self.nobj):
Fang Yuedong's avatar
Fang Yuedong committed
                #     break
                obj = self.cat.objs[j]
                if obj.type == 'star' and self.config["galaxy_only"]:
                    continue
                elif obj.type == 'galaxy' and self.config["star_only"]:
                    continue
                elif obj.type == 'quasar' and self.config["star_only"]:
                    continue
                # load SED
                try:
                    sed_data = self.cat.load_sed(obj)
                    norm_filt = self.cat.load_norm_filt(obj)
                    obj.sed, obj.param["mag_%s"%filt.filter_type] = self.cat.convert_sed(
                        mag=obj.param["mag_use_normal"],
                        sed=sed_data,
                        target_filt=filt, 
                        norm_filt=norm_filt,
                    )
                except Exception as e:
                    print(e)
                    continue
Fang Yuedong's avatar
Fang Yuedong committed

                # Exclude very bright/dim objects (for now)
                if filt.is_too_bright(mag=obj.getMagFilter(filt)):
                    # print("obj too birght!!", flush=True)
                    if obj.type != 'galaxy':
                        bright_obj += 1
                        obj.unload_SED()
                        continue
                if filt.is_too_dim(mag=obj.getMagFilter(filt)):
                    # print("obj too dim!!", flush=True)
                    dim_obj += 1
Fang Yuedong's avatar
Fang Yuedong committed
                    obj.unload_SED()
Fang Yuedong's avatar
Fang Yuedong committed
                    # print(obj.getMagFilter(filt))
Fang Yuedong's avatar
Fang Yuedong committed
                    continue

Fang Yuedong's avatar
Fang Yuedong committed
                if self.config["shear_setting"]["shear_type"] == "constant":
Fang Yuedong's avatar
Fang Yuedong committed
                    if obj.type == 'star':
                        obj.param["g1"], obj.param["g2"] = 0, 0
Fang Yuedong's avatar
Fang Yuedong committed
                    else:
                        obj.param["g1"], obj.param["g2"] = self.g1_field, self.g2_field
Fang Yuedong's avatar
Fang Yuedong committed
                elif self.config["shear_setting"]["shear_type"] == "extra":
                    try:
                        # TODO: every object with individual shear from input catalog(s)
                        obj.param["g1"], obj.param["g2"] = self.g1_field[j], self.g2_field[j]
Fang Yuedong's avatar
Fang Yuedong committed
                    except:
                        print("failed to load external shear.")
                        pass
                elif self.config["shear_setting"]["shear_type"] == "catalog":
                    pass
                else:
                    raise ValueError("Unknown shear input")
Fang Yuedong's avatar
Fang Yuedong committed

                pos_img, offset, local_wcs = obj.getPosImg_Offset_WCS(img=chip.img, fdmodel=self.fd_model, chip=chip, verbose=False)
                if pos_img.x == -1 or pos_img.y == -1:
                    # Exclude object which is outside the chip area (after field distortion)
                    # print("obj missed!!")
                    missed_obj += 1
                    obj.unload_SED()
                    continue
Fang Yuedong's avatar
Fang Yuedong committed

Fang Yuedong's avatar
Fang Yuedong committed
                # Draw object & update output catalog
                try:
Fang Yuedong's avatar
Fang Yuedong committed
                    if self.config["out_cat_only"]:
                        isUpdated = True
                    if chip.survey_type == "photometric" and not self.config["out_cat_only"]:
Fang Yuedong's avatar
Fang Yuedong committed
                        isUpdated, pos_shear = obj.drawObj_multiband(
                            tel=self.tel,
                            pos_img=pos_img, 
                            psf_model=psf_model, 
                            bandpass_list=filt.bandpass_sub_list, 
                            filt=filt, 
                            chip=chip, 
                            g1=obj.param["g1"], 
                            g2=obj.param["g2"], 
                            exptime=pointing.exp_time
                            )
Fang Yuedong's avatar
Fang Yuedong committed
                    elif chip.survey_type == "spectroscopic" and not self.config["out_cat_only"]:
Fang Yuedong's avatar
Fang Yuedong committed
                        isUpdated, pos_shear = obj.drawObj_slitless(
                            tel=self.tel, 
                            pos_img=pos_img, 
                            psf_model=psf_model, 
                            bandpass_list=filt.bandpass_sub_list, 
                            filt=filt, 
                            chip=chip, 
                            g1=obj.param["g1"], 
                            g2=obj.param["g2"], 
                            exptime=pointing.exp_time,
                            normFilter=norm_filt,
                            )
Fang Yuedong's avatar
Fang Yuedong committed
                    if isUpdated:
                        # TODO: add up stats
                        chip_output.cat_add_obj(obj, pos_img, pos_shear, obj.param["g1"], obj.param["g2"])
Fang Yuedong's avatar
Fang Yuedong committed
                        pass
                    else:
                        # print("object omitted", flush=True)
                        continue
                except Exception as e:
                    print(e)
Fang Yuedong's avatar
Fang Yuedong committed
                    pass
Fang Yuedong's avatar
Fang Yuedong committed
                # Unload SED:
                obj.unload_SED()
                del obj
Fang Yuedong's avatar
Fang Yuedong committed

Fang Yuedong's avatar
Fang Yuedong committed
            del psf_model
            del self.cat
Fang Yuedong's avatar
Fang Yuedong committed

        print("check running:1: pointing-{:} chip-{:} pid-{:} memory-{:6.2}GB".format(pointing.id, chip.chipID, os.getpid(), (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024) ), flush=True)
Fang Yuedong's avatar
Fang Yuedong committed

        # Detector Effects
        # ===========================================================
Fang Yuedong's avatar
Fang Yuedong committed
        # whether to output zero, dark, flat calibration images.
        chip.img = chip.addEffects(
            config=self.config, 
            img=chip.img, 
            chip_output=chip_output, 
            filt=filt, 
            ra_cen=pointing.ra, 
            dec_cen=pointing.dec,
            img_rot=pointing.img_pa,
            pointing_ID=pointing.id,
            timestamp_obs=pointing.timestamp,
            pointing_type=pointing.pointing_type,
Zhang Xin's avatar
Zhang Xin committed
            sky_map=sky_map, tel = self.tel)
Fang Yuedong's avatar
Fang Yuedong committed
        
        if pointing.pointing_type == 'MS':
            datetime_obs = datetime.fromtimestamp(pointing.timestamp)
Fang Yuedong's avatar
Fang Yuedong committed
            date_obs = datetime_obs.strftime("%y%m%d")
            time_obs = datetime_obs.strftime("%H%M%S")
            h_prim = generatePrimaryHeader(
                xlen=chip.npix_x, 
                ylen=chip.npix_y, 
                pointNum = str(pointing.id),
                ra=pointing.ra, 
                dec=pointing.dec, 
Fang Yuedong's avatar
Fang Yuedong committed
                psize=chip.pix_scale, 
                row_num=chip.rowID, 
                col_num=chip.colID,
                date=date_obs,
                time_obs=time_obs,
                im_type='MS')
            h_ext = generateExtensionHeader(
                xlen=chip.npix_x, 
                ylen=chip.npix_y, 
                ra=pointing.ra, 
                dec=pointing.dec, 
                pa=pointing.img_pa.deg, 
Fang Yuedong's avatar
Fang Yuedong committed
                gain=chip.gain, 
                readout=chip.read_noise, 
                dark=chip.dark_noise, 
                saturation=90000, 
                psize=chip.pix_scale, 
                row_num=chip.rowID, 
                col_num=chip.colID,
                extName='raw')
            chip.img = galsim.Image(chip.img.array, dtype=np.uint16)
            hdu1 = fits.PrimaryHDU(header=h_prim)
            hdu2 = fits.ImageHDU(chip.img.array, header=h_ext)
            hdu1 = fits.HDUList([hdu1, hdu2])
            fname = os.path.join(chip_output.subdir, h_prim['FILENAME'] + '.fits')
            hdu1.writeto(fname, output_verify='ignore', overwrite=True)
            print("# objects that are too bright %d out of %d"%(bright_obj, self.nobj))
            print("# objects that are too dim %d out of %d"%(dim_obj, self.nobj))
            print("# objects that are missed %d out of %d"%(missed_obj, self.nobj))
Fang Yuedong's avatar
Fang Yuedong committed
        del chip.img

        print("check running:2: pointing-{:} chip-{:} pid-{:} memory-{:6.2}GB".format(pointing.id, chip.chipID, os.getpid(), (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024) ), flush=True)
Fang Yuedong's avatar
Fang Yuedong committed

    def runExposure_MPI_PointingList(self, pointing_list, shear_cat_file=None, chips=None, use_mpi=False):
Fang Yuedong's avatar
Fang Yuedong committed
        if use_mpi:
            comm = MPI.COMM_WORLD
            ind_thread = comm.Get_rank()
            num_thread = comm.Get_size()
Fang Yuedong's avatar
Fang Yuedong committed

Fang Yuedong's avatar
Fang Yuedong committed
        if chips is None:
            nchips_per_fp = len(self.chip_list)
            run_chips = self.chip_list
            run_filts = self.filter_list
        else:
            # Only run a particular set of chips
            run_chips = []
            run_filts = []
            nchips_per_fp = len(chips)
            for ichip in range(len(self.chip_list)):
                chip = self.chip_list[ichip]
                filt = self.filter_list[ichip]
                if chip.chipID in chips:
                    run_chips.append(chip)
                    run_filts.append(filt)
Fang Yuedong's avatar
Fang Yuedong committed

        for ipoint in range(len(pointing_list)):
Fang Yuedong's avatar
Fang Yuedong committed
            for ichip in range(nchips_per_fp):
                i = ipoint*nchips_per_fp + ichip
                pointing = pointing_list[ipoint]
                pointing_ID = pointing.id
Fang Yuedong's avatar
Fang Yuedong committed
                if use_mpi:
                    if i % num_thread != ind_thread:
                        continue
Fang Yuedong's avatar
Fang Yuedong committed

                pid = os.getpid()

                sub_img_dir, prefix = makeSubDir_PointingList(path_dict=self.path_dict, config=self.config, pointing_ID=pointing_ID)

Fang Yuedong's avatar
Fang Yuedong committed
                chip = run_chips[ichip]
                filt = run_filts[ichip]
Fang Yuedong's avatar
Fang Yuedong committed
                print("running pointing#%d, chip#%d, at PID#%d..."%(pointing_ID, chip.chipID, pid), flush=True)
                chip_output = ChipOutput(
                    config=self.config, 
                    focal_plane=self.focal_plane, 
                    chip=chip, 
                    filt=filt,  
                    exptime=pointing.exp_time,
                    pointing_type=pointing.pointing_type,
Fang Yuedong's avatar
Fang Yuedong committed
                    pointing_ID=pointing_ID,  
                    subdir=sub_img_dir,
                    prefix=prefix)
Fang Yuedong's avatar
Fang Yuedong committed
                    chip=chip, 
                    filt=filt, 
                    chip_output=chip_output, 
Fang Yuedong's avatar
Fang Yuedong committed
                    cat_dir=self.path_dict["cat_dir"])
Zhang Xin's avatar
Zhang Xin committed
                print("finished running chip#%d..."%(chip.chipID), flush=True)