/* c++ -O2 -o burn7.x burn7.cpp -lm -lnetcdf_c++ -lnetcdf */ #define NETCDF_OUTPUT #define V0 "burn 7.7 (02-Feb-2017)" #define V1 "KlimaCampus" #define V2 "Usage: burn7 [-help|-c|-d|-m|-n|-r|-s] " #define V3 "New: option <-g> writes Grads ctl for service plotting" #define V4 "New: comments (#) are allowed in namelist file" /* ============= */ /* include files */ /* ============= */ #include #include #include #include #include #include #include #include #include #ifdef OPEN_MP #include #endif #ifdef NETCDF_OUTPUT #include #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 = -1; /* 1: use Gaussian grid, 0: use regular grid */ int DPM = 0; /* Days Per Month */ int DPY = 0; /* Days Per Year */ 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 ; valarrayhsp; valarrayhfc; valarrayhgp; valarraypgp; valarraymgp; valarraypfc; valarraypsp; 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; valarrayOrography; 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; vectorHeadSt(8,0); // First header vector vectorHeadIn(8,0); // Input header vector vectorHeadOu(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= 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.size() == 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(vectorHead, 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 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 \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]; // if gridtype for output is not selected, choose Gauss grid // for matching resolution and regular grid else if (GaussGrid < 0) GaussGrid = (Lats == Gats && Lons == Gons); Gaulat = new GauLat(Gats,"Gaulat"); // Gaussian latitudes of input grid Outlon = new RegLon(Lons,"Outlon"); // Regular longitudes of output grid if (GaussGrid) Outlat = new GauLat(Lats,"Outlat"); else Outlat = new RegLat(Lats,"Outlat"); if (Debug) { Gaulat->PrintArray(); if (Lats != Gats || !GaussGrid) Outlat->PrintArray(); Outlon->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; Fargwt[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 *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 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 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(" : SERVICE, or NetCDF format file\n"); #else printf(" : SERVICE format file\n"); #endif printf(" namelist is read from \n"); printf(" printout is written to \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 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); } DPY = scanpar("dpy",0); if (DPY > 0) DaysPerYear = DPY; 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(); } if (RealSize == sizeof(float)) DaysPerYear = ReadFLOAT(); else DaysPerYear = 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= 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] == 'r') GaussGrid = 0; 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; }