示例#1
0
def gpi_g10s40_asmanufactured(mag):
    """ In PPM metal space - measured cooordinates from sample G10S40"""
    holedia = 0.920 * mm
    holectrs = [
        [-1.061 * mm, -3.882 * mm],
        [-0.389 * mm, -5.192 * mm],
        [2.814 * mm, -0.243 * mm],
        [3.616 * mm, 0.995 * mm],
        [-4.419 * mm, 2.676 * mm],
        [-1.342 * mm, 5.077 * mm],
        [-4.672 * mm, -2.421 * mm],
        [4.157 * mm, -2.864 * mm],
        [5.091 * mm, 0.920 * mm],
        [1.599 * mm, 4.929 * mm],
    ]

    # design2metal mag
    holedia = holedia * mag
    print(mag)
    ctrs = []
    #REVERSE = -1 # Flip y dimensions to match I&T data Dec 2012
    REVERSE = 1  # With new affine updates, need to reverse the reverse March 2019
    for r in holectrs:
        ctrs.append([r[0] * mag, r[1] * mag * REVERSE])
    # return cut-the-metal coords per Lenox PPM mm spec in meters on PM
    ctrs_asbuilt = copy(ctrs)

    # March 2019:
    # Rotate hole centers by 90 deg to match GPI detector with new coordinate handling
    # no affine2d transformations 8/2018 AS
    ctrs_asbuilt = rotate2dccw(ctrs_asbuilt,
                               160 * np.pi / 180.0)  # overwrites attributes

    return holedia, ctrs_asbuilt
示例#2
0
    def set_ctrs_rot(self, rotation_ccw_deg):
        """ 
        test routine or used for preferrably small rotations of as_built centers.
        No-op, unchanged self.ctrs,  if rotation exactly zero or False.
        Otherwise overwrites self.ctrs, the "live" centers of mask holes.
        In the interests of code clarity do not use for coordinate flips
        In data reduction piupelines DO NOT USE THIS ROUTINE - use the
        BEING REMOVED - DON'T USE - use Affine2d resampling of the image plane instead.
        """
        vprint("""
        LG_Model.NRM_Model.set_ctrs_rot(): BEING REMOVED - DON'T USE - use Affine2d instead"""
               )

        if rotation_ccw_deg:
            self.ctrs = utils.rotate2dccw(self.ctrs_asbuilt,
                                          rotation_ccw_deg * np.pi / 180.0)
            self.rotation_ccw_deg = rotation_ccw_deg  # record-keeping
            vprint(
                "\tLG_Model.NRM_Model.set_ctrs_rot: ctrs in V2V3, meters after rot %.2f deg:"
                % rotation_ccw_deg)
        else:
            vprint(
                "\tLG_Model.NRM_ModelLG_Model.set_ctrs_rot: ctrs in V2V3, meters:"
            )

        vprint(self.ctrs, "****************")
示例#3
0
    def mast2sky(self):
        """
        Rotate hole center coordinates:
            Clockwise by the V3 position angle - V3I_YANG from north in degrees if VPARITY = -1
            Counterclockwise by the V3 position angle - V3I_YANG from north in degrees if VPARITY = 1
        Hole center coords are in the V2, V3 plane in meters.
        Return rotated coordinates to be put in info4oif_dict.
        implane2oifits.ObservablesFromText uses these to calculate baselines.
        """
        pa = self.pa
        mask_ctrs = self.mask.ctrs
        # rotate by an extra 90 degrees (RAC 9/21)
        # these coords are just used to orient output in OIFITS files
        # NOT used for the fringe fitting itself
        mask_ctrs = utils.rotate2dccw(mask_ctrs, np.pi / 2.)
        vpar = self.vparity  # Relative sense of rotation between Ideal xy and V2V3
        v3iyang = self.v3i_yang
        rot_ang = pa - v3iyang  # subject to change!

        if pa != 0.0:
            # Using rotate2sccw, which rotates **vectors** CCW in a fixed coordinate system,
            # so to rotate coord system CW instead of the vector, reverse sign of rotation angle.  Double-check comment
            if vpar == -1:
                # rotate clockwise  <rotate coords clockwise?>
                ctrs_rot = utils.rotate2dccw(mask_ctrs, np.deg2rad(-rot_ang))
                print(
                    f'InstrumentData.mast2sky: Rotating mask hole centers clockwise by {rot_ang:.3f} degrees'
                )
            else:
                # counterclockwise  <rotate coords counterclockwise?>
                ctrs_rot = utils.rotate2dccw(mask_ctrs, np.deg2rad(rot_ang))
                print(
                    'InstrumentData.mast2sky: Rotating mask hole centers counterclockwise by {rot_ang:.3f} degrees'
                )
        else:
            ctrs_rot = mask_ctrs
        return ctrs_rot
