ReFRACtor
l1b.py
Go to the documentation of this file.
1 import numpy as np
2 
3 from .base import Creator
4 from .. import param
5 
6 from refractor import framework as rf
7 
9  "Extracts the surface pressure value from the attached meterological file"
10 
11  l1b = param.InstanceOf(rf.Level1b)
12  field = param.Scalar(str)
13 
14  list_fields = [
15  'time',
16  ]
17 
18  array_fields = [
19  'stokes_coefficient',
20  ]
21 
22  # Fields that can become ArrayWithUnit if no channel_index supplied
23  array_with_unit_fields = [
24  'latitude',
25  'longitude',
26  'sounding_zenith',
27  'sounding_azimuth',
28  'solar_zenith',
29  'solar_azimuth',
30  'relative_azimuth',
31  'altitude',
32  'relative_velocity',
33  'signal',
34  'spectral_coefficient',
35  ]
36 
37  def _as_list(self, accessor):
38  num_channels = self.l1b().number_spectrometer
39 
40  vals = []
41  for chan_idx in range(num_channels):
42  vals.append(accessor(chan_idx))
43  return vals
44 
45  def _as_array(self, accessor):
46  return np.array(self._as_list(accessor))
47 
48  def _as_array_with_unit(self, accessor):
49 
50  num_channels = self.l1b().number_spectrometer
51 
52  vals = []
53  units = None
54  for chan_idx in range(num_channels):
55  chan_val = accessor(chan_idx)
56  vals.append(chan_val.value)
57  new_units = chan_val.units
58  if units != None and new_units.name != units.name:
59  raise param.ParamError("All units for L1B values must be the same to compact as an array")
60  else:
61  units = new_units
62 
63  val_arr = np.array(vals)
64 
65  if len(val_arr.shape) == 1:
66  return rf.ArrayWithUnit_double_1(vals, units)
67  if len(val_arr.shape) == 2:
68  return rf.ArrayWithUnit_double_2(vals, units)
69  else:
70  raise param.ParamError("Unhandled return value size from L1b class")
71 
72  def create(self, channel_index=None, **kwargs):
73 
74  field_val = getattr(self.l1b(), self.field(), None)
75 
76  if field_val is None:
77  return param.ParamError("Field does not exist in Level1b interface: %s" % self.field())
78 
79  if np.isscalar(field_val):
80  return np.full(1, field_val)
81  elif callable(field_val):
82  if channel_index is not None:
83  return field_val(channel_index)
84  elif self.field() in self.array_with_unit_fields:
85  return self._as_array_with_unit(field_val)
86  elif self.field() in self.array_fields:
87  return self._as_array(field_val)
88  elif self.field() in self.list_fields:
89  return self._as_list(field_val)
90  else:
91  return field_val()
92  else:
93  return field_val
94 
96 
97  l1b = param.InstanceOf(rf.Level1b)
98 
99  def create(self, channel_index=None, **kwargs):
100  # Azimuth is modified because the convention used by the OCO L1B file is to
101  # take both solar and observation angles as viewed from an observer
102  # standing in the FOV. In this convention, the convention for glint
103  # would be a relative azimuth difference of 180 degrees, as the
104  # spacecraft and sun would be on opposite sides of the sky. However, the
105  # radiative transfer convention is that the azimuth angles must be the
106  # same for glint (it is "follow the photons" convention). However, we'd
107  # like the solar azimuth to not be changed, so as to continue to agree
108  # with zenith, so this change of the observation azimuth has the effect
109  # of putting everything in a "reverse follow-the-photons" convention,
110  # where we look from the satellite to the FOV, then from the FOV to the
111  # sun. Note that because of an old historical reason, however, both
112  # zenith angles remain > 0 and < 90, even in the RT convention.
113 
114  l1b = self.l1b()
115  orig_units = l1b.sounding_azimuth(0).units;
116 
117  rel_azm_vals = []
118  deg_units = rf.Unit("deg")
119  for chan_idx in range(l1b.number_spectrometer):
120  val = (180 + l1b.sounding_azimuth(chan_idx).convert(deg_units).value) - \
121  l1b.solar_azimuth(chan_idx).convert(deg_units).value
122 
123  if val > 360:
124  val -= 360
125  elif val < 0:
126  val += 360
127 
128  rel_azm_vals.append(val)
129 
130  return rf.ArrayWithUnit_double_1(rel_azm_vals, orig_units)
131 
133 
134  l1b = param.InstanceOf(rf.Level1b)
135  constants = param.InstanceOf(rf.Constant)
136  do_doppler_shift = param.Scalar(bool, default=True)
137 
138  def create(self, **kwargs):
139 
140  l1b = self.l1b()
141  num_channels = l1b.number_spectrometer
142 
143  solar_dist_vals = np.empty(num_channels)
144  solar_dist_units = None
145  for chan_idx in range(num_channels):
146  chan_doppler_shift = \
147  rf.SolarDopplerShiftPolynomial(l1b.time(chan_idx),
148  l1b.latitude(chan_idx),
149  l1b.solar_zenith(chan_idx),
150  l1b.solar_azimuth(chan_idx),
151  l1b.altitude(chan_idx),
152  self.constants(),
153  self.do_doppler_shift());
154  chan_solar_dist = chan_doppler_shift.solar_distance
155  solar_dist_vals[chan_idx] = chan_solar_dist.value
156  solar_dist_units = chan_solar_dist.units
157 
158  return rf.ArrayWithUnit_double_1(solar_dist_vals, solar_dist_units)
def _as_array_with_unit(self, accessor)
Definition: l1b.py:48
def create(self, channel_index=None, kwargs)
Definition: l1b.py:72
def create(self, channel_index=None, kwargs)
Definition: l1b.py:99

Copyright © 2017, California Institute of Technology.
ALL RIGHTS RESERVED.
U.S. Government Sponsorship acknowledged.
Generated Fri Aug 24 2018 15:44:10