OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
get_npp.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <math.h>
3 #include "l12_proto.h"
4 #include "get_npp.h"
5 
6 
7 double betasw_ZHH2009(double, double, double);
8 float opp_cafe( float PAR,
9  float chl,
10  float mld,
11  float lat,
12  int yd,
13  float aph_443,
14  float adg_443,
15  float bbp_443,
16  float bbp_s,
17  float sst );
18 
35 void get_npp(l2str *l2rec, int prodnum, float prod[]) {
36  static int32_t ib440;
37  int32_t ip, ipb;
38  float *kd, *par;
39  static float32 *parin, *lat, *lon;
40  static int nlat, nlon;
41  float sst, chl, trise, tset, mld, bbp, zno3, irr;
42  static int firstCall = 1, havefile;
43  char *parfile = input->parfile;
44 
45  l1str *l1rec = l2rec->l1rec;
46 
47  int16_t year, day;
48  double sec;
49  unix2yds(l2rec->l1rec->scantime, &year, &day, &sec);
50 
51  char sdsname[H4_MAX_NC_NAME];
52  int ncid, ndims;
53  int32 sds_id;
54  int status;
55  nc_type rh_type; /* variable type */
56  int dimids[H4_MAX_VAR_DIMS]; /* dimension IDs */
57  int natts; /* number of attributes */
58  size_t length;
59 
60  int nbands=l1rec->l1file->nbands;
61  float *aph,*adg,*bbp_temp,*bbp_s;
62  static int32_t ib443;
63 
64  if (firstCall && strcmp(parfile, "") != 0) {
65  /* try netCDF first */
66  if (nc_open(parfile, NC_NOWRITE, &ncid) == NC_NOERR) {
67 
68 
69  strcpy(sdsname, "lat");
70 
71  status = nc_inq_varid(ncid, sdsname, &sds_id);
72  if (status != NC_NOERR) {
73  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
74  __FILE__, __LINE__, sdsname, parfile);
75  exit(1);
76  }
77 
78  status = nc_inq_var(ncid, sds_id, 0, &rh_type, &ndims, dimids,
79  &natts);
80 
81  if (nc_inq_dimlen(ncid, dimids[0], &length) != NC_NOERR) {
82  char name[H4_MAX_NC_NAME];
83  nc_inq_dim(ncid, dimids[0], name, &length);
84  fprintf(stderr,
85  "-E- %s line %d: could not get size of dimension \"%s\" in netCDF File.\n",
86  __FILE__, __LINE__, name);
87  exit(1);
88  }
89 
90  nlat = length;
91 
92  if ((lat = (float *) calloc(nlat, sizeof (float))) == NULL) {
93  printf("-E- : Error allocating memory to tindx\n");
94  exit(FATAL_ERROR);
95  }
96 
97  if (nc_get_var(ncid, sds_id, lat) != NC_NOERR) {
98  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
99  __FILE__, __LINE__, sdsname, parfile);
100  exit(1);
101  }
102 
103  strcpy(sdsname, "lon");
104 
105  status = nc_inq_varid(ncid, sdsname, &sds_id);
106  if (status != NC_NOERR) {
107  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
108  __FILE__, __LINE__, sdsname, parfile);
109  exit(1);
110  }
111 
112  status = nc_inq_var(ncid, sds_id, 0, &rh_type, &ndims, dimids,
113  &natts);
114  if (status != NC_NOERR) {
115  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
116  __FILE__, __LINE__, sdsname, parfile);
117  exit(1);
118  }
119 
120  if (nc_inq_dimlen(ncid, dimids[0], &length) != NC_NOERR) {
121  char name[H4_MAX_NC_NAME];
122  nc_inq_dim(ncid, dimids[0], name, &length);
123  fprintf(stderr,
124  "-E- %s line %d: could not get size of dimension \"%s\" in netCDF File.\n",
125  __FILE__, __LINE__, name);
126  exit(1);
127  }
128 
129  nlon = length;
130 
131  if ((lon = (float *) calloc(nlon, sizeof (float))) == NULL) {
132  printf("-E- : Error allocating memory to tindx\n");
133  exit(FATAL_ERROR);
134  }
135 
136  if (nc_get_var(ncid, sds_id, lon) != NC_NOERR) {
137  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
138  __FILE__, __LINE__, sdsname, parfile);
139  exit(1);
140  }
141 
142  strcpy(sdsname, "par");
143 
144  status = nc_inq_varid(ncid, sdsname, &sds_id);
145  if (status != NC_NOERR) {
146  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
147  __FILE__, __LINE__, sdsname, parfile);
148  exit(1);
149  }
150 
151  status = nc_inq_var(ncid, sds_id, 0, &rh_type, &ndims, dimids,
152  &natts);
153  if (status != NC_NOERR) {
154  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
155  __FILE__, __LINE__, sdsname, parfile);
156  exit(1);
157  }
158  if (ndims != 2) {
159  fprintf(stderr, "-E- %s line %d: Wrong number of dimensions for %s. Need 2 got %d.\n",
160  __FILE__, __LINE__, sdsname, ndims);
161  exit(1);
162 
163  }
164  printf("PARFILE: %s nlat=%d nlon=%d\n", parfile, nlat, nlon);
165 
166  if ((parin = (float *) calloc(nlat * nlon, sizeof (float))) == NULL) {
167  printf("-E- : Error allocating memory to tindx\n");
168  exit(FATAL_ERROR);
169  }
170 
171  if (nc_get_var_float(ncid, sds_id, parin) != NC_NOERR) {
172  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
173  __FILE__, __LINE__, sdsname, parfile);
174  exit(1);
175  }
176  // apply scale_factor and add_offset
177  double add_offset = 0.0, scale_factor = 1.0;
178  nc_get_att_double(ncid, sds_id, "add_offset", &add_offset);
179  nc_get_att_double(ncid, sds_id, "scale_factor", &scale_factor);
180  int i;
181  for (i=0; i<nlat*nlon; i++){
182  parin[i] *= scale_factor;
183  parin[i] += add_offset;
184  }
185 
186  havefile = 1;
187 
188  } else {
189  fprintf(stderr, "-E- %s line %d: Error opening parfile = %s.\n",
190  __FILE__, __LINE__, parfile);
191  exit(1);
192  }
193  }
194 
195  if ((kd = (float *) calloc(l1rec->npix, sizeof (float))) == NULL) {
196  printf("-E- : Error allocating memory to par in get_opp\n");
197  exit(FATAL_ERROR);
198  }
199  if ((par = (float *) calloc(l1rec->npix, sizeof (float))) == NULL) {
200  printf("-E- : Error allocating memory to par in get_opp\n");
201  exit(FATAL_ERROR);
202  }
203 
204  if (prodnum == CAT_npp_cbpm2) {
205  if (input->iop_opt == IOPNONE) {
206  printf("IOP-based Kd_lee product requires iop model selection (iop_opt). ");
207  printf("Using default model.\n");
208  input->iop_opt = IOPDEFAULT;
209  get_iops(l2rec, input->iop_opt);
210  }
211  Kd490_obpg(l2rec, kd);
212  }
213 
214  /* get irradiance E/D/m^2*/
215 
216  if (havefile)
217  get_par_clim(parin, lat, lon, nlat, nlon, l1rec->lat, l1rec->lon, l1rec->npix, par);
218  else
219  get_par(l2rec, par);
220 
221  for (ip = 0; ip < l1rec->npix; ip++) {
222  sst = l1rec->sstref[ip];
223  chl = l2rec->chl[ip];
224  /* Get the rise and set time for this day to get the number of hours of daylight:*/
225  triseset(day, l1rec->lon[ip], l1rec->lat[ip], &trise, &tset);
226 
227  switch (prodnum) {
228  case CAT_npp_mld:
229  prod[ip] = get_mld(input->mldfile, l1rec->lon[ip], l1rec->lat[ip], day);
230  break;
231  case CAT_npp_zno3:
232  prod[ip] = get_zno3(l1rec->lon[ip], l1rec->lat[ip], day);
233  break;
234  case CAT_npp_bbp:
235  prod[ip] = l2rec->bb[l1rec->l1file->nbands * ip + ib440];
236  break;
237  case CAT_npp_par:
238  prod[ip] = par[ip];
239  break;
240  default:
241 
242  if (par[ip] != BAD_FLT && chl > 0) {
243 
244  switch (prodnum) {
245  case CAT_npp_vgpm:
246  if (sst > -2)
247  prod[ip] = npp_vgpm(chl, par[ip], sst, tset - trise);
248  else
249  l1rec->flags[ip] |= PRODFAIL;
250 
251  break;
252  case CAT_npp_eppley:
253  if (sst > -2)
254  prod[ip] = npp_eppley(chl, par[ip], sst, tset - trise);
255  else
256  l1rec->flags[ip] |= PRODFAIL;
257  //if (ip % 100 == 0)
258  // printf("RJH: %f %f %f %f %f\n",prod[ip],chl, par[ip], sst, tset-trise);
259  break;
260  case CAT_npp_cbpm2:
261  if (firstCall) {
262  ib440 = bindex_get(440);
263  if (ib440 < 0) {
264  printf("opp_cbpm2: incompatible sensor wavelengths (no 440 for backscatter coefficient).\n");
265  exit(1);
266  }
267  }
268  mld = get_mld(input->mldfile, l1rec->lon[ip], l1rec->lat[ip], day); //193
269  zno3 = get_zno3(l1rec->lon[ip], l1rec->lat[ip], day); //125
270  bbp = l2rec->bb[l1rec->l1file->nbands * ip + ib440];
271  irr = par[ip]; //53
272  // bbp = 0.005;
273  // mld = 50;
274  // zno3=125;
275  // irr=53;
276  // tset=19;
277  // trise=5;
278  // kdtmp=0.03; //kd[ip]
279  // chl = 0.1;
280  // if (mld == BAD_FLT) mld = 50;
281  // if (zno3 == BAD_FLT) zno3 = 50;
282  if (bbp > 0 && mld != BAD_FLT && zno3 != BAD_FLT) {
283  prod[ip] = npp_cbpm2(chl, bbp, irr, kd[ip], mld, zno3, tset - trise);
284  //if (ip % 1 == 0)
285  // printf("RJH: %d %d %f %f %f %f %f %f %f %f %d ",ip,l2rec->iscan,chl, irr, sst, bbp, kd[ip], mld, zno3, tset-trise, *l2rec->day);
286  //if (prod[ip] == 0) prod[ip] = BAD_FLT;
287  // if (ip % 1 == 0)
288  // printf("%f\n",prod[ip]);
289  } else {
290  prod[ip] = BAD_FLT;
291  //l2rec->flags[ip] |= PRODFAIL;
292  }
293  break;
294  case CAT_npp_cafe:
295  if(firstCall){
296  ib443=bindex_get(443);
297  if (ib443 < 0) {
298  printf("npp_cafe: incompatible sensor wavelengths (no 443 for aph, adg, and bbp).\n");
299  exit(1);
300  }
301  }
302  mld = get_mld(input->mldfile, l1rec->lon[ip], l1rec->lat[ip], day);
303 
304  if (!giop_ran(l1rec->iscan)){
305  run_giop(l2rec);
306  }
307  aph=giop_get_aph_pointer();
308  adg=giop_get_adg_pointer();
309  bbp_temp=giop_get_bbp_pointer();
310  bbp_s=giop_get_bbp_s_pointer();
311  ipb=ip*nbands+ib443;
312 
313  prod[ip]=opp_cafe(par[ip],chl,mld,l1rec->lat[ip],day,aph[ipb],adg[ipb],bbp_temp[ipb],bbp_s[ip],sst);
314  break;
315  default:
316  printf("Error: %s : Unknown product specifier: %d\n", __FILE__, prodnum);
317  exit(1);
318  break;
319  }
320  } else {
321  l1rec->flags[ip] |= PRODFAIL;
322  prod[ip] = BAD_FLT;
323  }
324  break;
325  }
326 
327 
328  }
329 
330  free(kd);
331  free(par);
332 
333  firstCall = 0;
334 }
335 
336 void get_par_clim(float *parin, float *lat, float *lon, int nlat, int nlon, float *latp, float *lonp, int32_t npix, float *par) {
337 
338  int32_t i, j, n, incx, incy, startx, starty;
339  float dx, dy;
340 
341  dy = *(lat + 1) - *(lat);
342  dx = *(lon + 1) - *(lon);
343 
344  if (dx > 0) {
345  incx = -1;
346  startx = nlon - 1;
347  } else {
348  incx = 1;
349  startx = 0;
350  }
351  if (dy > 0) {
352  incy = -1;
353  starty = nlat - 1;
354  } else {
355  incy = 1;
356  starty = 0;
357  }
358 
359  for (n = 0; n < npix; n++) {
360  for (i = startx; i >= 0 && i < nlon && (fabs(lonp[n] - lon[i]) > fabs(dx)); i += incx);
361  for (j = starty; j >= 0 && j < nlat && (fabs(latp[n] - lat[j]) > fabs(dy)); j += incy);
362  // printf("RJH: lat[%d]=%f latp[%d]=%f diff=%f dy=%f\n",j,lat[j],n,latp[n],fabs(latp[n] - lat[j]),dy);
363  if (j < nlat && i < nlon && i > 0 && j > 0)
364  par[n] = parin[j * nlon + i];
365  else
366  par[n] = BAD_FLT;
367 
368  // printf("RJH: n=%d par=%f latp=%f lonp=%f lat[%d]=%f lon[%d]=%f\n",n,par[n], latp[n],lonp[n],j,lat[j],i,lon[i]);
369  }
370 }
371 
420 float npp_vgpm(float chl, float irr, float sst, float dayL) {
421 
422  float chl_tot,
423  z_eu,
424  pb_opt,
425  irrFunc,
426  npp;
427 
428 
429  /* Calculate euphotic depth (z_eu) with Morel's Case I model. */
430  /* Calculate chl_tot from Satellite Surface Chlorophyll Data. */
431 
432  if (chl < 1.0)
433  chl_tot = 38.0 * pow(chl, 0.425);
434  else
435  chl_tot = 40.2 * pow(chl, 0.507);
436 
437 
438  z_eu = 200.0 * pow(chl_tot, (-.293));
439 
440  if (z_eu <= 102.0)
441  z_eu = 568.2 * pow(chl_tot, (-.746));
442 
443 
444  /* Calculate the Pb_opt from satellite sea surface temperature (sst). */
445 
446  if (sst < -10.0)
447  pb_opt = 0.00;
448  else if (sst < -1.0)
449  pb_opt = 1.13;
450  else if (sst > 28.5)
451  pb_opt = 4.00;
452  else {
453  pb_opt = 1.2956 + 2.749e-1 * sst + 6.17e-2 * pow(sst, 2) - 2.05e-2 * pow(sst, 3)
454  + 2.462e-3 * pow(sst, 4) - 1.348e-4 * pow(sst, 5) + 3.4132e-6 * pow(sst, 6)
455  - 3.27e-8 * pow(sst, 7);
456  }
457 
458 
459  /* calculate the irradiance function */
460 
461  irrFunc = 0.66125 * irr / (irr + 4.1);
462 
463 
464  /* Return the primary production calculation. */
465 
466  npp = pb_opt * chl * dayL * irrFunc * z_eu;
467 
468  if (npp < 0)
469  npp = BAD_FLT;
470 
471  return npp;
472 }
473 
474 /*
475 !C--------------------------------------------------------------------------*\
476 
477  !Description: opp_eppley - computes daily primary productivity using
478  the Behrenfeld-Falkowski (BeFa) algorithm, but
479  modifies the pb_opt function after Eppley (as
480  implemented by Antoine and Morel). The BeFa
481  algorithm estimates productivity using surface chl
482  (mg m-3), surface irradiance (Einsteins m-2 d-1),
483  sea surface temperature (C), and day length (hours).
484  Pb_opt is modelled as an exponential function of SST.
485 
486  !Input Parameters:
487  @param[in] chl Chlorophyll_a surface concentration in milligrams
488  chlorophyl per cubic meter
489  @param[in] irr Photosynthetically available radiation in Einsteins per
490  day per square meter
491  @param[in] sst Sea surface temperature in degrees Centigrade
492  @param[in] dayL Length day in decimal hours.
493 
494  !Output Parameters:
495  @param[out] Primary productivity in milligrams Carbon per square meter
496  per hour
497 
498  !Revision History:
499 
500  First programmed up by Monica Chen at Rutgers
501  (1996)
502 
503  Revised by K. Turpie at NASA
504  (August 1997)
505 
506  Maintained by Don Shea at NASA
507 
508  Now maintained by Robert O'Malley at Oregon State University
509  (April, 2005 - present)
510 
511  Modified for inclusion in l2gen for OBPG by R. Healy at NASA
512  (January 2015)
513 
514  !References and Credits
515 
516  Behrenfeld,M.J; Falkowski,P.G.; 1997. Photosynthetic Rates Derived
517  from Satellite-Based Chlorophyll Concentration. Limnology and
518  Oceanography, Volume 42, Number 1
519 
520  Eppley, R.W.; 1972. Temperature and Phytoplankton Growth in the Sea.
521  Fishery Bulletin, Volume 79, Number 4
522 
523  Antoine, D.; Morel, A.; 1996. Oceanic Primary Production
524  1. Adatptation of a Spectral Light-Photosynthesis Model
525  in view of Application to Satellite Chlorophyll Observations
526 
527 !END------------------------------------------------------------------------*\
528  */
529 
530 float npp_eppley(float chl,
531  float irr,
532  float sst,
533  float dayL) {
534 
535  float chl_tot,
536  z_eu,
537  pb_opt,
538  irrFunc,
539  npp;
540 
541 
542  /* Calculate euphotic depth (z_eu) with Morel's Case I model. */
543  /* Calculate chl_tot from Satellite Surface Chlorophyll Data. */
544 
545  if (chl < 1.0)
546  chl_tot = 38.0 * pow(chl, 0.425);
547  else
548  chl_tot = 40.2 * pow(chl, 0.507);
549 
550 
551  z_eu = 200.0 * pow(chl_tot, (-.293));
552 
553  if (z_eu <= 102.0)
554  z_eu = 568.2 * pow(chl_tot, (-.746));
555 
556 
557  /* Calculate the Pb_opt from satellite sea surface temperature (sst). */
558 
559  pb_opt = 1.54 * pow(10, 0.0275 * sst - 0.07);
560 
561 
562  /* calculate the irradiance function */
563 
564  irrFunc = 0.66125 * irr / (irr + 4.1);
565 
566 
567  /* Return the primary production calculation. */
568 
569  npp = pb_opt * chl * dayL * irrFunc * z_eu;
570 
571  if (npp < 0)
572  npp = BAD_FLT;
573 
574  return npp;
575 }
576 
662 double npp_cbpm2(double chl,
663  double bbp,
664  double irr,
665  double k490,
666  double mld,
667  double zno3,
668  double daylength) {
669 
670  double austinPetzold_1986(double, double);
671 
672  double uMax; /* max growth rate */
673  double chlCarbonMax; /* max chl:carbon ration */
674  double nutTempFunc; /* f(nut,T) */
675  double chlCarbonSat; /* satalite chl:carbon ratio */
676  double carbon; /* bbp converted to carbon */
677  double IgFunc; /* f(Ig) */
678  double IgFuncz; /* f(Ig) below the mixed layer depth */
679  double z_eu; /* euphotic depth at 1% light level */
680  double npp; /* net primary production */
681 
682  /* --------------------- */
683  /* spectral variables */
684  /* --------------------- */
685 
686  double lambda[] = {400, 412, 443, 490, 510, 555, 625, 670, 700};
687  double parFraction[] = {0.0029, 0.0032, 0.0035, 0.0037, 0.0037, 0.0036, 0.0032, 0.0030, 0.0024};
688  double X[] = {.11748, .122858, .107212, .07242, .05943, .03996, .04000, .05150, .03000};
689  double e[] = {.64358, .653270, .673358, .68955, .68567, .64204, .64700, .69500, .60000};
690  double Kw[] = {.01042, .007932, .009480, .01660, .03385, .06053, .28400, .43946, .62438};
691  double Kd[9];
692  double Kbio;
693  double Kdif[9];
694 
695  double Klambda[9];
696  double Eo[9];
697  double Ez_mld[9];
698  double par_mld;
699  double delChlC;
700 
701  double y0;
702 
703  /* --------------------------- */
704  /* depth resolved variables */
705  /* --------------------------- */
706 
707  double z[200]; /* depths */
708  double chl_C[200]; /* chl:c ratio */
709  double chlz[200]; /* chl */
710  double mu[200]; /* growth */
711  double Ezlambda[9][200]; /* fraction of light at nine wavelengths */
712  double parz[200]; /* total light */
713  double prcnt[200]; /* percent light */
714  double Cz[200]; /* carbon */
715  double ppz[200]; /* npp */
716 
717  int i;
718  int m;
719  int mzeu;
720  double r;
721  double prcnt0;
722  double prcnt1;
723  double z0;
724  double z1;
725  double numerator;
726  double denominator;
727  double fraction;
728  double deltaZ;
729 
730  if (irr <= 0.0) {
731  return 0.0;
732  }
733 
734  /* --------------------- */
735  /* initialize values */
736  /* --------------------- */
737 
738  z_eu = -9999; // 1.05.2011
739  y0 = 0.0003; /* min chl:c when mu = 0 */
740  for (i = 0; i < 200; i++) {
741  z[i] = (float) (i + 1);
742  }
743  r = 0.1;
744 
745  uMax = 2.0; /* after Banse (1991) */
746  npp = 0.0;
747  mzeu = 0.0;
748 
749  for (i = 0; i < 9; i++) {
750  Klambda[i] = austinPetzold_1986(lambda[i], k490);
751  Eo[i] = irr * parFraction[i];
752  Ez_mld[i] = Eo[i] * 0.975 * exp(-Klambda[i] * mld / 2.0);
753  }
754 
755  /* ----------------------------- */
756  /* reintegrate to get par at */
757  /* depth ... */
758  /* do trapezoidal integration */
759  /* ----------------------------- */
760 
761  par_mld = 0.0;
762  for (i = 0; i < 8; i++) {
763  par_mld += (lambda[i + 1] - lambda[i])*(Ez_mld[i + 1] + Ez_mld[i]) / 2;
764  }
765 
766  par_mld /= daylength;
767 
768  IgFunc = 1 - exp(-5.0 * par_mld);
769 
770  if (bbp < 0.00035)
771  bbp = 0.00036;
772  carbon = 13000.0 * (bbp - 0.00035);
773 
774  chlCarbonSat = chl / carbon;
775 
776  if (chlCarbonSat < y0) {
777  chlCarbonSat = y0;
778  }
779 
780  chlCarbonMax = 0.022 + (0.045 - 0.022) * exp(-3.0 * par_mld);
781  delChlC = chlCarbonMax - chlCarbonSat;
782 
783  nutTempFunc = (chlCarbonSat - y0) / (chlCarbonMax - y0);
784 
785  /* ''''''''''''''''''''''''' */
786  /* calculate Kd offset */
787  /* carry through to depth */
788  /* non-chl attenuation */
789  /* ------------------------- */
790 
791  for (i = 0; i < 9; i++) {
792  Kbio = X[i] * pow(chl, e[i]);
793  Kd[i] = Kw[i] + Kbio;
794  Kdif[i] = Klambda[i] - Kd[i];
795  }
796 
797  /* ''''''''''''''''''''''''''''''''''' */
798  /* integrate down the water column */
799  /* in one-meter steps */
800  /* ----------------------------------- */
801 
802  for (m = 0; m < 200; m++) {
803 
804  /* ---------------------------------------------- */
805  /* if you are in the mixed layer, do this way */
806  /* ---------------------------------------------- */
807 
808  if (z[m] < mld) {
809  chl_C[m] = chlCarbonSat;
810  chlz[m] = chl_C[m] * carbon;
811  mu[m] = uMax * nutTempFunc * IgFunc;
812 
813  if (mu[m] > uMax) { // 1.05.2011
814  mu[m] = uMax; // 1.05.2011
815  } // 1.05.2011
816 
817  for (i = 0; i < 9; i++) {
818  Ezlambda[i][m] = Eo[i]*0.975 * exp(-Klambda[i] * z[m]);
819  }
820 
821  parz[m] = 0.0;
822  for (i = 0; i < 8; i++) {
823  parz[m] += (lambda[i + 1] - lambda[i])*(Ezlambda[i + 1][m] + Ezlambda[i][m]) / 2;
824  }
825 
826  Cz[m] = carbon;
827 
828  } else {
829 
830  /* '''''''''''''''''''''''''''''''''''''''''''''''''''''''''' */
831  /* if below mixed layer must treat properties differently */
832  /* ---------------------------------------------------------- */
833 
834  for (i = 0; i < 9; i++) {
835  Kbio = X[i] * pow(chlz[m - 1], e[i]); /* after Morel & Maritorena (2001) */
836  Kd[i] = Kw[i] + Kbio;
837  Kd[i] += Kdif[i];
838  Ezlambda[i][m] = Ezlambda[i][m - 1] * exp(-Kd[i]*1.0);
839  }
840 
841  parz[m] = 0.0;
842  for (i = 0; i < 8; i++) {
843  parz[m] += (lambda[i + 1] - lambda[i])*(Ezlambda[i + 1][m] + Ezlambda[i][m]) / 2;
844  }
845 
846  deltaZ = zno3 - z[m];
847  if (deltaZ < 0) {
848  deltaZ = 0;
849  }
850 
851  chl_C[m] = (0.022 + (0.045 - 0.022) * exp(-3.0 * parz[m] / daylength));
852  chl_C[m] -= delChlC * (1 - exp(-0.075 * deltaZ));
853 
854  IgFuncz = 1 - exp(-5.0 * parz[m] / daylength);
855  mu[m] = uMax * nutTempFunc * IgFuncz;
856 
857  if (mu[m] > uMax) { // 1.05.2011
858  mu[m] = uMax; // 1.05.2011
859  } // 1.05.2011
860 
861  if (mu[m - 1] >= r) {
862  Cz[m] = carbon;
863  } else {
864  Cz[m] = carbon * mu[m - 1] / r;
865  }
866 
867  chlz[m] = chl_C[m] * Cz[m];
868 
869  }
870 
871  prcnt[m] = parz[m] / (irr * 0.975);
872 
873  /* track this to get to the euphotic depth */
874 
875  if (prcnt[m] >= 0.01) {
876  mzeu = m;
877  } else {
878 
879  /* ''''''''''''''''''''''''''' */
880  /* now find 1% light depth */
881  /* in case the user wants */
882  /* to use this information */
883  /* --------------------------- */
884 
885  if (z_eu == -9999) { // 01.05.11
886  prcnt0 = prcnt[mzeu];
887  prcnt1 = prcnt[mzeu + 1];
888  z0 = z[mzeu];
889  z1 = z[mzeu + 1];
890  numerator = prcnt0 - 0.01;
891  denominator = prcnt0 - prcnt1;
892  fraction = numerator / denominator;
893  z_eu = z0 + (z1 - z0) * fraction;
894  }
895  }
896 
897  ppz[m] = mu[m] * Cz[m];
898 
899  }
900 
901  /* ------------------------------- */
902  /* do trapezoidal integration */
903  /* from m = 0 to m = 200 */
904  /* ------------------------------- */
905 
906  // note: 186 m is the euphotic depth for pure water
907 
908  if (mzeu < 186) {
909  npp = 0;
910  for (i = 0; i < 199; i++) {
911  npp += (z[i + 1] - z[i])*(ppz[i + 1] + ppz[i]) / 2;
912  }
913  } else {
914  npp = BAD_FLT;
915  }
916 
917  if (npp < 0)
918  npp = BAD_FLT;
919 
920  return npp;
921 }
922 
923 /* ================================================================= */
924 
926  double K490) {
927 
928  double wave[] = {350, 360, 370, 380, 390, 400,
929  410, 420, 430, 440, 450, 460, 470, 480, 490, 500,
930  510, 520, 530, 540, 550, 560, 570, 580, 590, 600,
931  610, 620, 630, 640, 650, 660, 670, 680, 690, 700};
932 
933  double M[] = {2.1442, 2.0504, 1.9610, 1.8772, 1.8009, 1.7383,
934  1.7591, 1.6974, 1.6108, 1.5169, 1.4158, 1.3077, 1.1982, 1.0955, 1.0000, 0.9118,
935  0.8310, 0.7578, 0.6924, 0.6350, 0.5860, 0.5457, 0.5146, 0.4935, 0.4840, 0.4903,
936  0.5090, 0.5380, 0.6231, 0.7001, 0.7300, 0.7301, 0.7008, 0.6245, 0.4901, 0.2891};
937 
938  double Kdw[] = {0.0510, 0.0405, 0.0331, 0.0278, 0.0242, 0.0217,
939  0.0200, 0.0189, 0.0182, 0.0178, 0.0176, 0.0176, 0.0179, 0.0193, 0.0224, 0.0280,
940  0.0369, 0.0498, 0.0526, 0.0577, 0.0640, 0.0723, 0.0842, 0.1065, 0.1578, 0.2409,
941  0.2892, 0.3124, 0.3296, 0.3290, 0.3559, 0.4105, 0.4278, 0.4521, 0.5116, 0.6514};
942 
943  double l0;
944  double l1;
945  double k0;
946  double k1;
947  double m0;
948  double m1;
949  double kdiff;
950  double mdiff;
951  double num;
952  double den;
953  double frac;
954  double Kdw_l;
955  double M_l;
956  double Kd;
957 
958  int ref;
959  int i;
960 
961  // -- INTERPOLATE TO WAVELENGTH OF INTEREST -- //
962 
963  for (i = 1; i < 36; i++) {
964  if (wave[i] >= lambda) {
965  l1 = wave[i];
966  k1 = Kdw[i];
967  m1 = M[i];
968  l0 = wave[i - 1];
969  k0 = Kdw[i - 1];
970  m0 = M[i - 1];
971  break;
972  }
973  }
974 
975  if(i==36) {
976  printf("-E- %s:%d - lambda = %f, out of range\n", __FILE__, __LINE__, lambda);
977  exit(EXIT_FAILURE);
978  }
979 
980  num = lambda - l0;
981  den = l1 - l0;
982  frac = num / den;
983 
984  kdiff = k1 - k0;
985  Kdw_l = k0 + frac*kdiff;
986 
987  mdiff = m1 - m0;
988  M_l = m0 + frac*mdiff;
989 
990 
991  // -- GET REFERENCE WAVELENGTH (=490 FOR NOW) AND APPLY MODEL -- //
992 
993  ref = 14;
994 
995  Kd = (M_l / M[ref]) * (K490 - Kdw[ref]) + Kdw_l;
996 
997  return Kd;
998 
999 }
1000 
1001 
1002 float opp_cafe( float PAR,
1003  float chl,
1004  float mld,
1005  float lat,
1006  int yd,
1007  float aph_443,
1008  float adg_443,
1009  float bbp_443,
1010  float bbp_s,
1011  float sst ) {
1012 
1013 /* ----------------------------------------------------------------------------------------------*/
1014 
1015 /* Description: Computes daily net primary production following the Carbon, Absorption, Fluorescence
1016  Euphotic-resolving (CAFE) model. For a full description of the model, please see:
1017 
1018  Silsbe, G.M., M.J. Behrenfeld, K.H. Halsey, A.J. Milligan, and T.K. Westberry. 2016.
1019  The CAFE model. A net production model for global ocean phytoplankton. Global
1020  Biogeochemical Cycles. doi: 10.1002/2016GB005521.
1021 
1022  Model inputs:
1023  PAR - Daily photosynthetic active radiation [mol photons m^-2 day^-1]
1024  chl - Chlorophyll concentration, NASA OCI algorithm [mg m^-3]
1025  mld - Mixed layer depth [m]
1026  lat - Latitude [Degrees, north positive]
1027  yd - Day of year
1028  aph_443 - Absorption due to phytoplankton at 443 nm, NASA GIOP algorithm [m-1]
1029  adg_443 - Absorption due to gelbstoff and detratial material at 443 nm, NASA GIOP model [m-1]
1030  bbp_443 - Particulate backscatter at 443 nm, NASA GIOP model [m-1]
1031  bbp_s - Backscattering spectral parameter for GIOP model [dimensionless]
1032  sst - Sea surface temperature [Degrees Celcuis]
1033 
1034  Modeling code below is divided into 10 steps:
1035 
1036  1) Declare all local variables
1037  2) Derive inherent optical properties (IOPs) at 10 nm increments from 400 to 700 nm
1038  3) Calculate the amount of energy in the eupotic zone that is absorbed by phytoplankton
1039  4) Derive the spectral attenunation coefficient and the attenuation coefficient of PAR
1040  5) Derive conversion factor (Eu) that converts downwelling planar irradiance to scalar
1041  irradiance
1042  6) Calculate the photoacclimation parameter (Ek) through depth
1043  7) Scale Ek to a spectrally explicit parameter (KPUR)
1044  8) Model the maximum quantum efficiency of net carbon fixation (phi_max)
1045  9) If the mixed layer depth (MLD) is shallower than the euphotic depth, then apply scaling
1046  factor to phytoplankton absorption beneath the MLD and adjust the energy absorbed by
1047  phytoplankton.
1048  10) Derive net phytoplankton production (NPP).
1049  11) Dependent function that calculates the wavelength, salinity and temperature dependence
1050  of the backscattering of pure water.
1051 */
1052 
1053 
1054 /* ----------------------------------------------------------------------------------------------*/
1055 /* Step 1: Declare all local variables */
1056 /* ----------------------------------------------------------------------------------------------*/
1057 
1058  int w; /* Wavelength step 10 nm between 400 and 700 nm */
1059  int t; /* Time step, day is divided into 101 evenly spaced increments */
1060  int tsym; /* morning index for equivalent afternoon time */
1061  int z; /* Depth step, euphotic zone is divided into 101 evenly spaced increments */
1062 
1063  /* Inherent Optical Properties*/
1064  double aphi[31]; /* Absorption[wavelength] due to phytoplankton */
1065  double a[31]; /* Total absorption[wavelength] */
1066  double bb[31]; /* Total backscattering[wavelength] */
1067  double bbw[31]; /* Backscattering of pure water[wavelength] */
1068 
1069  /* Wavelength */
1070  double wv[] = { 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560,
1071  570, 580, 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700 };
1072 
1073  /* Absorption due to pure water[wavelength] */
1074  double aw[] = { 0.00663, 0.00473, 0.00454, 0.00495, 0.00635, 0.00922, 0.00979, 0.0106, 0.0127,
1075  0.015, 0.0204, 0.0325, 0.0409, 0.0434, 0.0474, 0.0565, 0.0619, 0.0695,
1076  0.0896, 0.1351, 0.2224, 0.2644, 0.2755, 0.2916, 0.3108, 0.34, 0.41, 0.439, 0.465,
1077  0.516, 0.624 };
1078 
1079  /*Spectral shape of of aphi */
1080  double A_Bricaud[] = { 0.0241, 0.0287, 0.0328, 0.0359, 0.0378, 0.0350, 0.0328, 0.0309, 0.0281,
1081  0.0254, 0.0210, 0.0162, 0.0126, 0.0103, 0.0085, 0.0070, 0.0057, 0.0050,
1082  0.0051, 0.0054, 0.0052, 0.0055, 0.0061, 0.0066, 0.0071, 0.0078, 0.0108,
1083  0.0174, 0.0161, 0.0069, 0.0025 };
1084 
1085  double E_Bricaud[] = { 0.6877, 0.6834, 0.6664, 0.6478, 0.6266, 0.5993, 0.5961, 0.5970, 0.5890,
1086  0.6074, 0.6529, 0.7212, 0.7939, 0.8500, 0.9036, 0.9312, 0.9345, 0.9298,
1087  0.8933, 0.8589, 0.8410, 0.8548, 0.8704, 0.8638, 0.8524, 0.8155, 0.8233,
1088  0.8138, 0.8284, 0.9255, 1.0286 };
1089 
1090  /* Spectral shape of PAR */
1091  double PAR_spectrum[] = { 0.00227, 0.00218, 0.00239, 0.00189, 0.00297, 0.00348, 0.00345,
1092  0.00344, 0.00373, 0.00377, 0.00362, 0.00364, 0.00360, 0.00367,
1093  0.00354, 0.00368, 0.00354, 0.00357, 0.00363, 0.00332, 0.00358,
1094  0.00357, 0.00359, 0.00340, 0.00350, 0.00332, 0.00342, 0.00347,
1095  0.00342, 0.00290, 0.00314 };
1096 
1097  /* Parameters related to euphotic zone*/
1098  double decl; /* Solar declination [rads] */
1099  double m0; /* Coefficient to calculate kd (Lee et al. 2005) [m-1] */
1100  double DL; /* Daylength [day] */
1101  double solzen; /* Solar zenith angle [rads] */
1102  double kd[31]; /* Downwelling attenuation coefficient of irradiance [m-1] */
1103  double zeu; /* Euphotic depth [m] */
1104  double kdpar; /* Downwelling attenuation coefficient of PAR [m-1] */
1105 
1106  /* Parameters related to light and absorbed photons through depth, time, and wavelength */
1107  double tseq[101]; /* Fractional time of day */
1108  double zseq[101]; /* Euphotic depth divided into 101 increments */
1109  double delz; /* Depth of zseq (i.e. zeu/101) */
1110  double absorbed_photons = 0.0; /* Absorbed photons calculated in Step 3 */
1111  double PAR_noon[31]; /* PAR at solar noon[wavelength] [mol photons m-2 day-1 wv-] */
1112  double AP_tzw[101][101][31]; /* Absorbed photons[depth, time, wavelength] */
1113  double AP_tz[101][101]; /* Absorbed photons[depth, time] */
1114  double AP_tz2[101][101]; /* Absorbed photons[depth, time] */
1115  double AP_z[101]; /* Absorbed photons[depth] */
1116  double AP_z2[101]; /* Absorbed photons[depth] */
1117  double AP = {0.0}; /* Absorbed photons [mol m-2 day-1] */
1118  double AP2 = {0.0}; /* Absorbed photons [mol m-2 day-1] */
1119  double E_tzw[101][101][31]; /* Irradiance [depth, time, wavelength] */
1120  double E_tz[101][101]; /* Irradiance [depth, time] */
1121  double Eu; /* conversion factor (Eu) that converts downwelling planar
1122  irradiance to scalar irradiance */
1123 
1124  /* Parameters related to derivation of Ek*/
1125  double Ek[101]; /* Photoacclimation parameter[depth] (Behrenfeld et al. 2016) [mol m-2 day-1] */
1126  double IML; /* Median irradiance in the mixed layer [umol m-2 day-1] */
1127  double Eg; /* Growth irradiance at a specific depth */
1128  double Eg_mld; /* Growth irradiance at a specific depth */
1129 
1130  /* Parameters used to convert Ek into the spectrally explicit equivalent KPUR */
1131  double KPUR[101]; /* Spectrally explicit Ek */
1132  double numerator; /* Numerator to calculate spectral correction factor */
1133  double denominator; /* Denominator to calculate spectral correction factor */
1134  double mean_aphi = 0.0; /* Spectrally averaged absorption due to phytoplankton */
1135 
1136  /* Parameters used to calculate the maximum quantum yield of net carbon fixation */
1137  double phimax[101]; /* maximum quantum yield of net carbon fixation [mol C (mol photons)-1] */
1138  double phirange[2] = {0.018, 0.030}; /* range of phimax values */
1139  double Ekrange[2] = {150*0.086400, 10*0.0864}; /* relates phimax to Ek */
1140  double slope; /* relates phimax to Ek */
1141 
1142  double aphi_fact[101]; /* Parameter to increase aphi beneath the MLD */
1143 
1144  /* Net primary production [mg C m-2 day-1] */
1145  double NPP_tz[101][101] = {{0.0}};
1146  double NPP_z[101] = {0.0};
1147  double NPP = {0.0};
1148 
1149 
1150  //FILE *fp;
1151  // fp = fopen("test.txt", "a");
1152 
1153  /* ----------------------------------------------------------------------------------------------*/
1154  /* Step 2: Derive IOPs at 10 nm increments from 400 to 700 nm */
1155  /* Comment: Currently assume salinity is 32.5 ppmil */
1156  /* ----------------------------------------------------------------------------------------------*/
1157 
1158  for ( w=0; w<31; w++ ){
1159  bbw[w] = betasw_ZHH2009(wv[w], 32.5, sst) / 2;
1160  aphi[w] = aph_443 * A_Bricaud[w] * pow(chl, E_Bricaud[w]) / (0.03711 * pow(chl, 0.61479));
1161  a[w] = aw[w] + aphi[w] + adg_443 * exp(-0.018 * (wv[w] - 443));
1162  bb[w] = bbw[w] + bbp_443 * pow(443 / wv[w], bbp_s);
1163  }
1164 
1165  /* ----------------------------------------------------------------------------------------------*/
1166  /* Step 3: Calculate Absorbed Energy */
1167  /* ----------------------------------------------------------------------------------------------*/
1168 
1169  for (w=0; w<30; w++){
1170  absorbed_photons += 0.5 * 10 * (PAR_spectrum[w+1] * aphi[w+1]/a[w+1] +
1171  PAR_spectrum[w] * aphi[w]/a[w]);
1172  }
1173 
1174  absorbed_photons *= PAR * 0.95;
1175 
1176  /* ----------------------------------------------------------------------------------------------*/
1177  /* Step 4: Derive Kd following Lee et al 2005, Eq. 11 and kdpar */
1178  /* from Morel et al 2007, Eq. 9' */
1179  /*---------- ------------------------------------------------------------------------------------*/
1180 
1181  decl = 23.5 * cos (2 * M_PI * (yd - 172) / 365) * M_PI / 180;
1182  DL = -1 * tan(lat*M_PI/180) * tan(decl);
1183 
1184  if (DL > 1) {DL = 1;} /* Check for daylength less than 0 hours */
1185  if (DL < -1) {DL = -1;} /* Check for daylength greater than 24 hours */
1186 
1187  DL = acos(DL) / M_PI; /* Daylength in days */
1188 
1189  solzen = 90 - asin (sin(lat*M_PI/180) * sin(decl) - cos(lat*M_PI/180) * cos(decl) *
1190  cos(M_PI)) * 180 / M_PI;
1191  m0 = sqrt((1 + 0.005 * solzen) * (1 + 0.005 * solzen)); /* absolute value */
1192 
1193  for (w=0; w<31; w++){
1194  kd[w] = m0 * a[w] + 4.18 * (1 - 0.52 * exp(-10.8 * a[w])) * bb[w];
1195  }
1196 
1197  kdpar = 0.0665 + (0.874 * kd[9]) - (0.00121 / kd[9]);
1198  zeu = -1 * log (0.1 /(PAR * 0.95)) / kdpar;
1199 
1200  /* debug variable */
1201  // oppDebugDepthEu = z_eu;
1202 
1203 
1204  /* ----------------------------------------------------------------------------------------------*/
1205  /* Step 5: Derive conversion factor (Eu) that converts downwelling planar irradiance to scalar */
1206  /* irradiance */
1207  /* ----------------------------------------------------------------------------------------------*/
1208 
1209  for (t=0; t<101; t++){
1211  zseq[t] = (double)t / 100 * ceil(zeu);
1212  }
1213  for (t=0; t<51; t++){
1214  tseq[t] = (double)t / 50;
1215  }
1216  delz = zseq[1] - zseq[0];
1217 
1218  for (w=0; w<31; w++){
1219  PAR_noon[w] = M_PI / 2 * PAR * 0.95 * PAR_spectrum[w];
1220  }
1221 
1223 
1224  /* ==================================== */
1225  /* light is symmetrical about noon */
1226  /* take advantage of that */
1227  /* to get rid of 1/2 the calculations */
1228  /* ==================================== */
1229 
1230  // for (t=0; t<51; t++){
1231  for (t=0; t<26; t++){
1232  for (z=0; z<101; z++){
1233  for (w=0; w<31; w++){
1234  E_tzw[t][z][w] = PAR_noon[w] * sin(M_PI*tseq[t]) * exp(-1*kd[w]*zseq[z]);
1235  AP_tzw[t][z][w] = E_tzw[t][z][w] * aphi[w];
1236  }
1237  }
1238  }
1239  for (t=26; t<51; t++){
1240  tsym = 25 - (t - 25);
1241  for (z=0; z<101; z++){
1242  for (w=0; w<31; w++){
1243  E_tzw[t][z][w] = E_tzw[tsym][z][w];
1244  AP_tzw[t][z][w] = AP_tzw[tsym][z][w];
1245  }
1246  }
1247  }
1248 
1249  /* Integrate E and AP through wavelength*/
1250  for (z=0; z<101; z++){
1252 
1253  /* ==================================== */
1254  /* light is symmetrical about noon */
1255  /* take advantage of that */
1256  /* to get rid of 1/2 the calculations */
1257  /* ==================================== */
1258 
1259  // for (t=0; t<51; t++){
1260  for (t=0; t<26; t++){
1261  E_tz[t][z] = 0.0;
1262  AP_tz[t][z] = 0.0;
1263  for (w=0; w<30; w++){
1264  E_tz[t][z] += 10 * (E_tzw[t][z][w+1] + E_tzw[t][z][w])/2;
1265  AP_tz[t][z] += 10 * (AP_tzw[t][z][w+1] + AP_tzw[t][z][w])/2;
1266  }
1267  }
1268  for (t=26; t<51; t++){
1269  tsym = 25 - (t - 25);
1270  for (w=0; w<30; w++){
1271  E_tz[t][z] = E_tz[tsym][z];
1272  AP_tz[t][z] = AP_tz[tsym][z];
1273  }
1274  }
1275  }
1276 
1277  /* Integrate AP through time*/
1278  for (z=0; z<101; z++){
1279  AP_z[z] = 0.0;
1281 
1282  /* ==================================== */
1283  /* light is symmetrical about noon */
1284  /* take advantage of that */
1285  /* to get rid of 1/2 the calculations */
1286  /* ==================================== */
1287 
1288  // for (t=0; t<50; t++){
1289  for (t=0; t<25; t++){
1291  AP_z[z] += 0.02 * (AP_tz[t+1][z] + AP_tz[t][z])/2;
1292  }
1293  AP_z[z] = 2*AP_z[z];
1294  }
1295 
1296  /* Integrate AP through depth*/
1297  for (z=0; z<100; z++){
1298  AP += delz * (AP_z[z] + AP_z[z+1])/2;
1299  }
1300 
1301  /* Derive Upwelling Irradiance, absorbed energy is from Section 3 */
1302  Eu = absorbed_photons / AP;
1303 
1304  /* Multiply E_tz by Eu */
1305 
1307 
1308  /* ==================================== */
1309  /* light is symmetrical about noon */
1310  /* take advantage of that */
1311  /* to get rid of 1/2 the calculations */
1312  /* ==================================== */
1313 
1314  // for (t=0; t<51; t++){
1315  for (t=0; t<26; t++){
1316  for (z=0; z<101; z++){
1317  E_tz[t][z] *= Eu;
1318  AP_tz[t][z] *= Eu;
1319  }
1320  }
1321  for (t=26; t<51; t++){
1322  tsym = 25 - (t - 25);
1323  for (z=0; z<101; z++){
1324  E_tz[t][z] = E_tz[tsym][z];
1325  AP_tz[t][z] = AP_tz[tsym][z];
1326  }
1327  }
1328 
1329  /* ----------------------------------------------------------------------------------------------*/
1330  /* Step 6: CALCULATE EK through depth (modified from Behrenfeld et al. 2016) */
1331  /* ----------------------------------------------------------------------------------------------*/
1332 
1333  IML = (PAR * 0.95 / (DL* 24)) * exp(-0.5 * kdpar * mld);
1334 
1335  for (z=0; z<101; z++){
1336  Ek[z] = 19 * exp(0.038 * pow(PAR * 0.95 / (DL * 24), 0.45) / kdpar);
1337  }
1338 
1339  /* Modify Ek beneath the MLD */
1340 
1341  if (mld < zeu){
1342  Eg_mld = (PAR / DL) * exp(-1*kdpar*mld);
1343  for (z=0; z<101; z++){
1344  Ek[z] *= (1 + exp(-0.15 * (0.95 * PAR / (DL * 24)))) / (1 + exp(-3 * IML));
1345  if (zseq[z] > mld){
1346  Eg = (PAR / DL) * exp(-1*kdpar*zseq[z]);
1347  Ek[z] = 10 + (Ek[z] - 10) / (Eg_mld - 0.1) * (Eg -0.1);
1348  }
1349  if (Ek[z] < 10) {Ek[z] = 10;}
1350  }
1351  }
1352 
1353  for (z=0; z<101; z++){
1354  Ek[z] *= 0.0864; /* 0.0864 #Convert to mol photons/m2/day */
1355  }
1356 
1357  /* debug variable */
1358  // oppDebugEk0 = Ek[0];
1359 
1360 
1361  /* ----------------------------------------------------------------------------------------------*/
1362  /* Step 7: Make Ek spectrally explicit (KPUR) using a spectral correction factor */
1363  /* ----------------------------------------------------------------------------------------------*/
1364 
1365  for (w=0; w<31; w++){
1366  mean_aphi += aphi[w];
1367  }
1368  mean_aphi /= 31;
1369 
1370  for (z=0; z<101; z++){
1371  numerator = 0.0;
1372  denominator = 0.0;
1373  for (w=0; w<30; w++){
1376 
1377  numerator += 10 * 0.5 * (AP_tzw[24][z][w] + AP_tzw[24][z][w+1]);
1378  denominator += 10 * 0.5 * (E_tzw[24][z][w] + E_tzw[24][z][w+1]);
1379  }
1380  KPUR[z] = Ek[z] / (numerator / (denominator * mean_aphi) / 1.3);
1381  }
1382 
1383  /* ----------------------------------------------------------------------------------------------*/
1384  /* Step 8: Calculate phimax as a function of Ek */
1385  /* ----------------------------------------------------------------------------------------------*/
1386 
1387  slope = (phirange[1] - phirange[0]) / (Ekrange[1] - Ekrange[0]);
1388 
1389  for (z=0; z<101; z++){
1390  phimax[z] = phirange[1] + (Ek[z] - Ekrange[1]) * slope;
1391  if (phimax[z] > phirange[1]) {phimax[z] = phirange[1];}
1392  if (phimax[z] < phirange[0]) {phimax[z] = phirange[0];}
1393  }
1394 
1395  /* ----------------------------------------------------------------------------------------------*/
1396  /* Step 9: Scale aphi beneath the MLD to Ek */
1397  /* ----------------------------------------------------------------------------------------------*/
1398 
1399  if ( mld < zeu ) {
1400  for (z=0; z<101; z++){
1401  if (zseq[z] > mld){
1402  aphi_fact[z] = 1 + Ek[0]/Ek[z] * 0.15;
1403  } else {
1404  aphi_fact[z] = 1;
1405  }
1406  }
1407 
1408  // for (z=21; z<23; z++){
1409  // fprintf(fp, "z = %d\n",z);
1410  // fprintf(fp, " %lf",aphi_fact[z]);
1411  // fprintf(fp,"\n");
1412  // }
1413 
1414  /* Modify Irradiance and absorbed energy to account for any change to aphi */
1416 
1417  /* ==================================== */
1418  /* light is symmetrical about noon */
1419  /* take advantage of that */
1420  /* to get rid of 1/2 the calculations */
1421  /* ==================================== */
1422 
1423  // for (t=0; t<51; t++){
1424  for (t=0; t<26; t++){
1425  for (w=0; w<31; w++){
1426  AP_tzw[t][0][w] = E_tzw[t][0][w] * aphi[w];
1427  }
1428  for (z=1; z<101; z++){
1429  for (w=0; w<31; w++){
1430  a[w] = aw[w] + aphi[w] * aphi_fact[z] + adg_443 * exp(-0.018 * (wv[w] - 443));
1431  kd[w] = m0 * a[w] + 4.18 * (1 - 0.52 * exp(-10.8 * a[w])) * bb[w];
1432  E_tzw[t][z][w] = E_tzw[t][z-1][w] * exp(-1*kd[w]*delz);
1433  AP_tzw[t][z][w] = E_tzw[t][z][w] * aphi[w] * aphi_fact[z];
1434  }
1435  }
1436  }
1437  for (t=26; t<51; t++){
1438  tsym = 25 - (t - 25);
1439  for (w=0; w<31; w++){
1440  AP_tzw[t][0][w] = AP_tzw[tsym][0][w];
1441  }
1442  for (z=1; z<101; z++){
1443  for (w=0; w<31; w++){
1444  E_tzw[t][z][w] = E_tzw[tsym][z][w];
1445  AP_tzw[t][z][w] = AP_tzw[tsym][z][w];
1446  }
1447  }
1448  }
1449 
1450  /* Integrate AP through wavelength and multiply by Eu*/
1451  for (z=0; z<101; z++){
1453 
1454  /* ==================================== */
1455  /* light is symmetrical about noon */
1456  /* take advantage of that */
1457  /* to get rid of 1/2 the calculations */
1458  /* ==================================== */
1459 
1460  // for (t=0; t<51; t++){
1461  for (t=0; t<26; t++){
1462  AP_tz2[t][z] = 0.0;
1463  for (w=0; w<30; w++){
1464  AP_tz2[t][z] += 10 * (AP_tzw[t][z][w+1] + AP_tzw[t][z][w])/2;
1465  }
1466  AP_tz2[t][z] *= Eu;
1467  }
1468  for (t=26; t<51; t++){
1469  tsym = 25 - (t - 25);
1470  AP_tz2[t][z] = AP_tz2[tsym][z];
1471  }
1472  }
1473  // fprintf(fp, "\nEu = %lf\n",Eu);
1474  } else {
1475 
1476  for (z=0; z<101; z++){
1478  for (t=0; t<51; t++){
1479  AP_tz2[t][z] = AP_tz[t][z];
1480  }
1481  }
1482 
1483  }
1484 
1485 
1486  /* ------------------------------------------------------------------------------------*/
1487  /* Step 9: CALCULATE NPP */
1488  /* ------------------------------------------------------------------------------------*/
1489 
1491 
1492  /* ==================================== */
1493  /* light is symmetrical about noon */
1494  /* take advantage of that */
1495  /* to get rid of 1/2 the calculations */
1496  /* ==================================== */
1497 
1498  // for (t=0; t<51; t++){
1499  for (t=0; t<26; t++){
1500  for (z=0; z<101; z++){
1501  NPP_tz[t][z] = phimax[z] * AP_tz2[t][z] * tanh(KPUR[z] / E_tz[t][z]) * 12000;
1502  }
1503  }
1504  for (t=26; t<51; t++){
1505  tsym = 25 - (t - 25);
1506  for (z=0; z<101; z++){
1507  NPP_tz[t][z] = NPP_tz[tsym][z];
1508  }
1509  }
1510 
1511 
1512  /* Integrate NPP through time */
1513  for (z=0; z<101; z++){
1514  NPP_z[z] = 0.0;
1515  AP_z2[z] = 0.0;
1517 
1518  /* ==================================== */
1519  /* light is symmetrical about noon */
1520  /* take advantage of that */
1521  /* to get rid of 1/2 the calculations */
1522  /* ==================================== */
1523 
1524  // for (t=0; t<50; t++){
1525  for (t=0; t<25; t++){
1527  NPP_z[z] += 0.02 * (NPP_tz[t+1][z] + NPP_tz[t][z])/2;
1528  AP_z2[z] += 0.02 * (AP_tz2[t+1][z] + AP_tz2[t][z])/2;
1529  }
1530  NPP_z[z] = 2*NPP_z[z];
1531  AP_z2[z] = 2*AP_z2[z];
1532  }
1533 
1534  /* Integrate NPP through depth */
1535  NPP = 0.0;
1536  AP2 = 0.0;
1537  for (z=0; z<100; z++){
1538  NPP += delz * (NPP_z[z] + NPP_z[z+1])/2;
1539  AP2 += delz * (AP_z2[z] + AP_z2[z+1])/2;
1540  }
1541 
1542  // FILE *fp;
1543  // fp = fopen("test.txt", "a");
1544 
1545  // fprintf(fp, "\n %.14lf %.12lf %.13lf %.14lf\n", AP2, NPP, zeu, Ek[0]);
1546  // fprintf(fp, " %lf %lf %lf\n",delz,Eu,absorbed_photons);
1547 
1548  // for (z=0; z<100; z++){
1549  // fprintf(fp, " %lf",AP_z2[z]);
1550  // }
1551 
1552  // fprintf(fp,"\n");
1553 
1554 
1555  // fprintf(fp, " %.11lf %.11lf %.11lf\n",kd[0], kd[9], kdpar);
1556  // fprintf(fp, " %.14lf %.14lf %.14lf\n",m0, a[9], bb[9]);
1557  // fprintf(fp, " %.14lf %lf\n",bbw[9], wv[9]);
1558  // fprintf(fp, " %.14lf %lf\n",aw[9], aphi[9]);
1559 
1560  // for (w=0; w<30; w++){
1561  // fprintf(fp, " %lf",aw[w] + aphi[w] + adg_443*exp(-0.018*(wv[w]-443)));
1562  // }
1563  // fprintf(fp,"\n");
1564 
1565  // fprintf(fp, "adg_443: %lf\n",adg_443);
1566 
1567 
1568  // fprintf(fp," NPP Ek phimax aphi_fact KPUR Ap_tz zseq index\n");
1569  // for (z=0; z<101; z++){
1570  // fprintf(fp, " %lf %lf %lf %lf %lf %lf %lf %lf %d\n",NPP_z[z],Ek[z],phimax[z],aphi_fact[z],KPUR[z],AP_tz[26][z],AP_tz2[26][z],zseq[z],z+1);
1571  // }
1572  // fprintf(fp,"\n");
1573 
1574  // fclose(fp);
1575 
1576  return NPP;
1577 
1578 }
1579 
1580 double betasw_ZHH2009 (double lambda, double S, double Tc){
1581 
1582  /* function [theta,betasw,bsw,beta90sw]= betasw_ZHH2009(lambda,S,Tc,delta)
1583  Scattering by pure seawater: Effect of salinity Xiaodong Zhang, Lianbo Hu,
1584  and Ming-Xia He, Optics Express, 2009
1585  lambda (nm): wavelength
1586  Tc: temperature in degree Celsius, must be a scalar
1587  S: salinity, must be scalar
1588  delta: depolarization ratio, if not provided, default = 0.039 will be used.
1589  betasw: volume scattering at angles defined by theta. Its size is [x y],
1590  where x is the number of angles (x = length(theta)) and y is the number
1591  of wavelengths in lambda (y = length(lambda))
1592  beta90sw: volume scattering at 90 degree. Its size is [1 y]
1593  bw: total scattering coefficient. Its size is [1 y]
1594  for backscattering coefficients, divide total scattering by 2
1595  */
1596 
1597  /* values of the constants */
1598  double Na = 6.0221417930e23 ; /* Avogadro's constant */
1599  double Kbz = 1.3806503e-23 ; /* Boltzmann constant */
1600  double Tk = Tc + 273.15 ; /* Absolute tempearture */
1601  double M0 = 18e-3; /* Molecular weigth of water in kg/mol */
1602  double delta= 0.039;
1603  //double rad[181];
1604  double nsw;
1605  //double dnds;
1606  double IsoComp;
1607  double density;
1608  double dlnawds;
1609  double DFRI;
1610  double beta_df;
1611  double flu_con;
1612  double beta_cf;
1613  double beta90sw;
1614  double bsw;
1615  //double betasw;
1616  double n_air;
1617  double dnswds;
1618 
1619  //for (i=0; i<181; i++){
1620  // rad[i] = i * M_PI/180; /* angle in radian as a colum variable */
1621  //}
1622 
1623  /* nsw: absolute refractive index of seawater */
1624  /* dnds: partial derivative of seawater refractive index w.r.t. salinity */
1625 
1626 
1627  /* refractive index of air is from Ciddor (1996,Applied Optics) */
1628  n_air = 1.0 + (5792105.0 / (238.0185 - 1 / pow(lambda / 1e3, 2)) + 167917.0 /
1629  (57.362 - 1 / pow(lambda/1e3,2))) /1e8;
1630 
1631  /* refractive index of seawater is from Quan and Fry (1994, Applied Optics) */
1632  double n0 = 1.31405; double n1 = 1.779e-4 ; double n2 = -1.05e-6 ;
1633  double n3 = 1.6e-8 ; double n4 = -2.02e-6 ; double n5 = 15.868;
1634  double n6 = 0.01155; double n7 = -0.00423; double n8 = -4382 ;
1635  double n9 = 1.1455e6;
1636 
1637  /* pure seawater */
1638  nsw = n0 + (n1 + n2 * Tc + n3 * pow(Tc, 2)) * S + n4 * pow(Tc, 2) +
1639  (n5+n6*S+n7*Tc)/ lambda + n8 / pow(lambda, 2) + n9 / pow(lambda, 3);
1640  nsw *= n_air;
1641  dnswds = (n1 + n2 * Tc + n3 * pow(Tc, 2) + n6 / lambda) * n_air;
1642 
1643  /* isothermal compressibility is from Lepple & Millero (1971,Deep Sea-Research), pages 10-11
1644  The error ~ ?0.004e-6 bar-1 */
1645  double kw;
1646  //double Btw_cal;
1647  //double Btw;
1648  double g0;
1649  double g1;
1650  double Ks;
1651 
1652  /* pure water secant bulk Millero (1980, Deep-sea Research) */
1653  kw = 19652.21 + 148.4206 * Tc - 2.327105 * pow(Tc, 2) + 1.360477e-2 * pow(Tc, 3) -
1654  5.155288e-5 * pow(Tc, 4);
1655  //Btw_cal = 1/kw;
1656 
1657  /* isothermal compressibility from Kell sound measurement in pure water */
1658  //Btw = (50.88630 + 0.717582 * Tc + 0.7819867e-3 * pow(Tc, 2) + 31.62214e-6 * pow(Tc, 3) -
1659  // 0.1323594e-6 * pow(Tc, 4) +
1660  //0.634575e-9 * pow(Tc, 5)) / (1 + 21.65928e-3 * Tc)*1e-6;
1661 
1662  /* seawater secant bulk */
1663  g0 = 54.6746 - 0.603459 * Tc + 1.09987e-2 * pow(Tc, 2) - 6.167e-5 * pow(Tc, 3);
1664  g1 = 7.944e-2 + 1.6483e-2 * Tc - 5.3009e-4 * pow(Tc, 2);
1665 
1666  Ks = kw + g0 * S + g1 * pow(S, 1.5);
1667 
1668  /* calculate seawater isothermal compressibility from the secant bulk */
1669  IsoComp = ( 1 / Ks * 1e-5); /* unit is pa */
1670 
1671 
1672  /* density of water and seawater,unit is Kg/m3, from UNESCO,38,1981
1673 
1674  density = density_sw(Tc, S);*/
1675  double a0 = 8.24493e-1; double a1 = -4.0899e-3; double a2 = 7.6438e-5;
1676  double a3 = -8.2467e-7; double a4 = 5.3875e-9; double a5 = -5.72466e-3;
1677  double a6 = 1.02270e-4; double a7 = -1.6546e-6; double a8 = 4.8314e-4;
1678  double b0 = 999.842594; double b1 = 6.793952e-2; double b2 = -9.09529e-3;
1679  double b3 = 1.001685e-4; double b4 = -1.120083e-6; double b5 = 6.536332e-9;
1680 
1681  /* density for pure water */
1682  density = b0 + b1 * Tc + b2 * pow(Tc, 2) + b3 * pow(Tc, 3) + b4 * pow(Tc, 4) + b5 * pow(Tc, 5);
1683  /* density for pure seawater */
1684  density += (( a0 + a1 * Tc + a2 * pow(Tc, 2) + a3 * pow(Tc, 3) + a4 * pow(Tc, 4)) * S +
1685  ( a5 + a6 * Tc + a7 * pow(Tc, 2)) * pow(S, 1.5) + a8 * pow(S, 2));
1686 
1687  /* water activity data of seawater is from Millero and Leung (1976,American
1688  Journal of Science,276,1035-1077). Table 19 was reproduced using
1689  Eq.(14,22,23,88,107) then were fitted to polynominal equation.
1690  dlnawds is partial derivative of natural logarithm of water activity
1691  w.r.t.salinity */
1692 
1693 // dlnawds = (-5.58651e-4 + 2.40452e-7 * Tc -3.12165e-9 * pow(Tc, 2) + 2.40808e-11 * pow(Tc, 3)) +
1694 // 1.5*(1.79613e-5 -9.9422e-8 * Tc +2.08919e-9 * pow(Tc, 2) - 1.39872e-11 * pow(Tc, 3)) *
1695 // pow(S, 1.5) + 2 * (-2.31065e-6 - 1.37674e-9 * Tc -1.93316e-11 * pow(Tc, 2)) * S;
1696 
1697  dlnawds = (-5.58651e-4 + 2.40452e-7 * Tc -3.12165e-9 * pow(Tc, 2) + 2.40808e-11 * pow(Tc, 3)) +
1698  1.5*(1.79613e-5 -9.9422e-8 * Tc +2.08919e-9 * pow(Tc, 2) - 1.39872e-11 * pow(Tc, 3)) *
1699  pow(S, 0.5) + 2 * (-2.31065e-6 - 1.37674e-9 * Tc -1.93316e-11 * pow(Tc, 2)) * S;
1700 
1701  /* density derivative of refractive index from PMH model */
1702  double n_wat2;
1703  double base;
1704  // double val;
1705 
1706  n_wat2 = pow(nsw, 2);
1707 // base = (nsw/3 - 0.333333333333 / nsw);
1708  base = (nsw/3 - (1.0/3.0) / nsw);
1709 // DFRI = (n_wat2 - 1) * (1 + 0.666666666667 * (n_wat2 + 2) * pow(base, 2)) ;
1710  DFRI = (n_wat2 - 1) * (1 + (2.0/3.0) * (n_wat2 + 2) * pow(base, 2)) ;
1711 // val = 1/3;
1712 // base = (nsw/3) - (val/nsw);
1713 // DFRI = (n_wat2 - 1) * (1 + (2/3) * (n_wat2 + 2) * pow(base, 2)) ;
1714 
1715  /* volume scattering at 90 degree due to the density fluctuation */
1716  beta_df = M_PI * M_PI / 2 * pow(lambda*1e-9, -4) * Kbz * Tk * IsoComp * pow(DFRI,2) *
1717  (6 + 6*delta) / (6-7*delta);
1718 
1719  /* volume scattering at 90 degree due to the concentration fluctuation */
1720  flu_con = S * M0 * pow(dnswds,2) / density / (-1 * dlnawds) / Na;
1721  beta_cf = 2 * M_PI * M_PI * pow(lambda*1e-9, -4) * pow(nsw, 2) * flu_con * (6 + 6 * delta) /
1722  (6 - 7 * delta);
1723 
1724  /* total volume scattering at 90 degree */
1725  beta90sw = beta_df + beta_cf;
1726  bsw = 8 * M_PI / 3 * beta90sw * (2+delta) / (1+delta);
1727 
1728 
1729  //if ( lambda == 490 ) {
1730  // FILE *fp2;
1731  // fp2 = fopen("test2.txt", "a");
1732  // fprintf(fp2, " %.9lf %.9lf %.9lf %.9lf\n",bsw/2, beta90sw, beta_df, beta_cf);
1733  // fprintf(fp2, " %e %.9lf %e %.9lf\n",Kbz, Tk, IsoComp, DFRI);
1734  // fprintf(fp2, " %.14lf %.14lf %.14lf \n",nsw,n_wat2,base);
1735 
1736 // fprintf(fp2, " %.9lf %e\n",nsw, flu_con);
1737 // fprintf(fp2, " %lf %lf %e %e %e %e\n",S, M0, dnswds, density, dlnawds, Na);
1738 // fprintf(fp2, " %lf\n",DFRI);
1739 //}
1740 
1741 
1742  return(bsw);
1743 
1744 }
#define CAT_npp_vgpm
Definition: l2prod.h:316
int r
Definition: decode_rs.h:73
data_t t[NROOTS+1]
Definition: decode_rs.h:77
float get_mld(char *mldfile, float lon, float lat, int day)
Definition: get_mld.cpp:347
int j
Definition: decode_rs.h:73
int32_t day
int status
Definition: l1_czcs_hdf.c:32
#define CAT_npp_cafe
Definition: l2prod.h:391
double betasw_ZHH2009(double, double, double)
Definition: get_npp.c:1580
#define CAT_npp_mld
Definition: l2prod.h:350
#define NULL
Definition: decode_rs.h:63
double austinPetzold_1986(double lambda, double K490)
Definition: get_npp.c:925
float * giop_get_aph_pointer()
Definition: giop.c:2782
read l1rec
float npp_eppley(float chl, float irr, float sst, float dayL)
Definition: get_npp.c:530
float32 base
Definition: maplists.h:106
float mu
float * lat
#define IOPDEFAULT
Definition: l12_parms.h:76
#define K490
Definition: regen_attr.h:49
#define PRODFAIL
Definition: l2_flags.h:41
data_t lambda[NROOTS+1]
Definition: decode_rs.h:75
float * giop_get_adg_pointer()
Definition: giop.c:2768
#define IOPNONE
Definition: l12_parms.h:67
instr * input
int giop_ran(int recnum)
Definition: giop.c:569
#define CAT_npp_cbpm2
Definition: l2prod.h:318
int bindex_get(int32_t wave)
Definition: windex.c:45
void Kd490_obpg(l2str *l2rec, float k490[])
Definition: get_Kd.c:143
#define CAT_npp_bbp
Definition: l2prod.h:353
float32 slope[]
Definition: l2lists.h:30
void get_iops(l2str *l2rec, int32_t iop_opt)
Definition: convl12.c:113
float opp_cafe(float PAR, float chl, float mld, float lat, int yd, float aph_443, float adg_443, float bbp_443, float bbp_s, float sst)
Definition: get_npp.c:1002
#define FATAL_ERROR
Definition: swl0_parms.h:5
const double delta
#define CAT_npp_zno3
Definition: l2prod.h:351
#define M_PI
Definition: pml_iop.h:15
#define CAT_npp_par
Definition: l2prod.h:352
void unix2yds(double usec, short *year, short *day, double *secs)
integer, parameter double
double npp_cbpm2(double chl, double bbp, double irr, double k490, double mld, double zno3, double daylength)
Definition: get_npp.c:662
int M[]
Definition: Usds.c:107
float get_zno3(float lon, float lat, int day)
Definition: get_zno3.c:20
void get_par(l2str *l2rec, float par[])
Definition: get_par.c:34
void get_par_clim(float *parin, float *lat, float *lon, int nlat, int nlon, float *latp, float *lonp, int32_t npix, float *par)
Definition: get_npp.c:336
instead the metadata field ProcessingEnvinronment is filled in from the output of a call to the POSIX compliant function uname from within the L1B code A small bug in L1B_Tables an incorrect comparison of RVS coefficients for TEBs to RVS coefficients for RSBs was being made This was replaced with a comparison between TEB coefficients This error never resulted in an incorrect RVS correction but did lead to recalculating the coefficients for each detector in a thermal band even if the coefficients were the same for all detectors To reduce to overall size of the reflective LUT HDF fill values were eliminated from all LUTs previously dimensioned where and where NUM_TIMES is the number of time dependent table pieces In Preprocess a small error where the trailing dropped scan counter was incremented when the leading dropped scan counter should have been was fixed This counter is internal only and is not yet used for any chiefly to casting of were added to make it LINUX compatible Output of code run on LINUX machines displays differences of at most scaled sector incalculable values of the Emissive calibration factor b1
Definition: HISTORY.txt:576
float * giop_get_bbp_pointer()
Definition: giop.c:2775
void triseset(int32_t jday, float xlon, float xlat, float *trise, float *tset)
Definition: par_utils.c:529
#define BAD_FLT
Definition: jplaeriallib.h:19
int32_t nbands
#define fabs(a)
Definition: misc.h:93
data_t den
Definition: decode_rs.h:74
#define CAT_npp_eppley
Definition: l2prod.h:317
float * lon
void run_giop(l2str *l2rec)
Definition: giop.c:1616
float * giop_get_bbp_s_pointer()
Definition: giop.c:2797
DL
Definition: get_dataday.cpp:28
float npp_vgpm(float chl, float irr, float sst, float dayL)
Definition: get_npp.c:420
int i
Definition: decode_rs.h:71
void get_npp(l2str *l2rec, int prodnum, float prod[])
Definition: get_npp.c:35
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
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
@ NPP
int npix
Definition: get_cmp.c:27