示例#4
0
def jwst_g7s6_centers_asbuilt(
        chooseholes=None):  # was jwst_g7s6_centers_asdesigned

    holedict = {
    }  # as_built names, C2 open, C5 closed, but as designed coordinates
    # Assemble holes by actual open segment names (as_built).  Either the full mask or the
    # subset-of-holes mask will be V2-reversed after the as_designed centers  are defined
    # Debug orientations with b4,c6,[c2]
    allholes = ('b4', 'c2', 'b5', 'b2', 'c1', 'b6', 'c6')
    b4, c2, b5, b2, c1, b6, c6 = ('b4', 'c2', 'b5', 'b2', 'c1', 'b6', 'c6')
    #                                              design  built
    holedict['b4'] = [0.00000000, -2.640000]  #B4 -> B4
    holedict['c2'] = [-2.2863100, 0.0000000]  #C5 -> C2
    holedict['b5'] = [2.2863100, -1.3200001]  #B3 -> B5
    holedict['b2'] = [-2.2863100, 1.3200001]  #B6 -> B2
    holedict['c1'] = [-1.1431500, 1.9800000]  #C6 -> C1
    holedict['b6'] = [2.2863100, 1.3200001]  #B2 -> B6
    holedict['c6'] = [1.1431500, 1.9800000]  #C1 -> C6

    # as designed MB coordinates (Mathilde Beaulieu, Peter, Anand).
    # as designed: segments C5 open, C2 closed, meters V2V3 per Paul Lightsey def
    # as built C5 closed, C2 open
    #
    # undistorted pupil coords on PM.  These numbers are considered immutable.
    # as designed seg -> as built seg in comments each ctr entry (no distortion)
    if chooseholes:  #holes B4 B5 C6 asbuilt for orientation testing
        print("\n  chooseholes creates mask with JWST as_built holes ",
              chooseholes)
        #time.sleep(2)
        holelist = []
        for h in allholes:
            if h in chooseholes:
                holelist.append(holedict[h])
        ctrs_asdesigned = np.array(holelist)
    else:
        # the REAL THING - as_designed 7 hole, m in PM space, no distortion  shape (7,2)
        ctrs_asdesigned = np.array([
            [0.00000000,
             -2.640000],  #B4 -> B4  as-designed -> as-built mapping
            [-2.2863100, 0.0000000],  #C5 -> C2
            [2.2863100, -1.3200001],  #B3 -> B5
            [-2.2863100, 1.3200001],  #B6 -> B2
            [-1.1431500, 1.9800000],  #C6 -> C1
            [2.2863100, 1.3200001],  #B2 -> B6
            [1.1431500, 1.9800000]
        ])  #C1 -> C6

    # Preserve ctrs.as-designed (treat as immutable)
    # Reverse V2 axis coordinates to close C5 open C2, and others follow suit...
    # preserve cts.as_built  (treat as immutable)
    ctrs_asbuilt = ctrs_asdesigned.copy()

    # create 'live' hole centers in an ideal, orthogonal undistorted xy pupil space,
    # eg maps open hole C5 in as_designed to C2 as_built, eg C4 unaffacted....
    ctrs_asbuilt[:, 0] *= -1

    # LG++ rotate hole centers by 90 deg to match MAST o/p DMS PSF with
    # no affine2d transformations 8/2018 AS
    # LG++ The above aligns the hole patern with the hex analytic FT,
    # flat top & bottom as seen in DMS data. 8/2018 AS
    ctrs_asbuilt = rotate2dccw(ctrs_asbuilt,
                               np.pi / 2.0)  # overwrites attributes

    # create 'live' hole centers in an ideal, orthogonal undistorted xy pupil space,
    return ctrs_asbuilt * m
