Commit 02287497 authored by Chitra Sivaraman's avatar Chitra Sivaraman
Browse files

Initial files to code.arm.gov.

parents
/*******************************************************************************
* COPYRIGHT (C) 2001 Battelle Memorial Institute.
* All Rights Reserved. (Now, with this out of the way...)
*
* RCS INFORMATION:
* $RCSfile: barnard_langley.c,v $
* $Revision: 1.19 $
* $Author: koontz $
* $Locker: $
* $Date: 2011/12/29 18:56:44 $
* $State: Exp $
* $Name: $
* $Id: barnard_langley.c,v 1.19 2011/12/29 18:56:44 koontz Exp $
*
* FUNCTIONS IN THIS FILE:
* barnard_langely (DATA *, DATA *)
*
* DESIGN:
* <Discuss overall design/purpose of class.>
*******************************************************************************/
#define BARNARD_LANGLEY_C
/****** General Includes ******/
#include <stdio.h>
#include <string.h>
#include <math.h>
/****** Zebra Includes ******/
/* #include "defs.h"
* #include "message.h"
* #include "DataStore.h"
*/
/****** BW Includes ******/
/* #define BW_CODE
* #include "bw_main.h"
* #include "bw_retriever.h"
*/
#define BW_CODE
#include "bw_adi.h"
/****** Application Includes ******/
#include "langley.h"
/*******************************************************************************
* Function:
* barnard_langley -
*
* Inputs:
*******************************************************************************/
DATA* barnard_langley (DATA *D, float *gNomCal)
{
DATA *newD;
ZebTime ztime[4325];
UItime t;
int ot, sot, eot;
int f, i,j,k, l, m, n,o, s, nsamples, npoints, norig, nruns, nmax;
int nrej, nzero, old_rej;
int nobs[NOUTPLATS] = {1, 2};
int badflag;
int hh, mm, ss, jday, old_jday;
int start[NSLABS], end[NSLABS];
float frac;
float lnI[NCHANNELS][4325], A[4325], AZ[4325],
lnItemp[4325], Atemp[4325],
weights[4325], wtemp[4325];
double airmass();
/* time stuff */
int year;
double dayfrac, arg, az, distance;
float sdist[4325];
float sdist_avg;
int sdist_count;
double efactor, el, ap_ra, ap_dec, refrac;
extern int solarposition();
/* fit variables */
float sigp, intercept, slope, sigi, sigs, y;
float resid;
#ifdef OLDFIT
extern fit_ ();
#endif
void lfit();
int yymmdd_to_juldate();
extern long startime;
extern long etime;
float dvalue;
/* function prototypes */
DATA* maker_AllocateMemoryForDATA();
nsamples = 0;
efactor = -9999; /* initialize */
/* determine the number of samples */
ot = 0;
eot = 0;
sot = -1;
for (o=0; o < D->nObs[B1]; o++)
{
/* Get the "ingest_software" info for this observation, from which
* we will extract the "Input_Datastreams" information
*/
for (i=0; i < D->nSamples[B1][o][0][IN_BROADBAND]; i++, ot++)
{
if (D->sampleTimes[B1][o][0][IN_BROADBAND][i].zt_Sec >= startime &&
D->sampleTimes[B1][o][0][IN_BROADBAND][i].zt_Sec <= etime)
{
if (sot == -1)
{
sot = ot;
/* Using this observation.
*
* Get version from a global attribute in the observation
* of MFR data we are using for the Langley.
*/
}
eot = ot;
} /* end if (D->sampleTimes... */
} /* end for (t... */
} /* end for (o... */
if (sot == -1)
{
bw_return(NULL, "Barnard: no samples for given time period");
}
nsamples = (eot - sot) + 1;
/******************************************************/
/* Now pull the BW fields into our lnI arrays - we */
/* have to multiply by efactor and take the log */
/* anyway, so we might as well loop over all obs and */
/* make one big array of all our values. Airmasses, */
/* too. */
/******************************************************/
n = 0;
m = 0;
old_jday = -9999;
ot = 0;
for (o=0; o < D->nObs[B1]; o++)
{
for (i=0; i < D->nSamples[B1][o][0][IN_BROADBAND]; i++, ot++)
{
if (ot >= sot && ot <= eot)
{
/* do the time first - we need to calculate */
/* efactor from first sample time anyway */
/* sample time */
ztime[n] = D->sampleTimes[B1][o][0][IN_BROADBAND][i];
TC_ZtToUI(&ztime[n], &t);
jday = yymmdd_to_juldate(t.ds_yymmdd);
year = t.ds_yymmdd / 10000;
if (year < 1900) year += 1900; /* y2k or not */
hh = t.ds_hhmmss / 10000;
mm = (t.ds_hhmmss /100 ) % 100;
ss = t.ds_hhmmss % 100;
dayfrac = (double) (hh*3600 + mm*60 + ss) / (24.0*3600.0);
dayfrac += (double) jday;
/* get efactor, if it's a new day */
if (efactor <= -8888 || jday != old_jday)
{
/* get efactor from first sample */
if (year % 4 == 0)
arg = (double) (jday - 1)/366.0*2.0*M_PI;
else
arg = (double) (jday - 1)/365.0*2.0*M_PI;
efactor = 1.00011 + .034221*cos(arg) + .00128*sin(arg) +
.000719*cos(2*arg) + 7.7e-5*sin(2*arg);
} /* end if (efactor... */
/* now get airmasses */
solarposition(year, 0, dayfrac, (double) 0.0, lat, lon,
&ap_ra, &ap_dec, &el, &refrac, &az, &distance);
sdist[n] = distance;
A[n] = airmass(el+refrac);
AZ[n] = az;
/* don't do it for first point... */
if (n > 1)
{
/* weight by inverse density of points, that is, by the */
/* gradiant of airmass vs. time */
/* we need the n+1 airmass and time to do the nth weight */
/* so we fill in the j=n-1 weight on the nth iteration */
j = n - 1;
#define TWEIGHT
#ifdef TWEIGHT
/* a scale factor of 2000.0 sets the weights in the middle*/
/* of a typical airmass slab to just about 1. This ought */
/* to help deal with our precision issues. */
// Check to see if our neighboring airmasses are bad -
// this should only happen when there's a gap in the
// data, as we only fit for A in [2,6]. Anyway, I'll use
// < 0 and > 10*HIGH_AM as the cutoff
if (A[j+1] < 0 || A[j+1] > 10*HIGH_AM ||
A[j-1] < 0 || A[j-1] > 10*HIGH_AM) {
weights[j]=0.0;
} else {
weights[j] = 2000.0*fabs((A[j+1] - A[j-1])/
(float) (ztime[j+1].zt_Sec - ztime[j-1].zt_Sec));
}
#else
weights[j] = 1.0;
#endif
/* mark start and end of our airmass slabs within range */
if (A[n] >= LOW_AM && A[n] <= HIGH_AM &&
(A[n-1] < LOW_AM || A[n-1] > HIGH_AM))
{
/* index start of slab */
start[m] = n;
} /* end if (A[n] >= ... */
else if (A[n] >= LOW_AM && A[n] <= HIGH_AM &&
(AZ[n] >= 180.0 && AZ[n - 1] < 180.0))
{
/* index end and start at solar noon local time */
end[m++] = n - 1;
start[m] = n;
} /* end else if *AZ[n] >= ... */
else if ((A[n-1] >= LOW_AM && A[n-1] <= HIGH_AM &&
(A[n] < LOW_AM || A[n] > HIGH_AM)))
{
/* index end of slab */
end[m++] = n - 1;
} /* end else if (A[n] >= ... */
else if ((A[n] <= HIGH_AM && A[n] >= LOW_AM) &&
(o == (D->nObs[B1] - 1) &&
i == D->nSamples[B1][o][0][IN_BROADBAND] - 1))
{
/*************************************************************/
/* this means that our last sample was not outside the valid */
/* airmass range - in other words, we probably didn't get all*/
/* the data for this day. We'll go ahead and peg the end of */
/* the slab and do a langley plot anyway - but we send a */
/* warning message, too. */
/*************************************************************/
msg_ELog(EF_PROBLEM,
"==> MISSING some daylight data for final Langley plot.");
msg_ELog(EF_PROBLEM,
"==> Possibly next day's data is missing.");
msg_ELog(EF_PROBLEM,
"==> May have to rerun when data is available to fix.");
end[m++] = n;
} /* end else if ((A[n] <= ... */
else if ((A[n] <= HIGH_AM && A[n] >= LOW_AM) && ot==eot)
{
// This means we are still in the Airmass range but
// we've hit the end of our analysis period. If the
// above test didn't catch it, it probably means that
// eot is local midnight, but the sun is still up,
// which probably means arctic or antarctic. At any
// rate, we have to close our langley slab, so:
msg_ELog(EF_INFO,
"==> Last airmass in slab %f still in range [%f, %f]",
A[n], LOW_AM, HIGH_AM);
msg_ELog(EF_INFO,
"==> Probably arctic or antarctic and sun is up at midnight");
msg_ELog(EF_INFO,
"==> Continuing with Langley analysis for this slab");
end[m++] = n;
}
} /* if (n > ... */
/* Finally, the ln(radiance/efactor) */
/* broadband channel in seperate field */
lnI[0][n] = D->BWdata[B1][o][0][IN_BROADBAND][i][0] > 0 ?
log (D->BWdata[B1][o][0][IN_BROADBAND][i][0] /
efactor) : -9999;
/* narrowband channels */
for (k=1; k < NCHANNELS; k++)
{
lnI[k][n] = D->BWdata[B1][o][0][IN_CHN1 + (k-1)][i][0] > 0.0 ?
log (D->BWdata[B1][o][0][IN_CHN1 + (k-1)][i][0] /
efactor) : -9999;
} /* end for (k... */
/* increment lnI counter */
old_jday = jday;
n++;
} /* end if (ot... */
} /* end for (i... */
} /* end for (o... */
/* setup our newD to accept data */
nobs[LANGLEY] = 1; /* writes out one file per run */
#ifdef PLOTDATA
nobs[PLOT] = m; /* one plotfile for each slab */
if (m <= 0)
bw_return(NULL, "==> No usable data for this time window (probably due to lack of daylight) <==");
#endif
nmax = 0;
for (i=0; i<m; i++)
{
npoints = end[i] - start[i] + 1;
if (npoints > nmax) nmax = npoints;
} /* end for (i... */
newD = (DATA *) maker_AllocateMemoryForDATA (nobs, nmax);
/***********************************************/
/* Okay, now we have big long lnI and A arrays */
/* Now we loop over each airmass slab within */
/* [2,6] and do another set of fits */
/***********************************************/
printf ("Doing main Barnard storage loop ... m= %d\n", m);
sdist_avg = 0.0;
sdist_count = 0;
for (i = 0; i < m; i++)
{
/* number of points in this slab */
npoints = end[i] - start[i] + 1;
norig = npoints;
nrej = 0;
for (k=start[i]; k < end[i]; k++)
{
sdist_avg = sdist_avg + sdist[k];
sdist_count++;
}
/* need two temp arrays, so we can shuffle back and forth */
for (k=0,l=0;k<NCHANNELS;k++)
{
/* initialize the temp arrays */
memcpy(lnItemp,&lnI[k][start[i]], npoints*sizeof(float));
memcpy(Atemp,&A[start[i]], npoints*sizeof(float));
memcpy(wtemp,&weights[start[i]], npoints*sizeof(float));
nrej = 0;
nzero=0;
/* scan down for missing radiances */
for (s=0;s<npoints;s++)
{
if (lnItemp[s] < -8888)
{
wtemp[s] = 0.0;
nzero++;
} /* end if (lnItemp[s]... */
} /* end for (s... */
#ifdef PLOTDATA
/* Write out our platform that contains the plot information */
for (s=0;s<npoints;s++)
{
/* things to do only once */
if (k == 0)
{
/* things to do for all fields */
for (f = 0; f < newD->nFields[PLOT][i]; f++)
{
/* write out sample times. */
newD->sampleTimes[PLOT][i][0][f][s] = ztime[start[i] + s];
/* write out nsamples */
newD->nSamples[PLOT][i][0][f] = npoints;
} /* end for (f... */
newD->BWdata[PLOT][i][0][AM][s][0] = Atemp[s];
/* write out sample location */
newD->subLoc[PLOT][i][0] = D->subLoc[B1][0][0];
/* write out new plot file for each slab */
newD->zebNewFileFlag[PLOT][i] = 1;
} /* end if (k... */
newD->BWdata[PLOT][i][0][LN_I+k][s][0] = lnItemp[s];
} /* end for (s... */
#endif /* end ifdef PLOTDATA */
/* now iterate over our fits */
nruns=0;
sigp = 1e9;
do
{
/* Here is our fit */
sigi=sigs=0;
lfit(Atemp, lnItemp, wtemp, npoints, &intercept, &slope,
&sigi, &sigs, &sigp, NULL);
#ifdef OLDFIT
fit_(Atemp, lnItemp, &npoints, sigtemp, &one, &intercept,
&slope, &sigi, &sigs, &chi2, &q);
sigp = sqrt(chi2/(float) (npoints-nrej-nzero-2));
/* we need to multiply sigs by sigp, because we've implicitly */
/* set our sigy=1 (in sigtemp) for all pts. in the fit. The */
/* estimated value for sigy is sigp... */
/* Really, I should just rewrite the fitting routine */
sigs *= sigp;
sigi *= sigp;
#endif /* end ifdef OLDFIT */
#define SIGLIM (k==1 ? .015 : .01)
old_rej = nrej;
/* Now run down the points and see if they are outside our fit */
for (j=0; j < npoints; j++)
{
y = intercept+slope*Atemp[j];
resid = lnItemp[j]-y;
/* reject data below the line and outside two sigmas */
if (wtemp[j] > 0 && resid < -2*sigp)
{
wtemp[j] = 0.0; /* this should zero out this point */
nrej++;
#ifdef PLOTDATA
/* tag the point as rejected in the plot platform */
newD->BWdata[PLOT][i][0][REJECTED+k][j][0] = 1;
#endif /* end ifdef PLOTDATA */
} /* end if (wtemp[j]... */
} /* end for (j... */
/* run the fit again, with the non rejected points */
nruns++;
} while (nruns < 20 && nrej > old_rej && sigp > SIGLIM);
/* take out the rejected points */
frac = (float)(npoints-nrej-nzero) / (float)npoints;
/* Now, set our badflags for various terms of rejection */
/* _track_ rejected fits */
if (sigp > SIGLIM)
badflag = 1;
else if (exp(intercept) < .05 ||
exp(intercept) > 5000.0)
badflag = 2;
else if (frac < .75 )
badflag = 3;
else
badflag = 0;
/* store our final field values */
if (isnan (slope) || isnan (intercept) || (npoints-nrej-nzero) < 3)
{
newD->BWdata[LANGLEY][0][0][OD + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][SC + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][ERR_FIT + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][ERR_SLOPE + k][i][0] = MISSING;
} /* end if (isnan (slope... */
else if (isinf ( slope) || isnan ( intercept) || (npoints-nrej-nzero) < 3)
{
newD->BWdata[LANGLEY][0][0][OD + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][SC + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][ERR_FIT + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][ERR_SLOPE + k][i][0] = MISSING;
} /* end if (isnan (slope... */
else if (badflag != 0)
{
/* The badflag value is not zero, so set fields missing */
newD->BWdata[LANGLEY][0][0][OD + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][SC + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][ERR_FIT + k][i][0] = MISSING;
newD->BWdata[LANGLEY][0][0][ERR_SLOPE + k][i][0] = MISSING;
}
else
{
newD->BWdata[LANGLEY][0][0][OD + k][i][0] = -slope;
dvalue = exp(intercept);
if (isnan(dvalue) || isinf(dvalue))
{
newD->BWdata[LANGLEY][0][0][SC + k][i][0] = MISSING;
}
else
{
/* For Filter 1 to 5 multiply the Solar Constant by gNomCal to convert the units
* back to "counts"
*/
dvalue = dvalue * gNomCal[k];
newD->BWdata[LANGLEY][0][0][SC + k][i][0] = dvalue;
}
/* final error in fit */
newD->BWdata[LANGLEY][0][0][ERR_FIT + k][i][0] = sigp;
/* error in slope */
newD->BWdata[LANGLEY][0][0][ERR_SLOPE + k][i][0] = sigs;
} /* end else */
newD->BWdata[LANGLEY][0][0][NPTS + k][i][0] = (float) (npoints-nrej-nzero);
newD->BWdata[LANGLEY][0][0][GOOD_FRACT + k][i][0] = frac;
newD->BWdata[LANGLEY][0][0][BAD_FLAG + k][i][0] = (float)badflag;
} /* end for (k... */
/* if key chn is good all chns are good */
if (newD->BWdata[LANGLEY][0][0][BAD_FLAG + KEY_CHN][i][0] == 0)
{
for (k = 0; k < NCHANNELS; k++)
newD->BWdata[LANGLEY][0][0][BAD_FLAG + k][i][0] = 0;
} /* end if (newD... */
else
{
for (k = 0; k < NCHANNELS; k++)
if (newD->BWdata[LANGLEY][0][0][BAD_FLAG + k][i][0] == 0)
newD->BWdata[LANGLEY][0][0][BAD_FLAG + k][i][0] = 4;
} /* end else */
/* report time in the middle of this slab. I do this way down */
/* here so I can trap on badflags in a later version if I want */
for (f=0; f<newD->nFields[LANGLEY][0]; f++)
{
newD->sampleTimes[LANGLEY][0][0][f][i]=ztime[start[i] + norig/2];
}
} /* end for (i... */
/***********************************************/
/* Okay, we now have values for all our slabs */
/* and for all channels. Just finish up with */
/* the boring stuff and we are ready to rock. */
/***********************************************/
/* Solar distance, Barnard ... may need to do some averaging ... */
dvalue = sdist_avg / sdist_count;
if (isinf(dvalue) || isnan(dvalue))
{
newD->BWdata[LANGLEY][0][0][BSDIST][0][0] = -9999.;
}
else
{
newD->BWdata[LANGLEY][0][0][BSDIST][0][0] = sdist_avg/sdist_count;
}
newD->nObs[LANGLEY] = 1;
for (f=0;f<newD->nFields[LANGLEY][0];f++)
{
newD->nSamples[LANGLEY][0][0][f] = m;
} /* end for (f... */
newD->subLoc[LANGLEY][0][0] = D->subLoc[B1][0][0];
/* platformNames = retriever_GetPlatformNames(); */
/* add a plot comment, if you want */
#if defined(TWEIGHT) && defined(PLOTDATA)
/* for (o=0; o<newD->nObs[PLOT]; o++) */
main_SetAttrValue (newD, PLOT, 0, -1, "plot_comment",
"Weighting by airmass gradient for fit");
#endif /* end if defined (... */
return (newD);
} /* barnard_langley */
int yymmdd_to_juldate (int yymmdd)
{
/* Local variables */
int i;
int leapyear;
int yy, mm, dd;
int remainder;
int month[12];
int jday = 0;
/* Allocate space */
yy = (int) (yymmdd / 10000);
mm = (yymmdd / 100) % 100;
dd = yymmdd % 100;
/* Is this a leap year? */
remainder = yy % 4;
leapyear = 0;
if (remainder == 0)
{
leapyear = 1;
}
/* Assign lengths to the months */
for (i=1; i<=12; i++)
{
month[i] = 31;
}
month[2] = leapyear ? 29 : 28;
month[4]=30;
month[6]=30;
month[9]=30;
month[11]=30;
/* Now just count up the days */
for (i=1; i<mm; i++)
{
jday += month[i];
}
jday += dd;
return (jday);
}
double airmass (double zeta)
{
/* cosine of zenith angle */
double costh;
double A;
costh = cos ((90-zeta) * 2 * M_PI / 360.0);
if (costh > 0)
{
A = 1.0/(costh + 0.50572 * exp (-1.6364 * log (6.07995 + zeta)));
return (A);
} /* if (costh... */
else
return (1e8);
} /* airmass (... */
#undef BARNARD_LANGLEY_C
/* end of file barnard_langley.c */
#include <stdio.h>
#include <math.h>
#include "jim-plot.h"
int jimmy_plot(plot_t *p)
{
int i, j;
FILE *f;
extern char *plot_fnm(void);
if ((f = fopen(plot_fnm(), "a")) == NULL) {
fprintf(stderr, "hey: can't open plot file\n");
return(-1);
}
fprintf(f, "%d\n", p->rows);
for (i=0; i<p->rows; i++) {
fprintf(f, "%d %.4f", i, p->am[i]);
for (j=0; j<p->cols; j++)
fprintf(f, " %.4f %d", log(p->points[j][i]), p->status_code[j][i]);
fputs("\n", f);
}
fclose(f);
return(1);
}
#ifndef JIM_PLOT_H
#define JIM_PLOT_H
typedef struct {
int cols, rows, type;
double *am, **points;
char *xlab, *ylab, *title,
**status_code;
} plot_t;
int jimmy_plot(plot_t *);
#endif
This diff is collapsed.
#ifndef LA_H
#define LA_H
#include <time.h>
#include "michalsky_langley.h"
/* tdh moved ana_t to michalsky_langley.h */
/* tdh moved la_cfg to michalsky_langley.h */
/* tdh moved obs_time_t to michalsky_langley.h */
/* tdh moved la_obs to michalsky_langley.h */
/* tdh - moved pt_t to michalsky_langley.h */
/* tdh - moved la_return to michalsky_langley.h */
/*
** Do langley analysis for a set of observations. The input records should
** be partitioned into whatever conditions are required.
** 'cfg' points to a description of the input data
** 'obs' points to a list of cfg->n_obs input records
**
** the return value is a pointer to a list of optical depth/i0 pairs; the
** number of pairs in the list is determined by how many 'columns' have
** langley analysis requested in cfg->ana.
*/
/* tdh - moved lang_ana(..) to michalsky_langley.h */
time_t time_of(obs_time_t *);
#ifndef M_DTOR
#define M_DTOR 0.0174532925199433
#define M_RTOD 57.2957795130823230
#define M_2PI 6.2831853071795862320E0
#define M_HTOR 0.2617993877991494
#define M_RTOH 3.8197186342054881
#define M_HTOD 15.0
#define M_DTOH 0.0666666666666667
#endif
#endif
This diff is collapsed.
/*******************************************************************************
* COPYRIGHT (C) 2001 Battelle Memorial Institute.
* All Rights Reserved. (Now, with this out of the way...)
*
* RCS INFORMATION:
* $RCSfile: langley.h,v $
* $Revision: 1.15 $
* $Author: koontz $
* $Locker: $
* $Date: 2010/01/22 20:45:31 $
* $State: Exp $
* $Name: $
* $Id: langley.h,v 1.15 2010/01/22 20:45:31 koontz Exp $
*
* LIBRARY DEPENDENCIES:
*
* DESCRIPTION:
* <Discuss overall design/purpose of class.>
*******************************************************************************/
#ifndef LANGLEY_H
#define LANGLEY_H
/* We'll be doing a lot of dynamic allocation, so let's make it easier */
#define CALLOC(n,t) (t*)calloc(n, sizeof(t))
#define REALLOC(p,n,t) (t*) realloc((char *) p, (n)*sizeof(t));
#define MISSING -9999.0
/*
* Really should have number of narrow and number of broad band channels,
* and have a narrow_idx[*] and a broad_idx[*] and work off of the idxs.
* But for now we will just assume that the fist chn is the broad and
* narrow starts at 1
*/
#define NCHANNELS 7 /* number of mfrsr channels 1 broadband, 6 narrow band */
#define KEY_CHN 1 /* this is the 500nm channel */
#define NSLABS 4 /* max number of langleys per day, should only get 2 */
#define PLOTDATA /* if set generate the plot netcdf file. */
#define LOW_AM 2.0
#define HIGH_AM 6.05
#define LSFITSD 0.006
#define OUTLIMIT 1.5
#define FRACPTS 0.3
#define CLOUDSLOP 0.015
#define DEFAULT_PLATFORM "mfrsr"
#define DEFAULT_SITE "sgp"
#define DEFAULT_FACILITY "C1"
#define UNCAL_DATALEVEL "a0"
#define UNCAL_NAME "uncalibrated"
enum platform_type
{
Input_Platform,
Output_Platform
}; /* enum platform_type */
enum input_platforms
{
B1_M = 0, /* platform #0 in retriever file is the mfrsr b1 datastream */
B1_N = 1, /* platform #0 in retriever file is the nimfr b1 datastream */
}; /* enum input_platforms */
int B1;
#define NPRESPLATS 4
#define PRES_CONF_FILE "langley_pres.conf"
enum input_fields
{
IN_BROADBAND = 0,
IN_CHN1,
IN_CHN2,
IN_CHN3,
IN_CHN4,
IN_CHN5,
IN_CHN6,
QC_BROADBAND,
QC_CHN1,
QC_CHN2,
QC_CHN3,
QC_CHN4,
QC_CHN5,
QC_CHN6
}; /* enum input_fields */
enum input_pres_flds
{
PRES
}; /* enum input_pres_flds */
enum output_fields
{
OD = 0, /* barnard then michalsky langley */
SC = 14, /* barnard then michalsky langley */
SC_NORM = 28, /* michalsky langley */
ERR_FIT = 35, /* barnard langley */
SD = 42, /* michalsky langley */
ERR_SLOPE = 49, /* barnard langley */
NPTS = 56, /* barnard then michalsky langley */
GOOD_FRACT = 70, /* barnard then michalsky langley */
BAD_FLAG = 84, /* barnard then michalsky langley */
AM = 0, /* barnard then michalsky plot */
LN_I = 2, /* barnard then michalsky plot */
BSDIST = 98, /* barnard sun earth distance */
MSDIST = 99, /* michalsky sun earth distance */
REJECTED = 16 /* barnard then michalsky plot */
}; /* enum input_fields */
#define NOUTFLDS 100
#define NOUTPLTFLDS 30
#define NOUTPLATS 2
enum output_platforms
{
LANGLEY,
PLOT
}; /* enum output_platforms */
#ifdef LANGLEY_C
char altPlatform[9] = "Altitude";
float channels[NCHANNELS] = {413., 499., 608., 665., 859., 939., 0};
double lat, lon, alt;
/* double presfraction; */
#else
extern char altPlatform[9];
extern int channels[NCHANNELS];
extern double lat, lon, alt;
/* extern double presfraction; */
#endif /* LANGLEY_C */
float gLSFITSD;
/****** function prototypes ******/
#endif /* LANGLEY_H */
/* LANGLEY_H */
This diff is collapsed.
; $Id: langley_batch.pro,v 1.9 2012-01-09 16:03:19 koontz Exp $
;--------------------------------------------------------------------------------
;+
; Abstract:
;
; Author:
; Todd Halter, PNNL
;
; Date Created:
; November, 1999
;
; Date Last Modified:
; $Date: 2012-01-09 16:03:19 $
;
;-
pro langley_batch
date = long (getenv ("DATE"))
platform = getenv ("PLATFORM")
site = getenv ("SITE")
facility = getenv ("FACILITY")
algorithm = getenv ("ALGORITHM")
resolve_routine, 'langley'
resolve_all
langley, 1, to=6, date = date, platform = platform, site=site, $
facility=facility, algorithm = 'barnard', $
plot_to = 'png'
langley, 1, to=6, date = date, platform = platform, site=site, $
facility=facility, algorithm = 'michalsky', $
plot_to = 'png'
; langley, 1, to=6, date = date, platform = platform, site=site, $
; facility=facility, algorithm = 'barnard', /onefile, $
; plot_to = 'ps', /zlog
; langley, 1, to=6, date = date, platform = platform, site=site, $
; facility=facility, algorithm = 'michalsky', /onefile, $
; plot_to = 'ps', /zlog
return
end
#ifndef _LANGLEY_RETRIEVER_H
#define _LANGLEY_RETRIEVER_H
#include "bw_adi.h"
#ifndef NO_RETRIEVER_H
const char *Platform_List[]=
{
//"nimfr.b1|mfrsr.b1",
"AUTO",
NULL
};
const char *Field_List[][BW_MAX_FIELDS]=
{
{
//mfrsr.b1
"direct_normal_broadband",
"direct_normal_narrowband_filter1",
"direct_normal_narrowband_filter2",
"direct_normal_narrowband_filter3",
"direct_normal_narrowband_filter4",
"direct_normal_narrowband_filter5",
"direct_normal_narrowband_filter6",
"qc_direct_normal_broadband",
"qc_direct_normal_narrowband_filter1",
"qc_direct_normal_narrowband_filter2",
"qc_direct_normal_narrowband_filter3",
"qc_direct_normal_narrowband_filter4",
"qc_direct_normal_narrowband_filter5",
"qc_direct_normal_narrowband_filter6",
"nominal_calibration_factor_broadband",
"nominal_calibration_factor_filter1",
"nominal_calibration_factor_filter2",
"nominal_calibration_factor_filter3",
"nominal_calibration_factor_filter4",
"nominal_calibration_factor_filter5",
"nominal_calibration_factor_filter6",
NULL
},
};
#endif // NO_RETRIEVER_H
#endif // _LANGLEY_RETRIEVER_H
/*
* $Id: lfit.c,v 1.2 1997/07/22 16:27:45 d3a230 vap-langley-2.25-0.sol5_10 $
*
* lfit() does a weighted linear fit, returning all sorts of error
* numbers. You can unweight by using NULL for the w array on input.
*
*
* $Log: lfit.c,v $
* Revision 1.2 1997/07/22 16:27:45 d3a230
* Added some sanity checking when we have two or fewer non-zero-weighted
* points. Pathological, of course, but if we don't do it we get math errors
* all the time.
*
* Revision 1.1 1997/07/18 15:58:43 d3a230
* Initial revision
*
*/
static char *rcsid="$Id: lfit.c,v 1.2 1997/07/22 16:27:45 d3a230 vap-langley-2.25-0.sol5_10 $";
static char *rcsstate="$State: vap-langley-2.25-0.sol5_10 $";
#include <math.h>
/*
* Do a linear fit y = a+bx, weighted by w
*
* Right now the siga and sigb assume no measurement uncertainty - i.e.
* we estimate via sampling theory - sigy =~ sqrt(npr*syx2)
*/
void lfit(float *x, float *y, float *w, int n, float *a, float *b,
float *siga, float *sigb, float *sigfit, int *count)
{
int i;
double sumx=0, sumy=0, sumxy=0, sumx2=0, sumy2=0, sumw=0;
double denom, slope, intercept, npr, m, syx2;
m=0;
/* This lets us set w=NULL on input to do an unweighted fit */
#define W (w ? w[i] : 1)
for (i=0; i<n; i++) {
sumx += W*x[i];
sumx2 += W*x[i]*x[i];
sumy += W*y[i];
sumy2 += W*y[i]*y[i];
sumxy += W*x[i]*y[i];
sumw += W;
/* This is a little goofy - m holds the number of non-zero */
/* weighted points, which we need to get our n/(n-2) factor right */
if (w[i] > 0.0) m += 1.0;
}
#undef W
/* simple formulas */
denom = sumw*sumx2 - sumx*sumx;
slope = (sumw*sumxy - sumx*sumy)/denom;
intercept = (sumy*sumx2 - sumx*sumxy)/denom;
/* I'm not sure this is right, especially with the weights */
/* syx2 is standard error of estimate */
syx2 = (sumy2 - intercept*sumy - slope*sumxy)/sumw;
// Actually, I think that is analytically correct - but there sometimes
// gives a roundoff that leads to negative values. I will look for both
// negative and small absolute values later on
/* sampling error */
npr = m > 2 ? m/(m-2) : 1;
*a = intercept;
*b = slope;
// A large negative value is bad, so blow stuff up
if (syx2 < -1e-6) {
if (siga) *siga = 1e8;
if (sigb) *sigb = 1e8;
if (sigfit) *sigfit = 1e8;
if (count) *count = m;
return;
}
// Now, trap for roundoffs - set the min error to 1e-6. This will
// capture really small errors of both signs
if (syx2 < 1e-6) {
syx2 = 1e-6;
}
// Now calculate errors of the fit
if (siga) *siga = m>2 ? sqrt(syx2*npr*sumx2/denom) : 1e8;
if (sigb) *sigb = m>2 ? sqrt(syx2*npr*sumw/denom) : 1e8;
if (sigfit) *sigfit = m>2 ? sqrt(syx2) : 1e8;
if (count) *count = m;
return;
}
char *get_fit_id()
{
return(rcsid);
}
char *get_fit_state()
{
return(rcsstate);
}
This diff is collapsed.
/*******************************************************************************
* COPYRIGHT (C) 2001 Battelle Memorial Institute.
* All Rights Reserved. (Now, with this out of the way...)
*
* RCS INFORMATION:
* $RCSfile: michalsky_langley.c,v $
* $Revision: 1.14 $
* $Author: koontz $
* $Locker: $
* $Date: 2011/12/29 18:57:13 $
* $State: Exp $
* $Name: $
* $Id: michalsky_langley.c,v 1.14 2011/12/29 18:57:13 koontz Exp $
*
* FUNCTIONS IN THIS FILE:
*
* DESIGN:
* <Discuss overall design/purpose of class.>
*******************************************************************************/
#define MICHALSKY_LANGLEY_C
/****** General Includes ******/
#include <stdio.h>
#include <time.h>
#include <math.h>
/****** Zebra Includes ******/
/* #include "defs.h"
* #include "message.h"
* #include "DataStore.h"
*/
/****** BW Includes ******/
/* #define BW_CODE
* #include "bw_main.h"
*/
/****** Application Includes ******/
#include "langley.h"
#include "michalsky_langley.h"
#define BW_CODE
#include "bw_adi.h"
#define TRUE 1
#define FALSE 0
float michalsky_sdist; /* To capture sdist from gest_solar_geom */
/*******************************************************************************
* Function:
* michalsky_langley -
*
* Inputs:
*******************************************************************************/
int michalsky_langley (DATA *D, DATA *newD, float *gNomCal)
{
/* functions used by michalsky_langley (... */
int setup_for_michalsky (DATA *);
int write_newD (DATA *, float *);
int status;
setup_for_michalsky (D);
/* I don't think this is needed
config_file ();*/ /* This is michalsky code */
langley (); /* This is michalsky code */
if ((status = write_newD (newD, gNomCal)) < 0) {
bw_return(-1, "Michalsky: problem writing newD");
}
return (TRUE);
} /* michalsky_langley (... */
int setup_for_michalsky (DATA *D)
{
char cfg_file[512];
int i, o, t, ot, r;
int sot, eot, valid_idx;
rec_t *rec;
extern long startime, etime;
/* functions used by setup_for_michalsky (... */
/*
* init global vars
*/
michalsky_npart = 0;
/* determin the number of samples */
ot = eot = 0;
sot = -1;
for (o=0; o<D->nObs[B1]; o++)
{
for (t=0; t<D->nSamples[B1][o][0][IN_BROADBAND]; t++, ot++)
{
if (D->sampleTimes[B1][o][0][IN_BROADBAND][t].zt_Sec >= startime &&
D->sampleTimes[B1][o][0][IN_BROADBAND][t].zt_Sec <= etime)
{
if (sot == -1) sot = ot;
eot = ot;
} /* end if (D->sampleTimes... */
} /* end for (t... */
} /* end for (o... */
if (sot == -1)
bw_return (-1, "Michalsky: no samples for given time period");
la_n_records = (eot - sot) + 10; /* was +1, changed to +10 because code bombs later ... A. Koontz, PNNL, June, 2013 */
printf ("DEBUG: la_n_records = %d\n", la_n_records);
/* set up arrays to hold michalsky data */
la_records = CALLOC (la_n_records, rec_t);
michalsky_status = CALLOC (la_n_records, int *);
michalsky_time = CALLOC (la_n_records, long);
michalsky_am = CALLOC (la_n_records, float);
michalsky_lnI = CALLOC (la_n_records, float *);
for (r=0; r<la_n_records; r++)
{
michalsky_lnI[r] = CALLOC (NCHANNELS, float);
michalsky_status[r] = CALLOC (NCHANNELS, int);
} /* for (r... */
/*
* set up arrays to hold michalsky return data.
* Using NSLABS as a guess, way to many but will work
* should have 2 obs for every day.
*/
michalsky_ret = CALLOC (NSLABS, la_return *);
for (o=0; o < NSLABS; o++)
michalsky_ret[o] = CALLOC (NCHANNELS, la_return);
/*
* populate data vars
*/
ot = 0;
valid_idx = 0;
for (o=0; o < D->nObs[B1]; o++)
{
for (t=0; t < D->nSamples[B1][o][0][IN_BROADBAND]; t++, ot++)
{
if (ot >= sot && ot <= eot)
{
#ifdef DEBUGIT
printf ("DEBUG: michalsky_langley at AAA: valid_idx = %d\n", valid_idx);
#endif
rec = &la_records[valid_idx];
jtoydm ((time_t) D->sampleTimes[B1][o][0][IN_BROADBAND][t].zt_Sec,
rec);
rec->n_direct = NCHANNELS;
rec->direct = CALLOC (NCHANNELS, double);
for (r=0; r < (NCHANNELS - 1); r++)
{
/* if new file format else old format */
rec->direct[r] = D->BWdata[B1][o][0][IN_CHN1+r][t][0];
}
rec->direct[NCHANNELS-1]= D->BWdata[B1][o][0][IN_BROADBAND][t][0];
valid_idx++;
} /* end if (ot... */
} /* for (t... */
} /* for (o... */
/*
* For the michalsky algorithm, broadband needs to be last
*/
for (i=0; i < NCHANNELS - 1; i++)
channels[i] = channels[i + 1];
channels[NCHANNELS - 1] = 0;
/*
* Setting up the arguments structure
*/
/* tdh sprintf (cfg_file, "%s/langley.cfg", getenv ("VAP_CONF_HOME"));
arguments.cfg_fnm = strdup (cfg_file);
*/
arguments.in_fnm = NULL;
arguments.debug = 0;
arguments.julian_out = 1;
arguments.version = 0;
arguments.smooth = 0;
arguments.parse_output = 1;
arguments.p_type = None;
/*
* set up other needed globals
*/
hours_gmt = 0; /* set time in gmt */
return (TRUE);
} /* setup_for_michalsky (... */
int write_newD (DATA *newD, float *gNomCal)
{
int o, f, t, ot, r, valid_idx;
int nobs[NOUTPLATS], chn;
long midpoint, timediff;
/* functions */
/* newD structure is setup and initialized in the barnard algroithm. */
/*
* Populate LANGLEY
* Only has 1 obs
*/
/*
* if the barnard and michalsky algorithms do not produce the same number
* of data points exit out
*/
if (newD->nSamples[LANGLEY][0][0][OD] != michalsky_npart)
{
bw_return (-1, "The algorithms do not give the same number of langleys.");
}
for (t=0; t<michalsky_npart; t++)
{
/* write out the sample time as the midpoint in the data used */
midpoint = ((michalsky_ret[t][0].last_am - michalsky_ret[t][0].first_am) /
2) + michalsky_ret[t][0].first_am;
if (labs (midpoint - newD->sampleTimes[LANGLEY][0][0][OD][t].zt_Sec) > 3600)
{
bw_return (-1, "Algorithm output times do not match within 1hr.");
}
for (r=0; r < NCHANNELS; r++)
{
/*
* the barnard chn flds come first then the then michalsky
* barnard fld start + NCHANNELS = michalsky fld start
*/
/* broadband need to be first in output */
chn = (r == 0) ? NCHANNELS - 1 : r - 1;
if ((int) michalsky_ret[t][chn].op_depth == -9999)
{
newD->BWdata[LANGLEY][0][0][OD + NCHANNELS + r][t][0] = -9999.;
}
else
{
newD->BWdata[LANGLEY][0][0][OD + NCHANNELS + r][t][0] =
(michalsky_ret[t][chn].op_depth == 0) ?
0 : -michalsky_ret[t][chn].op_depth;
}
/* Convert the Io values back to "counts" (undo nominal calibration done by ingest */
newD->BWdata[LANGLEY][0][0][SC + NCHANNELS + r][t][0] =
michalsky_ret[t][chn].i0;
if (michalsky_ret[t][chn].i0 > 0.0)
{
newD->BWdata[LANGLEY][0][0][SC + NCHANNELS + r][t][0] =
newD->BWdata[LANGLEY][0][0][SC + NCHANNELS + r][t][0] * gNomCal[r];
}
/* barnard does not have a SC_NORM */
newD->BWdata[LANGLEY][0][0][SC_NORM + r][t][0] =
michalsky_ret[t][chn].i0_sdist;
if (michalsky_ret[t][chn].i0_sdist > 0.0)
{
newD->BWdata[LANGLEY][0][0][SC_NORM + r][t][0] =
newD->BWdata[LANGLEY][0][0][SC_NORM + r][t][0] * gNomCal[r];
}
/* barnard does not have a SD */
newD->BWdata[LANGLEY][0][0][SD + r][t][0] =
michalsky_ret[t][chn].sd;
newD->BWdata[LANGLEY][0][0][NPTS + NCHANNELS + r][t][0] =
michalsky_ret[t][chn].n;
newD->BWdata[LANGLEY][0][0][GOOD_FRACT + NCHANNELS + r][t][0] =
(float)michalsky_ret[t][chn].n / (float)michalsky_ret[t][chn].n_am;
if (michalsky_ret[t][chn].op_depth == 0.0)
newD->BWdata[LANGLEY][0][0][BAD_FLAG + NCHANNELS + r][t][0] = 1;
else
{
if (michalsky_ret[t][chn].n == 0.0)
newD->BWdata[LANGLEY][0][0][BAD_FLAG + NCHANNELS + r][t][0] = 2;
else
newD->BWdata[LANGLEY][0][0][BAD_FLAG + NCHANNELS + r][t][0] = 0;
} /* end else */
} /* end for (r... */
} /* end for (t... */
/* for michalsky sun to earth distance ... may need to average ??? */
newD->BWdata[LANGLEY][0][0][MSDIST][0][0] = michalsky_sdist;
/*
* Populate PLOT
*/
ot = 0;
for (o=0; o<michalsky_npart; o++)
{
if (michalsky_npart != newD->nObs[PLOT])
{
/* set number of samples = 0 for o */
for (f=0; f < newD->nFields[PLOT][o]; f++)
newD->nSamples[PLOT][o][0][f] = 0;
msg_ELog (EF_INFO, "Plot data did not match for obs %i.", o);
return (FALSE);
} /* end if (michalsky_npart...*/
valid_idx = 0;
for (t=0; t < michalsky_nobs_part[o]; t++)
{
if (michalsky_time[ot] >=
newD->sampleTimes[PLOT][o][0][AM][0].zt_Sec &&
valid_idx <= newD->nSamples[PLOT][o][0][AM] - 1)
{
timediff = newD->sampleTimes[PLOT][o][0][AM][valid_idx].zt_Sec -
michalsky_time[ot];
if (timediff != 0.0)
msg_ELog (EF_INFO, "Sample times do not match for am: %f off by %ds",
michalsky_am[ot], timediff);
for (r=0; r<NCHANNELS; r++)
{
/* broadband need to be first in output */
chn = (r == 0) ? NCHANNELS - 1 : r - 1;
newD->BWdata[PLOT][o][0][LN_I + NCHANNELS + r][valid_idx][0] =
michalsky_lnI[ot][chn];
newD->BWdata[PLOT][o][0][REJECTED + NCHANNELS + r][valid_idx][0] =
michalsky_status[ot][chn];
} /* end for (r... */
newD->BWdata[PLOT][o][0][AM + 1][valid_idx][0] = michalsky_am[ot];
valid_idx++;
} /* end if (michalsky_am[ot]... */
ot++;
} /* end for (t=0... */
if (valid_idx != newD->nSamples[PLOT][o][0][LN_I])
msg_ELog (EF_INFO, "Number of plot samples for obs %i does not match",
o);
} /* end for (o=0... */
return (TRUE);
} /* write_newD (... */
int jtoydm (const time_t ztime,
rec_t *rec)
{
struct tm *ts;
#ifdef DEBUGIT
printf ("DEBUG jtoydm: ztime = %d\n", ztime);
#endif
ts = gmtime (&ztime);
rec->year = ts->tm_year;
rec->doy = ts->tm_yday + 1; /* tm_yday starts at 0 */
rec->tod = ts->tm_hour + ts->tm_min/60.0 + ts->tm_sec/3600.0;
#ifdef DEBUGIT
printf ("DEBUG jtoydm: year=%d doy=%d tod=%lf\n", rec->year, rec->doy, rec->tod);
#endif
return TRUE;
} /* jtoydm (... */
int
get_michalsky_data (la_cfg *cfg, la_obs *obs, la_return *l)
{
static int idx = 0;
static int o = 0;
int t, r;
/*
* if there are not any obs in the valid am range then exit
*/
if (l[0].first_am == 0 || l[0].last_am == 0)
return FALSE;
/*
* Data for langley
*/
for (r=0; r<cfg->n_data; r++)
{
michalsky_ret[o][r].op_depth = l[r].op_depth;
michalsky_ret[o][r].i0 = l[r].i0;
michalsky_ret[o][r].i0_sdist = l[r].i0_sdist;
michalsky_ret[o][r].sd = l[r].sd;
michalsky_ret[o][r].n = l[r].n;
michalsky_ret[o][r].n_am = l[r].n_am;
michalsky_ret[o][r].first_am = l[r].first_am;
michalsky_ret[o][r].last_am = l[r].last_am;
michalsky_ret[o][r].x = NULL;
michalsky_ret[o][r].y = NULL;
} /* end for (r... */
o++;
/*
* Data for langplot
*/
michalsky_nobs_part[michalsky_npart++] = cfg->n_obs;
for (t=0; t<cfg->n_obs; t++, idx++)
{
michalsky_time[idx] = obs[t].obs_time.tt;
michalsky_am[idx] = solar_geom[t].am;
for (r=0; r<cfg->n_data; r++)
{
/* this will pick up bad - values and missing values */
// Rarely, we get obs[t].data pointing to NULL, caused by our ten
// sample buffer on the end (cf. line 116, for la_n_records). So we
// need to make sure our pointer is non-null before using it. -trs, 6/15/15
if (! obs[t].data || obs[t].data[r] <= 0.0)
michalsky_lnI[idx][r] = 0.0;
else
michalsky_lnI[idx][r] = log (obs[t].data[r] * soldist2);
michalsky_status[idx][r] = ((int)rec_status[t][r] == 0) ? 0 : 1;
} /* end for (r... */
} /* end for (t... */
return TRUE;
} /* get_michalsky_data (... */
#undef MICHALSKY_LANGLEY_C
/* michalsky_langley.c */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef AE_H
#define AE_H
typedef struct {
int year, doy, is_tst;
double hour, lat, lon,
az, el, ha, dec, soldst;
} ae_pack;
double sunae(ae_pack *),
armass(double);
#endif /* AE_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment