Skip to content
camera.py 33.3 KiB
Newer Older
GZhao's avatar
GZhao committed
import os
import yaml
import numpy as np
import scipy.ndimage as nd
from astropy.io import fits
import matplotlib.pyplot as plt
import math

from CpicImgSim.config import cpism_refdata, solar_spectrum, MAG_SYSTEM
from CpicImgSim.utils import region_replace, random_seed_select
from CpicImgSim.io import log
from CpicImgSim.optics import filter_throughput


def sky_frame_maker(band, skybg, platescale, shape):
    """
    generate a sky background frame.

    Parameters
    ----------
    band : str
        The band of the sky background.
    skybg : str
        The sky background file name.
    platescale : float
        The platescale of the camera in arcsec/pixel.
    shape : tuple
        The shape of the output frame. (y, x)

    Returns
    -------
    sky_bkg_frame : numpy.ndarray
        The sky background frame.
    """
    filter = filter_throughput(band)
    sk_spec = solar_spectrum.renorm(skybg, MAG_SYSTEM, filter)
    sky_bkg_frame = np.zeros(shape)
    sky_bkg_frame += (sk_spec * filter).integrate() * platescale**2
    return sky_bkg_frame


class CRobj(object):
    """
    Cosmic ray object.

    Attributes
    ----------
    flux : float
        The flux of the cosmic ray.
    angle : float
        The angle of the cosmic ray.
    sigma : float
        The width of the cosmic ray.
    length : int
        The length of the cosmic ray.
    """

    def __init__(self, flux, angle, sigma, length) -> None:
        self.flux = flux
        self.angle = angle
        self.sigma = sigma
        self.length = length


class CosmicRayFrameMaker(object):
    """
    Cosmic ray frame maker.

    Parameters
    ----------
    depth : float
        The depth of the camera pixel in um.
    pitch : float
        The pitch of the camera pixel in um.
    cr_rate : float
        The cosmic ray rate per second per cm2.

    """

    def __init__(self) -> None:
        self.tmp_size = [7, 101]
        self.freq_power = -0.9
        self.trail_std = 0.1
        self.depth = 10  # um
        self.pitch = 13  # um
        self.cr_rate = 1  # particle per s per cm2 from Miles et al. 2021

    def make_CR(self, length, sigma, seed=-1):
        """
        make a image of cosmic ray with given length and sigma.

        Parameters
        ----------
        length : int
            The length of the cosmic ray in pixel.
        sigma : float
            The width of the cosmic ray in pixel.

        Returns
        -------
        output : numpy.ndarray
            The image of cosmic ray.
        """
        h = self.tmp_size[0]
        w = self.tmp_size[1]

        freq = ((w-1)/2-np.abs(np.arange(w)-(w-1)/2)+1)**(self.freq_power)

        x = np.arange(w) - (w-1)/2
        hl = (length-1)/2
        x_wing = np.exp(-(np.abs(x)-hl)**2/sigma/sigma/2)
        x_wing[np.abs(x) < hl] = 1

        cr = np.zeros([h, w])
        center = (h-1)/2

        for i in range(h):
            phase = np.random.rand(w)*2*np.pi
            trail0 = abs(np.fft.fft(freq*np.sin(phase) + 1j*x*np.cos(phase)))
            # TODO maybe somthing wrong
            trail_norm = (trail0 - trail0.mean())/trail0.std()
            cr[i, :] = np.exp(-(i - center)**2/sigma/sigma/2) \
                * (trail_norm * self.trail_std + 1) * x_wing

        output = np.zeros([w, w])
        d = (w-h)//2
        output[d:d+h, :] = cr
        return output

    def _length_rand(self, N, seed=-1):
        """
        randomly generate N cosmic ray length.
        """
        len_out = []
        seed = random_seed_select(seed=seed)
        log.debug(f"cr length seed: {seed}")
        for i in range(N):
            x2y2 = 2
            while x2y2 > 1:
                lx = 1 - 2 * np.random.rand()
                ly = 1 - 2 * np.random.rand()
                x2y2 = lx * lx + ly * ly

            z = 1 - 2 * x2y2
            r = 2 * np.sqrt(x2y2 * (1 - x2y2))
            length = abs(r / z * self.depth)
            pitch = self.pitch

            len_out.append(int(length/pitch))
        return np.array(len_out)

    def _number_rand(self, expt, pixsize, random=False, seed=-1):
        """
        randomly generate the number of cosmic rays.
        """
        area = (self.pitch / 1e4)**2 * pixsize[0] * pixsize[1]
        ncr = area * expt * self.cr_rate
        if random:
            seed = random_seed_select(seed=seed)
            log.debug(f"cr count: {seed}")
            ncr = np.random.poisson(ncr)
        else:
            ncr = int(ncr)
        self.ncr = ncr
        return ncr

    def _sigma_rand(self, N, seed=-1):
        """
        randomly generate N cosmic ray sigma.
        """
        sig_sig = 0.5  # asuming the sigma of size of cosmic ray is 0.5
        seed = random_seed_select(seed=seed)
        log.debug(f"cr width seed: {seed}")
        sig = abs(np.random.randn(N))*sig_sig + 1/np.sqrt(12) * 1.2
        # assume sigma is 1.2 times of pictch sig
        return sig

    def _flux_rand(self, N, seed=-1):
        """
        randomly generate N cosmic ray flux.
        """
        seed = random_seed_select(seed=seed)
        log.debug(f"cr flux seed: {seed}")
        u = np.random.rand(N)
        S0 = 800
        lam = 0.57
        S = (-np.log(1-u)/lam + S0**0.25)**4
        return S

    def random_CR_parameter(self, expt, pixsize):
        """
        randomly generate cosmic ray parameters, including number, length, flux, sigma and angle.

        Parameters
        ----------
        expt : float
            The exposure time in second.
        pixsize : list
            The size of the image in pixel.

Loading
Loading full blame…