OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
profile_management.c
Go to the documentation of this file.
1 /* this file is a partial copy of profile_utils.c/.h from UW-M 1km CT code */
2 
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <math.h>
6 #include "profile_management.h"
7 
8 #define GRAV_ACCEL_EARTH 9.80665 /* m / s^2 */
9 #define SPEC_GAS_CONST_AIR 287.05 /* J / kg K */
10 #define SPEC_GAS_CONST_H2O 461.51 /* J / kg K */
11 
12 /*******************************************************************************
13  /
14  *******************************************************************************/
15 double lin_int(double x1, double x2, double x, double y1, double y2) {
16 
17  return (x - x1) / (x2 - x1) * (y2 - y1);
18 }
19 
20 
21 /*******************************************************************************
22 /
23 *******************************************************************************/
24 
25 int profile_to_101_(double *p, double *t, double *w, int *nn, double *nlat,
26  double *pp, double *tt, double *ww, int *is_o3) {
27  int i;
28 
29  int iy;
30  int iz;
31  int nlx = 101;
32 
33  int i_str;
34  int i_end;
35 
36  double anum;
37  double aden;
38 
39  double rlogp;
40 
41  double delt;
42  double delw;
43 
44  double wmin;
45  double wmax;
46 
47  double pb[2];
48  double tb[2];
49  double wb[2];
50 
51  int n;
52  double lat;
53 
54  n = *nn;
55  lat = *nlat;
56 
57  if (n < 2) {
58  printf("number of levels must be atleast 2\n");
59  return -1;
60  }
61 
62  if (*is_o3 == 1)
63  wmin = 0.;
64  else
65  wmin = 0.003;
66 
67 
68  /*make_profile_101(pp);*/
69  int_levels_pp(p, t, w, n, pp, tt, ww, nlx, &i_str, &i_end);
70 
71  if (i_str >= 35) {
72  printf("ERROR: temperature profile doesn't go high enough\n");
73  return -1;
74  }
75 
76  for (i = 0; i < i_str; ++i) {
77  tt[i] = -1.;
78  ww[i] = wmin;
79  }
80 
81  extem101_64_(tt, &lat);
82 
83  iz = n - 1;
84 
85  if (p[iz] < pp[nlx-1]) {
86  pb[0] = p[iz];
87  tb[0] = t[iz];
88  wb[0] = w[iz];
89 
90  pb[1] = pp[nlx-1];
91 
92  iy = n - 2;
93 /*
94  while (p[iy] >= p[iz])
95  --iy;
96 */
97  anum = log(pb[1] / pb[0]);
98  aden = log(pb[1] / p[iy]);
99 
100  rlogp = anum / aden;
101 
102  delt = t[iz] - t[iy];
103  tb[1] = t[iz] + delt * rlogp;
104 
105  delw = w[iz] - w[iy];
106  wb[1] = w[iz] + delw * rlogp;
107 
108  if (wb[1] < wmin)
109  wb[1] = wmin;
110  else {
111  wmax = get_satmix(pb[1], tb[1]);
112 
113  if (wb[1] > wmax)
114  wb[1] = wmax;
115  }
116 
117  i = i_end + 1;
118 
119  int_levels_pp(pb, tb, wb, 2, pp+i, tt+i, ww+i, nlx-i, &i_str, &i_end);
120  }
121 
122  return 0;
123 }
124 
125 float get_satmix(float P, float T) {
126 
127 
131  const float c = 4187.;
132  const float cpv = 1870. ;
133  const float L0 = 2.501e6 ;
134  const float T0 = 273.;
135 
136  float L, esat, ws;
137 
138  if (T < 235.)
139  L = 2.83e6;
140  else
141  L = L0 - (c - cpv) * (T - T0); /* ! latent heat of water */
142 
143  esat = 6.11657*exp((L/461.51)*(1/273. - 1/T) );
145  ws = esat * 0.622 / (P - esat) * 1000.;
147  return ws;
148 
149 }
150 
151 
152 
153 
154 /*******************************************************************************
155 /
156 *******************************************************************************/
157 int make_profile_101_(double *p) {
158 
159  int i;
160 
161  double l;
162 
163  double a = -1.550789414500298e-04;
164  double b = -5.593654380586063e-02;
165  double c = 7.451622227151780e+00;
166 
167  l = 101;
168  for (i = 0; i < 101; ++i) {
169  p[i] = pow((a*l*l + b*l + c), (7./2.));
170  l = l - 1;
171  }
172 
173  return 0;
174 }
175 
176 /*******************************************************************************
177 /
178 *******************************************************************************/
179 int int_levels_pp(double *p, double *t, double *w, int n,
180  double *pp, double *tt, double *ww, int nn, int *i_str, int *i_end) {
181 
182  int i;
183  int ii;
184 
185  double dl;
186 
187  double slope_t;
188  double slope_w;
189 
190  if (n < 2) {
191  *i_str = 0;
192  *i_end = -1;
193 
194  return 0;
195  }
196 
197  for (i = 0; i < nn; ++i) {
198  if (pp[i] >= p[0])
199  break;
200 
201  tt[i] = 0.;
202  ww[i] = 0.;
203  }
204 
205  *i_str = i;
206 
207  ii = 1;
208 
209  dl = log(p[ii] / p[ii-1]);
210  slope_t = (t[ii] - t[ii-1]) / dl;
211  slope_w = (w[ii] - w[ii-1]) / dl;
212 
213  for ( ; i < nn; ) {
214  if (pp[i] < p[ii]) {
215  dl = log(pp[i] / p[ii-1]);
216  tt[i] = t[ii-1] + slope_t * dl;
217  ww[i] = w[ii-1] + slope_w * dl;
218 
219  ++i;
220  }
221  else {
222  ++ii;
223  if (ii >= n) {
224  if (p[ii-1] == pp[i]) {
225  tt[i] = t[ii-1];
226  ww[i] = w[ii-1];
227 
228  ++i;
229  }
230 
231  break;
232  }
233 
234  dl = log(p[ii] / p[ii-1]);
235  slope_t = (t[ii] - t[ii-1]) / dl;
236  slope_w = (w[ii] - w[ii-1]) / dl;
237  }
238  }
239 
240  *i_end = i - 1;
241 
242  for ( ; i < nn; ++i) {
243  tt[i] = 0.;
244  ww[i] = 0.;
245  }
246 
247  return 0;
248 }
249 
250 /*******************************************************************************
251 /
252 *******************************************************************************/
253 int height_profile_(double *p, double *t, double *w, double *z, int *nn, double *np0) {
254 
255  int i;
256 
257  int i_up;
258  int i_dn;
259 
260  double g;
261 
262  double Rd;
263  double Rv;
264 
265  double epsilon;
266 
267  double t0;
268  double w0;
269 
270  double z_cur;
271 
272  double p_last;
273  double t_last;
274  double w_last;
275 
276  double P;
277  double T;
278  double W;
279 
280  double e;
281 
282  double rho;
283 
284  int n;
285  double p0;
286 
287  n = *nn-1; /* we're calling from fortran */
288  p0 = *np0;
289 
291 
292  Rd = SPEC_GAS_CONST_AIR;
293  Rv = SPEC_GAS_CONST_H2O;
294 
295  epsilon = Rd / Rv;
296 
297 
298  for (i = 0; i < n; ++i) {
299  if (p[i] > p0)
300  break;
301  }
302 
303  if (i == 0) {
304  i_up = i;
305  i_dn = i+1;
306  }
307  else {
308  i_up = i-1;
309  i_dn = i;
310  }
311 
312  t0 = t[i_up] + lin_int(p[i_up], p[i_dn], p0, t[i_up], t[i_dn]);
313  w0 = w[i_up] + lin_int(p[i_up], p[i_dn], p0, w[i_up], w[i_dn]);
314 
315  z_cur = 0;
316 
317  p_last = p0;
318  t_last = t0;
319  w_last = w0;
320  for (i = i_up+1; i >= 0; --i) {
321  P = (p_last + p[i]) / 2. * 100.;
322  T = (t_last + t[i]) / 2.;
323  W = (w_last + w[i]) / 2. / 1000.;
324 
325  e = W / (W + epsilon) * P;
326 
327  rho = (P-e) / (Rd*T) + e / (Rv*T);
328 
329  z_cur += (p_last-p[i])*100. / (g*rho);
330 
331  z[i] = z_cur;
332 
333  p_last = p[i];
334  t_last = t[i];
335  w_last = w[i];
336  }
337 
338 
339  z_cur = 0;
340 
341  p_last = p0;
342  t_last = t0;
343  w_last = w0;
344  for (i = i_dn; i < n; ++i) {
345  P = (p_last + p[i]) / 2. * 100.;
346  T = (t_last + t[i]) / 2.;
347  W = (w_last + w[i]) / 2. / 1000.;
348 
349  e = W / (W + epsilon) * P;
350 
351  rho = (P-e) / (Rd*T) + e / (Rv*T);
352 
353  z_cur += (p_last-p[i])*100. / (g*rho);
354 
355  z[i] = z_cur;
356 
357  p_last = p[i];
358  t_last = t[i];
359  w_last = w[i];
360  }
361 
362 
363 
364  return 0;
365 }
data_t t[NROOTS+1]
Definition: decode_rs.h:77
#define L(lambda, T)
Definition: PreprocessP.h:185
#define SPEC_GAS_CONST_H2O
double lin_int(double x1, double x2, double x, double y1, double y2)
float * lat
int make_profile_101_(double *p)
float slope_t[1000]
Definition: readL2scan.c:133
#define GRAV_ACCEL_EARTH
float pp[MODELMAX]
Definition: atrem_corl1.h:173
subroutine tt(NMAX, NCHECK)
Definition: ampld.lp.f:1852
const double T0
int profile_to_101_(double *p, double *t, double *w, int *nn, double *nlat, double *pp, double *tt, double *ww, int *is_o3)
data_t b[NROOTS+1]
Definition: decode_rs.h:77
int int_levels_pp(double *p, double *t, double *w, int n, double *pp, double *tt, double *ww, int nn, int *i_str, int *i_end)
#define SPEC_GAS_CONST_AIR
float get_satmix(float P, float T)
int height_profile_(double *p, double *t, double *w, double *z, int *nn, double *np0)
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
int i
Definition: decode_rs.h:71
PGE01 indicating that PGE02 PGE01 V6 for and PGE01 V2 for MOD03 were used to produce the granule By convention adopted in all MODIS Terra PGE02 code versions are The fourth digit of the PGE02 version denotes the LUT version used to produce the granule The source of the metadata environment variable ProcessingCenter was changed from a QA LUT value to the Process Configuration A sign used in error in the second order term was changed to a
Definition: HISTORY.txt:424
void extem101_64_(double *tt, double *slat)
float p[MODELMAX]
Definition: atrem_corl1.h:131