example_interface.py 5.71 KB
Newer Older
BO ZHANG's avatar
BO ZHANG committed
1
2
3
4
5
6
import logging
import os
from typing import Union

import numpy as np
from astropy.io import fits
7
import joblib
BO ZHANG's avatar
BO ZHANG committed
8
from csst_common.data_manager import CsstMsDataManager
BO ZHANG's avatar
BO ZHANG committed
9
from csst_common.file_recorder import FileRecorder
BO ZHANG's avatar
BO ZHANG committed
10
11
12
13
from csst_common.logger import get_logger
from csst_common.status import CsstStatus


BO ZHANG's avatar
BO ZHANG committed
14
def read_image(filepath_input: str) -> np.ndarray:
BO ZHANG's avatar
BO ZHANG committed
15
    """ Read image. """
BO ZHANG's avatar
BO ZHANG committed
16
    return fits.getdata(filepath_input)
BO ZHANG's avatar
BO ZHANG committed
17
18
19
20
21
22
23


def process_data(data: np.ndarray) -> np.ndarray:
    """ Process data. """
    return np.fliplr(np.flipud(data))


24
# process a single image (NOT RECOMMENDED!)
BO ZHANG's avatar
BO ZHANG committed
25
def process_single_image(
BO ZHANG's avatar
BO ZHANG committed
26
27
        filepath_input: str,
        filepath_output: str,
BO ZHANG's avatar
BO ZHANG committed
28
        logger: Union[None, logging.Logger] = None
BO ZHANG's avatar
BO ZHANG committed
29
) -> tuple[CsstStatus, FileRecorder]:
BO ZHANG's avatar
BO ZHANG committed
30
31
32
33
34
35
36
    """
    Flip a single image.

    Flip a single image with ``numpy.fliplr`` and ``numpy.flipud``.

    Parameters
    ----------
BO ZHANG's avatar
BO ZHANG committed
37
38
39
40
    filepath_input : str
        The input filepath.
    filepath_output : str
        The output filepath.
BO ZHANG's avatar
BO ZHANG committed
41
42
43
44
45
    logger : logging.Logger
        The logger.

    Returns
    -------
BO ZHANG's avatar
BO ZHANG committed
46
    tuple[CsstStatus, FileRecorder]
BO ZHANG's avatar
BO ZHANG committed
47
48
49
50
51
        The final status.

    Examples
    --------
    >>> process_single_image(
BO ZHANG's avatar
BO ZHANG committed
52
53
    >>>     filepath_input="input_image.fits",
    >>>     filepath_output="output_image.fits",
BO ZHANG's avatar
BO ZHANG committed
54
55
56
57
58
59
60
    >>>     logger=None
    >>> )
    """
    # set default logger
    if logger is None:
        logger = get_logger()

BO ZHANG's avatar
BO ZHANG committed
61
62
63
    # get an empty file recorder
    fr = FileRecorder()

BO ZHANG's avatar
BO ZHANG committed
64
    # process data
BO ZHANG's avatar
BO ZHANG committed
65
66
67
68
69
70
71
72
73
74
75
76
    logger.info("Start processing image {}".format(filepath_input))
    # start processing
    data = read_image(filepath_input)
    data_processed = process_data(data)
    np.save(filepath_output, data_processed)
    # record file!
    fr.add_record(filepath=filepath_output, db=True, comment="the processed image")
    # this will be written into the log file
    logger.info("Finish processing, result saved to {}".format(filepath_output))

    # check result existence
    if os.path.exists(filepath_output):
BO ZHANG's avatar
BO ZHANG committed
77
78
79
80
        # file exists, check status and precision
        if fits.getheader(filepath_output)["STT_DIST"] == 0 and \
                fits.getheader(filepath_output)["PCS_DIST"] < 1e-5 and \
                fits.getheader(filepath_output)["NS_DIST"] >= 8:
BO ZHANG's avatar
BO ZHANG committed
81
            return CsstStatus.PERFECT, fr
BO ZHANG's avatar
BO ZHANG committed
82
        else:
BO ZHANG's avatar
BO ZHANG committed
83
            return CsstStatus.WARNING, fr
BO ZHANG's avatar
BO ZHANG committed
84
85
86
87
    else:
        # file doesn't exist, do your fallback solution
        fits.HDUList(fits.PrimaryHDU()).writeto(filepath_output)
        assert os.path.exists(filepath_output)
BO ZHANG's avatar
BO ZHANG committed
88
        return CsstStatus.WARNING, fr
BO ZHANG's avatar
BO ZHANG committed
89
90


91
92
# process multiple images in an exposure (RECOMMENDED, at least for MBI or SLS)
# define a single job
BO ZHANG's avatar
BO ZHANG committed
93
def one_job(dm: CsstMsDataManager, detector: int):
94
95
96
    """ Process a single image, defined for parallel processing. """
    filepath_input = dm.l0_detector(detector=detector)
    filepath_output = dm.l1_detector(detector=detector, post="L1_processed.fits")
BO ZHANG's avatar
BO ZHANG committed
97
98

    # data processing
99
100
101
    data = read_image(filepath_input)
    data_processed = process_data(data)
    np.save(filepath_output, data_processed)
BO ZHANG's avatar
BO ZHANG committed
102
103
104

    # check result existence
    if os.path.exists(filepath_output):
BO ZHANG's avatar
BO ZHANG committed
105
106
107
108
        # file exists, check status and precision
        if fits.getheader(filepath_output)["STT_DIST"] == 0 and \
                fits.getheader(filepath_output)["PCS_DIST"] < 1e-5 and \
                fits.getheader(filepath_output)["NS_DIST"] >= 8:
BO ZHANG's avatar
BO ZHANG committed
109
110
111
112
113
114
115
116
            return CsstStatus.PERFECT
        else:
            return CsstStatus.WARNING
    else:
        # file doesn't exist, do your fallback solution
        fits.HDUList(fits.PrimaryHDU()).writeto(filepath_output)
        assert os.path.exists(filepath_output)
        return CsstStatus.WARNING
117
118


BO ZHANG's avatar
BO ZHANG committed
119
# process in serial / parallel
BO ZHANG's avatar
BO ZHANG committed
120
121
def process_multiple_images(
        dm: CsstMsDataManager,
BO ZHANG's avatar
BO ZHANG committed
122
) -> tuple[CsstStatus, FileRecorder]:
BO ZHANG's avatar
BO ZHANG committed
123
124
125
    """
    Flip all images.

126
    Flip all images in an exposure in a for-loop (serial and parallel).
BO ZHANG's avatar
BO ZHANG committed
127
128
129
130
131
132
133
134

    Parameters
    ----------
    dm : CsstMsDataManager
        The data manager of the specified exposure.

    Returns
    -------
BO ZHANG's avatar
BO ZHANG committed
135
    tuple[CsstStatus, FileRecorder]
BO ZHANG's avatar
BO ZHANG committed
136
137
138
139
140
        The final status.

    Examples
    --------
    >>> dm = CsstMsDataManager.quickstart(
BO ZHANG's avatar
BO ZHANG committed
141
    >>>     ver_sim="C5.2", dir_l1="", datatype="sls", exposure_id=100)
BO ZHANG's avatar
BO ZHANG committed
142
    >>> process_multiple_images(dm)
BO ZHANG's avatar
BO ZHANG committed
143
144
    """

BO ZHANG's avatar
BO ZHANG committed
145
146
147
    # get an empty file recorder
    fr = FileRecorder()

BO ZHANG's avatar
BO ZHANG committed
148
    # process data
BO ZHANG's avatar
BO ZHANG committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
    # start processing (dm.target_detectors is a list of detector number that should be processed)

    # [1/2] single-thread mode
    for detector in dm.target_detectors:
        # this will NOT be written into the log file
        dm.logger_mod.info("Start data processing for detector {}".format(detector))
        filepath_input = dm.l0_detector(detector=detector)
        filepath_output = dm.l1_detector(detector=detector, post="L1_processed.fits")
        data = read_image(filepath_input)
        data_processed = process_data(data)
        np.save(filepath_output, data_processed)
        # record file!
        fr.add_record(filepath=filepath_output, db=True, comment="processed file for Detector {}".format(detector))

    # [2/2] multi-processing mode
    dm.logger_mod.info("Starting data processing with multiprocessing ...")
    status_list = joblib.Parallel(n_jobs=dm.n_jobs, backend=dm.backend)(
        joblib.delayed(one_job)(dm, detector) for detector in dm.target_detectors
    )
    dm.logger_mod.info("Finished processing ...")
    for detector in dm.target_detectors:
        filepath_output = dm.l1_detector(detector=detector, post="L1_processed.fits")
        fr.add_record(filepath=filepath_output, db=True, comment="processed file for Detector {}".format(detector))

    # check results
    assert fr.is_good()
    return CsstStatus.PERFECT if all([_ == CsstStatus.PERFECT for _ in status_list]) else CsstStatus.WARNING, fr