示例#5
0
    def __init__(self, maskname=None, rotdeg=None, holeshape="circ", rescale=False,\
                 verbose=False, chooseholes=None):

        print("NRM_Mask_definitions.NIRISS: maskname", maskname)
        if maskname not in ["gpi_g10s40",  "jwst_g7s6", "jwst_g7s6c", "visir_sam", \
                            "p1640", "keck_nirc2", "pharo", "NIRC2_9NRM"]:
            # Second row hopefully coming someday
            raise ValueError("mask %s not supported" % maskname)
        if holeshape == None:
            holeshape = 'circ'
        if holeshape not in [
                "circ",
                "hex",
        ]:
            raise ValueError("mask %s not supported" % maskname)
        self.maskname = maskname
        if verbose:
            print("\n\t=====================================")
            print("Mask %s being created" % self.maskname)

        if self.maskname == "gpi_g10s40":
            self.hdia, self.ctrs = gpi_g10s40(rescale=rescale)
            #self.rotdeg = 115.0 # By inspection of I&T data Dec 2012
            #if rotdeg is not None:
            #    self.rotdeg = rotdeg
            #    print("rotating by {0} deg".format(rotdeg))
            #else:
            #    print("rotating by 115.0 deg -- hard coded.")
            #self.ctrs = rotate2dccw(self.ctrs, self.rotdeg*np.pi/180.0)
            #self.rotate = self.rotdeg
            self.activeD = self.showmask(
            )  # calculates circle dia including all holes
            self.OD = 7770.1 * mm  # DGS = 7770.1 * mm with M2 cardboard baffle
            # GS OD from GPI fundamental values
            self.ID = 1023.75 * mm  # Formed by M2 diameter
            # (Bauman GPI_Optical_Fundamental_Values.doc)

        elif self.maskname == "jwst_g7s6c":
            """ activeD and D taken from webbpsf-data/NIRISS/coronagraph/MASK_NRM.fits"""
            print('self.maskname == "jwst_g7s6c":')
            self.hdia, self.ctrs = jwst_g7s6c(chooseholes=chooseholes)  #
            self.activeD = 6.559 * m  # webbpsf kwd DIAM  - not a 'circle including all holes'
            self.OD = 6.610645669291339 * m  # Full pupil file size, incl padding, webbpsf kwd PUPLDIAM
            if rotdeg is not None:
                self.rotdeg = rotdeg

        elif self.maskname == "jwst_g7s6":
            print("\tnot finished")

        elif self.maskname == "visir_sam":
            """Mask dimensions from Eric Pantin"""
            self.hdia, self.ctrs = visir_sam(rescale=rescale)
            self.rotdeg = 16.5  # By inspection of data
            if rotdeg is not None:
                self.rotdeg += rotdeg
                print("rotating by {0} + 9 (hardcoded) deg".format(rotdeg))
            else:
                print("rotating by 9 deg -- hard coded")
            self.ctrs = rotate2dccw(self.ctrs, self.rotdeg * np.pi / 180.0)
            self.rotate = self.rotdeg
            self.activeD = self.showmask(
            )  # calculated circle dia including all holes
            self.OD = 8115.0 * mm  # DVLT = 8115.0 * mm -- but what is the M2 dia??
            # From Eric Pantin Document
            self.ID = 1000.0 * mm  # Don't know this, but this number shouldn't matter

        elif self.maskname == "NIRC2_9NRM":
            """Mask dimensions from Steph Sallum?"""
            self.hdia, self.ctrs = keck_nrm()
            self.rotdeg = 28.0  # By inspection of data
            if rotdeg is not None:
                self.rotdeg += rotdeg
                print("rotating by {0} + 9 (hardcoded) deg".format(rotdeg))
            else:
                print("rotating by 9 deg -- hard coded")
            self.ctrs = rotate2dccw(self.ctrs, self.rotdeg * np.pi / 180.0)
            self.rotate = self.rotdeg
            self.activeD = self.showmask(
            )  # calculated circle dia including all holes
            self.OD = 10.0  # DVLT = 8115.0 * mm -- but what is the M2 dia??
            # From Eric Pantin Document
            self.ID = 1.0  # Don't know this, but this number shouldn't matter

        else:
            print("\tcheck back later")
