__init__.py 6.18 KB
Newer Older
1
2
from .forward import forward
from .adjoint import adjoint
3

4
import numpy as np
5
6
import os
import glob
7
from logging import info
8
9
from pycif.utils.path import init_dir, link

10
11
_name = "satellites"

12
13
14
15
16
17
requirements = {
    "model": {
        "any": True,
        "empty": False
    },
}
18

19
input_arguments = {
20
21
22
23
24
25
26
27
28
29
    # "dir_satellites": {
    #    "doc": "directory where the formatted monitor.nc files are located",
    #    "default": None,
    #    "accepted": str
    # },
    # "file": {
    #    "doc": "form of the name of the files to use",
    #    "default": None,
    #    "accepted": str
    # },
30
    "formula": {
31
        "doc": """
Robin Plauchu's avatar
Robin Plauchu committed
32
33
34
35
36
37
38
39
40
41
42
43
                Number of the formula to use to apply the averaging kernels.
                With :math:`nlevsat` the number of levels of the satellite,
                :math:`y` the equivalent of the satellite data,
                :math:`y^s` the simulated concentrations interpolated on these levels,
                :math:`\Delta P_i` the pressure thicknesses of these levels [remark: if the thicknesses are not provided directly, this implies that the pressures for the sides of the levels are provided, including the surface pressure for the bottom of the lowest level],
                :math:`y^0_i` the prior concentrations on these levels (prior profile),
                :math:`ak_i` the averaging kernels and if relevant,
                :math:`chosenlev` the number of the level of the chosen partial column.
                     - Formula 1: :math:`y= \\frac{\\sum_{i=1}^{nlevsat}y^s_i \Delta P_i  ak_i}{\\sum_{i=1}^{nlevsat}\Delta P_i  ak_i}`
                     - Formula 2: :math:`y= \\sum_{i=1}^{nlevsat}y^s_i ak_i`
                     - Formula 3: :math:`y= 10^{\\left(logy^0_{chosenlev}+\\sum_{i=1}^{nlevsat}(logy^s_i-logy^0_i)ak_i\\right)}`
                     - Formula 4: :math:`y= \\sum_{i=1}^{nlevsat}y^s_i ak_i 10^3`
44
45
                     - Formula 5: :math:`y= \\frac{y^0+\\sum_{i=1}^{nlevsat}ak_i(y_{dry,i}^s.dryair_i-y^0_i)}{dryair_{tot}}`

Robin Plauchu's avatar
Robin Plauchu committed
46
                """,
47
        "default": None,
48
        "accepted": [1, 2, 3, 4, 5]
49
50
    },
    "product": {
51
52
53
        "doc": "Type of product",
        "default": "level",
        "accepted": {
Antoine Berchet's avatar
Antoine Berchet committed
54
            "level": "Levels in ppb",
55
            "column": "Total column. In that case, carry out a conversion from "
56
                      "ppb to molec.cm-2XX pas super clair: ou? en quelle unite doit-on donner la col?"
57
        }
58
    },
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    "pressure": {
        "doc": "Unit for the pressure levels",
        "default": "hPa",
        "accepted": {
            "hPa": "hectoPascals",
            "Pa": "Pascals"
        }
    },
    "nchunks": {
        "doc": "Number of chunks for the application of averaging kernels. "
               "Averaging kernels are applied by chunks and not observation "
               "by observation to accelerate computation. "
               "Chunks should not be too small, neither too large. "
               "As a rule of thumb, chunks of a few hundreds to one thousand "
               "observations are working fine. Smaller chunks loose the "
               "advantage of chunk-based computations, while too big chunks "
               "can overload your memory. "
               "For very low number of observations, 1-2 chunks are sufficient;"
               "For big datasets, one should test different number (a few "
               "tens is typically recommended)",
        "default": 50,
80
81
82
        "accepted": int
    },
    "cropstrato": {
83
84
85
86
87
88
        "doc": "Cropping stratospheric averaging kernels. All averaging "
               "kernels above the top of the model are excluded. "
               "Warning: for domain-limited domain, if cropstrato is False, "
               "the top-most value from the model is interpolated to the top "
               "of the atmosphere, potentially biasing results (not "
               "recommended)",
89
90
91
        "default": False,
        "accepted": bool
    },
92
93
94
95
    "fill_strato": {
        "doc": "Filling stratosphere from a global model (temporary "
               "implemetation)",
        "default": False,
96
97
        "accepted": int
    },
98
99
100
101
102
103
104
    "molmass": {
        "doc": "If fill_strato is True and product is column, molar mass (in g)"
               " of the species whose field"
               " is read in the stratosphere files.",
        "default": None,
        "accepted": float
    },
105
    "correct_pthick": {
106
107
108
109
110
111
        "doc": "Correct for the thickness of the column. Due to topography "
               "and surface pressure approximations and errors in the model, "
               "the total column of air is never exactly the same between "
               "observations and the model. For that reason, a correcting "
               "factor can be applied to scale the thickness of the model "
               "column to make it fit the observed column",
112
113
114
        "default": False,
        "accepted": bool
    },
115
    "chosenlev": {
Antoine Berchet's avatar
Antoine Berchet committed
116
117
118
        "doc": "For formula type #3, level at which "
               "the equivalent of the observation are computed. "
               "Counting starts at 0.",
119
120
        "default": 0,
        "accepted": int
121
    },
122
}
123

124
125
navogadro = 6.02214199e+23
g = 9.8
126
dry_air_mass = 28.966
127

128

Antoine Berchet's avatar
Antoine Berchet committed
129
def ini_mapper(
130
        transform, general_mapper={}, backup_comps={}, transforms_order=[],
131
        ref_transform="", successor="", **kwargs
Antoine Berchet's avatar
Antoine Berchet committed
132
):
133
    """Initialize mapper for time cropping.
134
135
    Does not need to change the mapper as cropping time keep similar
    names and dimensions"""
136
137

    trid = (transform.component[0], transform.parameter[0])
138

139
140
    ref_inputs = general_mapper[successor]["inputs"] if successor != {} \
        else {}
141
    mapout = {trid: {param: ref_inputs.get(trid, {})[param]
142
143
144
145
146
                     for param in ref_inputs.get(trid, {})}}

    input_components = \
        ["concs", "pressure", "dpressure"] \
        + (transform.product == "column") * ["airm", "hlay"]
147
148
    mapin = {(comp, trid[1]): {
        "isobs": True, "force_loadin": True,
149
        **mapout.get(trid, {})}
150
        for comp in input_components
151
    }
152
    mapper = {"inputs": mapin,
153
              "outputs": mapout}
154

155
    if transform.fill_strato:
156
        mapper["inputs"].update({
157
158
159
            ("stratosphere", trid[1]):
                {**mapin[("concs", trid[1])],
                 **{"domain_from_previous": True}}
160
        })
161

162
    return mapper