6329 lines
171 KiB
C++
6329 lines
171 KiB
C++
/* c++ -O2 -o burn7.x burn7.cpp -lm -lnetcdf_c++ -lnetcdf */
|
|
|
|
#define NETCDF_OUTPUT
|
|
// #define OPEN_MP
|
|
|
|
#define V0 "burn 7.5 (20-May-2015)"
|
|
#define V1 "Edilbert Kirk - University of Hamburg"
|
|
#define V2 "Usage: burn7 [-help|-c|-d|-m|-n|-s] <modelfile> <resultfile>"
|
|
#define V3 "New: option <-g> writes Grads ctl for service plotting"
|
|
#define V4 "New: comments (#) are allowed in namelist file"
|
|
|
|
/* ============= */
|
|
/* include files */
|
|
/* ============= */
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include <sys/resource.h>
|
|
#include <vector>
|
|
#include <valarray>
|
|
|
|
#ifdef OPEN_MP
|
|
#include <omp.h>
|
|
#endif
|
|
|
|
#ifdef NETCDF_OUTPUT
|
|
#include <netcdfcpp.h>
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
#define LONG long long
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.1415926535
|
|
#endif
|
|
|
|
#ifndef M_SQRT2
|
|
#define M_SQRT2 1.4142136
|
|
#endif
|
|
|
|
#ifndef MAX
|
|
#define MAX(v1,v2) ((v1) > (v2) ? (v1) : (v2))
|
|
#endif
|
|
|
|
#ifndef min
|
|
#define min(v1,v2) ((v1) < (v2) ? (v1) : (v2))
|
|
#endif
|
|
|
|
#ifndef abs
|
|
#define abs(x) ((x) >= 0 ? (x) : -(x))
|
|
#endif
|
|
|
|
#ifndef TRUE
|
|
#define TRUE 1
|
|
#endif
|
|
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#endif
|
|
|
|
#define LEV_SURFACE 1
|
|
#define LEV_99 99
|
|
#define LEV_ISOBARIC 100
|
|
#define LEV_MEANSEA 102
|
|
#define LEV_ALTITUDE 103
|
|
#define LEV_HEIGHT 105
|
|
#define LEV_SIGMA 107
|
|
#define LEV_HYBRID 109
|
|
#define LEV_GROUND 112
|
|
|
|
#define REP_REGULAR 0
|
|
#define REP_GAUSS 4
|
|
#define REP_SPECTRAL 50
|
|
|
|
#define MAX_HOURS 4
|
|
#define MAX_LEVELS 99
|
|
|
|
#define MAX_NVCT (MAX_LEVELS * 2 + 2)
|
|
|
|
#define L_TIMES_RHOH2O (-333700000.0)
|
|
#define EARTH_RADIUS 6371220.0
|
|
#define MARS_RADIUS 3400000.0
|
|
#define SQUARE_RADIUS (-PlanetRadius * PlanetRadius)
|
|
#define EARTH_GRAV 9.80665
|
|
#define MARS_GRAV 3.728
|
|
#define RG (1.0 / Grav)
|
|
#define MARS_RD (189.0 )
|
|
|
|
/* ************************************** */
|
|
/* Thermodynamical constants adopted from */
|
|
/* ECMWF IFS-Code */
|
|
/* ************************************** */
|
|
|
|
#define RKBOL (1.380658e-23)
|
|
#define RNAVO (6.0221367e+23)
|
|
#define R (RKBOL * RNAVO)
|
|
#define RMD (28.9644)
|
|
#define RMV (18.0153)
|
|
#define EARTH_RD (1000. * R / RMD)
|
|
#define RV (1000. * R / RMV)
|
|
#define RCPD (3.5 * RD)
|
|
#define RCPV (4.0 * RV)
|
|
#define RETV (RV / RD - 1.)
|
|
#define RCW (4218.)
|
|
#define RCS (2106.)
|
|
#define RTT (273.16)
|
|
#define RLVTT (2.5008e+6)
|
|
#define RLSTT (2.8345e+6)
|
|
#define RESTT (611.14)
|
|
#define RLAPSE (0.0065)
|
|
|
|
#ifdef NETCDF_OUTPUT
|
|
|
|
NcFile *NetFile;
|
|
|
|
NcVar *LonVar;
|
|
NcVar *LatVar;
|
|
NcVar *LevVar;
|
|
NcVar *TimVar;
|
|
|
|
NcDim *LonDim;
|
|
NcDim *LatDim;
|
|
NcDim *LevDim;
|
|
NcDim *TimDim;
|
|
|
|
#endif
|
|
|
|
int SaveMemory = 0; /* Switch on for dynamic memory usage */
|
|
int PolyCreate = 0; /* Create polynomials files for hires T1365 and more */
|
|
int PolyDisk = 0; /* Read polynomials from disk */
|
|
int GaussGrid = 0; /* Output Guassian Grid */
|
|
int DPM = 0; /* Days Per Month if DPM > 99 */
|
|
int DayDivisor = 0; /* Use for day adjustment if more than 99 days per month */
|
|
|
|
char VerType; /* s=Sigma p=Pressure */
|
|
char HorType; /* s=Spherical f=Fourier z=Zonal Mean g=Gauss Grid */
|
|
char *filename;
|
|
char ifile[256]; // name of input file (PUMA-II format)
|
|
char ofile[256]; // Name of output file (Service or NetCDF format)
|
|
char gfile[256]; // Name of Grads control file
|
|
char rfile[256]; // Name of Grads data file (for zonal means only)
|
|
#define MAX_NL 40960
|
|
char namelist[MAX_NL];
|
|
char AllocName[256];
|
|
|
|
int PumaCode;
|
|
int PumaLevel;
|
|
int RepGrib;
|
|
int Debug;
|
|
int Dim3FC ;
|
|
int Dim3SP ;
|
|
int Dim3GG ;
|
|
int Dim3GP ;
|
|
int DimFC ; // Dimension of fourier array
|
|
int DimGP ; // Dimension of output grid
|
|
int DimGG ; // Dimension of Gauss grid
|
|
int DimAB ; // Dimension of array buffer
|
|
int DimSP ;
|
|
int DimSP_half ;
|
|
int CoreBigEndian ; // Do we run on a big endian machine ?
|
|
int FileBigEndian ;
|
|
int Endian = 0 ; /* Marker for reverse endian format */
|
|
int LongFCW = 0 ; /* Flag for 64bit (1) or 32bit (0) FCW's */
|
|
int RealSize = 4 ; /* Size of real data (4 = float) (8 = double) */
|
|
int HeadSize = 32 ; // 32:Service single 64:Service double
|
|
int EndOfMonth ;
|
|
int EndOfTerm ;
|
|
int Fouriers ;
|
|
int HumInfo ; // Flag for humidity info issued
|
|
double Grav = EARTH_GRAV;
|
|
double SigmaTop = 0.0;
|
|
int NetCDF ;
|
|
int GaussianOutput = 1;
|
|
int Grads ;
|
|
int HeaderWords ; /* Length of file header in 32-bit words */
|
|
int Gats ;
|
|
int Lats ;
|
|
int AllLevs = 0 ; // # of sigma levels in data file
|
|
int SigLevs = 0 ; // # of sigma levels used
|
|
int SingleLevel = 0 ; // Set to true for SAM/SOM models
|
|
double LevelFactor = 1.0 ; // Multiplier for head(2)
|
|
int LevelType ;
|
|
int Gons ;
|
|
int Lons ;
|
|
int Cyclical = 0 ; // 1 = Cyclical completion (Lons from 0 to 360)
|
|
double L_times_rhoH2O = L_TIMES_RHOH2O;
|
|
int mars ;
|
|
int Mean ;
|
|
int MeanCount ; // Count terms during month
|
|
int Multi ;
|
|
int FirstMonth = 1;
|
|
int LastMonth = 12;
|
|
double PlanetRadius= EARTH_RADIUS;
|
|
double RD = EARTH_RD;
|
|
int Spectral = FALSE;
|
|
int TermCount ;
|
|
int MonthCount ;
|
|
int OutputCount ;
|
|
int Truncation = 0;
|
|
int Waves ;
|
|
int SpecialUV ;
|
|
|
|
struct tm NewDate;
|
|
struct tm OldDate;
|
|
int NewMonth;
|
|
int OldMonth;
|
|
|
|
// Some functions for a nice printout
|
|
|
|
#define COLS 72
|
|
|
|
void Stars(int n) {while (n--) putchar('*');}
|
|
void ErrStars(int n) {while (n--) putc('*',stderr);}
|
|
void Blanks(int n) {while (n--) putchar(' ');}
|
|
void Dashes(int n) {while (n--) putchar('-');}
|
|
void NewLine(void) {putchar('\n');}
|
|
void ErrNewLine(void) {putc('\n',stderr);}
|
|
void StarLine(void) {Stars(COLS); NewLine();}
|
|
|
|
/* ==================================== */
|
|
/* Abort - Print error message and exit */
|
|
/* ==================================== */
|
|
|
|
void Abort(const char *errtext)
|
|
{
|
|
Stars(min(80,strlen(errtext))); NewLine();
|
|
puts(errtext); NewLine();
|
|
Stars(min(80,strlen(errtext))); NewLine();
|
|
ErrStars(min(80,strlen(errtext))); ErrNewLine();
|
|
fputs(errtext,stderr); ErrNewLine();
|
|
ErrStars(min(80,strlen(errtext))); ErrNewLine();
|
|
exit(1);
|
|
}
|
|
|
|
void BlankLine(void)
|
|
{
|
|
putchar('*');
|
|
Blanks(COLS-2);
|
|
putchar('*');
|
|
NewLine();
|
|
}
|
|
|
|
void DashLine(void)
|
|
{
|
|
putchar('*');
|
|
putchar(' ');
|
|
Dashes(COLS-4);
|
|
putchar(' ');
|
|
putchar('*');
|
|
NewLine();
|
|
}
|
|
|
|
void CenterText(const char *t)
|
|
{
|
|
int i,j,l;
|
|
l = strlen(t);
|
|
if (l < 1) return;
|
|
if (l > COLS-4) puts(t);
|
|
else
|
|
{
|
|
i = (COLS - 4 - l) / 2;
|
|
j = (COLS - 4 - l - i);
|
|
putchar('*');
|
|
Blanks(i+1);
|
|
fputs(t,stdout);
|
|
Blanks(j+1);
|
|
putchar('*');
|
|
NewLine();
|
|
}
|
|
}
|
|
|
|
void LeftText(const char *t)
|
|
{
|
|
int l;
|
|
l = strlen(t);
|
|
if (l < 1) return;
|
|
if (l > COLS-4) puts(t);
|
|
else
|
|
{
|
|
putchar('*');
|
|
putchar(' ');
|
|
fputs(t,stdout);
|
|
Blanks(COLS - l - 3);
|
|
putchar('*');
|
|
NewLine();
|
|
}
|
|
}
|
|
|
|
|
|
#define MAX_ID_LEN 8
|
|
#define MAX_NA_LEN 32
|
|
#define MAX_UN_LEN 16
|
|
|
|
class Control
|
|
{
|
|
public:
|
|
int readit ;
|
|
int needed ;
|
|
int selected ;
|
|
int detected ;
|
|
int hlev ;
|
|
int plev ;
|
|
int loff ;
|
|
int twod ;
|
|
int code ;
|
|
valarray<double>hsp;
|
|
valarray<double>hfc;
|
|
valarray<double>hgp;
|
|
valarray<double>pgp;
|
|
valarray<double>mgp;
|
|
valarray<double>pfc;
|
|
valarray<double>psp;
|
|
char Id[MAX_ID_LEN];
|
|
char Na[MAX_NA_LEN];
|
|
char Un[MAX_UN_LEN];
|
|
#ifdef NETCDF_OUTPUT
|
|
NcVar *NetVar ;
|
|
#endif
|
|
|
|
void Status(void);
|
|
void Init(const char* Idf, const char *Name, const char *Units, int TwoD);
|
|
void SetHSpec(int Hlev, int Plev, int Twod);
|
|
void SetHFour(int Hlev, int Plev, int Twod);
|
|
void SetHGrid(int Hlev, int Plev, int Twod);
|
|
void SetPGrid(void);
|
|
void SetPFour(void);
|
|
void SetPSpec(void);
|
|
};
|
|
|
|
void Control::Status(void)
|
|
{
|
|
printf("\nStatus for code %3d: %s\n",code,Id);
|
|
printf("-------------------------\n");
|
|
printf("needed: %5d\n",needed);
|
|
printf("selected: %5d\n",selected);
|
|
printf("detected: %5d\n",detected);
|
|
printf("hlev: %5d\n",hlev);
|
|
printf("plev: %5d\n",plev);
|
|
printf("twod: %5d\n",twod);
|
|
printf("hsp: %5ld\n",hsp.size());
|
|
printf("hfc: %5ld\n",hfc.size());
|
|
printf("hgp: %5ld\n",hgp.size());
|
|
printf("pgp: %5ld\n",pgp.size());
|
|
printf("mean: %5ld\n",mgp.size());
|
|
printf("pfc: %5ld\n",pfc.size());
|
|
printf("psp: %5ld\n",psp.size());
|
|
if (hgp.size()) printf("mean of hgp: %16.10lf\n",hgp.sum() / hgp.size());
|
|
if (pgp.size()) printf("mean of pgp: %16.10lf\n",pgp.sum() / pgp.size());
|
|
};
|
|
|
|
void Control::Init(const char* Idf, const char *Name, const char *Units, int TwoD)
|
|
{
|
|
strncpy(Id,Idf ,MAX_ID_LEN-1);
|
|
strncpy(Na,Name ,MAX_NA_LEN-1);
|
|
strncpy(Un,Units,MAX_UN_LEN-1);
|
|
twod = TwoD;
|
|
}
|
|
|
|
void Control::SetHSpec(int Hlev, int Plev, int Twod)
|
|
{
|
|
int OldSize;
|
|
int NewSize;
|
|
|
|
hlev = Hlev;
|
|
plev = Plev;
|
|
twod = Twod;
|
|
|
|
OldSize = hsp.size();
|
|
NewSize = Hlev * DimSP;
|
|
|
|
if (NewSize == OldSize) return;
|
|
|
|
hsp.resize(NewSize);
|
|
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
if (OldSize == 0)
|
|
sprintf(tb,"Alloc: %p %6s[%3d].hsp %6ld double",&hsp[0],Id,code,hsp.size());
|
|
else
|
|
sprintf(tb,"Realloc: %p %6s[%3d].hsp %6ld double",&hsp[0],Id,code,hsp.size());
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
|
|
void Control::SetHFour(int Hlev, int Plev, int Twod)
|
|
{
|
|
if (hfc.size() == Hlev * DimFC) return;
|
|
|
|
hlev = Hlev;
|
|
plev = Plev;
|
|
twod = Twod;
|
|
|
|
hfc.resize(hlev * DimFC);
|
|
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"Alloc: %p %6s[%3d].hfc %6ld double",&hfc[0],Id,code,hfc.size());
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
|
|
void Control::SetPFour(void)
|
|
{
|
|
if (pfc.size() == plev * DimFC) return;
|
|
|
|
pfc.resize(plev * DimFC);
|
|
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"Alloc: %p %6s[%3d].pfc %6ld double",&pfc[0],Id,code,pfc.size());
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
|
|
void Control::SetHGrid(int Hlev, int Plev, int Twod)
|
|
{
|
|
if (hgp.size() == Hlev * DimGP) return;
|
|
|
|
hlev = Hlev;
|
|
plev = Plev;
|
|
twod = Twod;
|
|
hgp.resize(hlev * DimGP);
|
|
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"Alloc: %p %6s[%3d].hgp %6d double",&hgp[0],Id,code,hlev*DimGP);
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
|
|
void Control::SetPGrid(void)
|
|
{
|
|
if (twod && hgp.size())
|
|
{
|
|
pgp.resize(DimGP);
|
|
pgp = hgp;
|
|
hgp.resize(0);
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"Moved: %p %6s[%3d].hgp to pgp",&pgp[0],Id,code);
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
else if (pgp.size() != plev * DimGP)
|
|
{
|
|
pgp.resize(plev * DimGP);
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"Alloc: %p %6s[%3d].pgp %6d double",&pgp[0],Id,code,plev*DimGP);
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::SetPSpec(void)
|
|
{
|
|
int OldSize;
|
|
int NewSize;
|
|
|
|
OldSize = psp.size();
|
|
NewSize = plev * DimSP;
|
|
|
|
if (NewSize == OldSize) return;
|
|
|
|
psp.resize(NewSize);
|
|
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
if (OldSize == 0)
|
|
sprintf(tb,"Alloc: %p %6s[%3d].psp %6ld double",&psp[0],Id,code,psp.size());
|
|
else
|
|
sprintf(tb,"Realloc: %p %6s[%3d].psp %6ld double",&psp[0],Id,code,psp.size());
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
|
|
#define CODES 512
|
|
#define MAXCODES (CODES+5)
|
|
|
|
#define GEOSCODE 129
|
|
#define TCODE 130
|
|
#define UCODE 131
|
|
#define VCODE 132
|
|
#define SHCODE 133
|
|
#define PSCODE 134
|
|
#define WCODE 135
|
|
#define WZCODE 137
|
|
#define VORCODE 138
|
|
#define STRCODE 148
|
|
#define VELCODE 149
|
|
#define SLPCODE 151
|
|
#define LNPSCODE 152
|
|
#define DIVCODE 155
|
|
#define ZCODE 156
|
|
#define RHCODE 157
|
|
|
|
int SpecialCodes[4] = {DIVCODE,VORCODE,STRCODE,VELCODE};
|
|
|
|
Control All[MAXCODES];
|
|
|
|
Control *Geopotential = &All[129];
|
|
Control *Temperature = &All[130];
|
|
Control *u_wind = &All[131];
|
|
Control *v_wind = &All[132];
|
|
Control *Humidity = &All[133];
|
|
Control *Ps = &All[134];
|
|
Control *Omega = &All[135];
|
|
Control *w_wind = &All[137];
|
|
Control *Vorticity = &All[138];
|
|
Control *Ts = &All[139];
|
|
Control *StreamF = &All[148];
|
|
Control *VeloPot = &All[149];
|
|
Control *SLP = &All[151];
|
|
Control *LnPs = &All[152];
|
|
Control *Divergence = &All[155];
|
|
Control *GeopotHeight = &All[156];
|
|
Control *Rhumidity = &All[157];
|
|
Control *speed = &All[259];
|
|
Control *precip = &All[260];
|
|
Control *net_top = &All[261];
|
|
Control *net_bot = &All[262];
|
|
Control *net_heat = &All[263];
|
|
Control *net_water = &All[264];
|
|
Control *sw_atm = &All[268];
|
|
Control *lw_atm = &All[269];
|
|
Control *net_atm = &All[270];
|
|
Control *surf_runoff = &All[271];
|
|
Control *dpsdx = &All[273];
|
|
Control *dpsdy = &All[274];
|
|
Control *fresh_water = &All[275];
|
|
|
|
Control *HalfPress = &All[277];
|
|
Control *FullPress = &All[278];
|
|
Control *ThetaH = &All[279];
|
|
Control *ThetaF = &All[280];
|
|
|
|
int *vert_index;
|
|
valarray<double>Orography;
|
|
double *poli;
|
|
double *pol2;
|
|
double *pliu;
|
|
double *pliv;
|
|
|
|
char polin[80]; /* filenames for polynomial files */
|
|
char pol2n[80];
|
|
char pliun[80];
|
|
char plivn[80];
|
|
|
|
FILE *polif;
|
|
FILE *pol2f;
|
|
FILE *pliuf;
|
|
FILE *plivf;
|
|
|
|
int OutLevs; /* number of requested output levels */
|
|
int nrpl; /* number of requested pressure levels */
|
|
int nrml; /* number of requested model levels */
|
|
int nrqh;
|
|
|
|
#define ATTR_MAX 20
|
|
int nattr; /* number of global attributes (NetCDF) */
|
|
char AttrNam[ATTR_MAX][80];
|
|
char AttrVal[ATTR_MAX][80];
|
|
|
|
int nvct = 0;
|
|
double vct[MAX_NVCT];
|
|
|
|
int DaysPerYear = 360;
|
|
double DataStep = 0.0;
|
|
int DeltaDy;
|
|
int DeltaHr;
|
|
int DeltaMn;
|
|
|
|
vector<int>HeadSt(8,0); // First header vector
|
|
vector<int>HeadIn(8,0); // Input header vector
|
|
vector<int>HeadOu(8,0); // Output header vector
|
|
|
|
#define HYB_SPEC 0
|
|
#define HYB_FOUR 1
|
|
#define HYB_ZONM 2
|
|
#define HYB_GRID 3
|
|
#define PRE_GRID 4
|
|
#define PRE_FOUR 5
|
|
#define PRE_ZONM 6
|
|
#define PRE_SPEC 7
|
|
|
|
int OutRep = HYB_SPEC; // Output Representation
|
|
|
|
int hours[MAX_HOURS+1];
|
|
double level[MAX_LEVELS+1];
|
|
int LevelFound[MAX_LEVELS+1];
|
|
|
|
double hPa[MAX_LEVELS];
|
|
int mol[MAX_LEVELS];
|
|
int mom[MAX_LEVELS]; /* Mask for selected levels */
|
|
int LevelUnits[MAX_LEVELS];
|
|
int SigmaF[MAX_LEVELS];
|
|
|
|
double *Record_double;
|
|
float *Record_float; // Buffer for FORTRAN records
|
|
int *Record_int; // All share the same space
|
|
unsigned short *Record_short;
|
|
char *Record_char;
|
|
|
|
double *CosPhi; /* Cosine of Phi (Latitude) */
|
|
double *RevCosPhi; /* 1.0 / CosPhi */
|
|
double *DerivationFactor;
|
|
|
|
double *wfc; /* FFT work array */
|
|
double *wgp; /* FFT work array */
|
|
int ifax[10]; /* FFT factorization */
|
|
|
|
FILE *fpi;
|
|
FILE *gp;
|
|
|
|
class RegLon // class for equidistant longituinal array
|
|
{
|
|
char Name[16]; // Array name
|
|
double DeltaLam; // Distance of Longitudes
|
|
|
|
public:
|
|
int Lons; // Number of latitudes
|
|
double *Lam; // Coordinate in degrees
|
|
|
|
RegLon(int, const char *); // Constructor
|
|
~RegLon(void); // Destructor
|
|
void PrintArray(void); // Print table
|
|
};
|
|
|
|
RegLon::RegLon(int n, const char *name)
|
|
{
|
|
int jlon;
|
|
|
|
Lons = n;
|
|
DeltaLam = 360.0 / Lons;
|
|
Lam = new double[Lons+1];
|
|
for (jlon=0 ; jlon < Lons ; ++jlon)
|
|
{
|
|
Lam[jlon] = jlon * DeltaLam;
|
|
}
|
|
Lam[Lons] = 360.0;
|
|
strncpy(Name,name,15);
|
|
}
|
|
|
|
RegLon::~RegLon(void)
|
|
{
|
|
delete Lam;
|
|
}
|
|
|
|
void RegLon::PrintArray(void)
|
|
{
|
|
int jlon;
|
|
|
|
printf("*******************************\n");
|
|
printf("* %16.16s Longitude *\n",Name);
|
|
printf("*******************************\n");
|
|
for (jlon=0 ; jlon < Lons ; ++jlon)
|
|
printf("* %16d %10.4f *\n",jlon,Lam[jlon]);
|
|
printf("*******************************\n");
|
|
}
|
|
|
|
class RegLat // class for equidistant latitudinal array
|
|
{
|
|
char Name[16]; // Array name
|
|
double DeltaPhi; // Distance of latitudes
|
|
double FirstPhi; // First latitude
|
|
|
|
public:
|
|
int Lats; // Number of latitudes
|
|
double *Phi; // Coordinate in degrees
|
|
double *gmu; // Sine of phi
|
|
double *gwt; // Gaussian weight
|
|
|
|
RegLat(int, const char *); // Constructor
|
|
~RegLat(void); // Destructor
|
|
void PrintArray(void); // Print table
|
|
};
|
|
|
|
RegLat::RegLat(int n, const char *name)
|
|
{
|
|
int jlat;
|
|
|
|
Lats = n;
|
|
DeltaPhi = 180.0 / (Lats - 1);
|
|
Phi = new double[Lats];
|
|
gmu = new double[Lats];
|
|
gwt = new double[Lats];
|
|
|
|
if (Lats & 1) /* odd -> start with DeltaPhi */
|
|
{
|
|
DeltaPhi = 180.0 / (Lats + 1);
|
|
FirstPhi = 90.0 - DeltaPhi;
|
|
}
|
|
else /* even -> start with 0.5 DeltaPhi */
|
|
{
|
|
DeltaPhi = 180.0 / Lats;
|
|
FirstPhi = 90.0 - 0.5 * DeltaPhi;
|
|
}
|
|
|
|
for (jlat=0 ; jlat < Lats ; ++jlat)
|
|
{
|
|
Phi[jlat] = FirstPhi - jlat * DeltaPhi;
|
|
gmu[jlat] = sin(Phi[jlat] * M_PI / 180.0);
|
|
gwt[jlat] = 0.0;
|
|
}
|
|
strncpy(Name,name,15);
|
|
}
|
|
|
|
RegLat::~RegLat(void)
|
|
{
|
|
delete Phi;
|
|
delete gmu;
|
|
delete gwt;
|
|
}
|
|
|
|
void RegLat::PrintArray(void)
|
|
{
|
|
int jlat;
|
|
|
|
printf("*******************************\n");
|
|
printf("* %16.16s Latitude *\n",Name);
|
|
printf("*******************************\n");
|
|
for (jlat=0 ; jlat < Lats ; ++jlat)
|
|
printf("* %16d %10.4f *\n",jlat,Phi[jlat]);
|
|
printf("*******************************\n");
|
|
}
|
|
|
|
class GauLat : public RegLat
|
|
{
|
|
public:
|
|
GauLat(int, const char *); // Constructor
|
|
~GauLat(void); // Destructor
|
|
private:
|
|
void IniGau(void);
|
|
double nlp(int, double);
|
|
double dlp(int, double);
|
|
};
|
|
|
|
GauLat::GauLat(int n, const char *name) : RegLat(n, name)
|
|
{
|
|
int jlat;
|
|
IniGau();
|
|
for (jlat = 0 ; jlat < Lats ; ++jlat)
|
|
Phi[jlat] = 180.0 * asin(gmu[jlat]) / M_PI;
|
|
}
|
|
|
|
GauLat::~GauLat(void)
|
|
{
|
|
}
|
|
|
|
/* ============================== */
|
|
/* Calculate Legendre Polynomials */
|
|
/* ============================== */
|
|
|
|
double GauLat::nlp(int k, double p) // After Nodorp (1988)
|
|
{
|
|
int j;
|
|
double z0,z1,z2,z3,z4;
|
|
|
|
z0 = acos(p);
|
|
z1 = 1.0;
|
|
z2 = 0.0;
|
|
z3 = 0.0;
|
|
|
|
for (j=k ; j >= 0 ; j-=2)
|
|
{
|
|
z3 = z1 * cos(j * z0);
|
|
z2 += z3;
|
|
z4 = (k-j+1) * (k+j)/2;
|
|
z1 *= z4 / (z4+j-1);
|
|
}
|
|
if (k % 2 == 0) z2 -= 0.5 * z3;
|
|
|
|
z0 = sqrt(2.0);
|
|
for (j=1; j <= k ; ++j)
|
|
z0 *= sqrt(1.0 - 0.25/(j*j));
|
|
return (z0*z2);
|
|
}
|
|
|
|
/* ============================================= */
|
|
/* Calculate Derivatives of Legendre Polynomials */
|
|
/* ============================================= */
|
|
|
|
double GauLat::dlp(int k, double p) // After Nodorp (1988)
|
|
{
|
|
double z0,z3,z4;
|
|
|
|
if (!k) return 0.0;
|
|
|
|
z0 = 1.0 / (p*p - 1.0);
|
|
z3 = sqrt((k+k+1.0)/(k+k-1.0));
|
|
z4 = p * nlp(k,p) - z3 * nlp(k-1,p);
|
|
|
|
return(k*z0*z4);
|
|
}
|
|
|
|
void GauLat::IniGau(void)
|
|
{
|
|
int jlat,Iter;
|
|
double z0, z1, z2, z3;
|
|
double eps=1.e-15;
|
|
|
|
z0 = M_PI / (2 * Lats + 1);
|
|
z1 = 1.0 / (8 * Lats * Lats);
|
|
for (jlat=0 ; jlat < Lats/2 ; ++jlat) // North to Equator
|
|
{
|
|
z2 = (2 * jlat + 1.5) * z0;
|
|
z2 = cos(z2 + z1 / tan(z2));
|
|
Iter = 0;
|
|
do
|
|
{
|
|
z3 = nlp(Lats,z2) / dlp(Lats,z2);
|
|
z2 -= z3;
|
|
} while ((z3 < -eps || z3 > eps) && ++Iter < 1000);
|
|
gmu[jlat] = z2;
|
|
gmu[Lats-1-jlat] = -z2;
|
|
}
|
|
z1 = 2.0 / (Lats * Lats);
|
|
for (jlat=0 ; jlat < Lats/2 ; ++jlat) // North to Equator
|
|
{
|
|
z0 = nlp(Lats-1,gmu[jlat]) / sqrt(Lats - 0.5);
|
|
z0 = z0 * z0;
|
|
gwt[jlat] = z1 * (1.0 - gmu[jlat] * gmu[jlat]) / z0;
|
|
gwt[Lats-1-jlat] = gwt[jlat];
|
|
}
|
|
}
|
|
|
|
RegLon *Outlon;
|
|
RegLat *Outlat;
|
|
GauLat *Gaulat;
|
|
|
|
#ifdef NETCDF_OUTPUT
|
|
#define TITLE "PUMA/PLASIM DATA"
|
|
#define HISTORY "Created by PumaBurner 7.4"
|
|
|
|
|
|
void NetOpen(char *NetFileName)
|
|
{
|
|
int yy,mm,dd;
|
|
int jlev;
|
|
int jvar;
|
|
int londim;
|
|
|
|
double *Outlev;
|
|
|
|
const char *title=TITLE;
|
|
const char *conv="CF-1.0";
|
|
const char *hist=HISTORY;
|
|
|
|
char cale[80];
|
|
char t_unit[80];
|
|
int BaseDate[4];
|
|
|
|
Outlev = new double[OutLevs];
|
|
|
|
if (VerType == 's') // sigma
|
|
{
|
|
for (jlev = 0 ; jlev < OutLevs ; ++jlev)
|
|
Outlev[jlev] = 0.5 *
|
|
(vct[SigLevs+mol[jlev]]+vct[SigLevs+mol[jlev]+1]);
|
|
}
|
|
else // pressure levels [hPa]
|
|
{
|
|
for (jlev = 0 ; jlev < OutLevs ; ++jlev) Outlev[jlev] = hPa[jlev];
|
|
}
|
|
|
|
BaseDate[0] = yy = HeadSt[2] / 10000;
|
|
BaseDate[1] = mm = HeadSt[2] / 100 % 100;
|
|
BaseDate[2] = dd = HeadSt[2] % 100;
|
|
BaseDate[3] = 0;
|
|
if (Mean)
|
|
{
|
|
sprintf(t_unit,"months since %04d-%02d-%02d 00:00:00",yy,mm,dd);
|
|
sprintf(cale,"360_day");
|
|
}
|
|
else
|
|
{
|
|
sprintf(t_unit,"days since %04d-%02d-%02d 00:00:00",yy,mm,dd);
|
|
if (DaysPerYear != 365) sprintf(cale,"%d_day",DaysPerYear);
|
|
else sprintf(cale,"proleptic_gregorian");
|
|
}
|
|
|
|
/* Create NetCDF file */
|
|
|
|
NetFile = new NcFile(NetFileName,NcFile::Replace,NULL,0,NcFile::Offset64Bits);
|
|
if (!NetFile->is_valid()) Abort("Could not open NetCDF file");
|
|
|
|
/* Define dimensions */
|
|
|
|
if (OutRep == HYB_ZONM || OutRep == PRE_ZONM) londim = 1;
|
|
else londim = Lons + Cyclical;
|
|
|
|
LonDim = NetFile->add_dim("lon" , londim);
|
|
LatDim = NetFile->add_dim("lat" , Lats );
|
|
LevDim = NetFile->add_dim("lev" , OutLevs );
|
|
TimDim = NetFile->add_dim("time" );
|
|
|
|
LonVar = NetFile->add_var("lon" , ncDouble, LonDim);
|
|
LatVar = NetFile->add_var("lat" , ncDouble, LatDim);
|
|
LevVar = NetFile->add_var("lev" , ncDouble, LevDim);
|
|
TimVar = NetFile->add_var("time", ncDouble, TimDim);
|
|
|
|
LonVar->add_att("axis" ,"X" );
|
|
LonVar->add_att("long_name" ,"longitude" );
|
|
LonVar->add_att("standard_name","longitude" );
|
|
LonVar->add_att("units" ,"degrees_east" );
|
|
|
|
LatVar->add_att("axis" ,"Y" );
|
|
LatVar->add_att("long_name" ,"latitude" );
|
|
LatVar->add_att("standard_name","latitude" );
|
|
LatVar->add_att("units" ,"degrees_north");
|
|
|
|
if (VerType == 's') // sigma level
|
|
{
|
|
LevVar->add_att("axis" ,"Z" );
|
|
LevVar->add_att("long_name" ,"sigma at layer midpoints" );
|
|
LevVar->add_att("standard_name","atmosphere_sigma_coordinate");
|
|
LevVar->add_att("positive" ,"down" );
|
|
LevVar->add_att("units" ,"level" );
|
|
}
|
|
else // pressure level
|
|
{
|
|
LevVar->add_att("axis" ,"Z" );
|
|
LevVar->add_att("long_name" ,"pressure" );
|
|
LevVar->add_att("standard_name","pressure" );
|
|
LevVar->add_att("units" ,"hPa" );
|
|
}
|
|
|
|
TimVar->add_att("calendar" ,cale );
|
|
TimVar->add_att("units" ,t_unit );
|
|
TimVar->add_att("base_date", 4 ,BaseDate );
|
|
|
|
|
|
NetFile->add_att("title" , title);
|
|
NetFile->add_att("history" , hist );
|
|
NetFile->add_att("Conventions", conv );
|
|
|
|
for (jvar = 0 ; jvar < nattr ; ++jvar)
|
|
{
|
|
NetFile->add_att(AttrNam[jvar],AttrVal[jvar]);
|
|
}
|
|
|
|
LonVar->put(Outlon->Lam,londim );
|
|
LatVar->put(Outlat->Phi,Lats );
|
|
LevVar->put(Outlev ,OutLevs);
|
|
|
|
}
|
|
|
|
|
|
void NetVarDefine(void)
|
|
{
|
|
int jvar;
|
|
|
|
for (jvar = 0 ; jvar < CODES ; ++jvar)
|
|
if (All[jvar].selected)
|
|
{
|
|
if (All[jvar].twod)
|
|
{
|
|
if (RealSize == 8)
|
|
All[jvar].NetVar = NetFile->add_var(All[jvar].Id,ncDouble,TimDim,LatDim,LonDim);
|
|
else
|
|
All[jvar].NetVar = NetFile->add_var(All[jvar].Id,ncFloat ,TimDim,LatDim,LonDim);
|
|
}
|
|
else
|
|
{
|
|
if (RealSize == 8)
|
|
All[jvar].NetVar = NetFile->add_var(All[jvar].Id,ncDouble,TimDim,LevDim,LatDim,LonDim);
|
|
else
|
|
All[jvar].NetVar = NetFile->add_var(All[jvar].Id,ncFloat ,TimDim,LevDim,LatDim,LonDim);
|
|
}
|
|
All[jvar].NetVar->add_att("long_name" ,All[jvar].Na);
|
|
All[jvar].NetVar->add_att("standard_name",All[jvar].Na);
|
|
All[jvar].NetVar->add_att("units" ,All[jvar].Un);
|
|
All[jvar].NetVar->add_att("code" , jvar );
|
|
if (GaussianOutput)
|
|
All[jvar].NetVar->add_att("grid_type" ,"gaussian" );
|
|
}
|
|
}
|
|
|
|
|
|
void NetBuffer(double *d, float *f)
|
|
{
|
|
for (int jdim = 0 ; jdim < DimGP ; ++jdim) *f++ = *d++;
|
|
}
|
|
|
|
|
|
void NetScale(float *f, int dim, double s)
|
|
{
|
|
int j;
|
|
|
|
for (j = 0 ; j < dim ; ++j) *f++ *= s;
|
|
}
|
|
|
|
|
|
void NetScale(double *f, int dim, double s)
|
|
{
|
|
int j;
|
|
|
|
for (j = 0 ; j < dim ; ++j) *f++ *= s;
|
|
}
|
|
|
|
|
|
void NetWrite32(int code, double *Var)
|
|
{
|
|
int jlev;
|
|
|
|
if (All[code].twod)
|
|
{
|
|
NetBuffer(Var,Record_float);
|
|
if (code==SLPCODE || code==PSCODE)
|
|
NetScale(Record_float,Lats*(Lons+Cyclical),0.01);
|
|
All[code].NetVar->set_cur(OutputCount);
|
|
All[code].NetVar->put(Record_float,1,Lats,Lons+Cyclical);
|
|
}
|
|
else
|
|
{
|
|
for (jlev = 0 ; jlev < OutLevs ; ++jlev, Var += DimGP)
|
|
{
|
|
NetBuffer(Var,Record_float);
|
|
if (code==WCODE)
|
|
NetScale(Record_float,Lats*(Lons+Cyclical),0.01);
|
|
All[code].NetVar->set_cur(OutputCount,jlev);
|
|
All[code].NetVar->put(Record_float,1,1,Lats,Lons+Cyclical);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void NetWrite64(int code, double *Var)
|
|
{
|
|
int jlev;
|
|
|
|
if (All[code].twod)
|
|
{
|
|
memcpy(Record_double,Var,DimGP * sizeof(double));
|
|
if (code==SLPCODE || code==PSCODE)
|
|
NetScale(Record_double,Lats*(Lons+Cyclical),0.01);
|
|
All[code].NetVar->set_cur(OutputCount);
|
|
All[code].NetVar->put(Record_double,1,Lats,Lons+Cyclical);
|
|
}
|
|
else
|
|
{
|
|
for (jlev = 0 ; jlev < OutLevs ; ++jlev, Var += DimGP)
|
|
{
|
|
memcpy(Record_double,Var,DimGP * sizeof(double));
|
|
if (code==WCODE)
|
|
NetScale(Record_double,Lats*(Lons+Cyclical),0.01);
|
|
All[code].NetVar->set_cur(OutputCount,jlev);
|
|
All[code].NetVar->put(Record_double,1,1,Lats,Lons+Cyclical);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void NetWriteSection(int code, double *Var)
|
|
{
|
|
int jvar,jlev;
|
|
double *vp;
|
|
|
|
for (jlev = 0 ; jlev < OutLevs ; ++jlev)
|
|
{
|
|
vp = Var + jlev * DimFC;
|
|
if (code==SLPCODE || code==PSCODE || code==WCODE)
|
|
{
|
|
for (jvar = 0 ; jvar < Lats ; ++jvar)
|
|
{
|
|
Record_float[jvar] = vp[jvar] * 0.01;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (jvar = 0 ; jvar < Lats ; ++jvar)
|
|
{
|
|
Record_float[jvar] = vp[jvar];
|
|
}
|
|
}
|
|
All[code].NetVar->set_cur(OutputCount,jlev);
|
|
All[code].NetVar->put(Record_float,1,1,Lats,1);
|
|
}
|
|
}
|
|
|
|
|
|
void NetClose(void)
|
|
{
|
|
int jt;
|
|
double * Outtim;
|
|
Outtim = new double[OutputCount];
|
|
for (jt = 0 ; jt < OutputCount ; jt++) Outtim[jt] = jt;
|
|
if (Mean == 0 && (DataStep < 0.99999 || DataStep > 1.00001))
|
|
for (jt = 0 ; jt < OutputCount ; jt++) Outtim[jt] *= DataStep;
|
|
|
|
TimVar->put(Outtim,OutputCount);
|
|
delete Outtim;
|
|
delete NetFile;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
class ServiceGrid
|
|
{
|
|
int HeadControl;
|
|
FILE *File;
|
|
float *FloatBuffer;
|
|
public:
|
|
int h4; // head[4] = 1st dimension
|
|
int h5; // head[5] = 2nd dimension
|
|
int Dim; // total dimension
|
|
int FieldControl;
|
|
ServiceGrid(FILE *, int, int);
|
|
~ServiceGrid(void);
|
|
void Write(int *, double *);
|
|
void WriteCode(int code, double *field, int twod);
|
|
void Write_hspec(void);
|
|
void Write_pspec(void);
|
|
void Write_hfour(void);
|
|
void Write_pfour(void);
|
|
void Write_hgrid(void);
|
|
void Write_pgrid(void);
|
|
void Clear_hspec(void);
|
|
void Clear_pspec(void);
|
|
void Clear_hfour(void);
|
|
void Clear_pfour(void);
|
|
void Clear_hgrid(void);
|
|
void Clear_pgrid(void);
|
|
};
|
|
|
|
ServiceGrid::ServiceGrid(FILE *fd, int Dim1, int Dim2)
|
|
{
|
|
h4 = Dim1;
|
|
h5 = Dim2;
|
|
Dim = Dim1 * Dim2;
|
|
HeadControl = 8 * RealSize;
|
|
FieldControl = Dim * RealSize;
|
|
File = fd;
|
|
FloatBuffer = new float[Dim];
|
|
}
|
|
|
|
ServiceGrid::~ServiceGrid(void)
|
|
{
|
|
delete FloatBuffer;
|
|
}
|
|
|
|
void ServiceGrid::Write(int *Head, double *Array)
|
|
{
|
|
int i,j;
|
|
LONG lhc,lfc;
|
|
|
|
if (Debug) // Check for NaN (Not A Number)
|
|
{
|
|
for (j=0 ; j<Dim ; ++j)
|
|
{
|
|
if (isnan(Array[j]))
|
|
{
|
|
printf("\n Head: ");
|
|
for (i=0 ; i<6 ; i++) printf(" %d",Head[i]);
|
|
printf("\n Array[%d] = NaN\n",j);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
if (RealSize == 4)
|
|
{
|
|
for (j=0 ; j<Dim ; ++j) FloatBuffer[j] = Array[j];
|
|
|
|
if (LongFCW)
|
|
{
|
|
lhc = HeadControl;
|
|
lfc = FieldControl;
|
|
fwrite(&lhc ,sizeof(lhc) ,1 ,File);
|
|
fwrite( Head ,sizeof(int) ,8 ,File);
|
|
fwrite(&lhc ,sizeof(lhc) ,1 ,File);
|
|
fwrite(&lfc ,sizeof(lfc) ,1 ,File);
|
|
fwrite( FloatBuffer,sizeof(float),Dim,File);
|
|
fwrite(&lfc ,sizeof(lfc) ,1 ,File);
|
|
}
|
|
else
|
|
{
|
|
fwrite(&HeadControl ,sizeof(int) ,1 ,File);
|
|
fwrite( Head ,sizeof(int) ,8 ,File);
|
|
fwrite(&HeadControl ,sizeof(int) ,1 ,File);
|
|
fwrite(&FieldControl,sizeof(int) ,1 ,File);
|
|
fwrite( FloatBuffer ,sizeof(float),Dim,File);
|
|
fwrite(&FieldControl,sizeof(int) ,1 ,File);
|
|
}
|
|
}
|
|
else // RealSize == 8
|
|
{
|
|
if (LongFCW)
|
|
{
|
|
lhc = HeadControl;
|
|
lfc = FieldControl;
|
|
fwrite(&lhc ,sizeof(lhc) ,1 ,File);
|
|
fwrite( Head ,sizeof(int) ,8 ,File);
|
|
fwrite(&lhc ,sizeof(lhc) ,1 ,File);
|
|
fwrite(&lfc ,sizeof(lfc) ,1 ,File);
|
|
fwrite( Array ,sizeof(double),Dim,File);
|
|
fwrite(&lfc ,sizeof(lfc) ,1 ,File);
|
|
}
|
|
else
|
|
{
|
|
long LongHead[8];
|
|
for (int i=0 ; i<8 ; ++i) LongHead[i] = Head[i];
|
|
fwrite(&HeadControl ,sizeof(int) ,1 ,File);
|
|
fwrite( LongHead ,RealSize ,8 ,File);
|
|
fwrite(&HeadControl ,sizeof(int) ,1 ,File);
|
|
fwrite(&FieldControl,sizeof(int) ,1 ,File);
|
|
fwrite( Array ,RealSize ,Dim,File);
|
|
fwrite(&FieldControl,sizeof(int) ,1 ,File);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ServiceGrid::WriteCode(int code, double *field, int twod)
|
|
{
|
|
int jlev;
|
|
|
|
if (field == NULL)
|
|
{
|
|
fprintf(stderr, "*** Error in ServiceGrid::WriteCode\n");
|
|
fprintf(stderr, " Code %d not defined for this OutRep\n",code);
|
|
fprintf(stderr, " Skipping this record\n\n");
|
|
return;
|
|
}
|
|
|
|
HeadOu[0] = code;
|
|
HeadOu[4] = h4;
|
|
HeadOu[5] = h5;
|
|
if (twod)
|
|
{
|
|
HeadOu[1] = 0;
|
|
HeadOu[7] = 0;
|
|
Write(&HeadOu[0],field);
|
|
}
|
|
else for (jlev = 0; jlev < OutLevs; jlev++)
|
|
{
|
|
HeadOu[1] = LevelUnits[jlev];
|
|
HeadOu[7] = SigmaF[jlev];
|
|
Write(&HeadOu[0], field + jlev * Dim);
|
|
}
|
|
}
|
|
|
|
|
|
void ServiceGrid::Write_hspec(void)
|
|
{
|
|
for (int code = 0; code < CODES; code++)
|
|
if (All[code].selected)
|
|
WriteCode(code,&All[code].hsp[0],All[code].twod);
|
|
}
|
|
|
|
|
|
void ServiceGrid::Write_pspec(void)
|
|
{
|
|
for (int code = 0; code < CODES; code++)
|
|
if (All[code].selected)
|
|
WriteCode(code,&All[code].psp[0],All[code].twod);
|
|
}
|
|
|
|
|
|
void ServiceGrid::Clear_hspec(void)
|
|
{
|
|
for (int code = CODES-1 ; code >= 0 ; --code)
|
|
if (All[code].hsp.size() && !All[code].twod)
|
|
{
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"Clear: %p %6s[%3d].hsp",
|
|
&All[code].hsp[0],All[code].Id,code);
|
|
LeftText(tb);
|
|
}
|
|
All[code].hsp.resize(0);
|
|
}
|
|
}
|
|
|
|
void ServiceGrid::Clear_hfour(void)
|
|
{
|
|
for (int code = CODES-1 ; code >= 0 ; --code)
|
|
if (All[code].hfc.size() && !All[code].twod)
|
|
{
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"CLear: %p %6s[%3d].hfc",&All[code].hfc[0],All[code].Id,code);
|
|
LeftText(tb);
|
|
}
|
|
All[code].hfc.resize(0);
|
|
}
|
|
}
|
|
|
|
void ServiceGrid::Clear_hgrid(void)
|
|
{
|
|
for (int code = CODES-1 ; code >= 0 ; --code)
|
|
if (All[code].hgp.size())
|
|
{
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"CLear: %p %6s[%3d].hgp",&All[code].hgp[0],All[code].Id,code);
|
|
LeftText(tb);
|
|
}
|
|
All[code].hgp.resize(0);
|
|
}
|
|
}
|
|
|
|
void ServiceGrid::Clear_pgrid(void)
|
|
{
|
|
for (int code = CODES-1 ; code >= 0 ; --code)
|
|
if (All[code].pgp.size())
|
|
{
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"CLear: %p %6s[%3d].pgp",&All[code].pgp[0],All[code].Id,code);
|
|
LeftText(tb);
|
|
}
|
|
All[code].pgp.resize(0);
|
|
}
|
|
}
|
|
|
|
void ServiceGrid::Clear_pfour(void)
|
|
{
|
|
for (int code = CODES-1 ; code >= 0 ; --code)
|
|
if (All[code].pfc.size())
|
|
{
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"CLear: %p %6s[%3d].pfc",&All[code].pfc[0],All[code].Id,code);
|
|
LeftText(tb);
|
|
}
|
|
All[code].pfc.resize(0);
|
|
}
|
|
}
|
|
|
|
void ServiceGrid::Clear_pspec(void)
|
|
{
|
|
for (int code = CODES-1 ; code >= 0 ; --code)
|
|
if (All[code].psp.size())
|
|
{
|
|
if (Debug)
|
|
{
|
|
char tb[COLS];
|
|
sprintf(tb,"CLear: %p %6s[%3d].psp",&All[code].psp[0],All[code].Id,code);
|
|
LeftText(tb);
|
|
}
|
|
All[code].psp.resize(0);
|
|
}
|
|
}
|
|
|
|
void ServiceGrid::Write_hfour(void)
|
|
{
|
|
int code;
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].selected)
|
|
WriteCode(code,&All[code].hfc[0],All[code].twod);
|
|
}
|
|
|
|
|
|
void ServiceGrid::Write_pfour(void)
|
|
{
|
|
int code;
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].selected)
|
|
WriteCode(code,&All[code].pfc[0],All[code].twod);
|
|
}
|
|
|
|
|
|
void ServiceGrid::Write_hgrid(void)
|
|
{
|
|
int code;
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].selected)
|
|
{
|
|
if (!&All[code].hgp[0])
|
|
{
|
|
fprintf(stderr, "*** Error in ServiceGrid::Write_hgrid\n");
|
|
fprintf(stderr, " Code %d is not available on sigma level\n",code);
|
|
fprintf(stderr, " Skipping this record\n\n");
|
|
return;
|
|
}
|
|
#ifdef NETCDF_OUTPUT
|
|
if (NetCDF)
|
|
{
|
|
if (RealSize == 8) NetWrite64(code,&All[code].hgp[0]);
|
|
else NetWrite32(code,&All[code].hgp[0]);
|
|
}
|
|
else
|
|
#endif
|
|
WriteCode(code,&All[code].hgp[0],All[code].twod);
|
|
}
|
|
OutputCount++;
|
|
}
|
|
|
|
|
|
void ServiceGrid::Write_pgrid(void)
|
|
{
|
|
int code;
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].selected)
|
|
{
|
|
#ifdef NETCDF_OUTPUT
|
|
if (NetCDF)
|
|
{
|
|
if (RealSize == 8) NetWrite64(code,&All[code].pgp[0]);
|
|
else NetWrite32(code,&All[code].pgp[0]);
|
|
}
|
|
else
|
|
#endif
|
|
WriteCode(code,&All[code].pgp[0],All[code].twod);
|
|
}
|
|
OutputCount++;
|
|
}
|
|
|
|
|
|
class ServiceSect : public ServiceGrid
|
|
{
|
|
double *Buffer;
|
|
public:
|
|
ServiceSect(FILE *, int, int);
|
|
~ServiceSect(void);
|
|
void WriteCode(int code, double *field, int twod);
|
|
void Write_hfour(void);
|
|
void Write_pfour(void);
|
|
};
|
|
|
|
ServiceSect::ServiceSect(FILE *fd, int Dim1, int Dim2) :
|
|
ServiceGrid(fd,Dim1,Dim2)
|
|
{
|
|
Buffer = new double[Dim1*Dim2];
|
|
}
|
|
|
|
ServiceSect::~ServiceSect(void)
|
|
{
|
|
delete Buffer;
|
|
}
|
|
|
|
void ServiceSect::WriteCode(int code, double *field, int twod)
|
|
{
|
|
int jlev;
|
|
|
|
HeadOu[0] = code;
|
|
HeadOu[1] = -1;
|
|
HeadOu[7] = 0;
|
|
if (twod)
|
|
{
|
|
h5 = 1;
|
|
memcpy(Buffer,field,Lats * sizeof(double));
|
|
}
|
|
else
|
|
{
|
|
h5 = OutLevs;
|
|
for (jlev=0 ; jlev < OutLevs ; ++jlev)
|
|
memcpy(Buffer+jlev*Lats,field+jlev*DimFC,Lats*sizeof(double));
|
|
}
|
|
HeadOu[4] = h4;
|
|
HeadOu[5] = h5;
|
|
Dim = h4 * h5;
|
|
FieldControl = Dim * sizeof(float);
|
|
Write(&HeadOu[0],Buffer);
|
|
}
|
|
|
|
void ServiceSect::Write_hfour(void)
|
|
{
|
|
int code;
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].selected)
|
|
{
|
|
#ifdef NETCDF_OUTPUT
|
|
if (NetCDF)
|
|
NetWriteSection(code,&All[code].hfc[0]);
|
|
else
|
|
#endif
|
|
WriteCode(code,&All[code].hfc[0],All[code].twod);
|
|
}
|
|
OutputCount++;
|
|
}
|
|
|
|
|
|
void ServiceSect::Write_pfour(void)
|
|
{
|
|
int code;
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].selected)
|
|
{
|
|
#ifdef NETCDF_OUTPUT
|
|
if (NetCDF)
|
|
NetWriteSection(code,&All[code].pfc[0]);
|
|
else
|
|
#endif
|
|
WriteCode(code,&All[code].pfc[0],All[code].twod);
|
|
}
|
|
OutputCount++;
|
|
}
|
|
|
|
|
|
ServiceGrid *HybSpec;
|
|
ServiceGrid *HybFour;
|
|
ServiceGrid *HybGrid;
|
|
ServiceSect *HybSect;
|
|
|
|
void HeadToDate(vector<int>Head, struct tm *Date)
|
|
{
|
|
Date->tm_year = Head[2] / 10000;
|
|
Date->tm_mon = Head[2] / 100 % 100;
|
|
Date->tm_mday = Head[2] % 100;
|
|
Date->tm_hour = Head[3] / 100;
|
|
Date->tm_min = Head[3] % 100;
|
|
}
|
|
|
|
|
|
/* ============================================== */
|
|
/* DoubleZero - Set array of type double to zero */
|
|
/* ============================================== */
|
|
|
|
inline void DoubleZero(double *field, int words)
|
|
{
|
|
memset((char *)field,0,words * sizeof(double));
|
|
}
|
|
|
|
/* ====================== */
|
|
/* Fast Fourier Transform */
|
|
/* ====================== */
|
|
|
|
/* constants in math.h :
|
|
#define M_E 2.71828182845904523536
|
|
#define M_LOG2E 1.44269504088896340736
|
|
#define M_LOG10E 0.434294481903251827651
|
|
#define M_LN2 0.693147180559945309417
|
|
#define M_LN10 2.30258509299404568402
|
|
#define M_PI 3.14159265358979323846
|
|
#define M_PI_2 1.57079632679489661923
|
|
#define M_PI_4 0.785398163397448309616
|
|
#define M_1_PI 0.318309886183790671538
|
|
#define M_2_PI 0.636619772367581343076
|
|
#define M_1_SQRTPI 0.564189583547756286948
|
|
#define M_2_SQRTPI 1.12837916709551257390
|
|
#define M_SQRT2 1.41421356237309504880
|
|
#define M_SQRT_2 0.707106781186547524401
|
|
*/
|
|
|
|
#define QUA 0.25
|
|
#define QT5 0.559016994374947
|
|
|
|
#define S36 0.587785252292473
|
|
#define S60 0.866025403784437
|
|
#define S72 0.951056516295154
|
|
|
|
#define SQ2 0.707106781186547524401
|
|
|
|
#define D60 (S60+S60)
|
|
|
|
#define FORK for(k=la;k<=kstop;k+=la){
|
|
#define LOOP for(l=0;l<la;++l){i=ibase;j=jbase;for(ijk=0;ijk<lot;++ijk){
|
|
#define ENDL i+=inc3;j+=inc4;}ibase++;jbase++;}
|
|
|
|
void fft_set(int n)
|
|
{
|
|
int j,k,nfax;
|
|
nfax = 0;
|
|
for (k = 0; k < 9; ++k) ifax[k] = 0;
|
|
ifax[9] = n;
|
|
if (n % 8 == 0) {ifax[++nfax] = 8; n /= 8;}
|
|
while (n % 6 == 0) {ifax[++nfax] = 6; n /= 6;}
|
|
while (n % 5 == 0) {ifax[++nfax] = 5; n /= 5;}
|
|
while (n % 4 == 0) {ifax[++nfax] = 4; n /= 4;}
|
|
while (n % 3 == 0) {ifax[++nfax] = 3; n /= 3;}
|
|
if (n % 2 == 0) {ifax[++nfax] = 2; n /= 2;}
|
|
ifax[0] = nfax;
|
|
for (k = 0; k < nfax/2; ++k)
|
|
{
|
|
j = ifax[k+1];
|
|
ifax[k+1] = ifax[nfax-k];
|
|
ifax[nfax-k] = j;
|
|
}
|
|
}
|
|
|
|
|
|
int rpassc(double *a, double *b, double *c, double *d,
|
|
int inc3, int inc4,
|
|
int lot , int n , int ifac, int la )
|
|
{
|
|
/*
|
|
rpassc' - performs one pass through data as part;
|
|
of multiple real fft (fourier synthesis) routine;
|
|
|
|
a is first real input vector
|
|
b is equivalent to a + la
|
|
c is first real output vector
|
|
d is equivalent to c + ifac * la
|
|
inc3 is the increment between input vectors a;
|
|
inc4 is the increment between output vectors c;
|
|
lot is the number of vectors;
|
|
n is the length of the vectors;
|
|
ifac is the current factor of n;
|
|
la is the product of previous factors;
|
|
ierr is an error indicator:;
|
|
0 - pass completed without error;
|
|
2 - ifac not catered for;
|
|
3 - ifac only catered for if la=n/ifac;
|
|
*/
|
|
|
|
int i0,i1,i2,i3,i4,i5,i6,i7;
|
|
int j0,j1,j2,j3,j4,j5,j6,j7;
|
|
int ia,ib,ic,id,ie,iF;
|
|
int ja,jb,jc,jd,je,jf;
|
|
int i,j,k,ijk,l,m;
|
|
int ibase,jbase;
|
|
int iink,jink;
|
|
int jump;
|
|
int kstop;
|
|
|
|
double c1,c2,c3,c4,c5;
|
|
double s1,s2,s3,s4,s5;
|
|
double kpidn;
|
|
double angle;
|
|
double qqrt5;
|
|
double ssin36;
|
|
double ssin72;
|
|
double pin;
|
|
|
|
double a10,a11,a20,a21;
|
|
double b10,b11,b20,b21;
|
|
|
|
m = n / ifac;
|
|
iink = la;
|
|
jink = la;
|
|
jump = (ifac-1) * jink;
|
|
kstop = (n-ifac) / (2*ifac);
|
|
pin = 2.0 * M_PI / n;
|
|
ibase = 0;
|
|
jbase = 0;
|
|
|
|
switch (ifac)
|
|
{
|
|
case 2:
|
|
{
|
|
double a0m1,b0p1;
|
|
|
|
i0 = j0 = 0;
|
|
i1 = i0 + (m+m-la);
|
|
j1 = j0 + jink;
|
|
if (la != m)
|
|
{
|
|
LOOP
|
|
c[j0+j] = a[i0+i] + a[i1+i];
|
|
c[j1+j] = a[i0+i] - a[i1+i];
|
|
ENDL
|
|
i0 += iink;
|
|
iink += iink;
|
|
i1 -= iink;
|
|
ibase = 0;
|
|
jbase += jump;
|
|
jump += jump + jink;
|
|
|
|
if (i0 != i1)
|
|
{
|
|
FORK
|
|
angle = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
ibase = 0;
|
|
LOOP
|
|
a0m1 = a[i0+i] - a[i1+i];
|
|
b0p1 = b[i0+i] + b[i1+i];
|
|
|
|
c[j0+j] = a[i0+i] + a[i1+i];
|
|
d[j0+j] = b[i0+i] - b[i1+i];
|
|
c[j1+j] = c1 * a0m1 - s1 * b0p1;
|
|
d[j1+j] = s1 * a0m1 + c1 * b0p1;
|
|
ENDL
|
|
i0 += iink;
|
|
i1 -= iink;
|
|
jbase += jump;
|
|
} /* End FORK */
|
|
if (i0 > i1) return 0;
|
|
} /* End (i0 != i1) */
|
|
ibase = 0;
|
|
LOOP
|
|
c[j0+j] = a[i0+i];
|
|
c[j1+j] = -b[i0+i];
|
|
ENDL
|
|
}
|
|
else /* (la != m) */ {
|
|
LOOP
|
|
c[j0+j] = 2.0 * (a[i0+i] + a[i1+i]);
|
|
c[j1+j] = 2.0 * (a[i0+i] - a[i1+i]);
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 3: {
|
|
double afa1,a1p2,a1m2,a0mm,a0mp;
|
|
double bfa1,b1p2,b1m2,b0mm,b0mp;
|
|
|
|
i0 = j0 = 0 ;
|
|
i1 = i0 + (m+m-la);
|
|
i2 = i1;
|
|
j1 = j0 + jink;
|
|
j2 = j1 + jink;
|
|
|
|
if (la != m) {
|
|
LOOP
|
|
afa1 = a[i0+i] - 0.5 * a[i1+i];
|
|
bfa1 = S60 * b[i1+i];
|
|
|
|
c[j0+j] = a[i0+i] + a[i1+i];
|
|
c[j1+j] = afa1 - bfa1;
|
|
c[j2+j] = afa1 + bfa1;
|
|
ENDL
|
|
i0 += iink;
|
|
iink += iink;
|
|
i1 += iink;
|
|
i2 -= iink;
|
|
jbase += jump;
|
|
jump += jump + jink;
|
|
|
|
if (i0 != i2) {
|
|
FORK
|
|
angle = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
angle += angle;
|
|
c2 = cos(angle);
|
|
s2 = sin(angle);
|
|
ibase = 0;
|
|
LOOP
|
|
a1p2 = a[i0+i] - 0.5 * (a[i1+i] + a[i2+i]);
|
|
b1m2 = b[i0+i] - 0.5 * (b[i1+i] - b[i2+i]);
|
|
a1m2 = S60 * (a[i1+i] - a[i2+i]);
|
|
b1p2 = S60 * (b[i1+i] + b[i2+i]);
|
|
|
|
a0mm = a1p2 - b1p2;
|
|
a0mp = a1p2 + b1p2;
|
|
b0mm = b1m2 - a1m2;
|
|
b0mp = b1m2 + a1m2;
|
|
|
|
c[j0+j] = a[i0+i] + a[i1+i] + a[i2+i];
|
|
d[j0+j] = b[i0+i] + b[i1+i] - b[i2+i];
|
|
c[j1+j] = c1 * a0mm - s1 * b0mp;
|
|
d[j1+j] = s1 * a0mm + c1 * b0mp;
|
|
c[j2+j] = c2 * a0mp - s2 * b0mm;
|
|
d[j2+j] = s2 * a0mp + c2 * b0mm;
|
|
ENDL
|
|
i0 += iink;
|
|
i1 += iink;
|
|
i2 -= iink;
|
|
jbase += jump;
|
|
} /* End FORK */
|
|
if (i0 > i2) return 0;
|
|
} /* End (i0 != i2) */
|
|
ibase=0;
|
|
LOOP
|
|
a0mp = 0.5 * a[i0+i];
|
|
b0mp = S60 * b[i0+i];
|
|
|
|
c[j0+j] = a[i0+i] + a[i1+i];
|
|
c[j1+j] = a0mp - a[i1+i] - b0mp;
|
|
c[j2+j] = a[i1+i] - a0mp - b0mp;
|
|
ENDL
|
|
}
|
|
else /* (la != m) */ {
|
|
LOOP
|
|
a0mp = 2.0 * a[i0+i] - a[i1+i];
|
|
b0mp = D60 * b[i1+i];
|
|
|
|
c[j0+j] = 2.0 * (a[i0+i] + a[i1+i]);
|
|
c[j1+j] = a0mp - b0mp;
|
|
c[j2+j] = a0mp + b0mp;
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 4: {
|
|
double a0m1,a0p2,a1p3,a0m2,a1m3,a0p2ma1p3,a0m2pb1p3,a0m2mb1p3;
|
|
double b0p1,b0p2,b1p3,b0m2,b1m3,b0p2pa1m3,b0p2ma1m3,b0m2mb1m3;
|
|
|
|
i0 = j0 = 0;
|
|
i1 = i3 = i0 + (m+m-la);
|
|
i2 = i1 + (m+m);
|
|
j1 = j0 + jink;
|
|
j2 = j1 + jink;
|
|
j3 = j2 + jink;
|
|
|
|
if (la != m) {
|
|
LOOP
|
|
a0p2 = a[i0+i] + a[i2+i];
|
|
a0m2 = a[i0+i] - a[i2+i];
|
|
|
|
c[j0+j] = a0p2 + a[i1+i];
|
|
c[j1+j] = a0m2 - b[i1+i];
|
|
c[j2+j] = a0p2 - a[i1+i];
|
|
c[j3+j] = a0m2 + b[i1+i];
|
|
ENDL
|
|
i0 += iink;
|
|
iink += iink;
|
|
i1 += iink;
|
|
i2 -= iink;
|
|
i3 -= iink;
|
|
jbase += jump;
|
|
jump += jump + jink;
|
|
|
|
if (i1 != i2) {
|
|
FORK
|
|
angle = kpidn = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
angle += kpidn;
|
|
c2 = cos(angle);
|
|
s2 = sin(angle);
|
|
angle += kpidn;
|
|
c3 = cos(angle);
|
|
s3 = sin(angle);
|
|
ibase=0;
|
|
LOOP
|
|
a0p2 = a[i0+i] + a[i2+i];
|
|
a0m2 = a[i0+i] - a[i2+i];
|
|
a1p3 = a[i1+i] + a[i3+i];
|
|
a1m3 = a[i1+i] - a[i3+i];
|
|
b0p2 = b[i0+i] + b[i2+i];
|
|
b0m2 = b[i0+i] - b[i2+i];
|
|
b1p3 = b[i1+i] + b[i3+i];
|
|
b1m3 = b[i1+i] - b[i3+i];
|
|
|
|
a0p2ma1p3 = a0p2 - a1p3;
|
|
a0m2pb1p3 = a0m2 + b1p3;
|
|
a0m2mb1p3 = a0m2 - b1p3;
|
|
b0p2pa1m3 = b0p2 + a1m3;
|
|
b0p2ma1m3 = b0p2 - a1m3;
|
|
b0m2mb1m3 = b0m2 - b1m3;
|
|
|
|
c[j0+j] = a0p2 + a1p3;
|
|
d[j0+j] = b0m2 + b1m3;
|
|
c[j2+j] = c2 * a0p2ma1p3 - s2 * b0m2mb1m3;
|
|
d[j2+j] = s2 * a0p2ma1p3 + c2 * b0m2mb1m3;
|
|
c[j1+j] = c1 * a0m2mb1p3 - s1 * b0p2pa1m3;
|
|
d[j1+j] = s1 * a0m2mb1p3 + c1 * b0p2pa1m3;
|
|
c[j3+j] = c3 * a0m2pb1p3 - s3 * b0p2ma1m3;
|
|
d[j3+j] = s3 * a0m2pb1p3 + c3 * b0p2ma1m3;
|
|
ENDL
|
|
i0 += iink;
|
|
i1 += iink;
|
|
i2 -= iink;
|
|
i3 -= iink;
|
|
jbase += jump;
|
|
} /* End FORK */
|
|
if (i1 > i2) return 0;
|
|
} /* End (i1 != i2) */
|
|
ibase=0;
|
|
LOOP
|
|
a0m1 = a[i0+i] - a[i1+i];
|
|
b0p1 = b[i0+i] + b[i1+i];
|
|
|
|
c[j0+j] = a[i0+i] + a[i1+i];
|
|
c[j2+j] = b[i1+i] - b[i0+i];
|
|
|
|
c[j1+j] = SQ2 * (a0m1 - b0p1);
|
|
c[j3+j] = -SQ2 * (a0m1 + b0p1);
|
|
ENDL
|
|
}
|
|
else /* (la != m) */ {
|
|
LOOP
|
|
a0p2 = a[i0+i] + a[i2+i];
|
|
a0m2 = a[i0+i] - a[i2+i];
|
|
|
|
c[j0+j] = 2.0 * (a0p2 + a[i1+i]);
|
|
c[j1+j] = 2.0 * (a0m2 - b[i1+i]);
|
|
c[j2+j] = 2.0 * (a0p2 - a[i1+i]);
|
|
c[j3+j] = 2.0 * (a0m2 + b[i1+i]);
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 5: {
|
|
double a1p2,a1m2,a0mm,a0mp,b136,b172,b236,b272;
|
|
|
|
i0 = j0 = 0;
|
|
i1 = i4 = i0 + (m+m-la);
|
|
i2 = i3 = i1 + (m+m);
|
|
j1 = j0 + jink;
|
|
j2 = j1 + jink;
|
|
j3 = j2 + jink;
|
|
j4 = j3 + jink;
|
|
|
|
if (la != m) {
|
|
LOOP
|
|
a1p2 = QUA * (a[i1+i] + a[i2+i]);
|
|
a1m2 = QT5 * (a[i1+i] - a[i2+i]);
|
|
|
|
a0mp = a[i0+i] - a1p2 + a1m2;
|
|
a0mm = a[i0+i] - a1p2 - a1m2;
|
|
|
|
b136 = b[i1+i] * S36;
|
|
b172 = b[i1+i] * S72;
|
|
b236 = b[i2+i] * S36;
|
|
b272 = b[i2+i] * S72;
|
|
|
|
c[j0+j] = a[i0+i] + a[i1+i] + a[i2+i];
|
|
c[j1+j] = a0mp - b172 - b236;
|
|
c[j2+j] = a0mm - b136 + b272;
|
|
c[j3+j] = a0mm + b136 - b272;
|
|
c[j4+j] = a0mp + b172 + b236;
|
|
ENDL
|
|
i0 += iink;
|
|
iink += iink;
|
|
i1 += iink;
|
|
i2 += iink;
|
|
i3 -= iink;
|
|
i4 -= iink;
|
|
jbase += jump;
|
|
jump += jump + jink;
|
|
|
|
if (i1 != i3) {
|
|
FORK
|
|
angle = kpidn = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
angle += kpidn;
|
|
c2 = cos(angle);
|
|
s2 = sin(angle);
|
|
angle += kpidn;
|
|
c3 = cos(angle);
|
|
s3 = sin(angle);
|
|
angle += kpidn;
|
|
c4 = cos(angle);
|
|
s4 = sin(angle);
|
|
ibase=0;
|
|
LOOP
|
|
a10=(a[i0+i]-0.25*((a[i1+i]+a[i4+i])+(a[i2+i]+a[i3+i])))
|
|
+QT5*((a[i1+i]+a[i4+i])-(a[i2+i]+a[i3+i]));
|
|
a20=(a[i0+i]-0.25*((a[i1+i]+a[i4+i])+(a[i2+i]+a[i3+i])))
|
|
-QT5*((a[i1+i]+a[i4+i])-(a[i2+i]+a[i3+i]));
|
|
b10=(b[i0+i]-0.25*((b[i1+i]-b[i4+i])+(b[i2+i]-b[i3+i])))
|
|
+QT5*((b[i1+i]-b[i4+i])-(b[i2+i]-b[i3+i]));
|
|
b20=(b[i0+i]-0.25*((b[i1+i]-b[i4+i])+(b[i2+i]-b[i3+i])))
|
|
-QT5*((b[i1+i]-b[i4+i])-(b[i2+i]-b[i3+i]));
|
|
|
|
a11=S72*(b[i1+i]+b[i4+i])+S36*(b[i2+i]+b[i3+i]);
|
|
a21=S36*(b[i1+i]+b[i4+i])-S72*(b[i2+i]+b[i3+i]);
|
|
b11=S72*(a[i1+i]-a[i4+i])+S36*(a[i2+i]-a[i3+i]);
|
|
b21=S36*(a[i1+i]-a[i4+i])-S72*(a[i2+i]-a[i3+i]);
|
|
|
|
c[j0+j]=a[i0+i]+((a[i1+i]+a[i4+i])+(a[i2+i]+a[i3+i]));
|
|
d[j0+j]=b[i0+i]+((b[i1+i]-b[i4+i])+(b[i2+i]-b[i3+i]));
|
|
c[j1+j]=c1*(a10-a11)-s1*(b10+b11);
|
|
d[j1+j]=s1*(a10-a11)+c1*(b10+b11);
|
|
c[j4+j]=c4*(a10+a11)-s4*(b10-b11);
|
|
d[j4+j]=s4*(a10+a11)+c4*(b10-b11);
|
|
c[j2+j]=c2*(a20-a21)-s2*(b20+b21);
|
|
d[j2+j]=s2*(a20-a21)+c2*(b20+b21);
|
|
c[j3+j]=c3*(a20+a21)-s3*(b20-b21);
|
|
d[j3+j]=s3*(a20+a21)+c3*(b20-b21);
|
|
ENDL
|
|
i0 += iink;
|
|
i1 += iink;
|
|
i2 += iink;
|
|
i3 -= iink;
|
|
i4 -= iink;
|
|
jbase += jump;
|
|
} /* End FORK */
|
|
if (i1 > i3) return 0;
|
|
} /* End (i1 != i3) */
|
|
ibase=0;
|
|
LOOP
|
|
c[j0+j] = a[i0+i] + a[i1+i] + a[i2+i];
|
|
c[j1+j] = (QT5 * (a[i0+i]-a[i1+i])
|
|
+ (0.25 * (a[i0+i]+a[i1+i])-a[i2+i]))
|
|
- (S36 * b[i0+i]+S72*b[i1+i]);
|
|
c[j4+j] =-(QT5 * (a[i0+i]-a[i1+i])
|
|
+ (0.25 * (a[i0+i]+a[i1+i])-a[i2+i]))
|
|
- (S36 * b[i0+i]+S72*b[i1+i]);
|
|
c[j2+j] = (QT5 * (a[i0+i]-a[i1+i])
|
|
- (0.25 * (a[i0+i]+a[i1+i])-a[i2+i]))
|
|
- (S72 * b[i0+i]-S36*b[i1+i]);
|
|
c[j3+j] =-(QT5 * (a[i0+i]-a[i1+i])
|
|
- (0.25 * (a[i0+i]+a[i1+i])-a[i2+i]))
|
|
- (S72 * b[i0+i]-S36*b[i1+i]);
|
|
ENDL
|
|
} else {
|
|
qqrt5 = 2.0 * QT5 ;
|
|
ssin36 = 2.0 * S36;
|
|
ssin72 = 2.0 * S72;
|
|
LOOP
|
|
c[j0+j]= 2.0 *(a[i0+i]+a[i1+i]+a[i2+i]);
|
|
c[j1+j]=(2.0 *(a[i0+i]-0.25*(a[i1+i]+a[i2+i]))
|
|
+qqrt5*(a[i1+i]-a[i2+i]))-(ssin72*b[i1+i]+ssin36*b[i2+i]);
|
|
c[j2+j]=(2.0 *(a[i0+i]-0.25*(a[i1+i]+a[i2+i]))
|
|
-qqrt5*(a[i1+i]-a[i2+i]))-(ssin36*b[i1+i]-ssin72*b[i2+i]);
|
|
c[j3+j]=(2.0 *(a[i0+i]-0.25*(a[i1+i]+a[i2+i]))
|
|
-qqrt5*(a[i1+i]-a[i2+i]))+(ssin36*b[i1+i]-ssin72*b[i2+i]);
|
|
c[j4+j]=(2.0 *(a[i0+i]-0.25*(a[i1+i]+a[i2+i]))
|
|
+qqrt5*(a[i1+i]-a[i2+i]))+(ssin72*b[i1+i]+ssin36*b[i2+i]);
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 6: {
|
|
ia = 0;
|
|
ib = ia+(2*m-la);
|
|
ic = ib+2*m;
|
|
id = ic+2*m;
|
|
ie = ic;
|
|
iF = ib;
|
|
ja = 0;
|
|
jb = ja+jink;
|
|
jc = jb+jink;
|
|
jd = jc+jink;
|
|
je = jd+jink;
|
|
jf = je+jink;
|
|
|
|
if (la != m) /* go to 690 */ {
|
|
LOOP
|
|
c[ja+j] = (a[ia+i]+a[id+i]) + (a[ib+i]+a[ic+i]) ;
|
|
c[jd+j] = (a[ia+i]-a[id+i]) - (a[ib+i]-a[ic+i]) ;
|
|
c[jb+j] = ((a[ia+i]-a[id+i]) +0.5*(a[ib+i]-a[ic+i]))
|
|
- S60*(b[ib+i]+b[ic+i]);
|
|
c[jf+j] = ((a[ia+i]-a[id+i]) +0.5*(a[ib+i]-a[ic+i]))
|
|
+ S60*(b[ib+i]+b[ic+i]);
|
|
c[jc+j] = ((a[ia+i]+a[id+i]) -0.5*(a[ib+i]+a[ic+i]))
|
|
- S60*(b[ib+i]-b[ic+i]);
|
|
c[je+j] = ((a[ia+i]+a[id+i]) -0.5*(a[ib+i]+a[ic+i]))
|
|
+ S60*(b[ib+i]-b[ic+i]);
|
|
ENDL
|
|
ia += iink;
|
|
iink += iink;
|
|
ib += iink;
|
|
ic += iink;
|
|
id -= iink;
|
|
ie -= iink;
|
|
iF -= iink;
|
|
jbase += jump;
|
|
jump += jump+jink;
|
|
|
|
if (ic != id) /* go to 660 */ {
|
|
FORK
|
|
angle = kpidn = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
angle += kpidn;
|
|
c2 = cos(angle);
|
|
s2 = sin(angle);
|
|
angle += kpidn;
|
|
c3 = cos(angle);
|
|
s3 = sin(angle);
|
|
angle += kpidn;
|
|
c4 = cos(angle);
|
|
s4 = sin(angle);
|
|
angle += kpidn;
|
|
c5 = cos(angle);
|
|
s5 = sin(angle);
|
|
ibase=0;
|
|
LOOP
|
|
a11 = a[ie+i] + a[ib+i] + a[ic+i] + a[iF+i];
|
|
a20 = a[ia+i] + a[id+i] - 0.5 * a11;
|
|
a21 = S60*((a[ie+i]+a[ib+i])-(a[ic+i]+a[iF+i]));
|
|
b11 = b[ib+i] - b[ie+i] + b[ic+i] - b[iF+i];
|
|
b20 = b[ia+i] - b[id+i] - 0.5 * b11;
|
|
b21 = S60*((b[ib+i]-b[ie+i])-(b[ic+i]-b[iF+i]));
|
|
|
|
c[ja+j] = a[ia+i] + a[id+i] + a11;
|
|
d[ja+j] = b[ia+i] - b[id+i] + b11;
|
|
c[jc+j] = c2*(a20-b21)-s2*(b20+a21);
|
|
d[jc+j] = s2*(a20-b21)+c2*(b20+a21);
|
|
c[je+j] = c4*(a20+b21)-s4*(b20-a21);
|
|
d[je+j] = s4*(a20+b21)+c4*(b20-a21);
|
|
|
|
a11 = (a[ie+i]-a[ib+i]) + (a[ic+i]-a[iF+i]);
|
|
b11 = (b[ie+i]+b[ib+i]) - (b[ic+i]+b[iF+i]);
|
|
a20 = (a[ia+i]-a[id+i]) - 0.5 * a11;
|
|
a21 = S60 * ((a[ie+i]-a[ib+i]) - (a[ic+i]-a[iF+i]));
|
|
b20 = (b[ia+i]+b[id+i]) + 0.5 * b11;
|
|
b21 = S60 * ((b[ie+i]+b[ib+i]) + (b[ic+i]+b[iF+i]));
|
|
|
|
c[jd+j] = c3*(a[ia+i] - a[id+i] + a11)
|
|
- s3*(b[ia+i] + b[id+i] - b11);
|
|
d[jd+j] = s3*(a[ia+i] - a[id+i] + a11)
|
|
+ c3*(b[ia+i] + b[id+i] - b11);
|
|
c[jb+j] = c1*(a20-b21)-s1*(b20-a21);
|
|
d[jb+j] = s1*(a20-b21)+c1*(b20-a21);
|
|
c[jf+j] = c5*(a20+b21)-s5*(b20+a21);
|
|
d[jf+j] = s5*(a20+b21)+c5*(b20+a21);
|
|
ENDL
|
|
ia += iink;
|
|
ib += iink;
|
|
ic += iink;
|
|
id -= iink;
|
|
ie -= iink;
|
|
iF -= iink;
|
|
jbase += jump;
|
|
}
|
|
if (ic > id) return 0;
|
|
}
|
|
ibase=0;
|
|
LOOP
|
|
c[ja+j]= a[ib+i] + (a[ia+i] + a[ic+i]);
|
|
c[jd+j]= b[ib+i] - (b[ia+i] + b[ic+i]);
|
|
c[jb+j]= (S60*(a[ia+i]-a[ic+i]))-(0.5*(b[ia+i]+b[ic+i])+b[ib+i]);
|
|
c[jf+j]=-(S60*(a[ia+i]-a[ic+i]))-(0.5*(b[ia+i]+b[ic+i])+b[ib+i]);
|
|
c[jc+j]= S60*(b[ic+i]-b[ia+i]) +(0.5*(a[ia+i]+a[ic+i])-a[ib+i]);
|
|
c[je+j]= S60*(b[ic+i]-b[ia+i]) -(0.5*(a[ia+i]+a[ic+i])-a[ib+i]);
|
|
ENDL
|
|
} else {
|
|
LOOP
|
|
c[ja+j]=(2.0*(a[ia+i]+a[id+i]))+(2.0*(a[ib+i]+a[ic+i]));
|
|
c[jd+j]=(2.0*(a[ia+i]-a[id+i]))-(2.0*(a[ib+i]-a[ic+i]));
|
|
c[jb+j]=(2.0*(a[ia+i]-a[id+i])+(a[ib+i]-a[ic+i]))
|
|
-(D60*(b[ib+i]+b[ic+i]));
|
|
c[jf+j]=(2.0*(a[ia+i]-a[id+i])+(a[ib+i]-a[ic+i]))
|
|
+(D60*(b[ib+i]+b[ic+i]));
|
|
c[jc+j]=(2.0*(a[ia+i]+a[id+i])-(a[ib+i]+a[ic+i]))
|
|
-(D60*(b[ib+i]-b[ic+i]));
|
|
c[je+j]=(2.0*(a[ia+i]+a[id+i])-(a[ib+i]+a[ic+i]))
|
|
+(D60*(b[ib+i]-b[ic+i]));
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 8: {
|
|
double a0p7,a1p5,a2p6,p073,p074,p152;
|
|
double a0m7,a1m5,a2m6,m073,m074,m152;
|
|
|
|
if (la != m) return 3;
|
|
i0 = 0;
|
|
i1 = i0 + iink;
|
|
i2 = i1 + iink;
|
|
i3 = i2 + iink;
|
|
i4 = i3 + iink;
|
|
i5 = i4 + iink;
|
|
i6 = i5 + iink;
|
|
i7 = i6 + iink;
|
|
j0 = 0;
|
|
j1 = j0 + jink;
|
|
j2 = j1 + jink;
|
|
j3 = j2 + jink;
|
|
j4 = j3 + jink;
|
|
j5 = j4 + jink;
|
|
j6 = j5 + jink;
|
|
j7 = j6 + jink;
|
|
|
|
LOOP
|
|
a0p7 = a[i0+i] + a[i7+i];
|
|
a0m7 = a[i0+i] - a[i7+i];
|
|
a1p5 = a[i1+i] + a[i5+i];
|
|
a1m5 = a[i1+i] - a[i5+i];
|
|
a2p6 = a[i2+i] + a[i6+i];
|
|
a2m6 = a[i2+i] - a[i6+i];
|
|
|
|
p073 = a0p7 + a[i3+i];
|
|
m073 = a0p7 - a[i3+i];
|
|
|
|
p074 = 2.0 * (a0m7 + a[i4+i]);
|
|
m074 = 2.0 * (a0m7 - a[i4+i]);
|
|
|
|
p152 = M_SQRT2 * (a1m5 + a2p6);
|
|
m152 = M_SQRT2 * (a1m5 - a2p6);
|
|
|
|
c[j0+j] = 2.0 * (p073 + a1p5);
|
|
c[j4+j] = 2.0 * (p073 - a1p5);
|
|
c[j2+j] = 2.0 * (m073 - a2m6);
|
|
c[j6+j] = 2.0 * (m073 + a2m6);
|
|
|
|
c[j1+j] = m074 + m152;
|
|
c[j5+j] = m074 - m152;
|
|
c[j3+j] = p074 - p152;
|
|
c[j7+j] = p074 + p152;
|
|
ENDL
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int qpassc(double *a, double *b, double *c, double *d,
|
|
int inc3, int inc4,
|
|
int lot , int n , int ifac, int la )
|
|
{
|
|
/*
|
|
qpassc - performs one pass through data as part;
|
|
of multiple real fft (fourier analysis) routine;
|
|
|
|
a is first real input vector;
|
|
b is equivalent to a + ifac * la
|
|
c is first real output vector;
|
|
d is equivalent to c + la
|
|
inc3 is the increment between input vectors a;
|
|
inc4 is the increment between output vectors c;
|
|
lot is the number of vectors;
|
|
n is the length of the vectors;
|
|
ifac is the current factor of n;
|
|
la is the product of previous factors;
|
|
qpassc returns an error indicator:;
|
|
0 - pass completed without error;
|
|
2 - ifac not catered for;
|
|
3 - ifac only catered for if la=n/ifac;
|
|
*/
|
|
|
|
int i0,i1,i2,i3,i4,i5,i6,i7;
|
|
int j0,j1,j2,j3,j4,j5,j6,j7;
|
|
int ia,ib,ic;
|
|
int ja,jb,jc;
|
|
int i,j,k;
|
|
int ibase,jbase;
|
|
int iink,jink;
|
|
int ijk;
|
|
int jump;
|
|
int kstop;
|
|
int l;
|
|
int m;
|
|
|
|
double a0,a1,a2,a3;
|
|
double b0,b1,b2,b3;
|
|
double c1,c2,c3,c4,c5;
|
|
double s1,s2,s3,s4,s5;
|
|
double w,x,y,z;
|
|
double angle,kpidn,pin;
|
|
|
|
m = n / ifac;
|
|
iink = la;
|
|
jink = la;
|
|
jump = (ifac-1) * iink;
|
|
kstop = (n-ifac) / (2*ifac);
|
|
pin = 2.0 * M_PI / n;
|
|
ibase = 0;
|
|
jbase = 0;
|
|
|
|
switch (ifac) {
|
|
case 2: {
|
|
i0 = j0 = 0;
|
|
i1 = i0 + iink;
|
|
j1 = j0 + (m+m-la);
|
|
if (la != m) {
|
|
LOOP
|
|
c[j0+j] = a[i0+i] + a[i1+i];
|
|
c[j1+j] = a[i0+i] - a[i1+i];
|
|
ENDL
|
|
j0 += jink;
|
|
jink += jink;
|
|
j1 -= jink;
|
|
ibase += jump;
|
|
jump += jump + iink;
|
|
|
|
if (j0 != j1) {
|
|
FORK
|
|
angle = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
jbase = 0;
|
|
LOOP
|
|
c[j0+j] = a[i0+i] + c1 * a[i1+i] + s1 * b[i1+i];
|
|
c[j1+j] = a[i0+i] - c1 * a[i1+i] - s1 * b[i1+i];
|
|
d[j0+j] = c1 * b[i1+i] - s1 * a[i1+i] + b[i0+i];
|
|
d[j1+j] = c1 * b[i1+i] - s1 * a[i1+i] - b[i0+i];
|
|
ENDL
|
|
j0 += jink;
|
|
j1 -= jink;
|
|
ibase += jump;
|
|
} /* End FORK */
|
|
if (j0 > j1) return 0;
|
|
} /* End (i0 != i1) */
|
|
jbase = 0;
|
|
LOOP
|
|
c[j0+j] = a[i0+i];
|
|
d[j1+j] = -a[i1+i];
|
|
ENDL
|
|
}
|
|
else /* (la != m) */ {
|
|
z = 1.0 / n;
|
|
LOOP
|
|
c[j0+j] = z * (a[i0+i] + a[i1+i]);
|
|
c[j1+j] = z * (a[i0+i] - a[i1+i]);
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 3: {
|
|
ia = 0;
|
|
ib = ia + iink;
|
|
ic = ib + iink;
|
|
|
|
ja = 0;
|
|
jb = ja + (m+m-la);
|
|
jc = jb;
|
|
|
|
if (la != m) /* else 390 */ {
|
|
LOOP
|
|
c[ja+j] = a[ia+i] + a[ib+i] + a[ic+i];
|
|
c[jb+j] = a[ia+i] - 0.5 * (a[ib+i] + a[ic+i]);
|
|
d[jb+j] = S60 * (a[ic+i] - a[ib+i]);
|
|
ENDL
|
|
ja += jink;
|
|
jink += jink;
|
|
jb += jink;
|
|
jc -= jink;
|
|
ibase += jump;
|
|
jump += jump + iink;
|
|
|
|
if (ja != jc) /* else 360 */ {
|
|
FORK
|
|
angle = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
angle += angle;
|
|
c2 = cos(angle);
|
|
s2 = sin(angle);
|
|
jbase = 0;
|
|
LOOP
|
|
a1 = c1 * a[ib+i] + s1 * b[ib+i] + c2 * a[ic+i] + s2 * b[ic+i];
|
|
b1 = c1 * b[ib+i] - s1 * a[ib+i] + c2 * b[ic+i] - s2 * a[ic+i];
|
|
a2 = a[ia+i] - 0.5 * a1;
|
|
b2 = b[ia+i] - 0.5 * b1;
|
|
a3 = S60 * (c1 * a[ib+i] + s1 * b[ib+i] - c2 * a[ic+i] - s2 * b[ic+i]);
|
|
b3 = S60 * (c1 * b[ib+i] - s1 * a[ib+i] - c2 * b[ic+i] + s2 * a[ic+i]);
|
|
|
|
c[ja+j] = a[ia+i] + a1;
|
|
d[ja+j] = b[ia+i] + b1;
|
|
c[jb+j] = a2 + b3;
|
|
d[jb+j] = b2 - a3;
|
|
c[jc+j] = a2 - b3;
|
|
d[jc+j] =-b2 - a3;
|
|
ENDL
|
|
ja += jink;
|
|
jb += jink;
|
|
jc -= jink;
|
|
ibase += jump;
|
|
} /* End FORK */
|
|
if (ja > jc) return 0;
|
|
} /* End (ia != ic) */
|
|
jbase = 0;
|
|
LOOP
|
|
/* soweit */
|
|
c[ja+j] = a[ia+i] + 0.5 * (a[ib+i] - a[ic+i]);
|
|
d[ja+j] =-S60 * (a[ib+i] + a[ic+i]);
|
|
c[jb+j] = a[ia+i] - a[ib+i] + a[ic+i];
|
|
ENDL
|
|
}
|
|
else /* (la != m) */ {
|
|
z = 1.0 / n;
|
|
y = S60 / n;
|
|
LOOP
|
|
c[ja+j] = z * (a[ia+i] + a[ib+i] + a[ic+i]);
|
|
c[jb+j] = z * (a[ia+i] - 0.5 * (a[ib+i] + a[ic+i]));
|
|
d[jb+j] = y * (a[ic+i] - a[ib+i]);
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 4: {
|
|
double a0p2,a1p3;
|
|
|
|
i0 = 0;
|
|
i1 = i0 + iink;
|
|
i2 = i1 + iink;
|
|
i3 = i2 + iink;
|
|
j0 = 0;
|
|
j1 = j0 + (m+m-la);
|
|
j2 = j1 + (m+m );
|
|
j3 = j1;
|
|
|
|
if (la != m) /*else go to 490 */ {
|
|
LOOP
|
|
a0p2 = a[i0+i] + a[i2+i];
|
|
a1p3 = a[i1+i] + a[i3+i];
|
|
|
|
c[j0+j] = a0p2 + a1p3;
|
|
c[j2+j] = a0p2 - a1p3;
|
|
|
|
c[j1+j] = a[i0+i] - a[i2+i];
|
|
d[j1+j] = a[i3+i] - a[i1+i];
|
|
ENDL
|
|
j0 += jink;
|
|
jink += jink;
|
|
j1 += jink;
|
|
j2 -= jink;
|
|
j3 -= jink;
|
|
ibase += jump;
|
|
jump += jump + iink;
|
|
|
|
if (j1 != j2) /* else go to 460; */ {
|
|
FORK
|
|
angle = kpidn = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
angle += kpidn;
|
|
c2 = cos(angle);
|
|
s2 = sin(angle);
|
|
angle += kpidn;
|
|
c3 = cos(angle);
|
|
s3 = sin(angle);
|
|
jbase=0;
|
|
LOOP
|
|
a0 = a[i0+i] + c2 * a[i2+i] + s2 * b[i2+i];
|
|
a2 = a[i0+i] - c2 * a[i2+i] - s2 * b[i2+i];
|
|
b0 = b[i0+i] + c2 * b[i2+i] - s2 * a[i2+i];
|
|
b2 = b[i0+i] - c2 * b[i2+i] + s2 * a[i2+i];
|
|
|
|
a1 = c1*a[i1+i] + s1*b[i1+i] + c3*a[i3+i] + s3*b[i3+i];
|
|
a3 = c1*a[i1+i] + s1*b[i1+i] - c3*a[i3+i] - s3*b[i3+i];
|
|
b1 = c1*b[i1+i] - s1*a[i1+i] + c3*b[i3+i] - s3*a[i3+i];
|
|
b3 = c1*b[i1+i] - s1*a[i1+i] - c3*b[i3+i] + s3*a[i3+i];
|
|
|
|
c[j0+j] = a0 + a1;
|
|
c[j2+j] = a0 - a1;
|
|
d[j0+j] = b0 + b1;
|
|
d[j2+j] = b1 - b0;
|
|
c[j1+j] = a2 + b3;
|
|
c[j3+j] = a2 - b3;
|
|
d[j1+j] = b2 - a3;
|
|
d[j3+j] =-b2 - a3;
|
|
ENDL
|
|
j0 += jink;
|
|
j1 += jink;
|
|
j2 -= jink;
|
|
j3 -= jink;
|
|
ibase += jump;
|
|
} /* End FORK */
|
|
if (j1 > j2) return 0;
|
|
} /* End (i1 != i2) */
|
|
jbase=0;
|
|
LOOP
|
|
c[j0+j] = a[i0+i] + SQ2 * (a[i1+i] - a[i3+i]);
|
|
c[j1+j] = a[i0+i] - SQ2 * (a[i1+i] - a[i3+i]);
|
|
d[j0+j] =-a[i2+i] - SQ2 * (a[i1+i] + a[i3+i]);
|
|
d[j1+j] = a[i2+i] - SQ2 * (a[i1+i] + a[i3+i]);
|
|
ENDL
|
|
}
|
|
else /* (la != m) */ {
|
|
z = 1.0 / n;
|
|
LOOP
|
|
a0p2 = a[i0+i] + a[i2+i];
|
|
a1p3 = a[i1+i] + a[i3+i];
|
|
|
|
c[j0+j] = z * (a0p2 + a1p3);
|
|
c[j2+j] = z * (a0p2 - a1p3);
|
|
c[j1+j] = z * (a[i0+i] - a[i2+i]);
|
|
d[j1+j] = z * (a[i3+i] - a[i1+i]);
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 5: {
|
|
double a1p4,a2p3,b1p4,b2p3,a025,b025,asps,bsps,a0pq,b0pq;
|
|
double a1m4,a2m3,b1m4,b2m3,aqrt,bqrt,asms,bsms,a0mq,b0mq;
|
|
|
|
i0 = 0;
|
|
i1 = i0 + iink;
|
|
i2 = i1 + iink;
|
|
i3 = i2 + iink;
|
|
i4 = i3 + iink;
|
|
j0 = 0;
|
|
j1 = j0 + (m+m-la);
|
|
j2 = j1 + (m+m);
|
|
j3 = j2;
|
|
j4 = j1;
|
|
|
|
if (la != m) /* else go to 590; */ {
|
|
LOOP
|
|
a1p4 = a[i1+i] + a[i4+i];
|
|
a1m4 = a[i1+i] - a[i4+i];
|
|
a2p3 = a[i2+i] + a[i3+i];
|
|
a2m3 = a[i2+i] - a[i3+i];
|
|
|
|
a025 = a[i0+i] - 0.25 * (a1p4 + a2p3);
|
|
aqrt = QT5 * (a1p4 - a2p3);
|
|
|
|
c[j0+j] = a[i0+i] + a1p4 + a2p3;
|
|
c[j1+j] = a025 + aqrt;
|
|
c[j2+j] = a025 - aqrt;
|
|
d[j1+j] = -S72 * a1m4 - S36 * a2m3;
|
|
d[j2+j] = -S36 * a1m4 + S72 * a2m3;
|
|
ENDL
|
|
j0 += jink;
|
|
jink += jink;
|
|
j1 += jink;
|
|
j2 += jink;
|
|
j3 -= jink;
|
|
j4 -= jink;
|
|
ibase += jump;
|
|
jump += jump + iink;
|
|
|
|
if (j1 != j3) {
|
|
FORK
|
|
angle = kpidn = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
angle += kpidn;
|
|
c2 = cos(angle);
|
|
s2 = sin(angle);
|
|
angle += kpidn;
|
|
c3 = cos(angle);
|
|
s3 = sin(angle);
|
|
angle += kpidn;
|
|
c4 = cos(angle);
|
|
s4 = sin(angle);
|
|
jbase=0;
|
|
LOOP
|
|
a1p4 = c1*a[i1+i] + s1*b[i1+i] + c4*a[i4+i] + s4*b[i4+i];
|
|
a1m4 = c1*a[i1+i] + s1*b[i1+i] - c4*a[i4+i] - s4*b[i4+i];
|
|
a2p3 = c2*a[i2+i] + s2*b[i2+i] + c3*a[i3+i] + s3*b[i3+i];
|
|
a2m3 = c2*a[i2+i] + s2*b[i2+i] - c3*a[i3+i] - s3*b[i3+i];
|
|
b1p4 = c1*b[i1+i] - s1*a[i1+i] + c4*b[i4+i] - s4*a[i4+i];
|
|
b1m4 = c1*b[i1+i] - s1*a[i1+i] - c4*b[i4+i] + s4*a[i4+i];
|
|
b2p3 = c2*b[i2+i] - s2*a[i2+i] + c3*b[i3+i] - s3*a[i3+i];
|
|
b2m3 = c2*b[i2+i] - s2*a[i2+i] - c3*b[i3+i] + s3*a[i3+i];
|
|
|
|
a025 = a[i0+i] - 0.25 * (a1p4 + a2p3);
|
|
aqrt = QT5 * (a1p4 - a2p3);
|
|
b025 = b[i0+i] - 0.25 * (b1p4 + b2p3);
|
|
bqrt = QT5 * (b1p4 - b2p3);
|
|
|
|
a0pq = a025 + aqrt;
|
|
a0mq = a025 - aqrt;
|
|
b0pq = b025 + bqrt;
|
|
b0mq = b025 - bqrt;
|
|
|
|
asps = S72 * a1m4 + S36 * a2m3;
|
|
asms = S36 * a1m4 - S72 * a2m3;
|
|
bsps = S72 * b1m4 + S36 * b2m3;
|
|
bsms = S36 * b1m4 - S72 * b2m3;
|
|
|
|
c[j0+j] = a[i0+i] + a1p4 + a2p3;
|
|
c[j1+j] = a0pq + bsps;
|
|
c[j2+j] = a0mq + bsms;
|
|
c[j3+j] = a0mq - bsms;
|
|
c[j4+j] = a0pq - bsps;
|
|
d[j0+j] = b[i0+i] + b1p4 + b2p3;
|
|
d[j1+j] = b0pq - asps;
|
|
d[j2+j] = b0mq - asms;
|
|
d[j3+j] =-b0mq - asms;
|
|
d[j4+j] =-b0pq - asps;
|
|
ENDL
|
|
j0 += jink;
|
|
j1 += jink;
|
|
j2 += jink;
|
|
j3 -= jink;
|
|
j4 -= jink;
|
|
ibase += jump;
|
|
} /* End FORK */
|
|
if (j1 > j3) return 0;
|
|
} /* End (jb != jd) */
|
|
jbase=0;
|
|
LOOP
|
|
a1p4 = a[i1+i] + a[i4+i];
|
|
a1m4 = a[i1+i] - a[i4+i];
|
|
a2p3 = a[i2+i] + a[i3+i];
|
|
a2m3 = a[i2+i] - a[i3+i];
|
|
|
|
a025 = a[i0+i] + 0.25 * (a1m4 - a2m3);
|
|
aqrt = QT5 * (a1m4 + a2m3);
|
|
|
|
c[j0+j] = a025 + aqrt;
|
|
c[j1+j] = a025 - aqrt;
|
|
c[j2+j] = a[i0+i] - a1m4 + a2m3;
|
|
d[j0+j] = -S36 * a1p4 - S72 * a2p3;
|
|
d[j1+j] = -S72 * a1p4 + S36 * a2p3;
|
|
|
|
ENDL
|
|
} else {
|
|
z = 1.0 / n;
|
|
y = QT5 / n;
|
|
x = S36 / n;
|
|
w = S72 / n;
|
|
|
|
LOOP
|
|
a1p4 = a[i1+i] + a[i4+i];
|
|
a1m4 = a[i1+i] - a[i4+i];
|
|
a2p3 = a[i2+i] + a[i3+i];
|
|
a2m3 = a[i2+i] - a[i3+i];
|
|
|
|
a025 = z * (a[i0+i] - 0.25 * (a1p4 + a2p3));
|
|
aqrt = y * (a1p4 - a2p3);
|
|
|
|
c[j0+j] = z * (a[i0+i] + a1p4 + a2p3);
|
|
c[j1+j] = a025 + aqrt;
|
|
c[j2+j] = a025 - aqrt;
|
|
d[j1+j] = -w * a1m4 - x * a2m3;
|
|
d[j2+j] = w * a2m3 - x * a1m4;
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 6: {
|
|
double ab1a,ab2a,ab3a,ab4a,ab5a;
|
|
double ab1b,ab2b,ab3b,ab4b,ab5b;
|
|
double a0p3,a1p4,a1p5,a2p4,a2p5;
|
|
double a0m3,a1m4,a1m5,a2m4,a2m5;
|
|
double b1p4,b2p5;
|
|
double b1m4,b2m5;
|
|
double ap05,bp05,ap60,bp60;
|
|
double am05,bm05,am60,bm60;
|
|
|
|
i0 = 0;
|
|
i1 = i0 + iink;
|
|
i2 = i1 + iink;
|
|
i3 = i2 + iink;
|
|
i4 = i3 + iink;
|
|
i5 = i4 + iink;
|
|
j0 = 0;
|
|
j1 = j0 + (m+m-la);
|
|
j2 = j1 + (m+m);
|
|
j3 = j2 + (m+m);
|
|
j4 = j2;
|
|
j5 = j1;
|
|
|
|
if (la != m) {
|
|
LOOP
|
|
a0p3 = a[i0+i] + a[i3+i];
|
|
a0m3 = a[i0+i] - a[i3+i];
|
|
a1p4 = a[i1+i] + a[i4+i];
|
|
a1m4 = a[i1+i] - a[i4+i];
|
|
a2p5 = a[i2+i] + a[i5+i];
|
|
a2m5 = a[i2+i] - a[i5+i];
|
|
|
|
c[j0+j] = a0p3 + a1p4 + a2p5;
|
|
c[j3+j] = a0m3 + a2m5 - a1m4;
|
|
|
|
c[j1+j] = a0m3 - 0.5 * (a2m5 - a1m4);
|
|
c[j2+j] = a0p3 - 0.5 * (a1p4 + a2p5);
|
|
|
|
d[j1+j] = S60 * (-a2m5 - a1m4);
|
|
d[j2+j] = S60 * ( a2p5 - a1p4);
|
|
ENDL
|
|
j0 += jink;
|
|
jink += jink;
|
|
j1 += jink;
|
|
j2 += jink;
|
|
j3 -= jink;
|
|
j4 -= jink;
|
|
j5 -= jink;
|
|
ibase += jump;
|
|
jump += jump+iink;
|
|
|
|
if (j2 != j3) {
|
|
FORK
|
|
angle = kpidn = k * pin;
|
|
c1 = cos(angle);
|
|
s1 = sin(angle);
|
|
angle += kpidn;
|
|
c2 = cos(angle);
|
|
s2 = sin(angle);
|
|
angle += kpidn;
|
|
c3 = cos(angle);
|
|
s3 = sin(angle);
|
|
angle += kpidn;
|
|
c4 = cos(angle);
|
|
s4 = sin(angle);
|
|
angle += kpidn;
|
|
c5 = cos(angle);
|
|
s5 = sin(angle);
|
|
jbase = 0;
|
|
LOOP
|
|
ab1a = c1 * a[i1+i] + s1 * b[i1+i];
|
|
ab1b = c1 * b[i1+i] - s1 * a[i1+i];
|
|
ab2a = c2 * a[i2+i] + s2 * b[i2+i];
|
|
ab2b = c2 * b[i2+i] - s2 * a[i2+i];
|
|
ab3a = c3 * a[i3+i] + s3 * b[i3+i];
|
|
ab3b = c3 * b[i3+i] - s3 * a[i3+i];
|
|
ab4a = c4 * a[i4+i] + s4 * b[i4+i];
|
|
ab4b = c4 * b[i4+i] - s4 * a[i4+i];
|
|
ab5a = c5 * a[i5+i] + s5 * b[i5+i];
|
|
ab5b = c5 * b[i5+i] - s5 * a[i5+i];
|
|
|
|
a1p4 = ab1a + ab4a;
|
|
a1m4 = ab1a - ab4a;
|
|
a2p5 = ab2a + ab5a;
|
|
a2m5 = ab2a - ab5a;
|
|
|
|
b1p4 = ab1b + ab4b;
|
|
b1m4 = ab1b - ab4b;
|
|
b2p5 = ab2b + ab5b;
|
|
b2m5 = ab2b - ab5b;
|
|
|
|
ap05 = a[i0+i] + ab3a - 0.5 * (a1p4 + a2p5);
|
|
bp05 = b[i0+i] + ab3b - 0.5 * (b1p4 + b2p5);
|
|
am05 = a[i0+i] - ab3a - 0.5 * (a2m5 - a1m4);
|
|
bm05 =-b[i0+i] + ab3b - 0.5 * (b1m4 - b2m5);
|
|
|
|
ap60 = S60 * ( a2p5 - a1p4);
|
|
bp60 = S60 * ( b2p5 - b1p4);
|
|
am60 = S60 * (-a2m5 - a1m4);
|
|
bm60 = S60 * (-b2m5 - b1m4);
|
|
|
|
c[j0+j] = a[i0+i] + ab3a + a1p4 + a2p5;
|
|
d[j0+j] = b[i0+i] + ab3b + b1p4 + b2p5;
|
|
c[j1+j] = am05 - bm60;
|
|
d[j1+j] = am60 - bm05;
|
|
c[j2+j] = ap05 - bp60;
|
|
d[j2+j] = ap60 + bp05;
|
|
c[j3+j] = a[i0+i] - ab3a - a1m4 + a2m5;
|
|
d[j3+j] =-b[i0+i] + ab3b + b1m4 - b2m5;
|
|
c[j4+j] = ap05 + bp60;
|
|
d[j4+j] = ap60 - bp05;
|
|
c[j5+j] = am05 + bm60;
|
|
d[j5+j] = am60 + bm05;
|
|
ENDL
|
|
j0 += jink;
|
|
j1 += jink;
|
|
j2 += jink;
|
|
j3 -= jink;
|
|
j4 -= jink;
|
|
j5 -= jink;
|
|
ibase += jump;
|
|
}
|
|
if (j2 > j3) return 0;
|
|
}
|
|
jbase = 0;
|
|
LOOP
|
|
a1p5 = a[i1+i] + a[i5+i];
|
|
a1m5 = a[i1+i] - a[i5+i];
|
|
a2p4 = a[i2+i] + a[i4+i];
|
|
a2m4 = a[i2+i] - a[i4+i];
|
|
|
|
c[j0+j] = a[i0+i] + 0.5 * a2m4 + S60 * a1m5;
|
|
d[j0+j] =-a[i3+i] - 0.5 * a1p5 - S60 * a2p4;
|
|
c[j1+j] = a[i0+i] - a2m4;
|
|
d[j1+j] = a[i3+i] - a1p5;
|
|
c[j2+j] = a[i0+i] + 0.5 * a2m4 - S60 * a1m5;
|
|
d[j2+j] =-a[i3+i] - 0.5 * a1p5 + S60 * a2p4;
|
|
ENDL
|
|
} else {
|
|
z = 1.0 / n;
|
|
y = S60 / n;
|
|
LOOP
|
|
a0p3 = a[i0+i] + a[i3+i];
|
|
a0m3 = a[i0+i] - a[i3+i];
|
|
a1p4 = a[i1+i] + a[i4+i];
|
|
a1m4 = a[i1+i] - a[i4+i];
|
|
a2p5 = a[i2+i] + a[i5+i];
|
|
a2m5 = a[i2+i] - a[i5+i];
|
|
|
|
c[j0+j] = z * (a0p3 + a1p4 + a2p5);
|
|
c[j3+j] = z * (a0m3 + a2m5 - a1m4);
|
|
|
|
c[j1+j] = z * (a0m3 - 0.5 * (a2m5 - a1m4));
|
|
c[j2+j] = z * (a0p3 - 0.5 * (a1p4 + a2p5));
|
|
|
|
d[j1+j] = y * (-a2m5 - a1m4);
|
|
d[j2+j] = y * ( a2p5 - a1p4);
|
|
ENDL
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case 8: {
|
|
double a0p4,a1p5,a2p6,a3p7;
|
|
double a0m4,a1m5,a2m6,a3m7;
|
|
|
|
if (la != m) return 3;
|
|
i0 = 0;
|
|
i1 = i0 + iink;
|
|
i2 = i1 + iink;
|
|
i3 = i2 + iink;
|
|
i4 = i3 + iink;
|
|
i5 = i4 + iink;
|
|
i6 = i5 + iink;
|
|
i7 = i6 + iink;
|
|
j0 = 0;
|
|
j1 = j0 + jink;
|
|
j2 = j1 + jink;
|
|
j3 = j2 + jink;
|
|
j4 = j3 + jink;
|
|
j5 = j4 + jink;
|
|
j6 = j5 + jink;
|
|
j7 = j6 + jink;
|
|
z = 1.0 / n;
|
|
y = SQ2 / n;
|
|
|
|
LOOP
|
|
a0p4 = a[i0+i] + a[i4+i];
|
|
a0m4 = a[i0+i] - a[i4+i];
|
|
a1p5 = a[i1+i] + a[i5+i];
|
|
a1m5 = a[i1+i] - a[i5+i];
|
|
a2p6 = a[i2+i] + a[i6+i];
|
|
a2m6 = a[i2+i] - a[i6+i];
|
|
a3p7 = a[i3+i] + a[i7+i];
|
|
a3m7 = a[i3+i] - a[i7+i];
|
|
|
|
c[j0+j] = z * (a0p4 + a1p5 + a2p6 + a3p7);
|
|
c[j7+j] = z * (a0p4 - a1p5 + a2p6 - a3p7);
|
|
|
|
c[j3+j] = z * (a0p4 - a2p6);
|
|
c[j4+j] = z * (a3p7 - a1p5);
|
|
|
|
c[j1+j] = z * a0m4 + y * (a1m5 - a3m7);
|
|
c[j5+j] = z * a0m4 - y * (a1m5 - a3m7);
|
|
c[j2+j] =-z * a2m6 - y * (a1m5 + a3m7);
|
|
c[j6+j] = z * a2m6 - y * (a1m5 + a3m7);
|
|
ENDL
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void fc2gp(double *fc, double *gp, int Lat, int Lon, int Lev, int Fou)
|
|
{
|
|
int Lot;
|
|
int fou;
|
|
int ia;
|
|
int ifac;
|
|
int j;
|
|
int jump;
|
|
int k;
|
|
int la;
|
|
int lat;
|
|
int lev;
|
|
int lon;
|
|
int nfax;
|
|
int rix;
|
|
int wix;
|
|
|
|
double *wpt;
|
|
|
|
/* fc2gp performs fourier to gridpoint transforms using */
|
|
/* multiple fast fourier transform of length Lon */
|
|
/* */
|
|
/* fc - real array of fourier coefficients fc[Lev][Fou][Lat] */
|
|
/* gp - real array of gridpoints gp[Lev][Lat][Lon] */
|
|
/* Lat - Number of latitudes */
|
|
/* Lon - Number of longitudes */
|
|
/* Lev - Number of levels */
|
|
/* Fou - Number of fourier coefficients on 1 latitude */
|
|
|
|
/* x(j) = sum(k=0,...,n-1)(c(k)*exp(2*i*j*k*pi/Lon)) */
|
|
/* where c(k) = a(k) + i*b(k) and c(n-k) = a(k)-i*b(k) */
|
|
|
|
jump = (Lon + 2) | 1;
|
|
Lot = Lev * Lat;
|
|
nfax = ifax[0];
|
|
|
|
for (lev = 0; lev < Lev; ++lev)
|
|
{
|
|
for (lat = 0; lat < Lat; ++lat)
|
|
{
|
|
wix = jump * (lat + lev * Lat);
|
|
rix = lat + lev * Lat * Fou;
|
|
for (fou = 0 ; fou < Fou && fou < jump ; ++fou)
|
|
wfc[wix + fou] = fc[rix + fou * Lat];
|
|
for (fou = Fou; fou < jump; ++fou)
|
|
wfc[wix + fou] = 0.0;
|
|
wfc[wix+1] = 0.5 * wfc[wix];
|
|
}
|
|
}
|
|
|
|
ia = 1;
|
|
la = 1;
|
|
|
|
for (k = 0; k < nfax; ++k) {
|
|
ifac = ifax[k+1];
|
|
if (k&1) rpassc(wgp,wgp+la,wfc+ia,wfc+ia+ifac*la,
|
|
jump,jump,Lot,Lon,ifac,la);
|
|
else rpassc(wfc+ia,wfc+ia+la,wgp,wgp+ifac*la,
|
|
jump,jump,Lot,Lon,ifac,la);
|
|
la *= ifac;
|
|
ia = 0;
|
|
}
|
|
|
|
if (nfax & 1) wpt = wgp;
|
|
else wpt = wfc;
|
|
|
|
for (j = 0; j < Lot ; ++j)
|
|
for (lon = 0; lon < Lon; ++lon)
|
|
gp[lon + j * Lon] = wpt[lon + j * jump];
|
|
}
|
|
|
|
void gp2fc(double *gp, double *fc, int Lat, int Lon, int Lev, int Fou)
|
|
{
|
|
int Lot;
|
|
int fou;
|
|
int ia;
|
|
int ifac;
|
|
int jump;
|
|
int k;
|
|
int la;
|
|
int lat;
|
|
int lev;
|
|
int lon;
|
|
int lot;
|
|
int nfax;
|
|
int rix;
|
|
int wix;
|
|
|
|
double *wpt;
|
|
|
|
/* gp2fc performs gridpoint to fourier transforms using */
|
|
/* multiple fast fourier transform of length Lon */
|
|
/* */
|
|
/* fc - real array of fourier coefficients fc[Lev][Fou][Lat] */
|
|
/* gp - real array of gridpoints gp[Lev][Lat][Lon] */
|
|
/* Lat - Number of latitudes */
|
|
/* Lon - Number of longitudes */
|
|
/* Lev - Number of levels */
|
|
/* Fou - Number of fourier coefficients on 1 latitude */
|
|
|
|
/* a(k) = (1/n) * sum(j=0,...,n-1)(x(j) * cos(2*j*k*pi/n)) */
|
|
/* b(k) = -(1/n) * sum(j=0,...,n-1)(x(j) * sin(2*j*k*pi/n)) */
|
|
|
|
if (!gp) Abort("gp2fc called with NULL pointer for gp");
|
|
if (!fc) Abort("gp2fc called with NULL pointer for fc");
|
|
jump = (Lon + 2) | 1;
|
|
Lot = Lev * Lat;
|
|
nfax = ifax[0];
|
|
|
|
rix = 0;
|
|
wix = 0;
|
|
for (lot = 0; lot < Lot; ++lot) {
|
|
for (lon = 0; lon < Lon; ++lon) wgp[wix+lon] = gp[rix+lon];
|
|
wgp[wix+Lon ] = 0.0;
|
|
wgp[wix+Lon+1] = 0.0;
|
|
rix += Lon;
|
|
wix += jump;
|
|
}
|
|
|
|
ia = 0;
|
|
la = Lon;
|
|
|
|
for (k = 0; k < nfax; ++k) {
|
|
ifac = ifax[nfax-k];
|
|
la /= ifac;
|
|
if (k & 1) qpassc(wfc,wfc+ifac*la,wgp+ia,wgp+ia+la,
|
|
jump,jump,Lot,Lon,ifac,la);
|
|
else qpassc(wgp+ia,wgp+ia+ifac*la,wfc,wfc+la,
|
|
jump,jump,Lot,Lon,ifac,la);
|
|
ia = 1;
|
|
}
|
|
|
|
if (nfax & 1) wpt = wfc;
|
|
else wpt = wgp+1;
|
|
|
|
for (lev = 0; lev < Lev; ++lev) {
|
|
for (lat = 0; lat < Lat; ++lat) {
|
|
rix = jump * (lat + lev * Lat);
|
|
wix = lat + lev * Lat * Fou;
|
|
fc[wix ] = wpt[rix];
|
|
fc[wix+Lat] = 0.0;
|
|
for (fou = 2 ; fou < Fou ; ++fou)
|
|
fc[wix + fou * Lat] = wpt[rix + fou - 1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
inline void SwapIEEE(char W[4])
|
|
{
|
|
char B;
|
|
|
|
B = W[0]; W[0] = W[3]; W[3] = B;
|
|
B = W[1]; W[1] = W[2]; W[2] = B;
|
|
}
|
|
|
|
inline void SwapIEEE64(char W[8])
|
|
{
|
|
char B;
|
|
|
|
B = W[0]; W[0] = W[3]; W[3] = B;
|
|
B = W[1]; W[1] = W[2]; W[2] = B;
|
|
B = W[4]; W[4] = W[7]; W[7] = B;
|
|
B = W[5]; W[5] = W[6]; W[6] = B;
|
|
}
|
|
|
|
|
|
int check_fcw(int fcws, int fcwe)
|
|
{
|
|
if (fcwe != fcws)
|
|
{
|
|
printf("\n*************** ERROR reading input file **************\n");
|
|
printf("The FORTRAN control words (FCW) of a record don't match\n");
|
|
printf("FCW before record = %d\n",fcws);
|
|
printf("FCW after record = %d\n",fcwe);
|
|
printf("File position: %ld\n",ftell(fpi));
|
|
printf("Possible causes are:\n");
|
|
printf("1) Model crashed leaving an incomplete output file\n");
|
|
printf("2) Corrupt data file (cache or disk problems)\n");
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* =============================== */
|
|
/* Read IEEE 32 bit data from file */
|
|
/* =============================== */
|
|
|
|
|
|
inline int ReadINT(void)
|
|
{
|
|
int k;
|
|
fread(&k,sizeof(k),1,fpi);
|
|
if (Endian) SwapIEEE((char *)&k);
|
|
return k;
|
|
}
|
|
|
|
inline LONG ReadLONG(void)
|
|
{
|
|
LONG l;
|
|
fread(&l,sizeof(l),1,fpi);
|
|
if (Endian) SwapIEEE64((char *)&l);
|
|
return l;
|
|
}
|
|
|
|
inline int ReadFCW(void)
|
|
{
|
|
int k;
|
|
LONG l;
|
|
if (LongFCW)
|
|
{
|
|
fread(&l,sizeof(l),1,fpi);
|
|
if (Endian) SwapIEEE64((char *)&l);
|
|
k = (int)l;
|
|
}
|
|
else
|
|
{
|
|
fread(&k,sizeof(k),1,fpi);
|
|
if (Endian) SwapIEEE((char *)&k);
|
|
}
|
|
return k;
|
|
}
|
|
|
|
inline float ReadFLOAT(void)
|
|
{
|
|
int i;
|
|
float f;
|
|
i = fread(&f,sizeof(f),1,fpi);
|
|
if (i != 1) Abort("Unexpected EOF in ReadFLOAT");
|
|
if (Endian) SwapIEEE((char *)&f);
|
|
return f;
|
|
}
|
|
|
|
inline double ReadDOUBLE(void)
|
|
{
|
|
int i;
|
|
double f;
|
|
i = fread(&f,sizeof(f),1,fpi);
|
|
if (i != 1) Abort("Unexpected EOF in ReadDOUBLE");
|
|
if (Endian) SwapIEEE64((char *)&f);
|
|
return f;
|
|
}
|
|
|
|
inline int ReadINTRecord(void)
|
|
{
|
|
int k,b,e;
|
|
b = ReadFCW();
|
|
fread(&k,sizeof(k),1,fpi); /* IEEE 32-bit integer */
|
|
e = ReadFCW();
|
|
if (check_fcw(b,e)) Abort("record control word mismatch in ReadINTRecord");
|
|
if (Endian) SwapIEEE((char *)&k);
|
|
return k;
|
|
}
|
|
|
|
inline int Skip_FORTRAN_Record(void)
|
|
{
|
|
int fcws,fcwe;
|
|
|
|
fcws = ReadFCW();
|
|
if (feof(fpi)) return 0;
|
|
fseek(fpi,fcws,SEEK_CUR);
|
|
fcwe = ReadFCW();
|
|
if (check_fcw(fcws,fcwe))
|
|
Abort("record control word mismatch in Skip_FORTRAN_Record");
|
|
return fcws;
|
|
}
|
|
|
|
inline void Swap_FORTRAN_Record(char *c, int n)
|
|
{
|
|
char b;
|
|
int i;
|
|
|
|
for (i=0 ; i < n ; i+=4)
|
|
{
|
|
b = c[i ]; c[i ] = c[i+3]; c[i+3] = b;
|
|
b = c[i+1]; c[i+1] = c[i+2]; c[i+2] = b;
|
|
}
|
|
}
|
|
|
|
inline void Swap_FORTRAN_Double(char *c, int n)
|
|
{
|
|
char b;
|
|
int i;
|
|
|
|
for (i=0 ; i < n ; i+=8)
|
|
{
|
|
b = c[i ]; c[i ] = c[i+7]; c[i+7] = b;
|
|
b = c[i+1]; c[i+1] = c[i+6]; c[i+6] = b;
|
|
b = c[i+2]; c[i+2] = c[i+5]; c[i+5] = b;
|
|
b = c[i+3]; c[i+3] = c[i+4]; c[i+4] = b;
|
|
}
|
|
}
|
|
|
|
inline int Read_FORTRAN_Record(void)
|
|
{
|
|
int fcws,fcwe;
|
|
|
|
fcws = ReadFCW();
|
|
if (feof(fpi)) return 0;
|
|
fread(Record_char,1,fcws,fpi);
|
|
fcwe = ReadFCW();
|
|
if (check_fcw(fcws,fcwe)) Abort("record control word mismatch in Read_FORTRAN_Record");
|
|
if (Endian) Swap_FORTRAN_Record(Record_char,fcws);
|
|
return fcws;
|
|
}
|
|
|
|
inline int Read_FORTRAN_Double_Record(void)
|
|
{
|
|
int fcws,fcwe;
|
|
|
|
fcws = ReadFCW();
|
|
if (feof(fpi)) return 0;
|
|
fread(Record_char,1,fcws,fpi);
|
|
fcwe = ReadFCW();
|
|
if (check_fcw(fcws,fcwe)) Abort("record control word mismatch in Read_FORTRAN_Double_Record");
|
|
if (Endian) Swap_FORTRAN_Double(Record_char,fcws);
|
|
return fcws;
|
|
}
|
|
|
|
int ReadHeaderRecord(void)
|
|
{
|
|
int h,i,fcws,fcwe;
|
|
|
|
fcws = ReadFCW();
|
|
if (feof(fpi)) return 1;
|
|
if (fcws == 8) /* Skip PUMA header */
|
|
{
|
|
if (Debug)
|
|
{
|
|
printf("Skipping %d header words\n",HeaderWords);
|
|
for (i=0 ; i < HeaderWords ; ++i)
|
|
{
|
|
h = ReadINT();
|
|
printf("HW[%2d] = %8x %d\n",i,h,h);
|
|
}
|
|
}
|
|
else
|
|
for (i=0 ; i < HeaderWords ; ++i) ReadINT();
|
|
fcws = ReadFCW();
|
|
if (feof(fpi))
|
|
{
|
|
printf("\n#### Empty data file #####\n");
|
|
printf("Mark [Write Ouput] in MoSt\n");
|
|
printf("or set NOUTPUT=1 in file <puma_namelist>\n");
|
|
Abort("Empty data file");
|
|
}
|
|
}
|
|
if (fcws != HeadSize)
|
|
{
|
|
printf("FCW = %d (should be %d)\n",fcws,HeadSize);
|
|
Abort("Wrong FCW found in ReadHeaderRecord");
|
|
}
|
|
for (i=0 ; i < 8 ; ++i)
|
|
{
|
|
if (HeadSize == 32) HeadIn[i] = ReadINT();
|
|
else HeadIn[i] = ReadLONG();
|
|
}
|
|
fcwe = ReadFCW();
|
|
if (check_fcw(fcws,fcwe)) Abort("FCW mismatch in ReadHeaderRecord");
|
|
return 0;
|
|
}
|
|
|
|
|
|
void DecodePumaHeader(void)
|
|
{
|
|
PumaCode = HeadIn[0];
|
|
PumaLevel = HeadIn[1];
|
|
NewDate.tm_year = HeadIn[2] / 10000;
|
|
NewDate.tm_mon = HeadIn[2] / 100 % 100;
|
|
NewDate.tm_mday = HeadIn[2] % 100;
|
|
NewDate.tm_hour = HeadIn[3] / 100;
|
|
NewDate.tm_min = HeadIn[3] % 100;
|
|
if (DayDivisor > 1) NewMonth = (TermCount / DPM) % 12 + 1;
|
|
else NewMonth = NewDate.tm_mon;
|
|
if (HeadIn[4] * HeadIn[5] == DimSP) RepGrib = REP_SPECTRAL;
|
|
else RepGrib = REP_GAUSS;
|
|
|
|
if (PumaCode < 0 || PumaCode >= CODES)
|
|
{
|
|
printf("Illegal Code %d in header\n",PumaCode);
|
|
Abort("Code < 0 or Code > CODES found");
|
|
}
|
|
All[PumaCode].detected = TRUE;
|
|
}
|
|
|
|
// =============
|
|
// ReadPumaArray
|
|
// =============
|
|
|
|
void ReadPumaArray(double *Array)
|
|
{
|
|
int i,j,fcws;
|
|
double zfac;
|
|
double zmin;
|
|
|
|
if (RealSize == sizeof(float)) fcws = Read_FORTRAN_Record();
|
|
else fcws = Read_FORTRAN_Double_Record();
|
|
if (fcws == sizeof(float) * (Truncation + 2)) // Packed spectral data
|
|
{
|
|
for (i=0 ; i <= Truncation ; i++)
|
|
{
|
|
Array[2*i ] = Record_float[i];
|
|
Array[2*i+1] = 0.0; // Imaginary parts of zonal modes
|
|
}
|
|
zfac = 1.0 / Record_float[Truncation+1];
|
|
fcws = Read_FORTRAN_Record();
|
|
if (CoreBigEndian)
|
|
{
|
|
for (i=2*Truncation+2,j=0 ; i < DimSP ; ++i,++j)
|
|
{
|
|
Array[i] = (Record_short[j] - 32768) * zfac;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i=2*Truncation+2,j=0 ; i < DimSP ; i+=2,j+=2)
|
|
{
|
|
Array[i ] = (Record_short[j+1] - 32768) * zfac;
|
|
Array[i+1] = (Record_short[j ] - 32768) * zfac;
|
|
}
|
|
}
|
|
}
|
|
else if (fcws == sizeof(float) * DimSP) // Unpacked spectral float data
|
|
{
|
|
for (i=0 ; i < DimSP ; ++i) Array[i] = Record_float[i];
|
|
}
|
|
else if (fcws == sizeof(double) * DimSP) // Unpacked spectral double data
|
|
{
|
|
memcpy(Array,Record_double,fcws);
|
|
}
|
|
else if (fcws == sizeof(float) * DimGG) // Unpacked grid float data
|
|
{
|
|
for (i=0 ; i < DimGG ; ++i) Array[i] = Record_float[i];
|
|
}
|
|
else if (fcws == sizeof(double) * DimGG) // Unpacked grid double data
|
|
{
|
|
memcpy(Array,Record_double,fcws);
|
|
}
|
|
else if (fcws == 8) /* Packed grid data */
|
|
{
|
|
zmin = Record_float[0];
|
|
zfac = 1.0 / Record_float[1];
|
|
fcws = Read_FORTRAN_Record();
|
|
if (CoreBigEndian)
|
|
{
|
|
for (i=0 ; i < DimGG ; ++i)
|
|
{
|
|
Array[i] = Record_short[i] * zfac + zmin;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i=0 ; i < DimGG ; i+=2)
|
|
{
|
|
Array[i ] = Record_short[i+1] * zfac + zmin;
|
|
Array[i+1] = Record_short[i ] * zfac + zmin;
|
|
}
|
|
}
|
|
}
|
|
else Abort("fcws error in ReadPumaArray");
|
|
}
|
|
|
|
|
|
/* ============= */
|
|
/* SkipPumaArray */
|
|
/* ============= */
|
|
|
|
void SkipPumaArray(void)
|
|
{
|
|
int fcws;
|
|
fcws = Skip_FORTRAN_Record();
|
|
if (fcws == 8 || fcws == 4 * (Truncation + 2))
|
|
fcws = Skip_FORTRAN_Record();
|
|
}
|
|
|
|
|
|
/* ============================================= */
|
|
/* phcs - Compute values of Legendre polynomials */
|
|
/* and their meridional derivatives */
|
|
/* ============================================= */
|
|
|
|
void phcs(double *PNM, double *HNM, int Waves, double PMU,
|
|
double *ZTEMP1, double *ZTEMP2)
|
|
{
|
|
long TwoWaves;
|
|
|
|
long JK;
|
|
long JN;
|
|
long JM;
|
|
|
|
double JNmJK;
|
|
double ZCOS2;
|
|
double Lat;
|
|
double ZAN;
|
|
double ZSINPAR;
|
|
double ZCOSPAR;
|
|
double ZSQP;
|
|
double ZCOSFAK;
|
|
double ZSINFAK;
|
|
double ZQ;
|
|
double ZWM2;
|
|
double ZW;
|
|
double ZWQ;
|
|
double ZQ2M1;
|
|
double ZWM2Q2;
|
|
double Z2Q2;
|
|
double ZCNM;
|
|
double ZDNM;
|
|
double ZENM;
|
|
|
|
TwoWaves = Waves << 1;
|
|
ZCOS2 = sqrt(1.0 - PMU * PMU);
|
|
Lat = acos(PMU);
|
|
ZAN = 1.0;
|
|
ZTEMP1[0] = 0.5;
|
|
|
|
for (JN = 1; JN < TwoWaves; JN++) {
|
|
ZSQP = 1.0 / sqrt((double)(JN+JN*JN));
|
|
ZAN *= sqrt(1.0 - 1.0 / (4 * JN * JN));
|
|
|
|
ZCOSPAR = cos(Lat * JN);
|
|
ZSINPAR = sin(Lat * JN) * JN * ZSQP;
|
|
ZCOSFAK = 1.0;
|
|
|
|
for (JK = 2; JK < JN; JK += 2) {
|
|
JNmJK = JN - JK;
|
|
ZCOSFAK *= (JK-1) * (JN+JNmJK+2) / (JK * (JN+JNmJK+1));
|
|
ZSINFAK = ZCOSFAK * (JNmJK) * ZSQP;
|
|
ZCOSPAR += ZCOSFAK * cos(Lat * JNmJK);
|
|
ZSINPAR += ZSINFAK * sin(Lat * JNmJK);
|
|
}
|
|
|
|
/* Code for JK == JN */
|
|
|
|
if ((JN & 1) == 0) {
|
|
ZCOSFAK *= (double)((JN-1) * (JN+2)) / (double)(JN * (JN+1));
|
|
ZCOSPAR += ZCOSFAK * 0.5;
|
|
}
|
|
ZTEMP1[JN ] = ZAN * ZCOSPAR;
|
|
ZTEMP2[JN-1] = ZAN * ZSINPAR;
|
|
}
|
|
|
|
memcpy(PNM,ZTEMP1,Waves * sizeof(double));
|
|
PNM += Waves;
|
|
memcpy(PNM,ZTEMP2,Waves * sizeof(double));
|
|
PNM += Waves;
|
|
|
|
HNM[0] = 0.0;
|
|
for (JN = 1; JN < Waves; JN++) HNM[JN] =
|
|
JN * (PMU * ZTEMP1[JN] - sqrt((JN+JN+1.0) / (JN+JN-1.0)) * ZTEMP1[JN-1]);
|
|
HNM += Waves;
|
|
|
|
HNM[0] = PMU * ZTEMP2[0];
|
|
for (JN = 1; JN < Waves; JN++)
|
|
HNM[JN] = (JN+1) * PMU * ZTEMP2[JN]
|
|
- sqrt((double)((JN+JN+3) * ((JN+1) * (JN+1) - 1))
|
|
/ (double)(JN+JN+1)) * ZTEMP2[JN-1];
|
|
HNM += Waves;
|
|
|
|
for (JM = 2; JM < Waves; JM++) {
|
|
PNM[0] = sqrt(1.0 + 1.0 / (JM+JM)) * ZCOS2 * ZTEMP2[0];
|
|
HNM[0] = JM * PMU * PNM[0];
|
|
for (JN = 1; JN < TwoWaves-JM; JN++) {
|
|
ZQ = JM + JM + JN - 1;
|
|
ZWM2 = ZQ+JN;
|
|
ZW = ZWM2+2;
|
|
ZWQ = ZW*ZQ;
|
|
ZQ2M1 = ZQ*ZQ-1.;
|
|
ZWM2Q2 = ZWM2*ZQ2M1;
|
|
Z2Q2 = ZQ2M1*2;
|
|
ZCNM = sqrt((ZWQ*(ZQ-2.))/(ZWM2Q2-Z2Q2));
|
|
ZDNM = sqrt((ZWQ*(JN+1.))/ZWM2Q2);
|
|
ZENM = sqrt(ZW * JN /((ZQ+1.0) * ZWM2));
|
|
PNM[JN] = ZCNM * ZTEMP1[JN] - PMU
|
|
* (ZDNM * ZTEMP1[JN+1] - ZENM * PNM[JN-1]);
|
|
HNM[JN] = (JM + JN) * PMU * PNM[JN]
|
|
- sqrt(ZW * JN * (ZQ+1) / ZWM2) * PNM[JN-1];
|
|
}
|
|
memcpy(ZTEMP1,ZTEMP2,TwoWaves * sizeof(double));
|
|
memcpy(ZTEMP2,PNM ,TwoWaves * sizeof(double));
|
|
PNM += Waves;
|
|
HNM += Waves;
|
|
}
|
|
}
|
|
|
|
void legini(void)
|
|
{
|
|
int jlat,jm,jn,jz;
|
|
int jsp,pdim,hdim;
|
|
double *hnm,*pnm,*ZTEMP1,*ZTEMP2,gmusq;
|
|
double znn1,zgmu;
|
|
char tb[COLS+2];
|
|
double poliv,pol2v,pliuv,plivv;
|
|
|
|
hdim = 2 * Waves * Waves;
|
|
|
|
if (PolyCreate) /* Generate filenames for polynomials */
|
|
{
|
|
sprintf(polin,"b6poli.T%d",Truncation);
|
|
sprintf(pol2n,"b6pol2.T%d",Truncation);
|
|
sprintf(pliun,"b6pliu.T%d",Truncation);
|
|
sprintf(plivn,"b6pliv.T%d",Truncation);
|
|
}
|
|
else if (PolyDisk) /* Generate filenames for polynomials */
|
|
{
|
|
sprintf(polin,"/comm/T1365/b6poli.t%d",Truncation);
|
|
sprintf(pol2n,"/comm/T1365/b6pol2.t%d",Truncation);
|
|
sprintf(pliun,"/comm/T1365/b6pliu.t%d",Truncation);
|
|
sprintf(plivn,"/comm/T1365/b6pliv.t%d",Truncation);
|
|
polif = fopen(polin,"r");
|
|
pol2f = fopen(pol2n,"r");
|
|
pliuf = fopen(pliun,"r");
|
|
plivf = fopen(plivn,"r");
|
|
|
|
if (polif && pol2f && pliuf && plivf)
|
|
sprintf(tb,"Legendre Polynomials read from disk");
|
|
else
|
|
{
|
|
sprintf(tb,"Legendre Polynomials calculated");
|
|
PolyDisk = 0;
|
|
}
|
|
CenterText(tb);
|
|
}
|
|
|
|
if (PolyDisk) pdim = Lats;
|
|
else pdim = Lats * DimSP_half;
|
|
poli = new double[pdim];
|
|
pol2 = new double[pdim];
|
|
pliu = new double[pdim];
|
|
pliv = new double[pdim];
|
|
pnm = new double[hdim];
|
|
hnm = new double[hdim];
|
|
ZTEMP1 = new double[Fouriers];
|
|
ZTEMP2 = new double[Fouriers];
|
|
|
|
for (int i=0 ; i<hdim ; ++i) pnm[i]=hnm[i]=777.0;
|
|
Gaulat = new GauLat(Gats,"Gaulat");
|
|
Outlon = new RegLon(Lons,"Outlon");
|
|
if (GaussGrid) Outlat = new GauLat(Lats,"Outlat");
|
|
else Outlat = new RegLat(Lats,"Outlat");
|
|
if (Debug) Outlat->PrintArray();
|
|
if (Debug) Outlon->PrintArray();
|
|
|
|
if (Lats == Gats && Lons == Gons)
|
|
for (jlat = 0 ; jlat < Gats ; ++jlat)
|
|
{
|
|
Outlat->Phi[jlat] = Gaulat->Phi[jlat];
|
|
Outlat->gmu[jlat] = Gaulat->gmu[jlat];
|
|
Outlat->gwt[jlat] = Gaulat->gwt[jlat];
|
|
}
|
|
else if (Debug) Outlat->PrintArray();
|
|
|
|
if (PolyCreate)
|
|
{
|
|
polif = fopen(polin,"w");
|
|
pol2f = fopen(pol2n,"w");
|
|
pliuf = fopen(pliun,"w");
|
|
plivf = fopen(plivn,"w");
|
|
for (jlat = 0 ; jlat < Lats ; ++jlat)
|
|
{
|
|
gmusq = 1.0 - Outlat->gmu[jlat] * Outlat->gmu[jlat];
|
|
zgmu = sqrt(gmusq);
|
|
phcs(pnm,hnm,Waves,Outlat->gmu[jlat],ZTEMP1,ZTEMP2);
|
|
for (jm = 0; jm < Waves; jm++)
|
|
{
|
|
for (jn = 0; jn < Waves - jm ; jn++)
|
|
{
|
|
jz = jm+jn;
|
|
znn1 = 0.0;
|
|
if (jz > 0) znn1 = 1.0 / (jz * (jz+1));
|
|
poliv = pnm[jm*Waves+jn] * 2.0;
|
|
fwrite(&poliv,sizeof(double),1,polif);
|
|
pol2v = hnm[jm*Waves+jn] / PlanetRadius;
|
|
fwrite(&pol2v,sizeof(double),1,pol2f);
|
|
pliuv = pnm[jm*Waves+jn] * 2.0 * PlanetRadius * znn1 * jm / zgmu;
|
|
fwrite(&pliuv,sizeof(double),1,pliuf);
|
|
plivv = hnm[jm*Waves+jn] * 2.0 * PlanetRadius * znn1 / zgmu;
|
|
fwrite(&plivv,sizeof(double),1,plivf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (PolyDisk)
|
|
{
|
|
for (jlat = 0 ; jlat < Lats ; ++jlat)
|
|
{
|
|
gmusq = 1.0 - Outlat->gmu[jlat] * Outlat->gmu[jlat];
|
|
CosPhi[jlat] = sqrt(gmusq);
|
|
RevCosPhi[jlat] = 1.0 / CosPhi[jlat];
|
|
DerivationFactor[jlat] = RevCosPhi[jlat] / PlanetRadius;
|
|
}
|
|
}
|
|
else /* Normal computation of polynomials */
|
|
{
|
|
for (jlat = 0 ; jlat < Lats ; ++jlat)
|
|
{
|
|
gmusq = 1.0 - Outlat->gmu[jlat] * Outlat->gmu[jlat];
|
|
CosPhi[jlat] = sqrt(gmusq);
|
|
RevCosPhi[jlat] = 1.0 / CosPhi[jlat];
|
|
DerivationFactor[jlat] = RevCosPhi[jlat] / PlanetRadius;
|
|
phcs(pnm,hnm,Waves,Outlat->gmu[jlat],ZTEMP1,ZTEMP2);
|
|
jsp = jlat;
|
|
for (jm = 0; jm < Waves; jm++)
|
|
{
|
|
for (jn = 0; jn < Waves - jm ; jn++)
|
|
{
|
|
jz = jm+jn;
|
|
znn1 = 0.0;
|
|
if (jz > 0) znn1 = 1.0 / (jz * (jz+1));
|
|
poli[jsp] = pnm[jm*Waves+jn] * 2.0;
|
|
pol2[jsp] = hnm[jm*Waves+jn] / PlanetRadius;
|
|
pliu[jsp] = pnm[jm*Waves+jn] * 2.0 * PlanetRadius * znn1 * jm / sqrt(gmusq);
|
|
pliv[jsp] = hnm[jm*Waves+jn] * 2.0 * PlanetRadius * znn1 / sqrt(gmusq);
|
|
jsp += Lats;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete [] pnm;
|
|
delete [] hnm;
|
|
delete [] ZTEMP1;
|
|
delete [] ZTEMP2;
|
|
}
|
|
|
|
|
|
void spvfc(double *sd, double *sz, double *fu, double *fv, int klev,int nlat,int nfc,int nt)
|
|
{
|
|
int lev,jmm,jfc,lat;
|
|
double sdr,sdi,szr,szi;
|
|
double *fur,*fui,*fvr,*fvi;
|
|
double *poa,*pob;
|
|
|
|
DoubleZero(fu,klev*nlat*nfc);
|
|
DoubleZero(fv,klev*nlat*nfc);
|
|
|
|
for (lev = 0; lev < klev; lev++)
|
|
{
|
|
if (PolyDisk)
|
|
{
|
|
rewind(pliuf);
|
|
rewind(plivf);
|
|
}
|
|
poa = pliu;
|
|
pob = pliv;
|
|
for (jmm = 0; jmm <= nt; jmm++)
|
|
{
|
|
for (jfc = jmm; jfc <= nt; jfc++)
|
|
{
|
|
sdr = *sd++;
|
|
sdi = *sd++;
|
|
szr = *sz++;
|
|
szi = *sz++;
|
|
fur = fu ;
|
|
fui = fu + nlat;
|
|
fvr = fv ;
|
|
fvi = fv + nlat;
|
|
if (PolyDisk)
|
|
{
|
|
fread(poa=pliu,sizeof(double),Lats,pliuf);
|
|
fread(pob=pliv,sizeof(double),Lats,plivf);
|
|
}
|
|
for (lat = 0; lat < nlat; lat++)
|
|
{
|
|
*fur += -*pob * szr + *poa * sdi;
|
|
*fui += -*pob * szi - *poa * sdr;
|
|
*fvr += *poa * szi + *pob * sdr;
|
|
*fvi += -*poa * szr + *pob * sdi;
|
|
fur++;
|
|
fui++;
|
|
fvr++;
|
|
fvi++;
|
|
poa++;
|
|
pob++;
|
|
}
|
|
}
|
|
fu += 2 * nlat;
|
|
fv += 2 * nlat;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ========================================
|
|
// sp2fci - Inverse Legendre Transformation
|
|
// ========================================
|
|
|
|
void sp2fci(double *sa,double *fa,int klev)
|
|
{
|
|
int lev,m,n;
|
|
double sar,sai;
|
|
double *Far,*Fai,*pol;
|
|
DoubleZero(fa,klev*DimFC);
|
|
for (lev = 0; lev < klev; ++lev)
|
|
{
|
|
if (PolyDisk) rewind(polif);
|
|
pol = poli;
|
|
for (n = 0; n <= Truncation; ++n)
|
|
{
|
|
if (PolyDisk) fread(pol=poli,sizeof(double),Lats,polif);
|
|
sar = *sa;
|
|
sa += 2;
|
|
for (Far=fa; Far < fa+Lats;++Far,++pol)
|
|
{
|
|
*Far += *pol * sar;
|
|
}
|
|
}
|
|
fa += 2 * Lats;
|
|
|
|
for (m = 1; m <= Truncation; ++m)
|
|
{
|
|
for (n = m; n <= Truncation; ++n)
|
|
{
|
|
if (PolyDisk) fread(pol=poli,sizeof(double),Lats,polif);
|
|
sar = *sa++ ;
|
|
sai = *sa++ ;
|
|
for (Far=fa,Fai=fa+Lats; Far<fa+Lats; ++Far,++Fai,++pol)
|
|
{
|
|
*Far += *pol * sar;
|
|
*Fai += *pol * sai;
|
|
}
|
|
}
|
|
fa += 2 * Lats;
|
|
}
|
|
}
|
|
}
|
|
|
|
void sp2fcd(double *sa,double *fa,int klev,int nlat,int nfc,int nt)
|
|
{
|
|
int lev,jmm,jfc,lat;
|
|
double sar,sai;
|
|
double *Far,*fai,*pol;
|
|
double zpo;
|
|
DoubleZero(fa,klev*nlat*nfc);
|
|
for (lev = 0; lev < klev; lev++)
|
|
{
|
|
pol = pol2;
|
|
if (PolyDisk) rewind(pol2f);
|
|
for (jmm = 0; jmm <= nt; jmm++)
|
|
{
|
|
for (jfc = jmm; jfc <= nt; jfc++)
|
|
{
|
|
sar = *sa++ ;
|
|
sai = *sa++ ;
|
|
Far = fa ;
|
|
fai = fa + nlat ;
|
|
if (PolyDisk) fread(pol=pol2,sizeof(double),Lats,pol2f);
|
|
for (lat = 0; lat < nlat; lat++)
|
|
{
|
|
zpo = -2.0 * *pol * RevCosPhi[lat];
|
|
*Far += zpo * sar;
|
|
*fai += zpo * sai;
|
|
Far++;
|
|
fai++;
|
|
pol++;
|
|
}
|
|
}
|
|
fa += 2 * nlat;
|
|
}
|
|
}
|
|
}
|
|
|
|
void fc2sp(double *fa, double *sa, int klev, int nlat, int nt)
|
|
{
|
|
int lev,jmm,jfc,lat;
|
|
double sar,sai,*Far,*fai,*pol;
|
|
double zpo;
|
|
for (lev = 0; lev < klev; lev++)
|
|
{
|
|
pol = poli;
|
|
if (PolyDisk) rewind(polif);
|
|
for (jmm = 0; jmm <= nt; jmm++)
|
|
{
|
|
for (jfc = jmm; jfc <= nt; jfc++)
|
|
{
|
|
Far = fa ;
|
|
fai = fa + nlat ;
|
|
sar = 0.0 ;
|
|
sai = 0.0 ;
|
|
if (PolyDisk) fread(pol=poli,sizeof(double),Lats,polif);
|
|
for (lat = 0; lat < nlat; lat++)
|
|
{
|
|
zpo = *pol * 0.5 * Outlat->gwt[lat];
|
|
sar += zpo * *Far;
|
|
sai += zpo * *fai;
|
|
Far++;
|
|
fai++;
|
|
pol++;
|
|
}
|
|
*sa++ = sar;
|
|
*sa++ = sai;
|
|
}
|
|
fa += 2 * nlat;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OMEGA(void)
|
|
{
|
|
int i,j;
|
|
double DeltaHybrid;
|
|
double Cterm;
|
|
double Pterm;
|
|
double *omega = &Omega->hgp[0];
|
|
double *diver = &Divergence->hgp[0];
|
|
double *halfp = &HalfPress->hgp[0];
|
|
double *fullp = &FullPress->hgp[0];
|
|
double *uwind = &u_wind->hgp[0];
|
|
double *vwind = &v_wind->hgp[0];
|
|
|
|
/* Compute half level part of vertical velocity */
|
|
|
|
for (i = 0; i < DimGP ; i++) omega[i] = 0.0;
|
|
for (j = 0; j < SigLevs; j++) {
|
|
DeltaHybrid = vct[SigLevs+j+2] - vct[SigLevs+j+1];
|
|
for (i = 0; i < DimGP; i++) {
|
|
omega[DimGP] = *omega
|
|
- *diver * (halfp[DimGP] - *halfp) - DeltaHybrid
|
|
* (*uwind * dpsdx->hgp[i]
|
|
+ *vwind * dpsdy->hgp[i]);
|
|
omega++;
|
|
halfp++;
|
|
diver++;
|
|
uwind++;
|
|
vwind++;
|
|
}
|
|
}
|
|
|
|
/* interpolate to full levels */
|
|
|
|
omega = &Omega->hgp[0];
|
|
for (i = 0; i < Dim3GP; i++)
|
|
omega[i] = 0.5 * (omega[i] + omega[i+DimGP]);
|
|
|
|
/* compute full level part of vertical velocity */
|
|
|
|
omega = &Omega->hgp[0];
|
|
halfp = &HalfPress->hgp[0];
|
|
fullp = &FullPress->hgp[0];
|
|
uwind = &u_wind->hgp[0];
|
|
vwind = &v_wind->hgp[0];
|
|
|
|
for (j = 0; j < SigLevs; j++) {
|
|
DeltaHybrid = vct[SigLevs+j+2] - vct[SigLevs+j+1];
|
|
if (DeltaHybrid) {
|
|
Cterm = vct[j+1] * vct[SigLevs+j+1] - vct[j] * vct[SigLevs+j+2];
|
|
for (i = 0; i < DimGP; i++) {
|
|
if (Cterm != 0.0) Pterm = Cterm /
|
|
(halfp[DimGP] - *halfp) * log(halfp[DimGP] / *halfp);
|
|
else Pterm = 0.0;
|
|
|
|
*omega += *fullp *
|
|
(*uwind * dpsdx->hgp[i] + *vwind * dpsdy->hgp[i])
|
|
/ (halfp[DimGP] - *halfp) * (DeltaHybrid + Pterm);
|
|
omega++;
|
|
halfp++;
|
|
fullp++;
|
|
uwind++;
|
|
vwind++;
|
|
}
|
|
}
|
|
else {
|
|
omega += DimGP;
|
|
halfp += DimGP;
|
|
fullp += DimGP;
|
|
uwind += DimGP;
|
|
vwind += DimGP;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Omega_w(double w[], double om[], double T[], double P[])
|
|
{
|
|
int i;
|
|
|
|
for (i=0 ; i < Dim3GP ; ++i)
|
|
{
|
|
w[i] = -om[i] * RD * T[i] / (Grav * P[i]);
|
|
}
|
|
|
|
}
|
|
|
|
void Extrap(double *slp, double *aph, double *apf,
|
|
double *Geopotential, double *t, int nhor)
|
|
{
|
|
double zrg = 1.0 / Grav;
|
|
double alpha,tstar,tmsl,ZPRT,ZPRTAL;
|
|
|
|
int j;
|
|
|
|
for (j = 0; j < nhor; ++j) {
|
|
if (Geopotential[j] < 0.0001 && Geopotential[j] > -0.0001) slp[j] = aph[j];
|
|
else {
|
|
alpha = RD * RLAPSE * zrg;
|
|
tstar = (1.0 + alpha * (aph[j]/apf[j] - 1.0)) * t[j];
|
|
if (tstar < 255.0) tstar = 0.5 * (255.0 + tstar);
|
|
tmsl = tstar + RLAPSE * zrg * Geopotential[j];
|
|
if (tmsl > 290.5 && tstar > 290.5) {
|
|
tstar = 0.5 * (290.5 + tstar);
|
|
tmsl = tstar;
|
|
}
|
|
if (tmsl-tstar < 0.000001 && tstar-tmsl < 0.000001) alpha = 0.0;
|
|
else if (Geopotential[j] > 0.0001 || Geopotential[j] < -0.0001)
|
|
alpha = RD * (tmsl-tstar) / Geopotential[j];
|
|
ZPRT = Geopotential[j] / (RD * tstar);
|
|
ZPRTAL = ZPRT * alpha;
|
|
slp[j] = aph[j] * exp(ZPRT*(1.0-ZPRTAL*(0.5-ZPRTAL/3.0)));
|
|
}
|
|
}
|
|
}
|
|
|
|
double ExtraT(double PRES, double APH, double APF, double GEOS, double T)
|
|
{
|
|
double zrg = 1.0 / Grav;
|
|
double tstar,ztsz,Z1,ZTMSL,ZALPH,PEVAL,ZHTS,ZALP;
|
|
|
|
tstar = (1.0 + RLAPSE * RD * zrg * (APH/APF - 1.0)) * T;
|
|
ztsz = tstar;
|
|
Z1 = tstar + RLAPSE * zrg * GEOS;
|
|
if (tstar < 255.0) tstar = 0.5 * (255.0 + tstar);
|
|
ZTMSL = tstar + RLAPSE * zrg * GEOS;
|
|
if (ZTMSL > 290.5 && tstar > 290.5)
|
|
{
|
|
tstar = 0.5 * (290.5 + tstar);
|
|
ZTMSL = tstar;
|
|
}
|
|
if (ZTMSL > 290.5 && tstar <= 290.5) ZTMSL=290.5;
|
|
ZALPH=RD*RLAPSE*zrg;
|
|
if ( ZTMSL-tstar < 0.000001 && tstar-ZTMSL < 0.000001) ZALPH=0.0;
|
|
if ((ZTMSL-tstar > 0.000001 || tstar-ZTMSL > 0.000001) &&
|
|
(GEOS > 0.0001 || GEOS < -0.0001))
|
|
ZALPH=RD*(ZTMSL-tstar)/GEOS;
|
|
if (PRES <= APH) PEVAL = ((APH-PRES)*T+ (PRES-APF)*tstar)/ (APH-APF);
|
|
else
|
|
{
|
|
ZTMSL=Z1;
|
|
tstar=ztsz;
|
|
ZHTS=GEOS*zrg;
|
|
if (ZHTS > 2000. && Z1 > 298.)
|
|
{
|
|
ZTMSL=298.;
|
|
if (ZHTS < 2500.) ZTMSL=0.002*((2500.-ZHTS)*Z1+(ZHTS-2000.)*ZTMSL);
|
|
}
|
|
if ((ZTMSL-tstar) < 0.000001) ZALPH=0.;
|
|
else if (GEOS > 0.0001 || GEOS < -0.0001) ZALPH=RD*(ZTMSL-tstar)/GEOS;
|
|
else ZALPH=RD*RLAPSE*zrg;
|
|
ZALP=ZALPH*log(PRES/APH);
|
|
PEVAL=tstar*(1.0+ZALP*(1.0+ZALP*(0.5+0.16666666667*ZALP)));
|
|
}
|
|
return PEVAL;
|
|
}
|
|
|
|
double ExtraZ(double pres, double aph, double apf, double sg, double t)
|
|
{
|
|
double zrg = 1.0 / Grav;
|
|
double alpha,tstar,tmsl,ZALP,ZALPAL;
|
|
|
|
alpha = RD * RLAPSE * zrg;
|
|
tstar = (1.0 + alpha * (aph/apf - 1.0)) * t;
|
|
if (tstar < 255.0) tstar = 0.5 * (255.0 + tstar);
|
|
tmsl = tstar + RLAPSE * zrg * sg;
|
|
if (tmsl > 290.5 && tstar > 290.5)
|
|
{
|
|
tstar = 0.5 * (290.5 + tstar);
|
|
tmsl = tstar;
|
|
}
|
|
if (tmsl > 290.5 && tstar <= 290.5) tmsl = 290.5;
|
|
if (tmsl-tstar < 0.000001 && tstar-tmsl < 0.000001) alpha = 0.0;
|
|
else if (sg > 0.0001 || sg < -0.0001) alpha = RD * (tmsl-tstar) / sg;
|
|
ZALP = log(pres/aph);
|
|
ZALPAL = ZALP * alpha;
|
|
return (sg - RD * tstar * ZALP * (1.0 + ZALPAL * (0.5 + ZALPAL/6.0))) * zrg;
|
|
}
|
|
|
|
|
|
void Interpolate_T(int Code)
|
|
{
|
|
int lp, i;
|
|
int nl,nh;
|
|
double pres;
|
|
|
|
int *nx = vert_index;
|
|
|
|
double *gt = &All[Code].hgp[0];
|
|
double *pt = &All[Code].pgp[0];
|
|
double *pf = &FullPress->hgp[0];
|
|
double *ph = &HalfPress->hgp[0];
|
|
|
|
for (lp = 0; lp < OutLevs; lp++)
|
|
{
|
|
pres = level[lp];
|
|
for (i = 0; i < DimGP; i++)
|
|
{
|
|
nl = i + DimGP * *nx;
|
|
nh = nl + DimGP;
|
|
if (nl < 0) // Above top level
|
|
{
|
|
*pt = gt[i];
|
|
}
|
|
else if (nh >= Dim3GP) // Below bottom level
|
|
{
|
|
if (!mars && Code == TCODE) *pt = ExtraT(pres,ph[nh],pf[nl],Orography[i],gt[nl]);
|
|
else *pt = gt[nl];
|
|
}
|
|
else // Inside
|
|
{
|
|
*pt = gt[nl] + (pres-pf[nl]) * (gt[nh]-gt[nl]) / (pf[nh]-pf[nl]);
|
|
}
|
|
++nx;
|
|
++pt;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Interpolate_Z(void)
|
|
{
|
|
int lp, i;
|
|
int nl,nh;
|
|
double pres;
|
|
|
|
int *nx = vert_index;
|
|
|
|
double *gz = &GeopotHeight->hgp[0];
|
|
double *pz = &GeopotHeight->pgp[0];
|
|
double *gt = &Temperature->hgp[0];
|
|
double *pf = &FullPress->hgp[0];
|
|
double *ph = &HalfPress->hgp[0];
|
|
|
|
for (lp = 0; lp < OutLevs; lp++)
|
|
{
|
|
pres = level[lp];
|
|
for (i = 0; i < DimGP; i++)
|
|
{
|
|
nl = i + DimGP * *nx;
|
|
if (pres > ph[nl+DimGP]) nl += DimGP;
|
|
nh = nl + DimGP;
|
|
if (nl < 0) // Above top level
|
|
{
|
|
*pz = gz[i];
|
|
}
|
|
else if (nl >= Dim3GP) // Below bottom level
|
|
{
|
|
if (mars) *pz = gz[nl-DimGP];
|
|
else *pz = ExtraZ(pres,ph[nl], pf[nl-DimGP],Orography[i],gt[nl-DimGP]);
|
|
}
|
|
else // Inside
|
|
{
|
|
*pz = gz[nl] + (pres-ph[nl]) * (gz[nh]-gz[nl]) / (ph[nh] - ph[nl]);
|
|
}
|
|
++nx;
|
|
++pz;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CheckDependencies(void)
|
|
{
|
|
|
|
u_wind->needed = ( Divergence->needed && !Divergence->detected) ||
|
|
( Vorticity->needed && !Vorticity->detected) ||
|
|
( VeloPot->needed && !VeloPot->detected) ||
|
|
( StreamF->needed && !StreamF->detected) ||
|
|
( Omega->needed && !Omega->detected) ||
|
|
( speed->needed && !speed->detected) ||
|
|
( v_wind->needed && !v_wind->detected) ||
|
|
u_wind->selected;
|
|
v_wind->needed = ( Divergence->needed && !Divergence->detected) ||
|
|
( Vorticity->needed && !Vorticity->detected) ||
|
|
( VeloPot->needed && !VeloPot->detected) ||
|
|
( StreamF->needed && !StreamF->detected) ||
|
|
( Omega->needed && !Omega->detected) ||
|
|
( speed->needed && !speed->detected) ||
|
|
( u_wind->needed && !u_wind->detected) ||
|
|
v_wind->selected;
|
|
Divergence->needed = ( u_wind->needed && !u_wind->detected) ||
|
|
( v_wind->needed && !v_wind->detected) ||
|
|
( Omega->needed && !Omega->detected) ||
|
|
( VeloPot->needed && !VeloPot->detected) ||
|
|
Divergence->selected;
|
|
Vorticity->needed = ( u_wind->needed && !u_wind->detected) ||
|
|
( v_wind->needed && !v_wind->detected) ||
|
|
( StreamF->needed && !StreamF->detected) ||
|
|
Vorticity->selected;
|
|
Humidity->needed = (GeopotHeight->needed && !GeopotHeight->detected) ||
|
|
( Rhumidity->needed && !Rhumidity->detected) ||
|
|
Humidity->selected;
|
|
Ps->needed |= dpsdx->needed || dpsdy->needed ||
|
|
Rhumidity->needed || Omega->needed;
|
|
LnPs->needed |= Ps->needed;
|
|
Temperature->needed = (GeopotHeight->needed && !GeopotHeight->detected) ||
|
|
( Rhumidity->needed && !Rhumidity->detected) ||
|
|
( SLP->needed && !SLP->detected) ||
|
|
( w_wind->needed && !w_wind->detected) ||
|
|
Temperature->selected;
|
|
|
|
All[176].needed = ( net_heat->needed && !net_heat->detected) ||
|
|
( net_bot->needed && !net_bot->detected) ||
|
|
( net_atm->needed && !net_atm->detected) ||
|
|
( sw_atm->needed && !sw_atm->detected) ||
|
|
All[176].selected;
|
|
All[177].needed = ( net_heat->needed && !net_heat->detected) ||
|
|
( net_bot->needed && !net_bot->detected) ||
|
|
( net_atm->needed && !net_atm->detected) ||
|
|
( lw_atm->needed && !lw_atm->detected) ||
|
|
All[177].selected;
|
|
All[178].needed = ( net_top->needed && !net_top->detected) ||
|
|
( net_atm->needed && !net_atm->detected) ||
|
|
( sw_atm->needed && !sw_atm->detected) ||
|
|
All[178].selected;
|
|
All[179].needed = ( net_top->needed && !net_top->detected) ||
|
|
( net_atm->needed && !net_atm->detected) ||
|
|
( lw_atm->needed && !lw_atm->detected) ||
|
|
All[179].selected;
|
|
}
|
|
|
|
void CheckContent(void)
|
|
{
|
|
int code;
|
|
|
|
for (code = 0; code < 256; code++)
|
|
{
|
|
if (code == GEOSCODE) continue;
|
|
if (code == SLPCODE) continue;
|
|
if (code == ZCODE) continue;
|
|
if (code == STRCODE) continue;
|
|
if (code == VELCODE) continue;
|
|
if (code == UCODE) continue;
|
|
if (code == VCODE) continue;
|
|
if (code == WCODE) continue;
|
|
if (code == RHCODE) continue;
|
|
if (code == PSCODE) continue;
|
|
if (code == WZCODE) continue;
|
|
if (code == SHCODE)
|
|
{
|
|
if (All[code].needed && !All[code].selected &&
|
|
All[code].hsp.size() == 0 &&
|
|
All[code].hgp.size() == 0 &&
|
|
HumInfo == 0)
|
|
{
|
|
printf("\n ********* I N F O **********\n");
|
|
printf( " * No humidity in data file *\n");
|
|
printf( " * Humidity set to zero ! *\n");
|
|
printf( " ****************************\n");
|
|
All[code].needed = FALSE;
|
|
HumInfo = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (All[code].needed &&
|
|
All[code].hsp.size() == 0 &&
|
|
All[code].hgp.size() == 0)
|
|
{
|
|
printf("\n ****** E R R O R ******\n");
|
|
printf(" * Code %3d not found *\n",code);
|
|
printf(" ***********************\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Dependencies(void)
|
|
{
|
|
int code;
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
All[code].needed = All[code].selected;
|
|
|
|
CheckDependencies();
|
|
|
|
if (OutRep >= PRE_GRID)
|
|
{
|
|
u_wind->needed |= Divergence->needed;
|
|
v_wind->needed |= Divergence->needed;
|
|
u_wind->needed |= Vorticity->needed;
|
|
v_wind->needed |= Vorticity->needed;
|
|
u_wind->needed |= VeloPot->needed;
|
|
v_wind->needed |= VeloPot->needed;
|
|
u_wind->needed |= StreamF->needed;
|
|
v_wind->needed |= StreamF->needed;
|
|
}
|
|
|
|
Omega->needed |= w_wind->needed;
|
|
dpsdx->needed |= Omega->needed;
|
|
dpsdy->needed |= Omega->needed;
|
|
|
|
if (VerType == 'p')
|
|
{
|
|
LnPs->needed = TRUE;
|
|
Divergence->needed |= Omega->needed;
|
|
u_wind->needed |= Omega->needed;
|
|
v_wind->needed |= Omega->needed;
|
|
u_wind->needed |= speed->needed;
|
|
v_wind->needed |= speed->needed;
|
|
Temperature->needed |= Omega->needed || SLP->needed;
|
|
Humidity->needed |= GeopotHeight->needed || Rhumidity->needed;
|
|
Temperature->needed |= GeopotHeight->needed || Rhumidity->needed ||
|
|
ThetaF->needed;
|
|
}
|
|
|
|
Divergence->needed |= u_wind->needed || v_wind->needed;
|
|
Vorticity->needed |= u_wind->needed || v_wind->needed;
|
|
Divergence->needed |= VeloPot->needed;
|
|
Vorticity->needed |= StreamF->needed;
|
|
LnPs->needed |= HalfPress->needed || dpsdx->needed ||
|
|
Ps->needed || Rhumidity->needed;
|
|
|
|
All[139].needed |= ThetaF->selected;
|
|
All[142].needed |= precip->selected || net_water->selected ||
|
|
fresh_water->selected || surf_runoff->selected;
|
|
All[143].needed |= precip->selected || net_water->selected ||
|
|
fresh_water->selected || surf_runoff->selected;
|
|
All[146].needed |= net_heat->selected; /* sensible heat */
|
|
All[147].needed |= net_heat->selected; /* latent heat */
|
|
All[160].needed |= net_water->selected; /* Runoff */
|
|
All[176].needed |= net_heat->selected ||
|
|
net_bot->selected ||
|
|
net_atm->selected || sw_atm->selected;
|
|
All[177].needed |= net_heat->selected ||
|
|
net_bot->selected ||
|
|
net_atm->selected || lw_atm->selected;
|
|
All[178].needed |= net_top->selected ||
|
|
net_atm->selected || sw_atm->selected;
|
|
All[179].needed |= net_top->selected ||
|
|
net_atm->selected || lw_atm->selected;
|
|
All[182].needed |= net_water->selected ||
|
|
fresh_water->selected || surf_runoff->selected;
|
|
All[218].needed |= net_heat->selected; /* snow melt */
|
|
All[221].needed |= surf_runoff->selected; /* snow depth change */
|
|
|
|
}
|
|
|
|
void Speed(double *speed, double *u, double *v)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < Dim3GP; i++)
|
|
speed[i] = sqrt(u[i] * u[i] + v[i] * v[i]);
|
|
}
|
|
|
|
|
|
// ======================================================
|
|
// Compute derivation d(LnPs)/d(sin phi) in fourier space
|
|
// ======================================================
|
|
|
|
void Deriva(double field[], double derilam[])
|
|
{
|
|
int l,n;
|
|
int i;
|
|
|
|
i = 0;
|
|
for (n = 0; n < Waves ; n++)
|
|
{
|
|
for (l = 0; l < Lats; l++,i++) // cosine coefficients
|
|
derilam[i] = -n * field[i+Lats] * DerivationFactor[l];
|
|
for (l = 0; l < Lats; l++,i++) // sine coefficients
|
|
derilam[i] = n * field[i-Lats] * DerivationFactor[l];
|
|
}
|
|
}
|
|
|
|
void scaluv(double *fu, double Factor[], int nlat, int nlot)
|
|
{
|
|
for (int lot = 0; lot < nlot; lot++)
|
|
for (int lat = 0; lat < nlat; lat++)
|
|
{
|
|
*fu++ *= Factor[lat];
|
|
}
|
|
}
|
|
|
|
void uv2dv(double *fu, double *fv, double *sd, double *sv,
|
|
double *pol2, double *poli, int klev, int nlat, int nt)
|
|
{
|
|
int lev,jmm,jfc,lat;
|
|
double dir,dii,vor,voi;
|
|
double *ufr,*ufi,*vfr,*vfi;
|
|
double *po2,*pod;
|
|
double zo2, zod;
|
|
double gmuq;
|
|
for (lev = 0; lev < klev; lev++)
|
|
{
|
|
if (PolyDisk)
|
|
{
|
|
rewind(pol2f);
|
|
rewind(polif);
|
|
}
|
|
po2 = pol2;
|
|
pod = poli;
|
|
for (jmm = 0; jmm <= nt; jmm++)
|
|
{
|
|
for (jfc = jmm; jfc <= nt; jfc++)
|
|
{
|
|
ufr = fu ;
|
|
ufi = fu + nlat ;
|
|
vfr = fv ;
|
|
vfi = fv + nlat ;
|
|
dir = 0.0 ;
|
|
dii = 0.0 ;
|
|
vor = 0.0 ;
|
|
voi = 0.0 ;
|
|
if (PolyDisk)
|
|
{
|
|
fread(po2=pol2,sizeof(double),Lats,pol2f);
|
|
fread(pod=poli,sizeof(double),Lats,polif);
|
|
}
|
|
for (lat = 0; lat < nlat; lat++)
|
|
{
|
|
gmuq = 1.0 - Outlat->gmu[lat] * Outlat->gmu[lat];
|
|
zod = *pod * 0.5 * jmm * Outlat->gwt[lat] / (PlanetRadius * gmuq);
|
|
zo2 = *po2 * Outlat->gwt[lat] / gmuq;
|
|
dir += *vfr * zo2 - *ufi * zod;
|
|
dii += *vfi * zo2 + *ufr * zod;
|
|
vor -= *ufr * zo2 + *vfi * zod;
|
|
voi -= *ufi * zo2 - *vfr * zod;
|
|
ufr++;
|
|
ufi++;
|
|
vfr++;
|
|
vfi++;
|
|
po2++;
|
|
pod++;
|
|
}
|
|
*sd++ = dir;
|
|
*sd++ = dii;
|
|
*sv++ = vor;
|
|
*sv++ = voi;
|
|
}
|
|
fu += 2 * nlat;
|
|
fv += 2 * nlat;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void genind(int *Interpolation_Index, double lv[],
|
|
double *Full_Level_Pressure, int DimGP, int OutLevs)
|
|
{
|
|
int h,k,l;
|
|
int *nx;
|
|
double Pressure,*pf;
|
|
nx = Interpolation_Index;
|
|
for (h=0 ; h < DimGP * OutLevs ; ++h) nx[h] = -1;
|
|
for (k = 0; k<OutLevs; k++)
|
|
{
|
|
Pressure = lv[k];
|
|
pf = Full_Level_Pressure;
|
|
for (l = 0; l<SigLevs; l++)
|
|
for (h = 0; h<DimGP ; h++)
|
|
{
|
|
if (Pressure > *pf) nx[h] = l;
|
|
pf++;
|
|
}
|
|
nx += DimGP;
|
|
}
|
|
}
|
|
|
|
|
|
void theta(double *PThetaF, double *PThetaH, double *PH, double *PS,
|
|
double *TF, double *TS, int DimGP, int Dim3GP)
|
|
{
|
|
int h,l;
|
|
double Kappa = RD / RCPD;
|
|
double *ThetaH = PThetaH;
|
|
double *ThetaF = PThetaF;
|
|
|
|
for (h = 0; h < DimGP; h++) ThetaH[h] = 0.0;
|
|
ThetaH += DimGP;
|
|
for (l = 0; l < SigLevs - 1; l++)
|
|
{
|
|
for (h = 0; h < DimGP; h++)
|
|
{
|
|
ThetaH[h] = 0.5 * (TF[h] + TF[h+DimGP]) * pow((PS[h]/PH[h]),Kappa);
|
|
}
|
|
PH += DimGP;
|
|
TF += DimGP;
|
|
ThetaH += DimGP;
|
|
}
|
|
memcpy(ThetaH,TS,DimGP * sizeof(double));
|
|
ThetaH = PThetaH;
|
|
for (h = 0; h < Dim3GP; h++)
|
|
{
|
|
ThetaF[h] = 0.5 * (ThetaH[h] + ThetaH[h+DimGP]);
|
|
}
|
|
}
|
|
|
|
|
|
void presh(double *pf, double *php, double *vct, double *ps)
|
|
{
|
|
int h,l;
|
|
double zp,ze;
|
|
double *ph = php;
|
|
|
|
for (l = 0; l<SigLevs; l++)
|
|
{
|
|
zp = vct[l];
|
|
ze = vct[l+SigLevs+1];
|
|
for (h = 0; h<DimGP; h++) ph[h] = zp + ze * ps[h];
|
|
ph += DimGP;
|
|
}
|
|
memcpy(ph,ps,DimGP * sizeof(double));
|
|
ph = php;
|
|
for (h = 0; h<Dim3GP; h++) pf[h] = 0.5 * (ph[h] + ph[h+DimGP]);
|
|
}
|
|
|
|
|
|
/*****************************/
|
|
/* Compute relative humidity */
|
|
/*****************************/
|
|
|
|
double relhum(double q, double t, double p)
|
|
{
|
|
double rh;
|
|
double gascon;
|
|
double rv;
|
|
double TMELT;
|
|
double ra1;
|
|
double ra2;
|
|
double ra4;
|
|
double rdbrv;
|
|
double zqsat;
|
|
|
|
rv = 461.51;
|
|
TMELT = 273.16;
|
|
gascon = 287.0 ;
|
|
ra1 = 610.78;
|
|
ra2 = 17.2693882;
|
|
ra4 = 35.86;
|
|
rdbrv = gascon / rv;
|
|
|
|
zqsat = rdbrv * ra1 * exp(ra2 * (t-TMELT) / (t-ra4)) / p;
|
|
zqsat *= 1.0 / (1.0 - (1.0 / rdbrv - 1.0) * zqsat);
|
|
rh = q * 100.0 / zqsat;
|
|
if (rh < 0.0) rh = 0.0;
|
|
if (rh > 100.0) rh = 100.0;
|
|
|
|
return rh;
|
|
}
|
|
|
|
/*****************************/
|
|
/* Compute relative humidity */
|
|
/*****************************/
|
|
|
|
void sh2rh(double *sphum, double *rhum, double *t, int lev)
|
|
{
|
|
int jhor,jlev;
|
|
double *pp; // pressure
|
|
|
|
pp = &FullPress->hgp[0];
|
|
|
|
for (jlev = 0; jlev < lev; jlev++)
|
|
for (jhor = 0; jhor < DimGP; jhor++)
|
|
*rhum++ = relhum(*sphum++,*t++,*pp++);
|
|
}
|
|
|
|
|
|
void dv2ps(double *div, double *pot, int lev)
|
|
{
|
|
for (int l = 0; l < lev ; l++)
|
|
for (int m = 0; m <= Truncation; m++)
|
|
for (int n = m; n <= Truncation; n++)
|
|
{
|
|
if (n)
|
|
{
|
|
*pot++ = *div++ * SQUARE_RADIUS / (n * n + n);
|
|
*pot++ = *div++ * SQUARE_RADIUS / (n * n + n);
|
|
}
|
|
else
|
|
{
|
|
*pot++ = 0.0;
|
|
*pot++ = 0.0;
|
|
div += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void MakeGeopotHeight(double *geop, double* gt, double *gq, double *ph, int nhor, int nlev)
|
|
{
|
|
int i;
|
|
|
|
double VTMP = (RV / RD) - 1.0;
|
|
double zrg = 1.0 / Grav;
|
|
|
|
if (gq) /* Humidity is present */ {
|
|
for (i = nhor * nlev - 1; i >= nhor; i--)
|
|
geop[i] = geop[i+nhor] + RD * gt[i] * (1.0 + VTMP * gq[i])
|
|
* log(ph[i+nhor] / ph[i]);
|
|
|
|
for (i = 0; i < nhor; i++)
|
|
geop[i] = geop[i+nhor] + RD * gt[i] * (1.0 + VTMP * gq[i])
|
|
* 2.0 * log(2.0);
|
|
}
|
|
else /* No humidity */ {
|
|
for (i = nhor * nlev - 1; i >= nhor; i--)
|
|
geop[i] = geop[i+nhor] + RD * gt[i] * log(ph[i+nhor] / ph[i]);
|
|
|
|
for (i = 0; i < nhor; i++)
|
|
geop[i] = geop[i+nhor] + RD * gt[i] * 2.0 * log(2.0);
|
|
}
|
|
|
|
for (i = 0; i < nhor * (nlev+1); i++) geop[i] *= zrg;
|
|
}
|
|
|
|
|
|
void gp2fc_uv(void)
|
|
{
|
|
u_wind->SetPFour();
|
|
v_wind->SetPFour();
|
|
gp2fc(&u_wind->pgp[0],&u_wind->pfc[0],Lats,Lons,OutLevs,Fouriers);
|
|
gp2fc(&v_wind->pgp[0],&v_wind->pfc[0],Lats,Lons,OutLevs,Fouriers);
|
|
}
|
|
|
|
|
|
void fc2sp_uv(void)
|
|
{
|
|
scaluv(&u_wind->pfc[0],CosPhi,Lats,Fouriers*OutLevs);
|
|
scaluv(&v_wind->pfc[0],CosPhi,Lats,Fouriers*OutLevs);
|
|
|
|
u_wind->SetPSpec();
|
|
v_wind->SetPSpec();
|
|
Divergence->SetPSpec();
|
|
Vorticity->SetPSpec();
|
|
|
|
fc2sp(&u_wind->pfc[0],&u_wind->psp[0],OutLevs,Lats,Truncation);
|
|
fc2sp(&v_wind->pfc[0],&v_wind->psp[0],OutLevs,Lats,Truncation);
|
|
|
|
uv2dv(&u_wind->pfc[0],&v_wind->pfc[0],
|
|
&Divergence->psp[0],&Vorticity->psp[0],pol2,poli,OutLevs,Lats,Truncation);
|
|
|
|
if (VeloPot->needed)
|
|
{
|
|
VeloPot->plev = OutLevs;
|
|
VeloPot->SetPSpec();
|
|
dv2ps(&Divergence->psp[0],&VeloPot->psp[0],OutLevs);
|
|
}
|
|
|
|
if (StreamF->needed)
|
|
{
|
|
StreamF->plev = OutLevs;
|
|
StreamF->SetPSpec();
|
|
dv2ps(&Vorticity->psp[0],&StreamF->psp[0],OutLevs);
|
|
}
|
|
}
|
|
|
|
|
|
void sp2fc_uv(void)
|
|
{
|
|
for (int si = 0 ; si < 4 ; ++si)
|
|
{
|
|
int code = SpecialCodes[si];
|
|
if (All[code].selected && All[code].psp.size())
|
|
{
|
|
All[code].SetPFour();
|
|
sp2fci(&All[code].psp[0],&All[code].pfc[0],OutLevs);
|
|
}
|
|
}
|
|
if (u_wind->selected && u_wind->pfc.size())
|
|
scaluv(&u_wind->pfc[0],RevCosPhi,Lats,Fouriers*OutLevs);
|
|
if (v_wind->selected && v_wind->pfc.size())
|
|
scaluv(&v_wind->pfc[0],RevCosPhi,Lats,Fouriers*OutLevs);
|
|
}
|
|
|
|
|
|
void fc2gp_uv(void)
|
|
{
|
|
for (int si = 0 ; si < 4 ; ++si)
|
|
{
|
|
int code = SpecialCodes[si];
|
|
if (All[code].selected && All[code].pfc.size())
|
|
{
|
|
All[code].SetPGrid();
|
|
fc2gp(&All[code].pfc[0],&All[code].pgp[0],Lats,Lons,OutLevs,Fouriers);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void PumaProcess(void)
|
|
{
|
|
int code;
|
|
|
|
MeanCount++; // Count term inside month
|
|
TermCount++; // Count term
|
|
|
|
#ifdef NETCDF_OUTPUT
|
|
if (TermCount == 1 && NetCDF) NetVarDefine(); // Define NetCDF variables
|
|
#endif
|
|
if (MeanCount == 1) CheckContent(); // Everything OK ?
|
|
if (TermCount > 60) Debug = 0; // Limit debug output
|
|
|
|
// Reset level offset for all variables
|
|
|
|
for (code = 0; code < CODES; code++) All[code].loff = 0;
|
|
|
|
// Derive velocity potential and streamfunction from divergence and vorticity
|
|
|
|
if (VeloPot->needed && !VeloPot->detected && VerType == 's')
|
|
{
|
|
VeloPot->SetHSpec(SigLevs,OutLevs,FALSE);
|
|
dv2ps(&Divergence->hsp[0],&VeloPot->hsp[0],SigLevs);
|
|
}
|
|
|
|
if (StreamF->needed && !StreamF->detected && VerType == 's')
|
|
{
|
|
StreamF->SetHSpec(SigLevs,OutLevs,FALSE);
|
|
dv2ps(&Vorticity->hsp[0],&StreamF->hsp[0],SigLevs);
|
|
}
|
|
|
|
// -------------------------
|
|
// Output of spectral fields
|
|
// -------------------------
|
|
|
|
if (OutRep == HYB_SPEC)
|
|
{
|
|
HybSpec->Write_hspec();
|
|
return;
|
|
}
|
|
|
|
// =====================================================
|
|
// Transformation from spectral domain to fourier domain
|
|
// =====================================================
|
|
|
|
// Derive wind components u*cos(phi) and v*cos(phi)
|
|
|
|
if ((u_wind->needed || v_wind->needed) &&
|
|
(!u_wind->detected || !v_wind->detected))
|
|
{
|
|
u_wind->SetHFour(SigLevs,OutLevs,FALSE);
|
|
v_wind->SetHFour(SigLevs,OutLevs,FALSE);
|
|
spvfc(&Divergence->hsp[0],&Vorticity->hsp[0],
|
|
&u_wind->hfc[0] ,&v_wind->hfc[0] ,
|
|
Divergence->hlev ,Lats,Fouriers,Truncation);
|
|
}
|
|
|
|
// If divergence and vorticity were needed for u and v computation
|
|
// only, they are now released
|
|
|
|
Vorticity->needed = Vorticity->selected;
|
|
Divergence->needed = Divergence->selected || Omega->needed;
|
|
|
|
// Perform inverse Legendre transformation for all needed variables
|
|
|
|
for (code = 0 ; code < CODES; code++)
|
|
if (All[code].needed && All[code].hsp.size())
|
|
{
|
|
All[code].SetHFour(All[code].hlev,All[code].plev,All[code].twod);
|
|
sp2fci(&All[code].hsp[0],&All[code].hfc[0],All[code].hlev);
|
|
}
|
|
|
|
// Compute d(Lnps)/dx and d(Lnps)/dy if needed
|
|
|
|
if (dpsdx->needed || dpsdy->needed)
|
|
{
|
|
dpsdx->SetHFour(1,1,TRUE);
|
|
dpsdy->SetHFour(1,1,TRUE);
|
|
Deriva(&LnPs->hfc[0],&dpsdx->hfc[0]);
|
|
sp2fcd(&LnPs->hsp[0],&dpsdy->hfc[0],1,Lats,Fouriers,Truncation);
|
|
}
|
|
|
|
/* ------------------------ */
|
|
/* Output of fourier fields */
|
|
/* ------------------------ */
|
|
|
|
if (OutRep == HYB_FOUR)
|
|
{
|
|
HybFour->Write_hfour();
|
|
return;
|
|
}
|
|
|
|
/* --------------------- */
|
|
/* Output of zonal means */
|
|
/* --------------------- */
|
|
|
|
if (OutRep == HYB_ZONM)
|
|
{
|
|
HybSect->Write_hfour();
|
|
return;
|
|
}
|
|
|
|
/* ============================ */
|
|
/* Transformation to gridpoints */
|
|
/* ============================ */
|
|
|
|
if (SaveMemory) HybSpec->Clear_hspec();
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].needed && All[code].hfc.size())
|
|
{
|
|
All[code].SetHGrid(All[code].hlev,All[code].plev,All[code].twod);
|
|
fc2gp(&All[code].hfc[0],&All[code].hgp[0],Lats,Lons,All[code].hlev,Fouriers);
|
|
}
|
|
|
|
if (SaveMemory) HybSpec->Clear_hfour();
|
|
|
|
if (Humidity->hgp.size()) // Remove spurious negative humidity
|
|
{
|
|
for (int i=0 ; i < Dim3GP ; ++i)
|
|
if (Humidity->hgp[i] < 0.0) Humidity->hgp[i] = 0.0;
|
|
}
|
|
|
|
|
|
if (LnPs->hgp.size())
|
|
{
|
|
Ps->SetHGrid(1,1,TRUE);
|
|
Ps->hgp = exp(LnPs->hgp);
|
|
}
|
|
|
|
LnPs->needed = LnPs->selected;
|
|
|
|
if (Orography.size() != DimGP)
|
|
{
|
|
Orography.resize(DimGP);
|
|
if (Geopotential->hgp.size()) Orography = Geopotential->hgp;
|
|
else
|
|
{
|
|
if (Geopotential->selected || VerType == 'p')
|
|
{
|
|
CenterText("Orography not found - using zero orography");
|
|
Orography = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Geopotential->needed = Geopotential->selected;
|
|
|
|
if (Geopotential->needed && !Geopotential->hgp.size())
|
|
{
|
|
Geopotential->SetHGrid(1,1,TRUE);
|
|
Geopotential->hgp = Orography;
|
|
}
|
|
|
|
// This section is implemented for pressure level fields only
|
|
|
|
if (VerType == 'p' || Omega->needed)
|
|
{
|
|
FullPress->SetHGrid(SigLevs ,OutLevs,FALSE);
|
|
HalfPress->SetHGrid(SigLevs+1,OutLevs,FALSE);
|
|
presh(&FullPress->hgp[0],&HalfPress->hgp[0],vct,&Ps->hgp[0]);
|
|
|
|
if (ThetaF->needed)
|
|
{
|
|
ThetaF->SetHGrid(SigLevs,OutLevs,FALSE);
|
|
ThetaH->SetHGrid(SigLevs,OutLevs,FALSE);
|
|
theta(&ThetaF->hgp[0], &ThetaH->hgp[0], &HalfPress->hgp[0], &Ps->hgp[0],
|
|
&Temperature->hgp[0], &Ts->hgp[0], DimGP, Dim3GP);
|
|
}
|
|
|
|
if (GeopotHeight->needed)
|
|
{
|
|
GeopotHeight->SetHGrid(SigLevs+1,OutLevs,FALSE);
|
|
memcpy(&GeopotHeight->hgp[Dim3GP],&Orography[0],DimGP * sizeof(double));
|
|
MakeGeopotHeight(&GeopotHeight->hgp[0],&Temperature->hgp[0],
|
|
&Humidity->hgp[0],&HalfPress->hgp[0],DimGP,SigLevs);
|
|
Humidity->needed = Humidity->selected;
|
|
}
|
|
|
|
if (dpsdx->needed) dpsdx->hgp *= Ps->hgp;
|
|
if (dpsdy->needed) dpsdy->hgp *= Ps->hgp;
|
|
|
|
if (Omega->needed)
|
|
{
|
|
Omega->SetHGrid(SigLevs+1,OutLevs,FALSE);
|
|
OMEGA();
|
|
dpsdx->needed = dpsdx->selected;
|
|
dpsdy->needed = dpsdy->selected;
|
|
}
|
|
|
|
if (w_wind->needed)
|
|
{
|
|
w_wind->SetHGrid(SigLevs,OutLevs,FALSE);
|
|
Omega_w(&w_wind->hgp[0],&Omega->hgp[0],&Temperature->hgp[0],&FullPress->hgp[0]);
|
|
}
|
|
|
|
if (Rhumidity->needed)
|
|
{
|
|
Rhumidity->SetHGrid(SigLevs,OutLevs,FALSE);
|
|
sh2rh(&Humidity->hgp[0],&Rhumidity->hgp[0],
|
|
&Temperature->hgp[0],SigLevs);
|
|
|
|
Temperature->needed = Temperature->selected;
|
|
Humidity->needed = Humidity->selected;
|
|
}
|
|
|
|
if (SLP->needed)
|
|
{
|
|
SLP->SetHGrid(1,1,TRUE);
|
|
Extrap(&SLP->hgp[0],&HalfPress->hgp[0] + Dim3GP,
|
|
&FullPress->hgp[0] + Dim3GP - DimGP , &Orography[0],
|
|
&Temperature->hgp[0] + Dim3GP - DimGP , DimGP);
|
|
Temperature->needed = Temperature->selected || GeopotHeight->selected;
|
|
}
|
|
|
|
} // endif (VerType == 'p')
|
|
|
|
if (speed->needed)
|
|
{
|
|
speed->SetHGrid(SigLevs,OutLevs,FALSE);
|
|
Speed(&speed->hgp[0],&u_wind->hgp[0],&v_wind->hgp[0]);
|
|
}
|
|
|
|
if (precip->needed)
|
|
{
|
|
precip->SetHGrid(1,1,TRUE);
|
|
precip->hgp = All[142].hgp + All[143].hgp;
|
|
}
|
|
|
|
if (net_top->needed)
|
|
{
|
|
net_top->SetHGrid(1,1,TRUE);
|
|
net_top->hgp = All[178].hgp + All[179].hgp;
|
|
}
|
|
|
|
if (net_bot->needed)
|
|
{
|
|
net_bot->SetHGrid(1,1,TRUE);
|
|
net_bot->hgp = All[176].hgp + All[177].hgp;
|
|
}
|
|
|
|
if (net_heat->needed)
|
|
{
|
|
net_heat->SetHGrid(1,1,TRUE);
|
|
net_heat->hgp = All[218].hgp * L_times_rhoH2O
|
|
+ All[176].hgp + All[177].hgp + All[146].hgp + All[147].hgp;
|
|
}
|
|
|
|
if (net_water->needed)
|
|
{
|
|
net_water->SetHGrid(1,1,TRUE);
|
|
net_water->hgp = All[182].hgp - All[160].hgp + All[142].hgp + All[143].hgp;
|
|
}
|
|
|
|
if (sw_atm->needed)
|
|
{
|
|
sw_atm->SetHGrid(1,1,TRUE);
|
|
sw_atm->hgp = All[178].hgp - All[176].hgp;
|
|
}
|
|
|
|
if (lw_atm->needed)
|
|
{
|
|
lw_atm->SetHGrid(1,1,TRUE);
|
|
lw_atm->hgp = All[179].hgp - All[177].hgp;
|
|
}
|
|
|
|
if (net_atm->needed)
|
|
{
|
|
net_atm->SetHGrid(1,1,TRUE);
|
|
net_atm->hgp = All[178].hgp + All[179].hgp - All[176].hgp - All[177].hgp;
|
|
}
|
|
|
|
if (surf_runoff->needed)
|
|
{
|
|
surf_runoff->SetHGrid(1,1,TRUE);
|
|
surf_runoff->hgp = All[182].hgp - All[221].hgp + All[142].hgp + All[143].hgp;
|
|
}
|
|
|
|
if (fresh_water->needed)
|
|
{
|
|
fresh_water->SetHGrid(1,1,TRUE);
|
|
fresh_water->hgp = All[142].hgp + All[143].hgp + All[182].hgp;
|
|
}
|
|
|
|
// =============================
|
|
// Monthly means on hybrid grids
|
|
// =============================
|
|
|
|
if (Mean && OutRep == HYB_GRID)
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].selected && All[code].hgp.size())
|
|
{
|
|
if (MeanCount == 1)
|
|
{
|
|
All[code].mgp.resize(All[code].hgp.size());
|
|
All[code].mgp = All[code].hgp;
|
|
All[code].hgp.resize(0);
|
|
}
|
|
else All[code].mgp += All[code].hgp;
|
|
if (EndOfMonth)
|
|
{
|
|
double rmc = 1.0 / MeanCount;
|
|
All[code].hgp = All[code].mgp * rmc;
|
|
All[code].mgp.resize(0);
|
|
}
|
|
}
|
|
|
|
// ----------------------------
|
|
// Output of hybrid level grids
|
|
// ----------------------------
|
|
|
|
if (OutRep == HYB_GRID)
|
|
{
|
|
if (!Mean || EndOfMonth) HybGrid->Write_hgrid();
|
|
if (SaveMemory) HybGrid->Clear_hgrid();
|
|
return;
|
|
}
|
|
|
|
// ======================================
|
|
// Vertical interpolation / extrapolation
|
|
// ======================================
|
|
|
|
if (vert_index == NULL) vert_index = new int[OutLevs*DimGP];
|
|
genind(vert_index,level,&FullPress->hgp[0],DimGP,OutLevs);
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].needed && All[code].hgp.size())
|
|
{
|
|
All[code].SetPGrid();
|
|
if (!All[code].twod)
|
|
{
|
|
if (code == ZCODE) Interpolate_Z();
|
|
else Interpolate_T(code);
|
|
}
|
|
}
|
|
Temperature->needed = Temperature->selected;
|
|
if (SaveMemory) HybGrid->Clear_hgrid();
|
|
|
|
// ===========================
|
|
// Computation of Montly Means
|
|
// ===========================
|
|
|
|
if (Mean)
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].needed && All[code].pgp.size())
|
|
{
|
|
if (MeanCount == 1)
|
|
{
|
|
All[code].mgp.resize(All[code].pgp.size());
|
|
All[code].mgp = All[code].pgp;
|
|
All[code].pgp.resize(0);
|
|
}
|
|
else All[code].mgp += All[code].pgp;
|
|
if (EndOfMonth)
|
|
{
|
|
double rmc = 1.0 / MeanCount;
|
|
All[code].pgp = All[code].mgp * rmc;
|
|
All[code].mgp.resize(0);
|
|
}
|
|
}
|
|
|
|
if (Mean && !EndOfMonth)
|
|
{
|
|
if (SaveMemory) HybGrid->Clear_pgrid();
|
|
return;
|
|
}
|
|
|
|
// ------------------------------
|
|
// Output of pressure level grids
|
|
// ------------------------------
|
|
|
|
if (OutRep == PRE_GRID)
|
|
{
|
|
if (SpecialUV)
|
|
{
|
|
gp2fc_uv();
|
|
fc2sp_uv();
|
|
sp2fc_uv();
|
|
fc2gp_uv();
|
|
}
|
|
|
|
HybGrid->Write_pgrid();
|
|
if (SaveMemory) HybGrid->Clear_pgrid();
|
|
return;
|
|
}
|
|
|
|
// ===============================
|
|
// Transformation to fourier space
|
|
// ===============================
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].needed && All[code].pgp.size())
|
|
{
|
|
if (!All[code].pfc.size()) All[code].SetPFour();
|
|
gp2fc(&All[code].pgp[0],&All[code].pfc[0],
|
|
Lats,Lons,All[code].plev,Fouriers);
|
|
}
|
|
|
|
if (SaveMemory) HybGrid->Clear_pgrid();
|
|
|
|
// ---------------------------------------
|
|
// Output of fourier fields or zonal means
|
|
// ---------------------------------------
|
|
|
|
if (OutRep == PRE_FOUR || OutRep == PRE_ZONM)
|
|
{
|
|
if (SpecialUV)
|
|
{
|
|
fc2sp_uv();
|
|
sp2fc_uv();
|
|
}
|
|
if (OutRep == PRE_FOUR) HybFour->Write_pfour();
|
|
else HybSect->Write_pfour();
|
|
if (SaveMemory) HybFour->Clear_pfour();
|
|
return;
|
|
}
|
|
|
|
// ================================
|
|
// Transformation to spectral space
|
|
// ================================
|
|
|
|
if (!SpecialUV && u_wind->pfc.size() && v_wind->pfc.size())
|
|
{
|
|
scaluv(&u_wind->pfc[0],CosPhi,Lats,Fouriers*OutLevs);
|
|
scaluv(&v_wind->pfc[0],CosPhi,Lats,Fouriers*OutLevs);
|
|
}
|
|
|
|
for (code = 0; code < CODES; code++)
|
|
if (All[code].needed && All[code].pfc.size() && !All[code].psp.size())
|
|
{
|
|
All[code].SetPSpec();
|
|
fc2sp(&All[code].pfc[0],&All[code].psp[0],All[code].plev,Lats,Truncation);
|
|
}
|
|
|
|
if (SpecialUV) fc2sp_uv();
|
|
|
|
if (SaveMemory) HybFour->Clear_pfour();
|
|
|
|
// -------------------------
|
|
// Output of spectral fields
|
|
// -------------------------
|
|
|
|
if (OutRep == PRE_SPEC)
|
|
{
|
|
HybSpec->Write_pspec();
|
|
if (SaveMemory) HybSpec->Clear_pspec();
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void PostProcess(void)
|
|
{
|
|
int l;
|
|
char tb[COLS+2];
|
|
if (EndOfMonth)
|
|
{
|
|
sprintf(tb,"Processed Month %2d Year %4d", OldMonth,OldDate.tm_year);
|
|
l = strlen(tb);
|
|
if (MeanCount > 1)
|
|
{
|
|
if (Mean) sprintf(tb+l," (Mean of %3d Terms)",MeanCount);
|
|
else sprintf(tb+l," Terms %3d",MeanCount);
|
|
}
|
|
LeftText(tb);
|
|
EndOfMonth = FALSE;
|
|
MeanCount = 0;
|
|
MonthCount++ ;
|
|
}
|
|
}
|
|
|
|
/* ================= */
|
|
/* switch input file */
|
|
/* ================= */
|
|
|
|
void SwitchFile(void)
|
|
{
|
|
int l,YY,MM;
|
|
|
|
fclose(fpi);
|
|
l = strlen(ifile);
|
|
if (l > 4 && ifile[l-4] == '.' && atoi(ifile+l-3) != 0) // .YYY
|
|
{
|
|
YY = atoi(ifile+l-3) + 1;
|
|
sprintf(ifile+l-3,"%03d",YY);
|
|
}
|
|
else if (l > 5 && ifile[l-5] == '_' && atoi(ifile+l-4) != 0) // _YYYY
|
|
{
|
|
YY = atoi(ifile+l-4) + 1;
|
|
sprintf(ifile+l-4,"%04d",YY);
|
|
}
|
|
else if (l > 7 && ifile[l-7] == '_' && atoi(ifile+l-6) != 0) // _YYYYMM
|
|
{
|
|
MM = atoi(ifile+l-2);
|
|
YY = atoi(ifile+l-6);
|
|
if (MM == 12) YY += 88;
|
|
if (YY > 1) sprintf(ifile+l-6,"%06d",++YY);
|
|
}
|
|
else if (l > 5 && atoi(ifile+l-5) != 0) // "YYYMM" at end
|
|
{
|
|
MM = atoi(ifile+l-2);
|
|
YY = atoi(ifile+l-5);
|
|
if (MM == 12) YY += 88;
|
|
if (YY > 1) sprintf(ifile+l-5,"%05d",++YY);
|
|
}
|
|
else if (l > 4 && atoi(ifile+l-4) != 0) // "YYMM" at end
|
|
{
|
|
MM = atoi(ifile+l-2);
|
|
YY = atoi(ifile+l-4);
|
|
if (MM == 12) YY += 88;
|
|
if (YY > 1) sprintf(ifile+l-4,"%04d",++YY);
|
|
}
|
|
|
|
Multi--;
|
|
printf("Continuation File: %s\n",ifile);
|
|
fpi = fopen(ifile,"rb");
|
|
}
|
|
|
|
/* ====================================== */
|
|
/* Interpolate gauss grid to regular grid */
|
|
/* ====================================== */
|
|
|
|
void Regauss(double *r, double *g, double *Ghi)
|
|
{
|
|
int j,jlon,jlat;
|
|
double np,sp,fn,fs,fe,fw;
|
|
double rphi,rlam,gdx,rdx;
|
|
double *Gam;
|
|
|
|
Gam = new double[Gons];
|
|
|
|
gdx = 360.0 / Gons;
|
|
rdx = 360.0 / Lons;
|
|
|
|
np = sp = 0.0;
|
|
for (jlon = 0 ; jlon < Gons ; ++jlon)
|
|
{
|
|
np += g[jlon];
|
|
sp += g[jlon + DimGG - Gons];
|
|
}
|
|
|
|
np /= Gons;
|
|
sp /= Gons;
|
|
|
|
for (jlat = 0 ; jlat < Lats ; ++jlat)
|
|
{
|
|
rphi = Outlat->Phi[jlat];
|
|
if (rphi > Ghi[0]) // far north
|
|
{
|
|
fn = (rphi - Ghi[0]) / (90.0 - Ghi[0]);
|
|
fs = 1.0 - fn;
|
|
for (jlon = 0 ; jlon < Gons ; ++jlon)
|
|
Gam[jlon] = fn * np + fs * g[jlon];
|
|
}
|
|
else if (rphi < Ghi[Gats-1]) // far south
|
|
{
|
|
fs = (Ghi[Gats-1] - rphi) / (Ghi[Gats-1] + 90.0);
|
|
fn = 1.0 - fs;
|
|
for (jlon = 0 ; jlon < Gons ; ++jlon)
|
|
Gam[jlon] = fn * g[jlon + DimGG - Gons] + fs * sp;
|
|
}
|
|
else // inside
|
|
{
|
|
j = 0; // search neighboured gauss latitudes
|
|
while (j < Gats-1 && rphi < Ghi[j]) ++j;
|
|
fn = (rphi - Ghi[j]) / (Ghi[j-1] - Ghi[j]);
|
|
fs = 1.0 - fn;
|
|
for (jlon = 0 ; jlon < Gons ; ++jlon)
|
|
Gam[jlon] = fn * g[jlon+(j-1)*Gons] + fs * g[jlon+j*Gons];
|
|
}
|
|
|
|
for (jlon = 0 ; jlon < Lons ; ++jlon)
|
|
{
|
|
rlam = jlon * rdx;
|
|
j = (int)floor(rlam / gdx);
|
|
fe = (rlam - j * gdx) / gdx;
|
|
fw = 1.0 - fe;
|
|
if (j >= Gons-1) r[jlon + jlat * Lons] = fw * Gam[j] + fe * Gam[0];
|
|
else r[jlon + jlat * Lons] = fw * Gam[j] + fe * Gam[j+1];
|
|
}
|
|
}
|
|
delete Gam;
|
|
}
|
|
|
|
|
|
/*******************/
|
|
/* SetOutputHeader */
|
|
/*******************/
|
|
|
|
void SetOutputHeader(void)
|
|
{
|
|
int MM,DD,HH;
|
|
|
|
if (DPM > 99) // Workaround for months with more than 99 days
|
|
{
|
|
MM = (TermCount / DPM) % 12 + 1;
|
|
HeadOu[2] = OldDate.tm_year * 10000 + MM * 100;
|
|
HeadOu[3] = 0;
|
|
if (!Mean) // Add day & hour info
|
|
{
|
|
HeadOu[2] += (TermCount % DPM) / DayDivisor + 1;
|
|
HeadOu[3] = 100 * (24 / DayDivisor) * ((TermCount % DPM) % DayDivisor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HeadOu[2] = OldDate.tm_year * 10000 + OldDate.tm_mon * 100;
|
|
HeadOu[3] = 0;
|
|
if (!Mean)
|
|
{
|
|
HeadOu[2] += OldDate.tm_mday;
|
|
HeadOu[3] = OldDate.tm_hour * 100 + OldDate.tm_min;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*****************/
|
|
/* Puma Control */
|
|
/*****************/
|
|
|
|
void PumaControl(void)
|
|
{
|
|
int i;
|
|
int LevelOffset;
|
|
int Eof;
|
|
char tb[COLS+2];
|
|
struct tm D1;
|
|
struct tm D2;
|
|
|
|
while (1)
|
|
{
|
|
Eof = ReadHeaderRecord();
|
|
if (Eof && Multi)
|
|
{
|
|
SwitchFile();
|
|
if (fpi) Eof = ReadHeaderRecord();
|
|
}
|
|
|
|
if (DataStep < 0.01) // Compute time interval
|
|
{
|
|
if (HeadIn[2] != HeadSt[2] || HeadIn[3] != HeadSt[3])
|
|
{
|
|
HeadToDate(HeadSt,&D1);
|
|
HeadToDate(HeadIn,&D2);
|
|
DeltaDy = D2.tm_mday - D1.tm_mday;
|
|
DeltaHr = D2.tm_hour - D1.tm_hour;
|
|
DeltaMn = D2.tm_min - D1.tm_min ;
|
|
if (DeltaDy < 0) DeltaDy = 1; // month changed after 1.st term
|
|
DataStep = DeltaDy + DeltaHr / 24.0 + DeltaMn / 1440.0;
|
|
}
|
|
}
|
|
|
|
if ((HeadIn[2] / 100 % 100) > LastMonth && DayDivisor == 0) // Ignore rest of file
|
|
{
|
|
Eof = 1;
|
|
if (Multi)
|
|
{
|
|
SwitchFile();
|
|
if (fpi) Eof = ReadHeaderRecord();
|
|
}
|
|
}
|
|
|
|
if (Eof) // Process last read term and finish
|
|
{
|
|
EndOfMonth = TRUE;
|
|
SetOutputHeader();
|
|
PumaProcess();
|
|
PostProcess();
|
|
Dependencies();
|
|
return;
|
|
}
|
|
|
|
DecodePumaHeader();
|
|
|
|
if (NewMonth < FirstMonth) /* Skip months before FirstMonth */
|
|
{
|
|
SkipPumaArray();
|
|
if (Debug)
|
|
{
|
|
if (RepGrib == REP_SPECTRAL) sprintf(tb,"T%04d",Truncation);
|
|
else sprintf(tb,"N%04d",Lons);
|
|
sprintf(tb+5," SKIPPED Code %3d Level%6d %2.2d.%2.2d.%2.2d %2.2d:%2.2d",
|
|
PumaCode,PumaLevel,NewDate.tm_mday,NewDate.tm_mon,NewDate.tm_year,
|
|
NewDate.tm_hour,NewDate.tm_min);
|
|
LeftText(tb);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (Debug)
|
|
{
|
|
if (RepGrib == REP_SPECTRAL) sprintf(tb,"T%04d",Truncation);
|
|
else sprintf(tb,"N%04d",Lons);
|
|
sprintf(tb+5," Code %3d Level%6d %2.2d.%2.2d.%2.2d %2.2d:%2.2d",
|
|
PumaCode,PumaLevel,NewDate.tm_mday,NewDate.tm_mon,NewDate.tm_year,
|
|
NewDate.tm_hour,NewDate.tm_min);
|
|
LeftText(tb);
|
|
}
|
|
|
|
if (OldMonth > 0)
|
|
{
|
|
EndOfMonth = NewMonth != OldMonth;
|
|
EndOfTerm = memcmp(&NewDate,&OldDate,sizeof(struct tm));
|
|
if (EndOfTerm && MeanCount == DPM-1) EndOfMonth = 1;
|
|
if (EndOfTerm)
|
|
{
|
|
SetOutputHeader();
|
|
PumaProcess();
|
|
PostProcess();
|
|
Dependencies();
|
|
}
|
|
}
|
|
OldDate = NewDate;
|
|
OldMonth = NewMonth;
|
|
|
|
if (All[PumaCode].needed)
|
|
{
|
|
if (RepGrib == REP_SPECTRAL) // Spectral array
|
|
{
|
|
if (PumaLevel) All[PumaCode].SetHSpec(SigLevs,OutLevs,FALSE);
|
|
else All[PumaCode].SetHSpec( 1, 1,TRUE );
|
|
if (VerType != 's' || mom[PumaLevel])
|
|
{
|
|
ReadPumaArray(&All[PumaCode].hsp[0]+All[PumaCode].loff);
|
|
All[PumaCode].loff += DimSP;
|
|
}
|
|
else SkipPumaArray();
|
|
}
|
|
else // Gridpoint array
|
|
{
|
|
if (PumaLevel) All[PumaCode].SetHGrid(SigLevs,OutLevs,FALSE);
|
|
else All[PumaCode].SetHGrid( 1, 1,TRUE );
|
|
if (VerType != 's' || mom[PumaLevel])
|
|
{
|
|
if (DimGP == DimGG)
|
|
ReadPumaArray(&All[PumaCode].hgp[0]+All[PumaCode].loff);
|
|
else
|
|
{
|
|
double *ArrayBuffer;
|
|
ArrayBuffer = new double[DimGG];
|
|
ReadPumaArray(ArrayBuffer);
|
|
Regauss(&All[PumaCode].hgp[0]+All[PumaCode].loff,ArrayBuffer,Gaulat->Phi);
|
|
delete ArrayBuffer;
|
|
}
|
|
All[PumaCode].loff += DimGP;
|
|
}
|
|
else SkipPumaArray();
|
|
}
|
|
}
|
|
else SkipPumaArray();
|
|
}
|
|
}
|
|
|
|
char *amatch(char *msr, const char *sub)
|
|
{
|
|
int i,nm,ns;
|
|
nm = strlen(msr);
|
|
ns = strlen(sub);
|
|
|
|
for (i = 0; i < nm-ns; i++)
|
|
if (strncmp(msr+i,sub,ns) == 0) return (msr+i+ns);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int scanpar(const char *name, int def)
|
|
{
|
|
char *cp;
|
|
int value;
|
|
char tb[COLS+2];
|
|
|
|
cp = amatch(namelist,name);
|
|
if (cp == NULL)
|
|
{
|
|
value = def;
|
|
sprintf(tb,"%10.10s = %8d (default)",name,value);
|
|
}
|
|
else
|
|
{
|
|
value = atoi(cp);
|
|
sprintf(tb,"%10.10s = %8d ",name,value);
|
|
}
|
|
LeftText(tb);
|
|
return value;
|
|
}
|
|
|
|
double scanreal(const char *name, double def)
|
|
{
|
|
char *cp;
|
|
double value;
|
|
char tb[COLS+2];
|
|
|
|
cp = amatch(namelist,name);
|
|
if (cp == NULL)
|
|
{
|
|
value = def;
|
|
sprintf(tb,"%10.10s = %8.3f (default)",name,value);
|
|
}
|
|
else
|
|
{
|
|
value = strtod(cp,NULL);
|
|
sprintf(tb,"%10.10s = %8.3f ",name,value);
|
|
}
|
|
LeftText(tb);
|
|
return value;
|
|
}
|
|
|
|
char scantex(const char *name, const char choice[])
|
|
{
|
|
char *cp;
|
|
char value;
|
|
int i;
|
|
char tb[COLS+2];
|
|
|
|
value = choice[0];
|
|
cp = amatch(namelist,name);
|
|
if (cp)
|
|
{
|
|
while (isspace(*cp)) ++cp;
|
|
for (i=1 ; i < strlen(choice) ; ++i)
|
|
{
|
|
if (*cp == choice[i]) value = *cp;
|
|
}
|
|
}
|
|
sprintf(tb,"%10.10s = %c ",name,value);
|
|
LeftText(tb);
|
|
return value;
|
|
}
|
|
|
|
void scantime(void)
|
|
{
|
|
char *cp,*icp;
|
|
int time,i;
|
|
char tb[512];
|
|
|
|
nrqh = 0;
|
|
|
|
cp = amatch(namelist,"timesel");
|
|
if (cp == NULL)
|
|
{
|
|
hours[nrqh++] = -1;
|
|
sprintf(tb,"%10.10s = all ","timesel");
|
|
LeftText(tb);
|
|
return;
|
|
}
|
|
|
|
time = strtol(cp,&icp,10);
|
|
while ((char *)icp != (char *)cp && nrqh < MAX_HOURS) {
|
|
hours[nrqh++] = time;
|
|
cp = icp;
|
|
time = strtol(cp,&icp,10);
|
|
}
|
|
sprintf(tb,"%10.10s = ","timesel");
|
|
for (time = 0 ; time < nrqh ; ++time)
|
|
{
|
|
i = strlen(tb);
|
|
sprintf(tb+i," %02d",hours[time]);
|
|
}
|
|
LeftText(tb);
|
|
}
|
|
|
|
void PrintCodes(void)
|
|
{
|
|
int code;
|
|
char tb[COLS+2];
|
|
|
|
DashLine();
|
|
CenterText("Code Id Name Units ");
|
|
DashLine();
|
|
for (code=0 ; code < MAXCODES ; ++code) if (strncmp(All[code].Na,"Code",4))
|
|
{
|
|
sprintf(tb,"%4d %-8.8s %-32.32s %-16.16s",code,All[code].Id,All[code].Na,All[code].Un);
|
|
CenterText(tb);
|
|
}
|
|
}
|
|
|
|
int CodeOrName(char *a, char **b)
|
|
{
|
|
int l,code;
|
|
while (*a == ' ') ++a;
|
|
if (*a == '+' || *a == '-' || (*a >= '0' && *a <='9'))
|
|
return strtol(a,b,10);
|
|
for (code = 0 ; code < CODES ; ++code)
|
|
{
|
|
l = strlen(All[code].Id);
|
|
if (!strncmp(All[code].Id,a,l) && *(a+l) == ' ')
|
|
{
|
|
*b = a+l;
|
|
return code;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void scancode(void)
|
|
{
|
|
char *cp,*icp;
|
|
int code;
|
|
char tb[COLS+2];
|
|
|
|
cp = amatch(namelist,"code");
|
|
if (cp == NULL) Abort(" *** No code selected for output ***");
|
|
|
|
code = CodeOrName(cp,&icp);
|
|
DashLine();
|
|
while (code > 0 && code < CODES)
|
|
{
|
|
sprintf(tb,"Code %5d = %-6.6s %-24.24s",code,All[code].Id,All[code].Na);
|
|
LeftText(tb);
|
|
All[code].selected = 1;
|
|
cp = icp;
|
|
code = CodeOrName(cp,&icp);
|
|
}
|
|
}
|
|
|
|
void scanmol(void)
|
|
{
|
|
char *cp,*icp;
|
|
int lev;
|
|
|
|
nrml = 0;
|
|
cp = amatch(namelist,"modlev");
|
|
if (cp == NULL) return;
|
|
lev = strtol(cp,&icp,10);
|
|
while (lev > 0 && nrml < MAX_LEVELS)
|
|
{
|
|
mol[nrml++] = lev;
|
|
mom[lev] = 1;
|
|
cp = icp;
|
|
lev = strtol(cp,&icp,10);
|
|
}
|
|
}
|
|
|
|
void scanhPa(void)
|
|
{
|
|
char *cp,*icp;
|
|
double lev;
|
|
|
|
nrpl = 0;
|
|
cp = amatch(namelist,"hpa");
|
|
if (!cp) return;
|
|
lev = strtod(cp,&icp);
|
|
while (lev > 0 && nrpl < MAX_LEVELS)
|
|
{
|
|
hPa[nrpl++] = lev;
|
|
cp = icp;
|
|
lev = strtod(cp,&icp);
|
|
}
|
|
}
|
|
|
|
void scanattributes(void)
|
|
{
|
|
char *cp;
|
|
int i;
|
|
|
|
nattr = 0;
|
|
cp = amatch(namelist,"attributes");
|
|
if (!cp) return;
|
|
|
|
while (nattr < ATTR_MAX)
|
|
{
|
|
i = 0;
|
|
while (*cp == ':' || isspace(*cp)) ++cp;
|
|
while ((isalnum(*cp) || *cp == '_') && i < 80) AttrNam[nattr][i++] = *cp++;
|
|
while (isspace(*cp)) ++cp;
|
|
if (*cp != '=') break;
|
|
else ++cp;
|
|
while (isspace(*cp)) ++cp;
|
|
if (*cp != '"') break;
|
|
else ++cp;
|
|
i = 0;
|
|
while (*cp != '"' && i < 80) AttrVal[nattr][i++] = *cp++;
|
|
++cp;
|
|
while (isspace(*cp)) ++cp;
|
|
if (*cp != ';') break;
|
|
++cp;
|
|
++nattr;
|
|
}
|
|
}
|
|
|
|
void InitAll(void)
|
|
{
|
|
char Id[MAX_ID_LEN];
|
|
char Na[MAX_NA_LEN];
|
|
|
|
for (int code = 0 ; code < MAXCODES ; ++code)
|
|
{
|
|
sprintf(Id,"var%3.3d",code);
|
|
sprintf(Na,"Code[%d]",code);
|
|
All[code].Init(Id,Na,"1",0);
|
|
All[code].code = code;
|
|
}
|
|
|
|
All[110].Init("mld" ,"mixed_layer_depth" ,"m" ,1); // Not standard
|
|
All[129].Init("sg" ,"surface_geopotential" ,"m2 s-2" ,1);
|
|
All[130].Init("ta" ,"air_temperature" ,"K" ,0);
|
|
All[131].Init("ua" ,"eastward_wind" ,"m s-1" ,0);
|
|
All[132].Init("va" ,"northward_wind" ,"m s-1" ,0);
|
|
All[133].Init("hus" ,"specific_humidity" ,"1" ,0);
|
|
All[134].Init("ps" ,"surface_air_pressure" ,"hPa" ,1);
|
|
All[135].Init("wap" ,"vertical_air_velocity" ,"Pa s-1" ,0); // shortened
|
|
All[137].Init("wa" ,"upward_wind" ,"m s-1" ,0); // Not standard
|
|
All[138].Init("zeta" ,"atm_relative_vorticity" ,"s-1" ,0);
|
|
All[139].Init("ts" ,"surface_temperature" ,"K" ,1);
|
|
All[140].Init("mrso" ,"lwe_of_soil_moisture_content" ,"m" ,1); // shortened
|
|
All[141].Init("snd" ,"surface_snow_thickness" ,"m" ,1);
|
|
All[142].Init("prl" ,"lwe_of_large_scale_precipitation","m s-1" ,1); // rate !!
|
|
All[143].Init("prc" ,"convective_precipitation_rate" ,"m s-1" ,1);
|
|
All[144].Init("prsn" ,"lwe_of_snowfall_amount" ,"m s-1" ,1); // rate !!
|
|
All[145].Init("bld" ,"dissipation_in_atmosphere_bl" ,"W m-2" ,1); // shortened
|
|
All[146].Init("hfss" ,"surface_sensible_heat_flux" ,"W m-2" ,1); // shortened
|
|
All[147].Init("hfls" ,"surface_latent_heat_flux" ,"W m-2" ,1); // shortened
|
|
All[148].Init("stf" ,"streamfunction" ,"m2 s-2" ,0); // Not standard
|
|
All[149].Init("psi" ,"velocity_potential" ,"m2 s-2" ,0); // Not standard
|
|
All[151].Init("psl" ,"air_pressure_at_sea_level" ,"hPa" ,1);
|
|
All[152].Init("pl" ,"log_surface_pressure" ,"1" ,1);
|
|
All[155].Init("d" ,"divergence_of_wind" ,"s-1" ,0);
|
|
All[156].Init("zg" ,"geopotential_height" ,"m" ,0);
|
|
All[157].Init("hur" ,"relative_humidity" ,"1" ,0);
|
|
All[158].Init("tps" ,"tendency_of_surface_air_pressure","Pa s-1" ,1);
|
|
All[159].Init("u3" ,"ustar" ,"m3 s-3" ,1); // Not standard
|
|
All[160].Init("mrro" ,"surface_runoff" ,"m s-1" ,1); // Not standard
|
|
All[161].Init("clw" ,"liquid_water_content" ,"1" ,0); // Not standard
|
|
All[162].Init("cl" ,"cloud_area_fraction_in_layer" ,"1" ,0); // Not standard
|
|
All[163].Init("tcc" ,"total_cloud_cover" ,"1" ,1); // Not standard
|
|
All[164].Init("clt" ,"cloud_area_fraction" ,"1" ,1);
|
|
All[165].Init("uas" ,"eastward_wind_10m" ,"m s-1" ,1); // shortened
|
|
All[166].Init("vas" ,"northward_wind_10m" ,"m s-1" ,1); // shortened
|
|
All[167].Init("tas" ,"air_temperature_2m" ,"K" ,1); // shortened
|
|
All[168].Init("td2m" ,"dew_point_temperature_2m" ,"K" ,1); // shortened
|
|
All[169].Init("tsa" ,"surface_temperature_accumulated" ,"K" ,1); // Not standard
|
|
All[170].Init("tsod" ,"deep_soil_temperature" ,"K" ,1);
|
|
All[171].Init("dsw" ,"deep_soil_wetness" ,"1" ,1);
|
|
All[172].Init("lsm" ,"land_binary_mask" ,"1" ,1);
|
|
All[173].Init("z0" ,"surface_roughness_length" ,"m" ,1);
|
|
All[174].Init("alb" ,"surface_albedo" ,"1" ,1); // Not standard
|
|
All[175].Init("as" ,"surface_albedo" ,"1" ,1); // Not standard
|
|
All[176].Init("rss" ,"surface_net_shortwave_flux" ,"W m-2" ,1); // shortened
|
|
All[177].Init("rls" ,"surface_net_longwave_flux" ,"W m-2" ,1); // shortened
|
|
All[178].Init("rst" ,"toa_net_shortwave_flux" ,"W m-2" ,1); // shortened
|
|
All[179].Init("rlut" ,"toa_net_longwave_flux" ,"W m-2" ,1); // shortened
|
|
All[180].Init("tauu" ,"surface_eastward_stress" ,"Pa" ,1); // shortened
|
|
All[181].Init("tauv" ,"surface_northward_stress" ,"Pa" ,1); // shortened
|
|
All[182].Init("evap" ,"lwe_of_water_evaporation" ,"m s-1" ,1); // rate !!
|
|
All[183].Init("tso" ,"climate_deep_soil_temperature" ,"K" ,1); // Not standard
|
|
All[184].Init("wsoi" ,"climate_deep_soil_wetness" ,"1" ,1);
|
|
All[199].Init("vegc" ,"vegetation_cover" ,"1" ,1); // Not standard
|
|
All[203].Init("rsut" ,"toa_outgoing_shortwave_flux" ,"W m-2" ,1); // Not standard
|
|
All[204].Init("ssru" ,"surface_solar_radiation_upward" ,"W m-2" ,1); // Not standard
|
|
All[205].Init("stru" ,"surface_thermal_radiation_upward","W m-2" ,1); // Not standard
|
|
All[207].Init("tso2" ,"soil_temperature_level_2" ,"K" ,1); // Not standard
|
|
All[208].Init("tso3" ,"soil_temperature_level_3" ,"K" ,1); // Not standard
|
|
All[209].Init("tso4" ,"soil_temperature_level_4" ,"K" ,1); // Not standard
|
|
All[210].Init("sic" ,"sea_ice_cover" ,"1" ,1); // Not standard
|
|
All[211].Init("sit" ,"sea_ice_thickness" ,"m" ,1); // Not standard
|
|
All[212].Init("vegf" ,"forest_cover" ,"1" ,1); // Not standard
|
|
All[218].Init("snm" ,"snow_melt" ,"m s-1" ,1); // Not standard
|
|
All[221].Init("sndc" ,"snow_depth_change" ,"m s-1" ,1); // Not standard
|
|
All[230].Init("prw" ,"atmosphere_water_vapor_content" ,"kg m-2" ,1); // Not standard
|
|
All[232].Init("glac" ,"glacier_cover" ,"1" ,1); // Not standard
|
|
All[238].Init("tsn" ,"snow_temperature" ,"K" ,1);
|
|
All[259].Init("spd" ,"wind_speed" ,"m s-1" ,0); // Not standard
|
|
All[260].Init("pr" ,"total_precipitation" ,"m s-1" ,1); // Not standard
|
|
All[261].Init("ntr" ,"net_top_radiation" ,"W m-2" ,1); // Not standard
|
|
All[262].Init("nbr" ,"net_bottom_radiation" ,"W m-2" ,1); // Not standard
|
|
All[263].Init("hfns" ,"surface_downward_heat_flux" ,"W m-2" ,1); // shortened
|
|
All[264].Init("wfn" ,"net_water_flux" ,"m s-1" ,1); // Not standard
|
|
All[273].Init("dpdx" ,"d(ps)/dx" ,"Pa m-1" ,1); // Not standard
|
|
All[274].Init("dpdy" ,"d(ps)/dy" ,"Pa m-1" ,1); // Not standard
|
|
All[277].Init("hlpr" ,"half_level_pressure" ,"Pa" ,0); // Not standard
|
|
All[278].Init("flpr" ,"full_level_pressure" ,"Pa" ,0); // Not standard
|
|
}
|
|
|
|
void Usage(void)
|
|
{
|
|
char Line[132];
|
|
fpi = fopen("/usr/local/doc/burn7.txt","r");
|
|
if (fpi)
|
|
do
|
|
{
|
|
fgets(Line,130,fpi);
|
|
printf("%s",Line);
|
|
}
|
|
while (!feof(fpi) && Line[0] != '#');
|
|
if (fpi) fclose(fpi);
|
|
|
|
printf("\nburn7 [options] InputFile OutputFile <namelist >printout\n");
|
|
printf(" option -h : help (this output)\n");
|
|
printf(" option -c : print available codes and names\n");
|
|
printf(" option -d : debug mode (verbose output)\n");
|
|
printf(" option -m : Mean=1 output (override namelist option)\n");
|
|
printf(" option -n : NetCDF output (override namelist option)\n");
|
|
printf(" option -s : Save memory (increases CPU time)\n");
|
|
printf(" InputFile : PUMA or PlaSim data file\n");
|
|
#ifdef NETCDF_OUTPUT
|
|
printf(" <OutputFile> : SERVICE, or NetCDF format file\n");
|
|
#else
|
|
printf(" <OutputFile> : SERVICE format file\n");
|
|
#endif
|
|
printf(" namelist is read from <stdin>\n");
|
|
printf(" printout is written to <stdout>\n\n");
|
|
exit(1);
|
|
}
|
|
|
|
void parini(void)
|
|
{
|
|
char c;
|
|
unsigned int i;
|
|
int jind;
|
|
int lc;
|
|
char tb[COLS+2];
|
|
|
|
i = 1;
|
|
namelist[0] = ' ';
|
|
lc = 1;
|
|
c = getchar();
|
|
while (!feof(stdin) && i < MAX_NL)
|
|
{
|
|
if (c == ':' ) lc = 0; // No conversion to lower case
|
|
if (c == '\n') lc = 1;
|
|
if (c == '#') // Skip comment
|
|
{
|
|
while (!feof(stdin) && c != '\n') c = getchar();
|
|
}
|
|
if (lc)
|
|
{
|
|
if ((c >= '0' && c <= '9') ||
|
|
c == '-' || c == '.') namelist[i++] = c;
|
|
else if (c >= 'a' && c <= 'z') namelist[i++] = c;
|
|
else if (c >= 'A' && c <= 'Z') namelist[i++] = tolower(c);
|
|
else c = ' ';
|
|
if (c == ' ' && namelist[i-1] != ' ') namelist[i++] = c;
|
|
}
|
|
else namelist[i++] = c;
|
|
c = getchar();
|
|
}
|
|
namelist[i++] = ' ';
|
|
namelist[i] = 0;
|
|
|
|
if (Debug)
|
|
{
|
|
sprintf(tb,"Length of namelist: %d bytes",(int)strlen(namelist));
|
|
LeftText(tb);
|
|
for (i = 0; i<strlen(namelist); i+=40)
|
|
{
|
|
sprintf(tb,"namelist[%02d]=%-40.40s",i,namelist+i);
|
|
LeftText(tb);
|
|
}
|
|
StarLine();
|
|
}
|
|
|
|
Lats = scanpar("lats",Lats);
|
|
Lons = scanpar("lons",Lons);
|
|
DPM = scanpar("dpm",0);
|
|
if (DPM > 99 && DPM < 2400) /* Days Per Month */
|
|
{
|
|
DayDivisor = DPM / 100 + 1;
|
|
while (24 % DayDivisor && DayDivisor < 24) ++DayDivisor;
|
|
sprintf(tb,"%10.10s = %8d ","daydivisor",DayDivisor);
|
|
LeftText(tb);
|
|
}
|
|
Cyclical = scanpar("cyclical",Cyclical);
|
|
if (Cyclical) Cyclical = 1;
|
|
if (VerType == 0 || HorType == 0)
|
|
{
|
|
VerType = scantex("vtype" ,"ps"); // 1. char is default value (p)
|
|
HorType = scantex("htype" ,"gsfz"); // 1. char is default value (g)
|
|
}
|
|
Multi = scanpar("multi" ,0);
|
|
LevelFactor = scanreal("levelfactor",1.0);
|
|
if (NetCDF == 0) NetCDF = scanpar("netcdf",0);
|
|
HeadOu[6] = scanpar("head7",0);
|
|
mars = scanpar("mars" ,0);
|
|
FirstMonth = scanpar("first",1);
|
|
LastMonth = scanpar("last",12);
|
|
PlanetRadius = scanreal("radius",EARTH_RADIUS);
|
|
Grav = scanreal("gravity",EARTH_GRAV);
|
|
SigmaTop = scanreal("sigmatop",0.0);
|
|
vct[SigLevs] = SigmaTop;
|
|
if (FirstMonth < 1) FirstMonth = 1;
|
|
if (LastMonth > 12) LastMonth = 12;
|
|
if (LastMonth < FirstMonth) LastMonth = FirstMonth;
|
|
|
|
if (VerType == 's')
|
|
{
|
|
switch (HorType)
|
|
{
|
|
case 's': OutRep = HYB_SPEC; break;
|
|
case 'f': OutRep = HYB_FOUR; break;
|
|
case 'z': OutRep = HYB_ZONM; break;
|
|
case 'g': OutRep = HYB_GRID; break;
|
|
}
|
|
}
|
|
|
|
if (VerType == 'p')
|
|
{
|
|
switch (HorType)
|
|
{
|
|
case 's': OutRep = PRE_SPEC; break;
|
|
case 'f': OutRep = PRE_FOUR; break;
|
|
case 'z': OutRep = PRE_ZONM; break;
|
|
case 'g': OutRep = PRE_GRID; break;
|
|
}
|
|
}
|
|
|
|
if (Mean == 0) Mean = scanpar("mean" ,1);
|
|
if (Mean && OutRep < HYB_GRID)
|
|
{
|
|
sprintf(tb," mean = 1 ignored for spectral data on sigma levels");
|
|
LeftText(tb);
|
|
Mean = 0;
|
|
}
|
|
|
|
if (Multi) --Multi;
|
|
|
|
if (mars) {
|
|
Grav = MARS_GRAV;
|
|
PlanetRadius = MARS_RADIUS;
|
|
RD = MARS_RD;
|
|
}
|
|
|
|
scantime();
|
|
scancode();
|
|
DashLine();
|
|
if (VerType == 's') /* model levels */
|
|
{
|
|
scanmol();
|
|
mom[0] = 1; // surface arrays are selected always
|
|
if (nrml) /* Sigma levels explicitely given */
|
|
{
|
|
nrml = 0;
|
|
for (i=1 ; i <= SigLevs ; ++i)
|
|
{
|
|
if (mom[i])
|
|
{
|
|
level[nrml] = mol[nrml] = i;
|
|
nrml++;
|
|
}
|
|
}
|
|
SigLevs = OutLevs = nrml;
|
|
}
|
|
else /* No sigma levels specified -> select all */
|
|
{
|
|
OutLevs = nrml = SigLevs;
|
|
for (i=0 ; i < OutLevs ; ++i)
|
|
{
|
|
level[i] = mol[i] = mom[i+1] = i+1;
|
|
}
|
|
}
|
|
for (i=0 ; i < OutLevs ; ++i)
|
|
{
|
|
jind = mol[i] - 1;
|
|
LevelUnits[i] = mol[i];
|
|
SigmaF[i] = (int)(500000.0 * (vct[jind+1] - vct[jind])); // sigma * 1E6
|
|
sprintf(tb,"Level %4d = %10.6f",i+1,
|
|
0.5 * (vct[SigLevs+mol[i]]+vct[SigLevs+mol[i]+1]));
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
else /* pressure levels */
|
|
{
|
|
scanhPa();
|
|
if (nrpl)
|
|
{
|
|
OutLevs = nrpl;
|
|
for (i=0 ; i < OutLevs ; ++i)
|
|
{
|
|
level[i] = 100.0 * hPa[i];
|
|
if (hPa[i] < 0.0) Abort("pressure level < 0.0 is illegal");
|
|
// if (hPa[i] > 2000.0) Abort("pressure level > 2000 hPa is illegal");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OutLevs = nrpl = 10;
|
|
for (i=0 ; i < OutLevs ; ++i)
|
|
{
|
|
hPa[i] = (i+1) * 100.0;
|
|
level[i] = 100.0 * hPa[i];
|
|
}
|
|
}
|
|
for (i=0 ; i < OutLevs ; ++i)
|
|
{
|
|
LevelUnits[i] = (int)(LevelFactor * 100.0 * hPa[i] + 0.5);
|
|
sprintf(tb,"Level %4d = %14.4f hPa",i+1,hPa[i]);
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
DashLine();
|
|
scanattributes();
|
|
for (i=0 ; i < nattr ; ++i)
|
|
{
|
|
sprintf(tb,"NetCDF attribute[%2d] :%s = \"%s\" ;",
|
|
i,AttrNam[i],AttrVal[i]);
|
|
LeftText(tb);
|
|
}
|
|
}
|
|
|
|
void dimcalc(void)
|
|
{
|
|
PolyDisk = Lats == 2048; // Currently T1365 only
|
|
Waves = Truncation + 1;
|
|
Fouriers = Waves * 2;
|
|
DimSP = (Truncation + 1) * (Truncation + 2);
|
|
DimFC = Lats * Fouriers;
|
|
DimGP = Lats * Lons;
|
|
DimGG = Gats * Gons;
|
|
Dim3GP = SigLevs * DimGP;
|
|
Dim3GG = SigLevs * DimGG;
|
|
Dim3FC = SigLevs * DimFC;
|
|
Dim3SP = SigLevs * DimSP;
|
|
DimSP_half = DimSP / 2;
|
|
DimAB = MAX(DimGG,DimGP) + MAX(Lons,Gons);
|
|
|
|
DashLine();
|
|
if (VerType == 's') LeftText("Vertical Type = Sigma [S]");
|
|
if (VerType == 'p') LeftText("Vertical Type = Pressure [P]");
|
|
if (HorType == 's') LeftText("Horizontal Type = Spherical Harmonics [S]");
|
|
if (HorType == 'f') LeftText("Horizontal Type = Fourier Coefficients [F]");
|
|
if (HorType == 'z') LeftText("Horizontal Type = Zonal Means [Z]");
|
|
if (HorType == 'g')
|
|
{
|
|
if (Lons == Gons && Lats == Gats)
|
|
{
|
|
LeftText("Horizontal Type = Gaussian Grid [G]");
|
|
GaussianOutput = 1;
|
|
}
|
|
else
|
|
{
|
|
LeftText("Horizontal Type = Grid (Lons x Lats) [G]");
|
|
GaussianOutput = 0;
|
|
}
|
|
}
|
|
DashLine();
|
|
|
|
Record_double = new double[DimAB];
|
|
Record_float = (float *)Record_double;
|
|
Record_int = (int *)Record_double;
|
|
Record_short = (unsigned short *)Record_double;
|
|
Record_char = (char *)Record_double;
|
|
|
|
CosPhi = new double[Lats];
|
|
RevCosPhi = new double[Lats];
|
|
DerivationFactor = new double[Lats];
|
|
}
|
|
|
|
/* ------------------------------------------------------ */
|
|
/* Check file OutRep and decode level number and truncation */
|
|
/* ------------------------------------------------------ */
|
|
|
|
void AnalyzeFile(void)
|
|
{
|
|
int i;
|
|
LONG fcb,fce; /* Fortran Record Control Words */
|
|
char Id[8];
|
|
char tb[COLS+2];
|
|
|
|
union EndianCheck
|
|
{
|
|
char b[sizeof(int)];
|
|
int i;
|
|
} ec;
|
|
|
|
ec.i = 8;
|
|
CoreBigEndian = ec.b[0] == 0;
|
|
|
|
fread(Id,1,8,fpi); // Read first 8 bytes
|
|
FileBigEndian = Id[0] == 0;
|
|
Endian = CoreBigEndian != FileBigEndian;
|
|
|
|
if (FileBigEndian)
|
|
{
|
|
if (Id[3] == 0) LongFCW = 1;
|
|
}
|
|
else
|
|
{
|
|
if (Id[4] == 0) LongFCW = 1;
|
|
}
|
|
|
|
rewind(fpi);
|
|
HeadSize = fcb = ReadFCW();
|
|
if (fcb != 8 && fcb != 32 && fcb != 64) Abort("Not a PUMA/PLASIM file");
|
|
|
|
CenterText("Found PUMA/Planet Simulator data set");
|
|
if (CoreBigEndian) CenterText("Running on BIG endian machine");
|
|
else CenterText("Running on little endian machine");
|
|
if (FileBigEndian) CenterText("File is in BIG endian format");
|
|
else CenterText("File is in little endian format");
|
|
if (Endian) CenterText("Endian swap activated");
|
|
if (LongFCW) CenterText("Record control words have 64 bits");
|
|
else CenterText("Record control words have 32 bits");
|
|
if (fcb == 8) CenterText("Header format: PUMA-II ");
|
|
if (fcb == 32) CenterText("Header format: Service 32 bit");
|
|
if (fcb == 64) CenterText("Header format: Service 64 bit");
|
|
BlankLine();
|
|
|
|
if (fcb == 8)
|
|
{
|
|
HeadSize = 32;
|
|
i = fread(Id,1,8,fpi);
|
|
if (strncmp(Id,"PUMA-II ",8)) Abort("PUMA-II header missing");
|
|
|
|
fce = ReadFCW();
|
|
if (check_fcw(fcb,fce)) Abort("Wrong FORTRAN control word after PUMA header");
|
|
|
|
Truncation = ReadINTRecord();
|
|
Gats = ReadINTRecord();
|
|
AllLevs = SigLevs = ReadINTRecord();
|
|
if (SigLevs < 1 || SigLevs > 1000) Abort("Illegal value for Level");
|
|
SingleLevel = (SigLevs == 1);
|
|
nvct = 2 * SigLevs + 2;
|
|
|
|
/* Check length of sigma vector and determine precision */
|
|
|
|
fcb = ReadFCW();
|
|
RealSize = fcb / SigLevs; // Should be float (4) or double (8)
|
|
if (RealSize != sizeof(float) && RealSize != sizeof(double)) Abort("FCW error on level record");
|
|
for (i = 0 ; i < SigLevs ; i++)
|
|
{
|
|
if (RealSize == sizeof(float)) vct[i+SigLevs+2] = ReadFLOAT();
|
|
else vct[i+SigLevs+2] = ReadDOUBLE();
|
|
}
|
|
fce = ReadFCW();
|
|
if (check_fcw(fcb,fce)) Abort("FCW mismatch on level record");
|
|
|
|
|
|
/* Header = "PUMA-II " Truncation Lats SigLevs sigmah */
|
|
/* 2-FCW FCW-1-FCW FCW-1-FCW FCW-1-FCW FCW-SigLevs-FCW */
|
|
|
|
HeaderWords = SigLevs * RealSize / 4 + 5 + 9 * (1 + LongFCW);
|
|
|
|
ReadHeaderRecord();
|
|
if (HeadIn[7] > 100) DaysPerYear = HeadIn[7];
|
|
}
|
|
else
|
|
{
|
|
rewind(fpi);
|
|
ReadHeaderRecord();
|
|
if (HeadIn[0] != 333) Abort("Initial code 333 was not found");
|
|
Gats = HeadIn[5];
|
|
AllLevs = SigLevs = HeadIn[6];
|
|
SingleLevel = (SigLevs == 1);
|
|
nvct = 2 * SigLevs + 2;
|
|
Truncation = HeadIn[7];
|
|
|
|
/* Check length of array and determine precision */
|
|
|
|
fcb = ReadFCW();
|
|
RealSize = fcb / (Gats * Gats * 2); // Should be float (4) or double (8)
|
|
fseek(fpi,-4*LongFCW,SEEK_CUR);
|
|
if (RealSize != sizeof(float) && RealSize != sizeof(double)) Abort("FCW error on first array");
|
|
for (i = 0 ; i < SigLevs ; i++)
|
|
{
|
|
if (RealSize == sizeof(float)) vct[i+SigLevs+2] = ReadFLOAT();
|
|
else vct[i+SigLevs+2] = ReadDOUBLE();
|
|
}
|
|
}
|
|
HeadSt = HeadIn;
|
|
sprintf(tb,"Truncation = %6d",Truncation);
|
|
CenterText(tb);
|
|
sprintf(tb,"Latitudes = %6d",Gats);
|
|
CenterText(tb);
|
|
sprintf(tb,"Longitudes = %6d",Gats*2);
|
|
CenterText(tb);
|
|
sprintf(tb,"Sigma Levels = %6d",SigLevs);
|
|
CenterText(tb);
|
|
if (RealSize == 8)
|
|
sprintf(tb,"Double precision data: Bytes = %6d",RealSize);
|
|
else if (RealSize == 4)
|
|
sprintf(tb,"Single precision data: Bytes = %6d",RealSize);
|
|
else
|
|
sprintf(tb,"Size of real data = %6d",RealSize);
|
|
CenterText(tb);
|
|
BlankLine();
|
|
sprintf(tb,"Half Level [p] [sigma]");
|
|
CenterText(tb);
|
|
for (i = 0; i<nvct/2; i++)
|
|
{
|
|
sprintf(tb,"%10.1f %14.4f %14.4f",(float)i,vct[i],vct[i+nvct/2]);
|
|
CenterText(tb);
|
|
}
|
|
StarLine();
|
|
|
|
rewind(fpi);
|
|
}
|
|
|
|
const char *MoName[13] = {"Nix","Jan","Feb","Mar","Apr","May","Jun",
|
|
"Jul","Aug","Sep","Oct","Nov","Dec"};
|
|
void WriteGradsCtl()
|
|
{
|
|
int i,j,yy,mm,dd,code,varcodes;
|
|
FILE *fp;
|
|
double DelLon;
|
|
|
|
fp = fopen(gfile,"w");
|
|
if (HorType == 'z')
|
|
fprintf(fp,"DSET ^%s\n",rfile);
|
|
else
|
|
fprintf(fp,"DSET ^%s\n",ofile);
|
|
fprintf(fp,"UNDEF 9e09i\n");
|
|
if (HorType == 'z')
|
|
fprintf(fp,"XDEF 1 LINEAR 0 1\n");
|
|
else
|
|
{
|
|
DelLon = 360.0 / Gons;
|
|
fprintf(fp,"XDEF %5d LINEAR 0.0 %14.8f\n",Gons,DelLon);
|
|
}
|
|
fprintf(fp,"OPTIONS YREV\n");
|
|
fprintf(fp,"YDEF %5d LEVELS\n",Gats);
|
|
|
|
for (j=Gats-1 ; j >= 0 ; j-=8)
|
|
{
|
|
for (i=j ; i >= 0 && i> j-8 ; --i)
|
|
fprintf(fp,"%14.8f",Outlat->Phi[i]);
|
|
fprintf(fp,"\n");
|
|
}
|
|
if (HorType != 'z')
|
|
{
|
|
fprintf(fp,"OPTIONS SEQUENTIAL\n");
|
|
fprintf(fp,"XYHEADER %d\n",40 + 8 * LongFCW);
|
|
}
|
|
if (OutLevs < 2)
|
|
{
|
|
if (VerType == 'p') fprintf(fp,"ZDEF 1 LINEAR %14.8f 1\n",hPa[0]);
|
|
else fprintf(fp,"ZDEF 1 LINEAR %d 1\n",mol[0]);
|
|
}
|
|
else
|
|
{
|
|
fprintf(fp,"ZDEF %d LEVELS\n",OutLevs);
|
|
if (VerType == 'p')
|
|
{
|
|
|
|
for (j=0 ; j < OutLevs ; j+=8)
|
|
{
|
|
for (i=j ; i < OutLevs && i < j+8 ; ++i)
|
|
if (HorType == 'z' && hPa[0] < hPa[OutLevs-1])
|
|
fprintf(fp,"%14.8f",hPa[OutLevs-1-i]);
|
|
else
|
|
fprintf(fp,"%14.8f",hPa[i]);
|
|
fprintf(fp,"\n");
|
|
}
|
|
if (HorType == 'z' && hPa[0] < hPa[OutLevs-1])
|
|
fprintf(fp,"OPTIONS ZREV\n");
|
|
}
|
|
else
|
|
{
|
|
for (j=0 ; j < OutLevs ; j+=8)
|
|
{
|
|
for (i=j ; i < OutLevs && i < j+8 ; ++i)
|
|
if (HorType == 'z' && mol[0] < mol[OutLevs-1])
|
|
fprintf(fp,"%10d",mol[OutLevs-1-i]);
|
|
else
|
|
fprintf(fp,"%10d",mol[i]);
|
|
fprintf(fp,"\n");
|
|
}
|
|
if (HorType == 'z' && mol[0] < mol[OutLevs-1])
|
|
fprintf(fp,"OPTIONS ZREV\n");
|
|
}
|
|
}
|
|
yy = HeadSt[2] / 10000;
|
|
mm = HeadSt[2] / 100 % 100;
|
|
dd = HeadSt[2] % 100;
|
|
|
|
if (Mean)
|
|
fprintf(fp,"TDEF %d LINEAR 00:00z%d%s%d 1mo\n",
|
|
MonthCount,dd,MoName[mm],yy);
|
|
else if (DeltaMn > 0)
|
|
fprintf(fp,"TDEF %d LINEAR 00:00z%d%s%d %dmn\n",
|
|
TermCount,dd,MoName[mm],yy,DeltaMn);
|
|
else if (DeltaHr > 0)
|
|
fprintf(fp,"TDEF %d LINEAR 00:00z%d%s%d %dhr\n",
|
|
TermCount,dd,MoName[mm],yy,DeltaHr);
|
|
else
|
|
fprintf(fp,"TDEF %d LINEAR 00:00z%d%s%d %ddy\n",
|
|
TermCount,dd,MoName[mm],yy,DeltaDy);
|
|
|
|
|
|
varcodes = 0;
|
|
for (code = 0 ; code < CODES ; ++code)
|
|
if (All[code].selected) ++varcodes;
|
|
fprintf(fp,"VARS %d\n",varcodes);
|
|
for (code = 0 ; code < CODES ; ++code)
|
|
if (All[code].selected)
|
|
fprintf(fp,"%s %d 99 %s\n",
|
|
All[code].Id,All[code].plev,All[code].Na);
|
|
fprintf(fp,"ENDVARS\n");
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int i,l;
|
|
int wdim;
|
|
char tb[COLS+2];
|
|
time_t StartTime;
|
|
|
|
StartTime = time(NULL);
|
|
|
|
/*********************/
|
|
/* print information */
|
|
/*********************/
|
|
|
|
StarLine();
|
|
CenterText(V0);
|
|
CenterText(V1);
|
|
DashLine();
|
|
CenterText(V2);
|
|
CenterText(V3);
|
|
CenterText(V4);
|
|
StarLine();
|
|
sprintf(tb,"Run started at %s",ctime(&StartTime));
|
|
strcpy(tb+strlen(tb)-1," local time");
|
|
CenterText(tb);
|
|
StarLine();
|
|
|
|
InitAll();
|
|
|
|
/***********************/
|
|
/* options & filenames */
|
|
/***********************/
|
|
|
|
for (i = 1 ; i < argc ; ++i) {
|
|
if (argv[i][0] == '-') {
|
|
if (argv[i][1] == 'c') {PrintCodes(); exit(1);}
|
|
else if (argv[i][1] == 'd') Debug = 1;
|
|
else if (argv[i][1] == 'v') Debug = 1;
|
|
else if (argv[i][1] == 'n') NetCDF = 1;
|
|
else if (argv[i][1] == 'g') Grads = 1;
|
|
else if (argv[i][1] == 'm') Mean = 1;
|
|
else if (argv[i][1] == 'p') PolyCreate = 1;
|
|
else if (argv[i][1] == 'i') GaussGrid = 1;
|
|
else if (argv[i][1] == 's') SaveMemory = 1;
|
|
else Usage();
|
|
}
|
|
else if (ifile[0] == '\0') strcpy(ifile,argv[i]);
|
|
else if (ofile[0] == '\0') strcpy(ofile,argv[i]);
|
|
else if (strcmp("Debug",argv[i]) == 0) Debug = 1;
|
|
else Usage();
|
|
}
|
|
|
|
if (NetCDF) Grads = 0;
|
|
|
|
if (ifile[0] == '\0' || ofile[0] == '\0') {
|
|
printf("*** Missing filename ***\n");
|
|
Usage();
|
|
}
|
|
|
|
/*******************/
|
|
/* open input file */
|
|
/*******************/
|
|
|
|
fpi = fopen(ifile,"rb");
|
|
if (fpi == 0) {
|
|
printf("could not open input file %s\n",ifile);
|
|
exit(1);
|
|
}
|
|
|
|
/******************/
|
|
/* pre-processing */
|
|
/******************/
|
|
|
|
AnalyzeFile();
|
|
|
|
Gons = Gats * 2;
|
|
Lats = Gats;
|
|
Lons = Gons;
|
|
|
|
/*******************/
|
|
/* initializations */
|
|
/*******************/
|
|
|
|
parini();
|
|
|
|
l = strlen(ofile);
|
|
if (NetCDF) // Add ".nc" extension for NetCDF filename if not specified
|
|
{
|
|
if (l < 4 || strcmp(ofile+l-3,".nc")) strcat(ofile,".nc");
|
|
}
|
|
else // Add ".srv" extension for Service format if not specified
|
|
{
|
|
if (l > 4 && !strcmp(ofile+l-4,".srv")) l -= 4;
|
|
ofile[l] = 0;
|
|
strcpy(gfile,ofile);
|
|
strcpy(rfile,ofile);
|
|
strcat(ofile,".srv");
|
|
strcat(gfile,".ctl");
|
|
strcat(rfile,".gra");
|
|
}
|
|
|
|
sprintf(tb," Input File: %s",ifile); LeftText(tb);
|
|
sprintf(tb,"Output File: %s",ofile); LeftText(tb);
|
|
if (Grads) {sprintf(tb,"Grads File: %s",gfile); LeftText(tb);}
|
|
if (Grads && HorType == 'z')
|
|
{sprintf(tb,"Grads Data: %s",rfile); LeftText(tb);}
|
|
if (Debug) LeftText("Debug on");
|
|
|
|
#ifndef NETCDF_OUTPUT
|
|
if (NetCDF) Abort("This executable was not compiled for NetCDF");
|
|
#endif
|
|
|
|
/********************/
|
|
/* open output file */
|
|
/********************/
|
|
|
|
if (!NetCDF)
|
|
{
|
|
gp = fopen(ofile,"wb");
|
|
if (gp == 0)
|
|
{
|
|
printf("could not open output file <%s>\n",ofile);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
dimcalc();
|
|
|
|
HybSpec = new ServiceGrid(gp,DimSP,1);
|
|
HybFour = new ServiceGrid(gp,Lats,Fouriers);
|
|
HybGrid = new ServiceGrid(gp,Lons,Lats);
|
|
HybSect = new ServiceSect(gp,Lats,OutLevs);
|
|
|
|
/* FFT initialization */
|
|
|
|
if (OutLevs <= SigLevs) wdim = (Lons + 3) * Lats * SigLevs;
|
|
else wdim = (Lons + 3) * Lats * OutLevs ;
|
|
wfc = new double[wdim];
|
|
wgp = new double[wdim];
|
|
fft_set(Lons);
|
|
|
|
filename = strrchr(ifile,'/');
|
|
if (filename == 0) filename = ifile;
|
|
else filename++ ;
|
|
HeadOu[7] = atol(filename);
|
|
|
|
if (VerType == 'p' &&
|
|
(Divergence->selected || VeloPot->selected ||
|
|
Vorticity->selected || StreamF->selected))
|
|
SpecialUV = 1;
|
|
|
|
Dependencies();
|
|
|
|
// Check correct vertical coordinate
|
|
|
|
if (GeopotHeight->selected && VerType != 'p')
|
|
{
|
|
printf("\n ****************** E R R O R ************************\n");
|
|
printf(" * Geopotential height (156) requires pressure level *\n");
|
|
printf(" *****************************************************\n");
|
|
exit(1);
|
|
}
|
|
|
|
Geopotential->needed |= OutRep >= PRE_GRID
|
|
|| SLP->needed || GeopotHeight->needed;
|
|
if (OutRep) legini();
|
|
|
|
if (PolyCreate) exit(0); /* Called for Legendre Polynomials only */
|
|
|
|
#ifdef NETCDF_OUTPUT
|
|
if (NetCDF) NetOpen(ofile);
|
|
#endif
|
|
|
|
PumaControl();
|
|
if (gp) fclose(gp);
|
|
|
|
#ifdef NETCDF_OUTPUT
|
|
if (NetCDF) NetClose();
|
|
#endif
|
|
|
|
if (Grads) WriteGradsCtl();
|
|
|
|
StarLine();
|
|
if (DaysPerYear < 1) DaysPerYear = 360;
|
|
if (DPM > 99) DaysPerYear = DPM * 12;
|
|
sprintf(tb,"Using %d day calendar",DaysPerYear);
|
|
CenterText(tb);
|
|
sprintf(tb,"Data interval = %6.2f hours",DataStep * 24.0);
|
|
CenterText(tb);
|
|
StarLine();
|
|
{
|
|
double ut,st;
|
|
struct rusage ru;
|
|
getrusage(RUSAGE_SELF,&ru);
|
|
ut = ru.ru_utime.tv_sec + 0.000001 * ru.ru_utime.tv_usec;
|
|
st = ru.ru_stime.tv_sec + 0.000001 * ru.ru_stime.tv_usec;
|
|
|
|
sprintf(tb,"User time: %10.3lf seconds",ut);
|
|
LeftText(tb);
|
|
sprintf(tb,"System time: %10.3lf seconds",st);
|
|
LeftText(tb);
|
|
sprintf(tb,"Total time: %10.3lf seconds",ut+st);
|
|
LeftText(tb);
|
|
if (ru.ru_maxrss > 0)
|
|
{
|
|
sprintf(tb,"Memory usage: %10.3lf MBytes",0.000001 * ru.ru_maxrss);
|
|
LeftText(tb);
|
|
}
|
|
if (ru.ru_minflt > 0)
|
|
{
|
|
sprintf(tb,"Page reclaims: %10ld page",ru.ru_minflt);
|
|
if (ru.ru_minflt != 1) strcat(tb,"s");
|
|
LeftText(tb);
|
|
}
|
|
if (ru.ru_majflt > 0)
|
|
{
|
|
sprintf(tb,"Page faults: %10ld page",ru.ru_majflt);
|
|
if (ru.ru_majflt != 1) strcat(tb,"s");
|
|
LeftText(tb);
|
|
}
|
|
if (ru.ru_nswap > 0)
|
|
{
|
|
sprintf(tb,"Swaps : %10ld",ru.ru_nswap);
|
|
LeftText(tb);
|
|
}
|
|
if (ru.ru_inblock > 0)
|
|
{
|
|
sprintf(tb,"Disk read: %10ld block",ru.ru_inblock);
|
|
if (ru.ru_inblock != 1) strcat(tb,"s");
|
|
LeftText(tb);
|
|
}
|
|
if (ru.ru_oublock > 0)
|
|
{
|
|
sprintf(tb,"Disk Write: %10ld block",ru.ru_oublock);
|
|
if (ru.ru_oublock != 1) strcat(tb,"s");
|
|
LeftText(tb);
|
|
}
|
|
StarLine();
|
|
}
|
|
return 0;
|
|
}
|