示例#6
0
    def __init__(self,
                 mask=None,
                 holeshape="circ",
                 pixscale=None,
                 over=1,
                 log=_default_log,
                 pixweight=None,
                 datapath="",
                 phi=None,
                 refdir="",
                 chooseholes=False,
                 affine2d=None,
                 **kwargs):
        """
        mask will either be a string keyword for built-in values or
        an NRM_mask_geometry object.
        pixscale should be input in radians.
        phi (rad) default changedfrom "perfect" to None (with bkwd compat.)
        """

        # define a handler to write log messages to stdout
        sh = logging.StreamHandler(stream=sys.stdout)

        # define the format for the log messages, here: "level name: message"
        formatter = logging.Formatter("[%(levelname)s]: %(message)s")
        sh.setFormatter(formatter)
        self.logger = log
        self.logger.addHandler(sh)

        self.holeshape = holeshape
        self.pixel = pixscale  # det pix in rad (square)
        self.over = over
        self.maskname = mask
        self.pixweight = pixweight

        # WARNING! JWST CHOOSEHOLES CODE NOW DUPLICATED IN mask_definitions.py WARNING! ###
        holedict = {
        }  # as_built names, C2 open, C5 closed, but as designed coordinates
        # Assemble holes by actual open segment names.  Either the full mask or the
        # subset-of-holes mask will be V2-reversed after the as_designed ceenters
        # are installed in the object.
        allholes = ('b4', 'c2', 'b5', 'b2', 'c1', 'b6', 'c6')
        b4, c2, b5, b2, c1, b6, c6 = ('b4', 'c2', 'b5', 'b2', 'c1', 'b6', 'c6')
        holedict['b4'] = [0.00000000, -2.640000]  #B4 -> B4
        holedict['c2'] = [-2.2863100, 0.0000000]  #C5 -> C2
        holedict['b5'] = [2.2863100, -1.3200001]  #B3 -> B5
        holedict['b2'] = [-2.2863100, 1.3200001]  #B6 -> B2
        holedict['c1'] = [-1.1431500, 1.9800000]  #C6 -> C1
        holedict['b6'] = [2.2863100, 1.3200001]  #B2 -> B6
        holedict['c6'] = [1.1431500, 1.9800000]  #C1 -> C6
        if mask == 'jwst':
            # as designed MB coordinates (Mathilde Beaulieu, Peter, Anand).
            # as designed: segments C5 open, C2 closed, meters V2V3 per Paul Lightsey def
            # as built C5 closed, C2 open
            #
            # undistorted pupil coords on PM.  These numbers are considered immutable.
            # as designed seg -> as built seg in comments each ctr entry (no distortion)
            if chooseholes is not False:  #holes B4 B5 C6 asbuilt for orientation testing
                holelist = []
                for h in allholes:
                    if h in chooseholes:
                        holelist.append(holedict[h])
                self.ctrs_asdesigned = np.array(holelist)
            else:
                # the REAL THING - as_designed 7 hole, m in PM space, no distortion  shape (7,2)
                self.ctrs_asdesigned = np.array([
                    [0.00000000,
                     -2.640000],  #B4 -> B4  as-designed -> as-built mapping
                    [-2.2863100, 0.0000000],  #C5 -> C2
                    [2.2863100, -1.3200001],  #B3 -> B5
                    [-2.2863100, 1.3200001],  #B6 -> B2
                    [-1.1431500, 1.9800000],  #C6 -> C1
                    [2.2863100, 1.3200001],  #B2 -> B6
                    [1.1431500, 1.9800000]
                ])  #C1 -> C6
            self.d = 0.80 * m
            self.D = 6.5 * m

        else:

            try:
                #print(mask.ctrs)
                pass

            except AttributeError:
                raise AttributeError(
                    "Mask must be either 'jwst' or NRM_mask_geometry object")

            self.ctrs, self.d, self.D = np.array(
                mask.ctrs), mask.hdia, mask.activeD

        if mask == 'jwst':
            """
            Preserve ctrs.as_designed (treat as immutable)
            Reverse V2 axis coordinates to close C5 open C2, and others follow suit... 
            Preserve ctrs.as_built  (treat as immutable)
            """
            self.ctrs_asbuilt = self.ctrs_asdesigned.copy()

            # create 'live' hole centers in an ideal, orthogonal undistorted xy pupil space,
            # eg maps open hole C5 in as_designed to C2 as_built, eg C4 unaffacted....
            self.ctrs_asbuilt[:, 0] *= -1

            # LG++ rotate hole centers by 90 deg to match MAST o/p DMS PSF with
            # no affine2d transformations 8/2018 AS
            # LG++ The above aligns the hole patern with the hex analytic FT,
            # flat top & bottom as seen in DMS data. 8/2018 AS
            self.ctrs_asbuilt = utils.rotate2dccw(self.ctrs_asbuilt, np.pi /
                                                  2.0)  # overwrites attributes

            # create 'live' hole centers in an ideal, orthogonal undistorted xy pupil space,
            self.ctrs = self.ctrs_asbuilt.copy()

        self.N = len(self.ctrs)
        self.datapath = datapath
        self.refdir = refdir
        self.fmt = "%10.4e"

        if phi:  # meters of OPD at central wavelength
            if phi == "perfect":
                self.phi = np.zeros(self.N)  # backwards compatibility
                vprint(
                    'LG_Model.__init__(): phi="perfect" deprecated in LG++.  Omit phi or use phi=None'
                )
            else:
                self.phi = phi
        else:
            self.phi = np.zeros(self.N)

        self.chooseholes = chooseholes
        """  affine2d property not to be changed in NRM_Model - create a new instance instead 
             Save affine deformation of pupil object or create a no-deformation object. 
             We apply this when sampling the PSF, not to the pupil geometry.
        """
        if affine2d is None:
            self.affine2d = utils.Affine2d(mx=1.0,
                                           my=1.0,
                                           sx=0.0,
                                           sy=0.0,
                                           xo=0.0,
                                           yo=0.0,
                                           name="Ideal")
        else:
            self.affine2d = affine2d