From 9e537bfe539f5414af6663a249727e0a6fab2bf0 Mon Sep 17 00:00:00 2001 From: Uwe Schulzweida <uwe.schulzweida@mpimet.mpg.de> Date: Wed, 8 Apr 2015 13:30:53 +0000 Subject: [PATCH] added afterburnerlib.c --- .gitattributes | 2 + src/Makefile.am | 2 + src/Makefile.in | 79 +- src/afterburner.h | 281 +++++ src/afterburnerlib.c | 2837 ++++++++++++++++++++++++++++++++++++++++++ src/specspace.c | 1 + 6 files changed, 3167 insertions(+), 35 deletions(-) create mode 100644 src/afterburner.h create mode 100644 src/afterburnerlib.c diff --git a/.gitattributes b/.gitattributes index 65db04930..0e9d7bbac 100644 --- a/.gitattributes +++ b/.gitattributes @@ -504,6 +504,8 @@ src/after_fctrans.c -text src/after_sptrans.c -text src/after_vertint.c -text src/after_vertint.h -text +src/afterburner.h -text +src/afterburnerlib.c -text src/cdo.c -text src/cdo.h -text src/cdo_getopt.c -text diff --git a/src/Makefile.am b/src/Makefile.am index bb26de2fe..6042d63d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,6 +13,8 @@ libcdo_la_SOURCES = \ after_dvtrans.c \ after_vertint.c \ after_vertint.h \ + afterburnerlib.c\ + afterburner.h \ constants.h \ constants.c \ color.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 8424e691e..72f184590 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -120,15 +120,16 @@ am_libcdo_la_OBJECTS = libcdo_la-cdo_pthread.lo libcdo_la-cdo_vlist.lo \ libcdo_la-cdo_getopt.lo libcdo_la-cdo_history.lo \ libcdo_la-after_sptrans.lo libcdo_la-after_fctrans.lo \ libcdo_la-after_dvtrans.lo libcdo_la-after_vertint.lo \ - libcdo_la-constants.lo libcdo_la-color.lo \ - libcdo_la-commandline.lo libcdo_la-datetime.lo \ - libcdo_la-ecacore.lo libcdo_la-ecautil.lo \ - libcdo_la-exception.lo libcdo_la-expr.lo libcdo_la-expr_lex.lo \ - libcdo_la-expr_yacc.lo libcdo_la-features.lo \ - libcdo_la-field.lo libcdo_la-field2.lo libcdo_la-fieldc.lo \ - libcdo_la-fieldmem.lo libcdo_la-fieldmer.lo \ - libcdo_la-fieldzon.lo libcdo_la-gradsdeslib.lo \ - libcdo_la-grid.lo libcdo_la-grid_area.lo libcdo_la-grid_gme.lo \ + libcdo_la-afterburnerlib.lo libcdo_la-constants.lo \ + libcdo_la-color.lo libcdo_la-commandline.lo \ + libcdo_la-datetime.lo libcdo_la-ecacore.lo \ + libcdo_la-ecautil.lo libcdo_la-exception.lo libcdo_la-expr.lo \ + libcdo_la-expr_lex.lo libcdo_la-expr_yacc.lo \ + libcdo_la-features.lo libcdo_la-field.lo libcdo_la-field2.lo \ + libcdo_la-fieldc.lo libcdo_la-fieldmem.lo \ + libcdo_la-fieldmer.lo libcdo_la-fieldzon.lo \ + libcdo_la-gradsdeslib.lo libcdo_la-grid.lo \ + libcdo_la-grid_area.lo libcdo_la-grid_gme.lo \ libcdo_la-grid_lcc.lo libcdo_la-grid_rot.lo \ libcdo_la-gridreference.lo libcdo_la-griddes.lo \ libcdo_la-griddes_h5.lo libcdo_la-griddes_nc.lo \ @@ -543,32 +544,32 @@ noinst_LTLIBRARIES = libcdo.la libcdo_la_SOURCES = cdo_int.h compare.h cdo_pthread.c cdo_vlist.c \ cdo_getopt.c cdo_getopt.h cdo_history.c after_sptrans.c \ after_fctrans.c after_dvtrans.c after_vertint.c \ - after_vertint.h constants.h constants.c color.c color.h \ - commandline.c const.h counter.h datetime.c datetime.h \ - dmemory.h dtypes.h ecacore.c ecacore.h ecautil.c ecautil.h \ - error.h etopo.h temp.h mask.h exception.c expr.c expr.h \ - expr_lex.c expr_yacc.c expr_yacc.h features.c field.c field.h \ - field2.c fieldc.c fieldmem.c fieldmer.c fieldzon.c functs.h \ - gradsdeslib.c gradsdeslib.h grid.c grid.h grid_area.c \ - grid_gme.c grid_lcc.c grid_rot.c gridreference.c griddes.c \ - griddes.h griddes_h5.c griddes_nc.c hetaeta.c hetaeta.h \ - institution.c interpol.c interpol.h job.c juldate.c kvlist.c \ - kvlist.h list.c list.h merge_sort2.c merge_sort2.h modules.c \ - modules.h namelist.c namelist.h normal.c nth_element.c \ - nth_element.h operator_help.h par_io.c par_io.h percentiles.c \ - percentiles.h pipe.c pipe.h pragma_omp_atomic_update.h \ - printinfo.h process.c process.h pstream.c pstream.h \ - pstream_int.h pthread_debug.c pthread_debug.h readline.c \ - realtime.c remap.h remaplib.c remapsort.c remap_scrip_io.c \ - remap_search_reg2d.c remap_search_latbins.c remap_store_link.c \ - remap_store_link.h remap_store_link_cnsrv.c \ - remap_store_link_cnsrv.h remap_conserv.c remap_conserv_scrip.c \ - remap_distwgt_scrip.c remap_bicubic_scrip.c \ - remap_bilinear_scrip.c stdnametable.c stdnametable.h \ - specspace.c specspace.h statistic.c statistic.h table.c text.c \ - text.h timebase.h timer.c userlog.c util.c util.h zaxis.c \ - clipping/clipping.c clipping/clipping.h clipping/area.c \ - clipping/area.h clipping/ensure_array_size.c \ + after_vertint.h afterburnerlib.c afterburner.h constants.h \ + constants.c color.c color.h commandline.c const.h counter.h \ + datetime.c datetime.h dmemory.h dtypes.h ecacore.c ecacore.h \ + ecautil.c ecautil.h error.h etopo.h temp.h mask.h exception.c \ + expr.c expr.h expr_lex.c expr_yacc.c expr_yacc.h features.c \ + field.c field.h field2.c fieldc.c fieldmem.c fieldmer.c \ + fieldzon.c functs.h gradsdeslib.c gradsdeslib.h grid.c grid.h \ + grid_area.c grid_gme.c grid_lcc.c grid_rot.c gridreference.c \ + griddes.c griddes.h griddes_h5.c griddes_nc.c hetaeta.c \ + hetaeta.h institution.c interpol.c interpol.h job.c juldate.c \ + kvlist.c kvlist.h list.c list.h merge_sort2.c merge_sort2.h \ + modules.c modules.h namelist.c namelist.h normal.c \ + nth_element.c nth_element.h operator_help.h par_io.c par_io.h \ + percentiles.c percentiles.h pipe.c pipe.h \ + pragma_omp_atomic_update.h printinfo.h process.c process.h \ + pstream.c pstream.h pstream_int.h pthread_debug.c \ + pthread_debug.h readline.c realtime.c remap.h remaplib.c \ + remapsort.c remap_scrip_io.c remap_search_reg2d.c \ + remap_search_latbins.c remap_store_link.c remap_store_link.h \ + remap_store_link_cnsrv.c remap_store_link_cnsrv.h \ + remap_conserv.c remap_conserv_scrip.c remap_distwgt_scrip.c \ + remap_bicubic_scrip.c remap_bilinear_scrip.c stdnametable.c \ + stdnametable.h specspace.c specspace.h statistic.c statistic.h \ + table.c text.c text.h timebase.h timer.c userlog.c util.c \ + util.h zaxis.c clipping/clipping.c clipping/clipping.h \ + clipping/area.c clipping/area.h clipping/ensure_array_size.c \ clipping/ensure_array_size.h clipping/geometry_tools.c \ clipping/geometry.h clipping/grid.h clipping/points.h \ clipping/dep_list.h clipping/grid_cell.c clipping/grid_cell.h \ @@ -976,6 +977,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-after_fctrans.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-after_sptrans.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-after_vertint.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-afterburnerlib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-cdo_getopt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-cdo_history.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-cdo_pthread.Plo@am__quote@ @@ -1136,6 +1138,13 @@ libcdo_la-after_vertint.lo: after_vertint.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcdo_la-after_vertint.lo `test -f 'after_vertint.c' || echo '$(srcdir)/'`after_vertint.c +libcdo_la-afterburnerlib.lo: afterburnerlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcdo_la-afterburnerlib.lo -MD -MP -MF $(DEPDIR)/libcdo_la-afterburnerlib.Tpo -c -o libcdo_la-afterburnerlib.lo `test -f 'afterburnerlib.c' || echo '$(srcdir)/'`afterburnerlib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-afterburnerlib.Tpo $(DEPDIR)/libcdo_la-afterburnerlib.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='afterburnerlib.c' object='libcdo_la-afterburnerlib.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcdo_la-afterburnerlib.lo `test -f 'afterburnerlib.c' || echo '$(srcdir)/'`afterburnerlib.c + libcdo_la-constants.lo: constants.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcdo_la-constants.lo -MD -MP -MF $(DEPDIR)/libcdo_la-constants.Tpo -c -o libcdo_la-constants.lo `test -f 'constants.c' || echo '$(srcdir)/'`constants.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-constants.Tpo $(DEPDIR)/libcdo_la-constants.Plo diff --git a/src/afterburner.h b/src/afterburner.h new file mode 100644 index 000000000..392318748 --- /dev/null +++ b/src/afterburner.h @@ -0,0 +1,281 @@ +#ifndef _AFTER_H +#define _AFTER_H + +/* =============================================== */ +/* These include files should be standard on all */ +/* UNIX systems. */ +/* =============================================== */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include <ctype.h> +#include <math.h> +#include <float.h> +#include <time.h> +#include <pwd.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <limits.h> + +#ifndef _ERROR_H +# include "error.h" +#endif +#ifndef _DMEMORY_H +# include "dmemory.h" +#endif + +#define FT_GRIB 1 +#define FT_SERV 2 +#define FT_CDF 3 + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define MaxLevel 1024 + +#define MaxCodes 277 + +#define S_ECHAM5 1 + +struct Date +{ + int yr; + int mo; + int dy; + int hr; + int mn; +}; + +struct Control +{ + int Mean; + int MeanCount0; + int MeanCount; + int Multi; + int Nfiles; + int TermCount; + + int OutputInterval; + int EndOfInterval; + + int AnalysisData; /* 0 = ECHAM Data, 1 = ECMWF Spectral Analyses */ + int DayIn; /* day increment of infiles if Multi = TRUE */ + int Debug; + int Extrapolate; + int Szip; + + int istreamID; + int ostreamID; + int ostreamID2; + int ivlistID; + int ovlistID; + int ovlistID2; + + struct Date NextDate; + struct Date NewDate; + struct Date OldDate; + struct Date StartDate; + + int nvct; + double *vct; + + int *vert_index; + int *pnmiss; + double *Orography; + double *p_of_height; + + int Type; + int unitsel; + + int Fouriers; + int Latitudes; + int Longitudes; + int HalfLevels; + int Gaussian; + int Spectral; + + int Truncation; + int Waves; + + int Dim3FC, Dim3SP, Dim3GP; + int DimFC, DimGP, DimSP; + int DimSP_half; + + double *poli; + double *pold; + double *pdev; + double *pol2; + double *pol3; + + double *dv2uv_f1; + double *dv2uv_f2; + + int NumCodesRequest; + + int NumLevel; + int NumLevelFound; + int NumLevelRequest; + double LevelRequest[MaxLevel]; + + double *rcoslat; + double *coslat; + double *DerivationFactor; + double *Field; +}; + +struct Variable +{ + int needed0; /* var needed for process */ + int needed; /* var needed for process */ + int selected; /* var selected for output */ + int detected; /* var detected in input */ + int comp; /* compute var if selected and not detected */ + int sfit; + int hlev; + int plev; + int ivarID; + int ovarID; /* 1st variable ID */ + int ovarID2; /* 2nd variable ID used for variance */ + int tableID; + int igridID; + int ogridID; + int izaxisID; + int ozaxisID; + int nmiss0; + int nmiss; + double missval; + double *spectral; + double *spectral0; + double *fourier; + double *hybrid; + double *hybrid0; + double *height; + double *grid; + double *grid0; + double *mean; + double *variance; + int *samp; +}; + +/* FFT */ + +void fft_set(double *trigs, long *ifax, long n); +void fc2gp(double *trig, long *ifax, double *fc, double *gp, long nlat, long nlon, long nlev, long nfc); +void gp2fc(double *trig, long *ifax, double *gp, double *fc, long nlat, long nlon, long nlev, long nfc); + +/* Convert Spectral Array to new resolution */ +void sp2sp(double *arrayIn, int truncIn, double *arrayOut, int truncOut); +void sp2fc(const double *sa, double *fa, const double *poli, long nlev, long nlat, long nfc, long nt); +void fc2sp(double *fa, double *sa, double *poli, int klev, int nlat, int nfc, int nt); + +/* Physc */ + +void dv2ps(const double * restrict div, double * restrict pot, long nlev, long ntr); +void dv2uv(double *d, double *o, double *u, double *v, double *f, double *g, + int nt, int nsp, int nlev); +void scaluv(double *fu, double rclat[], int nlat, int lot); +void uv2dv(double *fu, double *fv, double *sd, double *sv, + double *pol2, double *pol3, int klev, int nlat, int nt); +void geninx(long ntr, double *f, double *g); + +void MakeGeopotHeight(double *geop, double* gt, double *gq, double *ph, int nhor, int nlev); +void LayerWater (double *ww, double *ll, double pmax, double pmin, + int DimGP, int HalfLevels, double *vct); +void LayerCloud (double *cc, double *ll, double pmax, double pmin, + int DimGP, int HalfLevels, double *vct); + +#define LOW_CLOUD 34 +#define MID_CLOUD 35 +#define HIH_CLOUD 36 +#define LOW_WATER 37 /* not used ? */ +#define MID_WATER 38 /* not used ? */ +#define HIH_WATER 39 /* not used ? */ +#define ALL_WATER 40 /* not used ? */ + +#define GEOPOTENTIAL 129 +#define TEMPERATURE 130 +#define U_WIND 131 +#define V_WIND 132 +#define HUMIDITY 133 +#define PS 134 +#define OMEGA 135 +#define VORTICITY 138 +#define TS 139 +#define STREAM 148 +#define VELOPOT 149 +#define SLP 151 +#define LNPS 152 +#define DIVERGENCE 155 +#define GEOPOTHEIGHT 156 +#define RHUMIDITY 157 + +#define SW_BOT_CLF 189 /* not used ? */ +#define LW_BOT_CLF 190 /* not used ? */ +#define SW_TOP_CLF 191 /* not used ? */ +#define LW_TOP_CLF 192 /* not used ? */ +#define NET_TOP_CLF 193 /* not computed */ + +#define WINDSPEED 259 +#define PRECIP 260 +#define NET_TOP 261 +#define NET_BOT 262 +#define NET_HEAT 263 +#define NET_WATER 264 +#define SW_CLF 265 +#define LW_CLF 266 +#define NET_CLF 267 +#define SW_ATM 268 +#define LW_ATM 269 +#define NET_ATM 270 +#define SURF_RUNOFF 271 +#define DPSDX 273 +#define DPSDY 274 +#define FRESH_WATER 275 +#define PS_PROG 276 /* PS for prognostic timestep */ +#define HALF_PRESS 277 +#define FULL_PRESS 278 +#define THETAH 279 +#define THETAF 280 + +void *FreeMemory(void *ptr); +double *alloc_dp(int words, char *array_name); + +void after_copy_array(void *destination, void *source, int words); +void after_zero_array(double *field, int words); + +void after_read_vct(const char *vctfile, double **vct, int *nvct); + +void after_gp2sp(struct Control *globs, struct Variable *vars, int ccode); +void after_GP2FC(double *gp, double *fc, long nlat, long nlon, long nlev, long nfc); +void after_FC2GP(double *fc, double *gp, long nlat, long nlon, long nlev, long nfc); +void after_FCrh2FCsh(struct Control *globs, struct Variable *vars); +void after_SPuv2SPdv(struct Control *globs, struct Variable *vars); +void after_FCsh2FCrh(struct Control *globs, struct Variable *vars); + +void after_EchamCompGP(struct Control *globs, struct Variable *vars); +void after_processPL(struct Control *globs, struct Variable *vars); +void after_processML(struct Control *globs, struct Variable *vars); + +void after_AnalysisAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, int nmiss); +void after_EchamAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, int nmiss); + +void after_AnalysisDependencies(struct Variable *vars, int ncodes); +void after_EchamDependencies(struct Variable *vars, int ncodes, int type, int source); + + +#endif /* afterburner.h */ diff --git a/src/afterburnerlib.c b/src/afterburnerlib.c new file mode 100644 index 000000000..09206559e --- /dev/null +++ b/src/afterburnerlib.c @@ -0,0 +1,2837 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "cdi.h" + +#include "error.h" +#include "afterburner.h" +#include "constants.h" +#include "compare.h" +#include "after_vertint.h" + +static +char *FieldName(int code, const char *text) +{ + static char name[256]; + + sprintf(name, "[%3d].%s", code, text); + + return (name); +} + +/* Free array space */ +void *FreeMemory(void *ptr) +{ + free(ptr); + + return (NULL); +} + +static +void FreeSpectral(struct Variable *vars) +{ + int code; + + for ( code = MaxCodes-1; code >= 0; --code ) + if ( vars[code].spectral ) + vars[code].spectral = FreeMemory(vars[code].spectral); +} + +static +void FreeFourier(struct Variable *vars) +{ + int code; + + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].fourier ) + vars[code].fourier = FreeMemory(vars[code].fourier); +} + +static +void FreeHybrid(struct Variable *vars) +{ + int code; + + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].hybrid ) + vars[code].hybrid = FreeMemory(vars[code].hybrid); +} + +static +void FreeGrid(struct Variable *vars) +{ + int code; + + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].grid ) + vars[code].grid = FreeMemory(vars[code].grid); +} + +static +void FreeSamp(struct Variable *vars) +{ + int code; + + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].samp ) + vars[code].samp = FreeMemory(vars[code].samp); +} + +/* alloc_dp - Allocate space for double array */ +double *alloc_dp(int words, char *array_name) +{ + double *result = NULL; + + if ( words > 0 ) + { + result = (double *) malloc(words * sizeof(double)); + + if ( result == NULL ) SysError(array_name, "No Memory!"); + } + + return(result); +} + + +/* after_copy_array - Copy array of type double */ +void after_copy_array(void *destination, void *source, int words) +{ + memcpy(destination, source, words*sizeof(double)); +} + +/* after_zero_array - Set array of type double to zero */ +void after_zero_array(double *field, int words) +{ + memset((char *)field, 0, words*sizeof(double)); +} + +static +void IniQuaSum(double *dest, const double *restrict src, int len) +{ + int i; + + for ( i = 0; i < len; i++ ) + dest[i] = src[i] * src[i]; +} + +static +void AddQuaSum(double *dest, const double *restrict src, int len) +{ + int i; + + for ( i = 0; i < len; i++ ) + dest[i] += src[i] * src[i]; +} + +static +void VarQuaSum(double *Variance, const double *restrict Sum, int len, int n) +{ + int i; + double rn1; + + rn1 = 1.0 / (n-1); + + for ( i = 0; i < len; i++ ) + Variance[i] = (Variance[i] - Sum[i] * Sum[i] * n) * rn1; + + for ( i = 0; i < len; i++ ) + if (Variance[i] > 0.0) Variance[i] = sqrt(Variance[i]); + else Variance[i] = 0.0; +} + +static +void AddVector(double * restrict dest, const double *restrict src, long len, int *nmiss, double missval) +{ + long i; + + if ( *nmiss > 0 ) + { + for ( i = 0; i < len; i++ ) + if ( IS_NOT_EQUAL(src[i], missval) ) + { + if ( IS_NOT_EQUAL(dest[i], missval) ) + dest[i] += src[i]; + else + dest[i] = src[i]; + } + + *nmiss = 0; + for ( i = 0; i < len; i++ ) + if ( IS_EQUAL(dest[i], missval) ) *nmiss = *nmiss + 1; + + if ( *nmiss == 0 ) *nmiss = 1; + } + else + { +#if defined (_OPENMP) +#pragma omp parallel for +#endif + for ( i = 0; i < len; i++ ) dest[i] += src[i]; + } +} + +static +void Add2Vectors(double *dest, const double *restrict srcA, const double *restrict srcB, int len) +{ + int i; + + for ( i = 0; i < len; i++ ) + dest[i] = srcA[i] + srcB[i]; +} + +static +void Sub2Vectors(double *dest, const double *restrict srcA, const double *restrict srcB, int len) +{ + int i; + + for ( i = 0; i < len; i++ ) + dest[i] = srcA[i] - srcB[i]; +} + +static +void MultVectorScalar(double *dest, const double *restrict src, double factor, int len, int nmiss, double missval) +{ + int i; + + if ( nmiss > 0 ) + { + for ( i = 0; i < len; i++ ) + { + if ( IS_EQUAL(src[i], missval) ) + dest[i] = missval; + else + dest[i] = src[i] * factor; + } + } + else + { + for ( i = 0; i < len; i++ ) dest[i] = src[i] * factor; + } +} + +static +void DivVectorIvector(double *dest, const double *restrict src, const int *samp, int len, int *nmiss, double missval) +{ + int i; + + *nmiss = 0; + + for ( i = 0; i < len; i++ ) + { + if ( IS_EQUAL(src[i], missval) || samp[i] == 0 ) + { + dest[i] = missval; + *nmiss = *nmiss + 1; + } + else + dest[i] = src[i] / samp[i]; + } +} + + +void after_read_vct(const char *vctfile, double **vct, int *nvct) +{ + int n; + char line[1024]; + double va, vb; + + FILE *fp = fopen(vctfile, "r"); + if ( fp == NULL ) SysError( "Open failed on %s", vctfile); + + while ( fgets(line, 1023, fp) ) nvct++; + + *nvct *= 2; + *vct = (double *) malloc(*nvct*sizeof(double)); + + rewind(fp); + for ( int i = 0; i < *nvct/2; i++ ) + { + fgets(line, 1023, fp); + sscanf(line, "%d %lg %lg", &n, &va, &vb); + *vct[i] = va; + *vct[i+*nvct/2] = vb; + } + fprintf(stdout, " Reading VCT for %d hybrid levels from file %s\n", *nvct/2-1, vctfile); + + fclose(fp); +} + + +void after_gp2sp(struct Control *globs, struct Variable *vars, int ccode) +{ + struct Variable *var = &vars[ccode]; + + if ( var->spectral == NULL ) + { + if ( var->hybrid == NULL ) + { + fprintf(stderr,"%d.hybrid not found\n", ccode); + exit(99); + } + + if ( var->fourier == NULL ) + { + long fieldSize = globs->DimFC * var->hlev; + var->fourier = alloc_dp(fieldSize, "gp2sp.fourier"); + after_GP2FC(var->hybrid, var->fourier, + globs->Latitudes, globs->Longitudes, var->hlev, globs->Fouriers); + } + + var->spectral = alloc_dp(globs->Dim3SP, "gp2sp.spectral"); + fc2sp(var->fourier, var->spectral, + globs->pold, var->hlev, globs->Latitudes, globs->Fouriers, globs->Truncation); + } +} + + +void after_GP2FC(double *gp, double *fc, long nlat, long nlon, long nlev, long nfc) +{ + static long ifax[10]; + static double *trig = NULL; + + if ( ifax[9] != nlon ) + { + if ( trig ) free (trig); + trig = (double *) malloc(nlon * sizeof(double)); + fft_set (trig, ifax, nlon); + } + + gp2fc(trig, ifax, gp, fc, nlat, nlon, nlev, nfc); +} + + +void after_FC2GP(double *fc, double *gp, long nlat, long nlon, long nlev, long nfc) +{ + static long ifax[10]; + static double *trig = NULL; + + if ( ifax[9] != nlon ) + { + if ( trig ) free (trig); + trig = (double *) malloc(nlon * sizeof(double)); + fft_set (trig, ifax, nlon); + } + + fc2gp(trig, ifax, fc, gp, nlat, nlon, nlev, nfc); +} + +/* HUMTEST */ + +static +void sh2rh(int AnalysisData, double *sphum, double *rhum, double *t, int lev, + int dimgpout, double *level, double *fullpresshybrid) +{ + int lp,i; + int lpi,lfp; + double es, qsatr; + double *fullp; + double RALPW, RBETW, RGAMW; + // double RALPS, RBETS, RGAMS; + double RALP , RBET , RGAM ; + + /* ***************************************************** */ + /* Define constants for calculation in presence of water */ + /* ***************************************************** */ + RGAMW = (C_RCW - C_RCPV) / C_RV; + RBETW = C_RLVTT / C_RV + RGAMW * C_RTT; + RALPW = log(C_RESTT) + RBETW / C_RTT + RGAMW * log(C_RTT); + + /* ***************************************************** */ + /* Define constants for calculation in presence of ice */ + /* ***************************************************** */ + /* + RGAMS = (C_RCS - C_RCPV) / C_RV; + RBETS = C_RLSTT / C_RV + RGAMS * C_RTT; + RALPS = log(C_RESTT) + RBETS / C_RTT + RGAMS * log(C_RTT); + */ + if (AnalysisData) fullp = level; + else fullp = fullpresshybrid; + + /***************************************************/ + /* Diagnostics of saturation water vapour pressure */ + /* over ice makes no sense, therefore ... */ + /* Hint of Michael Ponater 08.10.97 */ + /***************************************************/ + RGAM = RGAMW; RBET = RBETW; RALP = RALPW; + for (lp = 0; lp < lev; lp++) { + for (i = 0; i < dimgpout; i++) { + lpi = lp*dimgpout + i; + lfp = (1 - AnalysisData)*lpi + AnalysisData*lp; + /* + if (t[lpi] < C_RTT) { + RGAM = RGAMS; RBET = RBETS; RALP = RALPS; + } else { + RGAM = RGAMW; RBET = RBETW; RALP = RALPW; + } + */ + es = (exp(RALP - RBET / t[lpi] - RGAM * log(t[lpi]))) / fullp[lfp]; + // qsat = es / (1. + C_RETV * (1. - es)); + qsatr = (1. + C_RETV * (1. - es)) / es; + rhum[lpi] = sphum[lpi] * 100. * qsatr; + } + } +} + +static +void rh2sh(double *sphum, double *rhum, double *t, int lev, int dimgpout, double *level) +{ + int lp,i; + int lpi; + double es,qsat; + double RALPW, RBETW, RGAMW; + // double RALPS, RBETS, RGAMS; + double RALP , RBET , RGAM ; + +/* ***************************************************** */ +/* Define constants for calculation in presence of water */ +/* ***************************************************** */ + RGAMW = (C_RCW - C_RCPV) / C_RV; + RBETW = C_RLVTT / C_RV + RGAMW * C_RTT; + RALPW = log(C_RESTT) + RBETW / C_RTT + RGAMW * log(C_RTT); + +/* ***************************************************** */ +/* Define constants for calculation in presence of ice */ +/* ***************************************************** */ + // RGAMS = (C_RCS - C_RCPV) / C_RV; + // RBETS = C_RLSTT / C_RV + RGAMS * C_RTT; + // RALPS = log(C_RESTT) + RBETS / C_RTT + RGAMS * log(C_RTT); + +/***************************************************/ +/* Diagnostics of saturation water vapour pressure */ +/* over ice makes no sense, therefore ... */ +/* Hint of Michael Ponater 08.10.97 */ +/***************************************************/ + + RGAM = RGAMW; RBET = RBETW; RALP = RALPW; + for (lp = 0; lp < lev; lp++) { + for (i = 0; i < dimgpout; i++) { + lpi = lp*dimgpout + i; +/* if (t[lpi] < C_RTT) { */ +/* RGAM = RGAMS; RBET = RBETS; RALP = RALPS; */ +/* } else { */ +/* RGAM = RGAMW; RBET = RBETW; RALP = RALPW; */ +/* } */ + es = (exp(RALP - RBET / t[lpi] - RGAM * log(t[lpi]))) / level[lp]; + qsat = es / (1. + C_RETV * (1. - es)); + sphum[lpi] = rhum[lpi] * qsat / 100.; + } + } +} + + +void after_FCrh2FCsh(struct Control *globs, struct Variable *vars) +{ + long fieldSize = globs->DimGP * globs->NumLevelRequest; + + if ( vars[RHUMIDITY].grid == NULL ) + vars[RHUMIDITY].grid = alloc_dp(fieldSize, "vars[RHUMIDITY].grid"); + if ( vars[TEMPERATURE].grid == NULL ) + vars[TEMPERATURE].grid = alloc_dp(fieldSize, "vars[TEMPERATURE].grid"); + if ( vars[HUMIDITY].grid == NULL ) + vars[HUMIDITY].grid = alloc_dp(fieldSize, "vars[HUMIDITY].grid"); + + after_FC2GP(vars[RHUMIDITY].fourier, vars[RHUMIDITY].grid, + globs->Latitudes, globs->Longitudes, vars[RHUMIDITY].plev, globs->Fouriers); + after_FC2GP(vars[TEMPERATURE].fourier, vars[TEMPERATURE].grid, + globs->Latitudes, globs->Longitudes, vars[TEMPERATURE].plev, globs->Fouriers); + + rh2sh(vars[HUMIDITY].grid, vars[RHUMIDITY].grid, vars[TEMPERATURE].grid, globs->NumLevelRequest, + globs->DimGP, globs->LevelRequest); + + after_GP2FC(vars[HUMIDITY].grid, vars[HUMIDITY].fourier, + globs->Latitudes, globs->Longitudes, vars[HUMIDITY].plev, globs->Fouriers); + + vars[HUMIDITY].grid = FreeMemory(vars[HUMIDITY].grid); + vars[RHUMIDITY].grid = FreeMemory(vars[RHUMIDITY].grid); + vars[TEMPERATURE].grid = FreeMemory(vars[TEMPERATURE].grid); +} + + +void after_SPuv2SPdv(struct Control *globs, struct Variable *vars) +{ + int i; + long fieldSize; + double *Div, *DivOut, *Vor, *VorOut; + + Div = DivOut = vars[DIVERGENCE].spectral; + Vor = VorOut = vars[VORTICITY].spectral; + fieldSize = globs->DimFC * globs->NumLevelRequest; + + if ( vars[U_WIND].fourier == NULL ) + vars[U_WIND].fourier = alloc_dp(fieldSize, "vars[U_WIND].fourier"); + if ( vars[V_WIND].fourier == NULL ) + vars[V_WIND].fourier = alloc_dp(fieldSize, "vars[V_WIND].fourier"); + + sp2fc(vars[U_WIND].spectral, vars[U_WIND].fourier, globs->poli, + globs->NumLevelRequest, globs->Latitudes, globs->Fouriers, globs->Truncation); + sp2fc(vars[V_WIND].spectral, vars[V_WIND].fourier, globs->poli, + globs->NumLevelRequest, globs->Latitudes, globs->Fouriers, globs->Truncation); + uv2dv(vars[U_WIND].fourier, vars[V_WIND].fourier, Div, Vor, + globs->pol2, globs->pol3, globs->NumLevelRequest, globs->Latitudes, globs->Truncation); + + vars[U_WIND].fourier = FreeMemory(vars[U_WIND].fourier); + vars[V_WIND].fourier = FreeMemory(vars[V_WIND].fourier); + + for (i = 0; i < globs->NumLevelRequest; ++i) { + sp2sp(Div, globs->Truncation, DivOut, globs->Truncation); + sp2sp(Vor, globs->Truncation, VorOut, globs->Truncation); + Div += globs->DimSP; + Vor += globs->DimSP; + DivOut += globs->DimSP; + VorOut += globs->DimSP; + } +} + + +void after_FCsh2FCrh(struct Control *globs, struct Variable *vars) +{ + long fieldSize; + + fieldSize = globs->DimGP * globs->NumLevelRequest; + + if ( vars[RHUMIDITY].grid == NULL ) + vars[RHUMIDITY].grid = alloc_dp(fieldSize, "vars[RHUMIDITY].grid"); + if ( vars[TEMPERATURE].grid == NULL ) + vars[TEMPERATURE].grid = alloc_dp(fieldSize, "vars[TEMPERATURE].grid"); + if ( vars[HUMIDITY].grid == NULL ) + vars[HUMIDITY].grid = alloc_dp(fieldSize, "vars[HUMIDITY].grid"); + + after_FC2GP(vars[HUMIDITY].fourier, vars[HUMIDITY].grid, + globs->Latitudes, globs->Longitudes, vars[HUMIDITY].plev, globs->Fouriers); + after_FC2GP(vars[TEMPERATURE].fourier, vars[TEMPERATURE].grid, + globs->Latitudes, globs->Longitudes, vars[TEMPERATURE].plev, globs->Fouriers); + + sh2rh(globs->AnalysisData, vars[HUMIDITY].grid, vars[RHUMIDITY].grid, vars[TEMPERATURE].grid, globs->NumLevelRequest, + globs->DimGP, globs->LevelRequest, vars[FULL_PRESS].hybrid); + + after_GP2FC(vars[RHUMIDITY].grid, vars[RHUMIDITY].fourier, + globs->Latitudes, globs->Longitudes, vars[RHUMIDITY].plev, globs->Fouriers); + + vars[HUMIDITY].grid = FreeMemory(vars[HUMIDITY].grid); + vars[RHUMIDITY].grid = FreeMemory(vars[RHUMIDITY].grid); + vars[TEMPERATURE].grid = FreeMemory(vars[TEMPERATURE].grid); +} +/* ENDE HUMTEST */ + +static +void CheckAnalyses(struct Variable *vars) +{ + int code; + extern int labort_after; + + for ( code = 0; code < 272; code++ ) + if ( vars[code].needed && + code != DIVERGENCE && + code != VORTICITY && + code != STREAM && + code != U_WIND && + code != HUMIDITY && + code != VELOPOT && + code != V_WIND && + code != RHUMIDITY && + code != GEOPOTHEIGHT && + code != PS && + vars[code].spectral == NULL && vars[code].grid == NULL ) + { + if ( labort_after ) + Error("Code %3d not found", code); + else + Warning("Code %3d not found", code); + } +} + +/* Process Pressure Level data */ +void after_processPL(struct Control *globs, struct Variable *vars) +{ + int code, l; + long fieldSize; + int lindex, nlevel; + int offset; + + globs->MeanCount++; + globs->TermCount++; + + if ( globs->MeanCount == 1 ) + { + if ( globs->Debug ) fprintf(stderr, "CheckAnalyses: %d %d\n", globs->TermCount, globs->MeanCount); + CheckAnalyses(vars); + globs->StartDate = globs->OldDate; + } + if ( globs->TermCount > 120 ) globs->Debug = 0; + + /* ============================== */ + /* Computations in spectral space */ + /* ============================== */ + + if ( vars[TEMPERATURE].needed ) + { + vars[TEMPERATURE].hlev = 2; + vars[TEMPERATURE].plev = globs->NumLevelRequest; + vars[TEMPERATURE].sfit = TRUE; + } + + if ( vars[GEOPOTHEIGHT].comp ) + { + vars[GEOPOTHEIGHT].hlev = 2; + vars[GEOPOTHEIGHT].plev = globs->NumLevelRequest; + vars[GEOPOTHEIGHT].sfit = TRUE; + } + + if ( vars[GEOPOTHEIGHT].comp && vars[GEOPOTENTIAL].detected ) + { + if ( vars[GEOPOTHEIGHT].spectral == NULL ) + vars[GEOPOTHEIGHT].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "GEOPOTHEIGHT.spectral"); + MultVectorScalar(vars[GEOPOTHEIGHT].spectral, vars[GEOPOTENTIAL].spectral, + C_RG, globs->DimSP*globs->NumLevelRequest, 0, 0); + vars[GEOPOTENTIAL].needed = vars[GEOPOTENTIAL].selected; + } + + if ( globs->Type == 50 && vars[HUMIDITY].needed && vars[HUMIDITY].spectral == NULL ) + { + vars[HUMIDITY].plev = globs->NumLevelRequest; + vars[HUMIDITY].sfit = TRUE; + vars[HUMIDITY].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[HUMIDITY].spectral"); + /* + SPrh2SPsh(); + */ + vars[RHUMIDITY].needed = vars[RHUMIDITY].selected; + vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; + } + + if ( vars[U_WIND].spectral && vars[V_WIND].spectral && + (vars[DIVERGENCE].comp || vars[VORTICITY].comp) ) + { + vars[DIVERGENCE].hlev = vars[VORTICITY].hlev = 2; + vars[DIVERGENCE].plev = vars[VORTICITY].plev = globs->NumLevelRequest; + vars[DIVERGENCE].sfit = vars[VORTICITY].sfit = TRUE; + if ( vars[DIVERGENCE].spectral == NULL ) + vars[DIVERGENCE].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[DIVERGENCE].spectral"); + if ( vars[VORTICITY].spectral == NULL ) + vars[VORTICITY].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[VORTICITY].spectral"); + after_SPuv2SPdv(globs, vars); + } + + if ( vars[U_WIND].comp || vars[V_WIND].comp ) + { + vars[U_WIND].hlev = vars[V_WIND].hlev = 2; + vars[U_WIND].plev = vars[V_WIND].plev = globs->NumLevelRequest; + vars[U_WIND].sfit = vars[V_WIND].sfit = TRUE; + if ( vars[U_WIND].spectral == NULL ) + vars[U_WIND].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[U_WIND].spectral"); + if ( vars[V_WIND].spectral == NULL ) + vars[V_WIND].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[V_WIND].spectral"); + dv2uv(vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, + vars[U_WIND].spectral, vars[V_WIND].spectral, + globs->dv2uv_f1, globs->dv2uv_f2, + globs->Truncation, globs->DimSP, globs->NumLevelRequest); + } + + if ( vars[VELOPOT].comp ) + { + vars[VELOPOT].hlev = 2; + vars[VELOPOT].plev = globs->NumLevelRequest; + vars[VELOPOT].sfit = TRUE; + if ( vars[VELOPOT].spectral == NULL ) + vars[VELOPOT].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[VELOPOT].spectral"); + dv2ps(vars[DIVERGENCE].spectral, vars[VELOPOT].spectral, globs->NumLevelRequest, globs->Truncation); + } + + if ( vars[STREAM].comp ) + { + vars[STREAM].hlev = 2; + vars[STREAM].plev = globs->NumLevelRequest; + vars[STREAM].sfit = TRUE; + if ( vars[STREAM].spectral == NULL ) + vars[STREAM].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[STREAM].spectral"); + dv2ps(vars[VORTICITY].spectral, vars[STREAM].spectral, globs->NumLevelRequest, globs->Truncation); + } + + /* --------------------------- */ + /* Output of spectral fields */ + /* --------------------------- */ + + if ( globs->Type == 50 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].spectral ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].spectral, 0); + else + Error("Code %d not available on spectral space!", code); + } + + FreeSpectral(vars); + return; + } + + /* =============================== */ + /* Transformation to fourier space */ + /* Computations in fourier space */ + /* =============================== */ + + if ( globs->Type >= 60 ) + { + for (code = 0; code < MaxCodes; code++) + if (vars[code].needed && vars[code].spectral) + { + if (vars[code].fourier == NULL) + { + fieldSize = vars[code].plev * globs->DimFC; + vars[code].fourier = alloc_dp(fieldSize, FieldName(code,"fourier")); + } + sp2fc(vars[code].spectral,vars[code].fourier,globs->poli, + vars[code].plev,globs->Latitudes,globs->Fouriers,globs->Truncation); + } + if ( vars[U_WIND].needed && vars[U_WIND].fourier ) + scaluv(vars[U_WIND].fourier, globs->rcoslat, globs->Latitudes, globs->Fouriers*globs->NumLevelRequest); + if ( vars[V_WIND].needed && vars[V_WIND].fourier ) + scaluv(vars[V_WIND].fourier, globs->rcoslat, globs->Latitudes, globs->Fouriers*globs->NumLevelRequest); + + /* HUMTEST */ + if ( globs->Type < 70 && vars[HUMIDITY].needed && vars[HUMIDITY].fourier == NULL ) + { + vars[HUMIDITY].plev = globs->NumLevelRequest; + vars[HUMIDITY].sfit = TRUE; + vars[HUMIDITY].fourier = alloc_dp(globs->DimFC*globs->NumLevelRequest, "vars[HUMIDITY].fourier"); + + after_FCrh2FCsh(globs, vars); + + vars[RHUMIDITY].needed = vars[RHUMIDITY].selected; + vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; + } + + if ( globs->Type < 70 && vars[RHUMIDITY].needed && vars[RHUMIDITY].fourier == NULL ) + { + vars[RHUMIDITY].plev = globs->NumLevelRequest; + vars[RHUMIDITY].sfit = TRUE; + vars[RHUMIDITY].fourier = alloc_dp(globs->DimFC*globs->NumLevelRequest, "vars[RHUMIDITY].fourier"); + + after_FCsh2FCrh(globs, vars); + + vars[HUMIDITY].needed = vars[HUMIDITY].selected; + vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; + } + /* ENDE HUMTEST */ + } + + FreeSpectral(vars); + + /* -------------------------- */ + /* Output of fourier fields */ + /* -------------------------- */ + + if ( globs->Type == 60 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].fourier ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].fourier, 0); + else + Error("Code %d not available on fourier space!", code); + } + + FreeFourier(vars); + return; + } + + /* ----------------------- */ + /* Output of zonal means */ + /* ----------------------- */ + + if ( globs->Type == 61 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].fourier ) + { + nlevel = zaxisInqSize(vars[code].ozaxisID); + for ( lindex = 0; lindex < nlevel; lindex++ ) + { + offset = lindex*globs->DimFC; + streamWriteVarSlice(globs->ostreamID, vars[code].ovarID, lindex, vars[code].fourier+offset, 0); + } + } + else + Error("Code %d not available on zonal mean!", code); + } + + FreeFourier(vars); + return; + } + + /* ============================ */ + /* Transformation to gridpoints */ + /* ============================ */ + + if ( vars[PS].comp && vars[LNPS].grid ) + { + if (vars[PS].grid == NULL) vars[PS].grid = alloc_dp(globs->DimGP, "Ps"); + for (l = 0; l < globs->DimGP; l++) vars[PS].grid[l] = exp(vars[LNPS].grid[l]); + } + + if ( globs->Type >= 70 ) + { + for (code = 0; code < MaxCodes; code++) + if (vars[code].needed && vars[code].fourier) + { + if (vars[code].grid == NULL) + { + fieldSize = vars[code].plev * globs->DimGP; + vars[code].grid = alloc_dp(fieldSize,FieldName(code,"grid")); + } + + after_FC2GP(vars[code].fourier,vars[code].grid, + globs->Latitudes,globs->Longitudes,vars[code].plev,globs->Fouriers); + } + } + + FreeFourier(vars); + + /* HUMTEST */ + /* -------------------------------- */ + /* Computation in gridpoint space */ + /* -------------------------------- */ + + if ( vars[RHUMIDITY].needed && vars[RHUMIDITY].grid == NULL ) + { + vars[RHUMIDITY].plev = globs->NumLevelRequest; + vars[RHUMIDITY].sfit = TRUE; + vars[RHUMIDITY].grid = alloc_dp(globs->DimGP*globs->NumLevelRequest, "vars[RHUMIDITY].grid"); + sh2rh(globs->AnalysisData, vars[HUMIDITY].grid, vars[RHUMIDITY].grid, vars[TEMPERATURE].grid, globs->NumLevelRequest, + globs->DimGP, globs->LevelRequest, vars[FULL_PRESS].hybrid); + vars[HUMIDITY].needed = vars[HUMIDITY].selected; + vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; + } + + if ( vars[HUMIDITY].needed && vars[HUMIDITY].grid == NULL ) + { + vars[HUMIDITY].plev = globs->NumLevelRequest; + vars[HUMIDITY].sfit = TRUE; + vars[HUMIDITY].grid = alloc_dp(globs->DimGP*globs->NumLevelRequest, "vars[HUMIDITY].grid"); + rh2sh(vars[HUMIDITY].grid, vars[RHUMIDITY].grid, vars[TEMPERATURE].grid, globs->NumLevelRequest, + globs->DimGP, globs->LevelRequest); + vars[RHUMIDITY].needed = vars[RHUMIDITY].selected; + vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; + } + /* HUMTEST ENDE */ + + /* -------------------------- */ + /* Computation of Means */ + /* -------------------------- */ + + if ( globs->Mean ) + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].grid ) + { + fieldSize = globs->DimGP * vars[code].plev; + if (vars[code].mean == NULL) + vars[code].mean = alloc_dp(fieldSize,FieldName(code,"mean")); + + if (globs->MeanCount == 1) + after_copy_array(vars[code].mean, vars[code].grid, fieldSize); + else + AddVector(vars[code].mean, vars[code].grid, fieldSize, + &vars[code].nmiss, vars[code].missval); + + if ( globs->EndOfInterval ) + { + if ( vars[code].samp == NULL ) + MultVectorScalar(vars[code].mean, vars[code].mean, 1.0/globs->MeanCount, fieldSize, + vars[code].nmiss, vars[code].missval); + else + DivVectorIvector(vars[code].mean, vars[code].mean, vars[code].samp, fieldSize, + &vars[code].nmiss, vars[code].missval); + } + } + + /* -------------------------- */ + /* Computation of Variances */ + /* -------------------------- */ + + if ( globs->Mean > 1 ) + for (code = 0; code < MaxCodes; code++) + if (vars[code].needed && vars[code].mean) + { + fieldSize = globs->DimGP * vars[code].plev; + if (vars[code].variance == NULL) + vars[code].variance = alloc_dp(fieldSize,FieldName(code,"var")); + if (globs->MeanCount == 1) + IniQuaSum(vars[code].variance,vars[code].grid,fieldSize); + else + AddQuaSum(vars[code].variance,vars[code].grid,fieldSize); + + if (globs->EndOfInterval) VarQuaSum(vars[code].variance,vars[code].mean,fieldSize, globs->MeanCount); + } + + if ( globs->Mean && !globs->EndOfInterval ) + { + FreeGrid(vars); + return; + } + + /* ---------------------------------------------- */ + /* Output of pressure level means and variances */ + /* ---------------------------------------------- */ + + if ( globs->Type == 70 && globs->Mean && globs->EndOfInterval ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( globs->Mean != 2 ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].mean, vars[code].nmiss); + if ( globs->Mean >= 2 ) + streamWriteVar(globs->ostreamID2, vars[code].ovarID2, vars[code].variance, vars[code].nmiss); + } + + FreeSamp(vars); + FreeGrid(vars); + return; + } + + /* -------------------------------- */ + /* Output of pressure level grids */ + /* -------------------------------- */ + + if ( globs->Type == 70 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].grid, vars[code].nmiss); + + FreeGrid(vars); + return; + } +} + +static +void theta(double *pthetaf, double *pthetah, double *ph, double *ps, + double *tf, double *ts, int levels, int dimgp, int dim3gp) +{ + int h,l; + double kappa; + double *thetah = pthetah; + double *thetaf = pthetaf; + + kappa = PlanetRD / C_RCPD; + + for (h = 0; h < dimgp; h++) thetah[h] = 0.0; + thetah += dimgp; + for (l = 0; l < levels - 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; + } + after_copy_array(thetah,ts,dimgp); + thetah = pthetah; + for (h = 0; h < dim3gp; h++) { + thetaf[h] = 0.5 * (thetah[h] + thetah[h+dimgp]); + } +} + +static +void windSpeed(double *uvspeed, double *u, double *v, int dim3gp) +{ + int i; + + for (i = 0; i < dim3gp; i++) + uvspeed[i] = sqrt(u[i] * u[i] + v[i] * v[i]); +} + +static +void Omega(double *omega_in, double *divergence, double *u_wind, double *v_wind, + double *halfpress, double *fullpress, double *dpsdx, double *dpsdy, + double *vct, int dimgp, int nlev) +{ + int i, j; + double DeltaHybrid, Cterm, Pterm; + double *diver, *halfp, *fullp, *uwind, *vwind; + double *omega = omega_in; + + /* Compute half level part of vertical velocity */ + + for ( i = 0; i < dimgp; i++ ) omega[i] = 0.0; + + for ( j = 0; j < nlev; j++ ) + { + omega = omega_in + j*dimgp; + halfp = halfpress + j*dimgp; + diver = divergence + j*dimgp; + uwind = u_wind + j*dimgp; + vwind = v_wind + j*dimgp; + + DeltaHybrid = vct[nlev+j+2] - vct[nlev+j+1]; +#if defined (SX) +#pragma vdir nodep +#endif +#if defined (__uxp__) +#pragma loop novrec +#endif +#if defined (_OPENMP) +#pragma omp parallel for +#endif + for ( i = 0; i < dimgp; i++ ) + { + omega[i+dimgp] = omega[i] + - diver[i] * (halfp[i+dimgp] - halfp[i]) + - DeltaHybrid * (uwind[i]*dpsdx[i] + vwind[i]*dpsdy[i]); + } + } + + /* interpolate to full levels */ + + for ( j = 0; j < nlev; j++ ) + { + omega = omega_in + j*dimgp; +#if defined (SX) +#pragma vdir nodep +#endif +#if defined (__uxp__) +#pragma loop novrec +#endif +#if defined (_OPENMP) +#pragma omp parallel for +#endif + for ( i = 0; i < dimgp; i++ ) + omega[i] = 0.5 * (omega[i] + omega[i+dimgp]); + } + + /* compute full level part of vertical velocity */ + +#if defined (_OPENMP) +#pragma omp parallel for default(shared) private(i, omega, halfp, fullp, uwind, vwind, DeltaHybrid, Cterm, Pterm) +#endif + for ( j = 0; j < nlev; j++ ) + { + omega = omega_in + j*dimgp; + halfp = halfpress + j*dimgp; + fullp = fullpress + j*dimgp; + uwind = u_wind + j*dimgp; + vwind = v_wind + j*dimgp; + + DeltaHybrid = vct[nlev+j+2] - vct[nlev+j+1]; + if ( fabs(DeltaHybrid) > 0 ) + { + Cterm = vct[j+1]*vct[nlev+j+1] - vct[j]*vct[nlev+j+2]; +#if defined (__uxp__) +#pragma loop novrec +#endif + for ( i = 0; i < dimgp; i++ ) + { + if ( Cterm != 0.0 ) + Pterm = Cterm / (halfp[i+dimgp]-halfp[i]) * log(halfp[i+dimgp]/halfp[i]); + else + Pterm = 0.0; + + omega[i] += fullp[i] * (uwind[i]*dpsdx[i] + vwind[i]*dpsdy[i]) + / (halfp[i+dimgp] - halfp[i]) * (DeltaHybrid + Pterm); + } + } + } +} + + +void MakeGeopotHeight(double *geop, double* gt, double *gq, double *ph, int nhor, int nlev) +{ + int i, j; + double vtmp; + double zrg; + double z2log2; + double *geopl, *gtl, *gql, *phl; + + z2log2 = 2.0 * log(2.0); + vtmp = (C_RV / PlanetRD) - 1.0; + zrg = 1.0 / PlanetGrav; + + if ( gq ) /* Humidity is present */ + { + for ( j = nlev ; j > 1 ; j-- ) + { + geopl = geop + nhor*(j-1); + gtl = gt + nhor*(j-1); + gql = gq + nhor*(j-1); + phl = ph + nhor*(j-1); +#if defined (SX) +#pragma vdir nodep +#endif +#if defined (_OPENMP) +#pragma omp parallel for +#endif + for ( i = 0; i < nhor; i++ ) + geopl[i] = geopl[i+nhor] + PlanetRD * gtl[i] * (1.0 + vtmp * gql[i]) + * log(phl[i+nhor] / phl[i]); + } + +#if defined (SX) +#pragma vdir nodep +#endif +#if defined (_OPENMP) +#pragma omp parallel for +#endif + for ( i = 0; i < nhor; i++ ) + geop[i] = geop[i+nhor] + PlanetRD * gt[i] * (1.0 + vtmp * gq[i]) * z2log2; + } + else /* No humidity */ + { + for ( j = nlev ; j > 1 ; j-- ) +#if defined (SX) +#pragma vdir nodep +#endif + for ( i = nhor * (j-1) ; i < nhor * j ; i++ ) + geop[i] = geop[i+nhor] + PlanetRD * gt[i] * log(ph[i+nhor] / ph[i]); + +#if defined (SX) +#pragma vdir nodep +#endif + for ( i = 0; i < nhor; i++ ) + geop[i] = geop[i+nhor] + PlanetRD * gt[i] * z2log2; + } + +#if defined (SX) +#pragma vdir nodep +#endif +#if defined (_OPENMP) +#pragma omp parallel for +#endif + for ( i = 0; i < nhor * (nlev+1); i++ ) geop[i] *= zrg; +} + +#define SCALESLP (101325.0) + +/* ======================================== */ +/* LayerWater integral liquid water content */ +/* ======================================== */ + +void LayerWater(double *ww, double *ll, double pmax, double pmin, + int DimGP, int HalfLevels, double *vct) +{ + int i,k; + int MaxLev, MinLev; + double pph[MaxLevel]; + + for (k = 0; k < HalfLevels; k++) + pph[k] = vct[k] + vct[k+HalfLevels] * SCALESLP; + for (k = 0; k < HalfLevels; k++) + if (pph[k] > pmax) break; + MaxLev = k - 1; + for (k = HalfLevels - 1; k >= 0; k--) + if (pph[k] < pmin) break; + MinLev = k; + + after_zero_array (ll, DimGP); + + for (k = MaxLev; k <= MinLev; k++) { + for (i = 0; i < DimGP; i++) + ll[i] += ww[i+k*DimGP] * (pph[k+1] - pph[k]); + } + for (i = 0; i < DimGP; i++) ll[i] /= PlanetGrav; +} + +/* ================================================= */ +/* LayerCloud calculates random overlap cloud cover */ +/* ================================================= */ + +void LayerCloud(double *cc, double *ll, double pmax, double pmin, + int DimGP, int HalfLevels, double *vct) +{ + int i, k; + int MaxLev, MinLev; + double pph[MaxLevel]; + double ZEPSEC = 1.0e-12; + + for (k = 0; k < HalfLevels; k++) + pph[k] = vct[k] + vct[k+HalfLevels] * SCALESLP; + for (k = 0; k < HalfLevels; k++) + if (pph[k] > pmax) break; + MaxLev = k - 1; + for (k = HalfLevels - 1; k >=0; k--) + if (pph[k] < pmin) break; + MinLev = k; + + for (i = 0; i < DimGP; i++) ll[i] = 1. - cc[i+MaxLev*DimGP]; + + for (k = MaxLev + 1; k <= MinLev; k++) { + for (i = 0; i < DimGP; i++) + ll[i] *= (1. - MAX(cc[i+(k-1)*DimGP],cc[i+k*DimGP])) + / (1. - MIN(cc[i+(k-1)*DimGP],1.-ZEPSEC)); + } + for (i = 0; i < DimGP; i++) ll[i] = 1. - ll[i]; +} + +/* Grid Point Computations */ +void after_EchamCompGP(struct Control *globs, struct Variable *vars) +{ + int l; + + if ( vars[GEOPOTHEIGHT].comp || vars[SLP].comp || vars[THETAF].needed || + vars[HALF_PRESS].needed || vars[RHUMIDITY].comp || vars[OMEGA].comp || + globs->Type >= 30 ) + { + if ( vars[FULL_PRESS].hybrid == NULL ) + vars[FULL_PRESS].hybrid = alloc_dp(globs->Dim3GP, "vars[FULL_PRESS].hybrid"); + + vars[HALF_PRESS].hlev = globs->NumLevel+1; + vars[HALF_PRESS].plev = globs->NumLevelRequest; + vars[HALF_PRESS].sfit = FALSE; + + if ( vars[HALF_PRESS].hybrid == NULL ) + vars[HALF_PRESS].hybrid = alloc_dp(globs->Dim3GP+globs->DimGP, "vars[HALF_PRESS].hybrid"); + + presh(vars[FULL_PRESS].hybrid, vars[HALF_PRESS].hybrid, globs->vct, vars[PS_PROG].hybrid, + globs->NumLevel, globs->DimGP); + } + + if ( globs->unitsel > 2 ) vars[FULL_PRESS].hybrid = FreeMemory(vars[FULL_PRESS].hybrid); + + if ( vars[THETAF].needed ) + { + vars[THETAF].hlev = globs->NumLevel; + vars[THETAF].plev = globs->NumLevelRequest; + vars[THETAF].sfit = TRUE; + if ( vars[THETAF].hybrid == NULL ) + vars[THETAF].hybrid = alloc_dp(globs->Dim3GP, "vars[THETAF].hybrid"); + if ( vars[THETAH].hybrid == NULL ) + vars[THETAH].hybrid = alloc_dp(globs->Dim3GP, "vars[THETAH].hybrid"); + theta(vars[THETAF].hybrid, vars[THETAH].hybrid, vars[HALF_PRESS].hybrid, vars[PS_PROG].hybrid, + vars[TEMPERATURE].hybrid, vars[TS].hybrid, globs->NumLevel, globs->DimGP, globs->Dim3GP); + } + + if ( vars[GEOPOTHEIGHT].comp ) + { + vars[GEOPOTHEIGHT].hlev = globs->NumLevel+1; + vars[GEOPOTHEIGHT].plev = globs->NumLevelRequest; + vars[GEOPOTHEIGHT].sfit = TRUE; + vars[GEOPOTHEIGHT].hybrid = alloc_dp(globs->Dim3GP+globs->DimGP, "vars[GEOPOTHEIGHT].hybrid"); + + after_copy_array(vars[GEOPOTHEIGHT].hybrid+globs->Dim3GP, globs->Orography, globs->DimGP); + MakeGeopotHeight(vars[GEOPOTHEIGHT].hybrid, vars[TEMPERATURE].hybrid, + vars[HUMIDITY].hybrid, vars[HALF_PRESS].hybrid, globs->DimGP, globs->NumLevel); + + vars[HUMIDITY].needed = vars[HUMIDITY].selected; + } + + if ( vars[DPSDX].needed || vars[DPSDY].needed ) + for (l = 0; l < globs->DimGP; l++) + { + vars[DPSDX].hybrid[l] *= vars[PS_PROG].hybrid[l]; + vars[DPSDY].hybrid[l] *= vars[PS_PROG].hybrid[l]; + } + + if ( vars[OMEGA].comp ) + { + vars[OMEGA].hlev = globs->NumLevel+1; + vars[OMEGA].plev = globs->NumLevelRequest; + vars[OMEGA].sfit = TRUE; + vars[OMEGA].hybrid = alloc_dp(globs->Dim3GP+globs->DimGP, "OMEGA.hybrid"); + + Omega(vars[OMEGA].hybrid, vars[DIVERGENCE].hybrid, vars[U_WIND].hybrid, vars[V_WIND].hybrid, + vars[HALF_PRESS].hybrid, vars[FULL_PRESS].hybrid, vars[DPSDX].hybrid, vars[DPSDY].hybrid, + globs->vct, globs->DimGP, globs->NumLevel); + + vars[DPSDX].needed = vars[DPSDX].selected; + vars[DPSDY].needed = vars[DPSDY].selected; + } + + if ( vars[WINDSPEED].comp ) + { + vars[WINDSPEED].hlev = globs->NumLevel; + vars[WINDSPEED].plev = globs->NumLevelRequest; + vars[WINDSPEED].sfit = TRUE; + vars[WINDSPEED].hybrid = alloc_dp(globs->Dim3GP, "vars[WINDSPEED].hybrid"); + + windSpeed(vars[WINDSPEED].hybrid, vars[U_WIND].hybrid, vars[V_WIND].hybrid, globs->Dim3GP); + } + + if ( vars[RHUMIDITY].comp ) + { + vars[RHUMIDITY].hlev = globs->NumLevel; + vars[RHUMIDITY].plev = globs->NumLevelRequest; + vars[RHUMIDITY].sfit = FALSE; + vars[RHUMIDITY].hybrid = alloc_dp(globs->Dim3GP, "vars[RHUMIDITY].hybrid"); + + sh2rh(globs->AnalysisData, vars[HUMIDITY].hybrid, vars[RHUMIDITY].hybrid, vars[TEMPERATURE].hybrid, globs->NumLevel, + globs->DimGP, globs->LevelRequest, vars[FULL_PRESS].hybrid); + + vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; + vars[HUMIDITY].needed = vars[HUMIDITY].selected; + } + + if ( vars[PS].comp ) + { + vars[PS].hlev = 1; + vars[PS].plev = 1; + vars[PS].sfit = TRUE; /* ??? */ + vars[PS].hybrid = alloc_dp(globs->DimGP, "vars[PS].hybrid"); + for (l = 0; l < globs->DimGP; l++) vars[PS].hybrid[l] = exp(vars[LNPS].hybrid[l]); + } + + if ( vars[SLP].comp ) + { + vars[SLP].hlev = 1; + vars[SLP].plev = 1; + vars[SLP].sfit = TRUE; + vars[SLP].hybrid = alloc_dp(globs->DimGP, "vars[SLP].hybrid"); + + extra_P(vars[SLP].hybrid, vars[HALF_PRESS].hybrid + globs->Dim3GP, + vars[FULL_PRESS].hybrid + globs->Dim3GP - globs->DimGP , globs->Orography, + vars[TEMPERATURE].hybrid + globs->Dim3GP - globs->DimGP , globs->DimGP); + vars[TEMPERATURE].needed = vars[TEMPERATURE].selected || vars[GEOPOTHEIGHT].selected; + } + + if ( vars[PRECIP].comp ) + { + vars[PRECIP].hlev = vars[PRECIP].plev = 1; + vars[PRECIP].sfit = FALSE; + vars[PRECIP].hybrid = alloc_dp(globs->DimGP, "PRECIP.hybrid"); + Add2Vectors(vars[PRECIP].hybrid, vars[142].hybrid, vars[143].hybrid, globs->DimGP); + } + + if ( vars[NET_TOP].comp ) + { + vars[NET_TOP].hlev = vars[NET_TOP].plev = 1; + vars[NET_TOP].sfit = FALSE; + vars[NET_TOP].hybrid = alloc_dp(globs->DimGP, "NET_TOP.hybrid"); + Add2Vectors(vars[NET_TOP].hybrid, vars[178].hybrid, vars[179].hybrid, globs->DimGP); + } + + if ( vars[NET_BOT].comp ) + { + vars[NET_BOT].hlev = vars[NET_BOT].plev = 1; + vars[NET_BOT].sfit = FALSE; + vars[NET_BOT].hybrid = alloc_dp(globs->DimGP, "NET_BOT.hybrid"); + Add2Vectors(vars[NET_BOT].hybrid, vars[176].hybrid, vars[177].hybrid, globs->DimGP); + } + + if ( vars[NET_HEAT].comp ) + { + vars[NET_HEAT].hlev = vars[NET_HEAT].plev = 1; + vars[NET_HEAT].sfit = FALSE; + vars[NET_HEAT].hybrid = alloc_dp(globs->DimGP, "NET_HEAT.hybrid"); + /* + if ( Source == S_ECHAM5 ) + { + MultVectorScalar(vars[NET_HEAT].hybrid, vars[218].hybrid, (-3.345e5), globs->DimGP, + vars[218].nmiss, vars[218].missval); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[176].hybrid, globs->DimGP); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[177].hybrid, globs->DimGP); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[146].hybrid, globs->DimGP); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[147].hybrid, globs->DimGP); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[206].hybrid, globs->DimGP); + Sub2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[208].hybrid, globs->DimGP); + Sub2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[209].hybrid, globs->DimGP); + } + else + */ + { + MultVectorScalar(vars[NET_HEAT].hybrid, vars[218].hybrid, C_TIMES_RHOH2O, globs->DimGP, + vars[218].nmiss, vars[218].missval); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[176].hybrid, globs->DimGP); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[177].hybrid, globs->DimGP); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[146].hybrid, globs->DimGP); + Add2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[147].hybrid, globs->DimGP); + Sub2Vectors(vars[NET_HEAT].hybrid, vars[NET_HEAT].hybrid, vars[220].hybrid, globs->DimGP); + } + } + + if ( vars[NET_WATER].comp ) + { + vars[NET_WATER].hlev = vars[NET_WATER].plev = 1; + vars[NET_WATER].sfit = FALSE; + vars[NET_WATER].hybrid = alloc_dp(globs->DimGP, "NET_WATER.hybrid"); + Sub2Vectors(vars[NET_WATER].hybrid, vars[182].hybrid , vars[160].hybrid, globs->DimGP); + Add2Vectors(vars[NET_WATER].hybrid, vars[NET_WATER].hybrid, vars[142].hybrid, globs->DimGP); + Add2Vectors(vars[NET_WATER].hybrid, vars[NET_WATER].hybrid, vars[143].hybrid, globs->DimGP); + } + + if ( vars[LOW_WATER].comp) + { + vars[LOW_WATER].hlev = vars[LOW_WATER].plev = 1; + vars[LOW_WATER].sfit = FALSE; + vars[LOW_WATER].hybrid = alloc_dp(globs->DimGP, "vars[LOW_WATER].hybrid"); + LayerWater(vars[222].hybrid, vars[LOW_WATER].hybrid, 75000.,101300., globs->DimGP, globs->HalfLevels, globs->vct); + } + + if ( vars[MID_WATER].comp) + { + vars[MID_WATER].hlev = vars[MID_WATER].plev = 1; + vars[MID_WATER].sfit = FALSE; + vars[MID_WATER].hybrid = alloc_dp(globs->DimGP, "vars[MID_WATER].hybrid"); + LayerWater(vars[222].hybrid, vars[MID_WATER].hybrid, 46000., 73000., globs->DimGP, globs->HalfLevels, globs->vct); + } + + if ( vars[HIH_WATER].comp ) + { + vars[HIH_WATER].hlev = vars[HIH_WATER].plev = 1; + vars[HIH_WATER].sfit = FALSE; + vars[HIH_WATER].hybrid = alloc_dp(globs->DimGP, "vars[HIH_WATER].hybrid"); + LayerWater(vars[222].hybrid, vars[HIH_WATER].hybrid, 5000., 44000., globs->DimGP, globs->HalfLevels, globs->vct); + } + + if ( vars[ALL_WATER].comp ) + { + vars[ALL_WATER].hlev = vars[ALL_WATER].plev = 1; + vars[ALL_WATER].sfit = FALSE; + vars[ALL_WATER].hybrid = alloc_dp(globs->DimGP, "vars[ALL_WATER].hybrid"); + LayerWater(vars[222].hybrid, vars[ALL_WATER].hybrid, 5000.,101300., globs->DimGP, globs->HalfLevels, globs->vct); + } + + if ( vars[LOW_CLOUD].comp ) + { + vars[LOW_CLOUD].hlev = vars[LOW_CLOUD].plev = 1; + vars[LOW_CLOUD].sfit = FALSE; + vars[LOW_CLOUD].hybrid = alloc_dp(globs->DimGP, "vars[LOW_CLOUD].hybrid"); + LayerCloud(vars[223].hybrid, vars[LOW_CLOUD].hybrid, 75000.,101300., globs->DimGP, globs->HalfLevels, globs->vct); + } + + if ( vars[MID_CLOUD].comp ) + { + vars[MID_CLOUD].hlev = vars[MID_CLOUD].plev = 1; + vars[MID_CLOUD].sfit = FALSE; + vars[MID_CLOUD].hybrid = alloc_dp(globs->DimGP, "vars[MID_CLOUD].hybrid"); + LayerCloud(vars[223].hybrid, vars[MID_CLOUD].hybrid, 46000., 73000., globs->DimGP, globs->HalfLevels, globs->vct); + } + + if ( vars[HIH_CLOUD].comp ) + { + vars[HIH_CLOUD].hlev = vars[HIH_CLOUD].plev = 1; + vars[HIH_CLOUD].sfit = FALSE; + vars[HIH_CLOUD].hybrid = alloc_dp(globs->DimGP, "vars[HIH_CLOUD].hybrid"); + LayerCloud(vars[223].hybrid, vars[HIH_CLOUD].hybrid, 5000., 44000., globs->DimGP, globs->HalfLevels, globs->vct); + } + + if ( vars[SW_CLF].comp ) + { + vars[SW_CLF].hlev = vars[SW_CLF].plev = 1; + vars[SW_CLF].sfit = FALSE; + vars[SW_CLF].hybrid = alloc_dp(globs->DimGP, "SW_CLF.hybrid"); + Sub2Vectors(vars[SW_CLF].hybrid, vars[178].hybrid, vars[224].hybrid, globs->DimGP); + } + + if ( vars[SW_BOT_CLF].comp ) + { + vars[SW_BOT_CLF].hlev = vars[SW_BOT_CLF].plev = 1; + vars[SW_BOT_CLF].sfit = FALSE; + vars[SW_BOT_CLF].hybrid = alloc_dp(globs->DimGP, "vars[SW_BOT_CLF].hybrid"); + Sub2Vectors(vars[SW_BOT_CLF].hybrid, vars[176].hybrid, vars[185].hybrid, globs->DimGP); + } + + if ( vars[SW_TOP_CLF].comp ) + { + vars[SW_TOP_CLF].hlev = vars[SW_TOP_CLF].plev = 1; + vars[SW_TOP_CLF].sfit = FALSE; + vars[SW_TOP_CLF].hybrid = alloc_dp(globs->DimGP, "vars[SW_TOP_CLF].hybrid"); + Sub2Vectors(vars[SW_TOP_CLF].hybrid, vars[178].hybrid, vars[187].hybrid, globs->DimGP); + } + + if ( vars[LW_CLF].comp ) + { + vars[LW_CLF].hlev = vars[LW_CLF].plev = 1; + vars[LW_CLF].sfit = FALSE; + vars[LW_CLF].hybrid = alloc_dp(globs->DimGP, "LW_CLF.hybrid"); + Sub2Vectors(vars[LW_CLF].hybrid, vars[179].hybrid, vars[225].hybrid, globs->DimGP); + } + + if ( vars[LW_BOT_CLF].comp ) + { + vars[LW_BOT_CLF].hlev = vars[LW_BOT_CLF].plev = 1; + vars[LW_BOT_CLF].sfit = FALSE; + vars[LW_BOT_CLF].hybrid = alloc_dp(globs->DimGP, "vars[LW_BOT_CLF].hybrid"); + Sub2Vectors(vars[LW_BOT_CLF].hybrid, vars[177].hybrid, vars[186].hybrid, globs->DimGP); + } + + if ( vars[LW_TOP_CLF].comp ) + { + vars[LW_TOP_CLF].hlev = vars[LW_TOP_CLF].plev = 1; + vars[LW_TOP_CLF].sfit = FALSE; + vars[LW_TOP_CLF].hybrid = alloc_dp(globs->DimGP, "vars[LW_TOP_CLF].hybrid"); + Sub2Vectors(vars[LW_TOP_CLF].hybrid, vars[179].hybrid, vars[188].hybrid, globs->DimGP); + } + + if ( vars[NET_CLF].comp ) + { + vars[NET_CLF].hlev = vars[NET_CLF].plev = 1; + vars[NET_CLF].sfit = FALSE; + vars[NET_CLF].hybrid = alloc_dp(globs->DimGP, "NET_CLF.hybrid"); + Add2Vectors(vars[NET_CLF].hybrid, vars[178].hybrid, vars[179].hybrid, globs->DimGP); + Sub2Vectors(vars[NET_CLF].hybrid, vars[NET_CLF].hybrid, vars[224].hybrid, globs->DimGP); + Sub2Vectors(vars[NET_CLF].hybrid, vars[NET_CLF].hybrid, vars[225].hybrid, globs->DimGP); + } + + if ( vars[SW_ATM].comp ) + { + vars[SW_ATM].hlev = vars[SW_ATM].plev = 1; + vars[SW_ATM].sfit = FALSE; + vars[SW_ATM].hybrid = alloc_dp(globs->DimGP, "vars[SW_ATM].hybrid"); + Sub2Vectors(vars[SW_ATM].hybrid, vars[178].hybrid, vars[176].hybrid,globs->DimGP); + } + + if ( vars[LW_ATM].comp ) + { + vars[LW_ATM].hlev = vars[LW_ATM].plev = 1; + vars[LW_ATM].sfit = FALSE; + vars[LW_ATM].hybrid = alloc_dp(globs->DimGP, "vars[LW_ATM].hybrid"); + Sub2Vectors(vars[LW_ATM].hybrid, vars[179].hybrid, vars[177].hybrid,globs->DimGP); + } + + if ( vars[NET_ATM].comp ) + { + vars[NET_ATM].hlev = vars[NET_ATM].plev = 1; + vars[NET_ATM].sfit = FALSE; + vars[NET_ATM].hybrid = alloc_dp(globs->DimGP, "vars[NET_ATM].hybrid"); + Add2Vectors(vars[NET_ATM].hybrid, vars[178].hybrid, vars[179].hybrid,globs->DimGP); + Sub2Vectors(vars[NET_ATM].hybrid, vars[NET_ATM].hybrid, vars[176].hybrid,globs->DimGP); + Sub2Vectors(vars[NET_ATM].hybrid, vars[NET_ATM].hybrid, vars[177].hybrid,globs->DimGP); + } + + if ( vars[SURF_RUNOFF].comp ) + { + vars[SURF_RUNOFF].hlev = vars[SURF_RUNOFF].plev = 1; + vars[SURF_RUNOFF].sfit = FALSE; + vars[SURF_RUNOFF].hybrid = alloc_dp(globs->DimGP, "vars[SURF_RUNOFF].hybrid"); + Sub2Vectors(vars[SURF_RUNOFF].hybrid, vars[182].hybrid, vars[221].hybrid,globs->DimGP); + Add2Vectors(vars[SURF_RUNOFF].hybrid, vars[SURF_RUNOFF].hybrid, vars[142].hybrid,globs->DimGP); + Add2Vectors(vars[SURF_RUNOFF].hybrid, vars[SURF_RUNOFF].hybrid, vars[143].hybrid,globs->DimGP); + } + + if ( vars[FRESH_WATER].comp ) + { + vars[FRESH_WATER].hlev = vars[FRESH_WATER].plev = 1; + vars[FRESH_WATER].sfit = FALSE; + vars[FRESH_WATER].hybrid = alloc_dp(globs->DimGP, "vars[FRESH_WATER].hybrid"); + Add2Vectors(vars[FRESH_WATER].hybrid, vars[142].hybrid, vars[143].hybrid, globs->DimGP); + Add2Vectors(vars[FRESH_WATER].hybrid, vars[FRESH_WATER].hybrid, vars[182].hybrid, globs->DimGP); + } +} + +static +void CheckContent(struct Variable *vars, int timestep) +{ + int code; + extern int labort_after; + /* extern int NumLevelRequest; */ + + for ( code = 0; code < 272; code++ ) + { + /* if ( code == GEOPOTENTIAL ) continue; */ + if ( code == SLP ) continue; + if ( code == GEOPOTHEIGHT ) continue; + if ( code == STREAM ) continue; + if ( code == VELOPOT ) continue; + if ( code == U_WIND ) continue; + if ( code == V_WIND ) continue; + if ( code == OMEGA ) continue; + if ( code == RHUMIDITY ) continue; + if ( code == LOW_CLOUD ) continue; + if ( code == MID_CLOUD ) continue; + if ( code == HIH_CLOUD ) continue; + if ( code == PS ) continue; + if ( code == HUMIDITY ) + { + if ( vars[code].needed && !vars[code].selected && + vars[code].spectral == NULL && + vars[code].hybrid == NULL ) + { + Warning( "No humidity in data file, set to zero !"); + vars[code].needed = FALSE; + } + } + else + { + if ( vars[code].needed && !vars[code].comp && + vars[code].spectral == NULL && + vars[code].hybrid == NULL ) + { + if ( labort_after ) + Error( "Code %3d not found at timestep %d!", code, timestep); + else + Warning( "Code %3d not found at timestep %d!", code, timestep); + } + } + } + /* + if ( NumLevelRequest > 0 ) + { + vars[HALF_PRESS].needed = 1; + vars[FULL_PRESS].needed = 1; + } + + code = HALF_PRESS; + if ( vars[code].needed && !vars[code].comp && + vars[code].spectral == NULL && vars[code].hybrid == NULL ) + Error( "Hybrid model level not found!"); + + code = FULL_PRESS; + if ( vars[code].needed && !vars[code].comp && + vars[code].spectral == NULL && vars[code].hybrid == NULL ) + Error( "Hybrid model level not found!"); + */ +} + +static +void Derivate(double field[], double derilam[], int levels, + int Waves, int Latitudes, double DerivationFactor[]) +{ + int l, n, lev; + int i; + + i = 0; + for (lev = 0; lev < levels; lev++) + for (n = 0; n < Waves ; n++) { + for (l = 0; l < Latitudes; l++) { + derilam[i] = -n * field[i+Latitudes] * DerivationFactor[l]; + i++; + } + for (l = 0; l < Latitudes; l++) { + derilam[i] = n * field[i-Latitudes] * DerivationFactor[l]; + i++; + } + } +} + +/* Process Model Level data */ +void after_processML(struct Control *globs, struct Variable *vars) +{ + int code,l,i; + long fieldSize = 0; + int lindex, ilevel, nlevel; + int offset; + int leveltype; + int nmiss; + double *pressureLevel = NULL; + + globs->MeanCount++; + globs->TermCount++; + + CheckContent(vars, globs->TermCount); + + if ( globs->MeanCount == 1 ) + { + if ( globs->Debug ) Message( "TermCount = %d MeanCount = %d", globs->TermCount, globs->MeanCount); + globs->StartDate = globs->OldDate; + } + + if ( globs->TermCount > 120 ) globs->Debug = 0; + + /* ============================== */ + /* Computations in spectral space */ + /* ============================== */ + + if ( vars[U_WIND].comp || vars[V_WIND].comp ) + { + vars[U_WIND].hlev = vars[V_WIND].hlev = vars[DIVERGENCE].hlev; + vars[U_WIND].plev = vars[V_WIND].plev = vars[DIVERGENCE].plev; + vars[U_WIND].sfit = vars[V_WIND].sfit = TRUE; + vars[U_WIND].spectral = alloc_dp(globs->Dim3SP, "vars[U_WIND].spectral"); + vars[V_WIND].spectral = alloc_dp(globs->Dim3SP, "vars[V_WIND].spectral"); + + if ( vars[DIVERGENCE].spectral == NULL ) after_gp2sp(globs, vars, DIVERGENCE); + if ( vars[VORTICITY].spectral == NULL ) after_gp2sp(globs, vars, VORTICITY); + + dv2uv(vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, + vars[U_WIND].spectral, vars[V_WIND].spectral, + globs->dv2uv_f1, globs->dv2uv_f2, + globs->Truncation, globs->DimSP, vars[DIVERGENCE].hlev); + } + + if ( vars[VELOPOT].comp && globs->Type < 30 ) + { + vars[VELOPOT].hlev = vars[DIVERGENCE].hlev; + vars[VELOPOT].plev = vars[DIVERGENCE].plev; + vars[VELOPOT].spectral = alloc_dp(globs->Dim3SP, "vars[VELOPOT].spectral"); + + if ( vars[DIVERGENCE].spectral == NULL ) after_gp2sp(globs, vars, DIVERGENCE); + + dv2ps(vars[DIVERGENCE].spectral, vars[VELOPOT].spectral, + vars[DIVERGENCE].hlev, globs->Truncation); + } + + if ( vars[STREAM].comp && globs->Type < 30 ) + { + vars[STREAM].hlev = vars[VORTICITY].hlev; + vars[STREAM].plev = vars[VORTICITY].plev; + vars[STREAM].spectral = alloc_dp(globs->Dim3SP, "vars[STREAM].spectral"); + + if ( vars[VORTICITY].spectral == NULL ) after_gp2sp(globs, vars, VORTICITY); + + dv2ps(vars[VORTICITY].spectral, vars[STREAM].spectral, + vars[VORTICITY].hlev, globs->Truncation); + } + + if ( vars[VORTICITY].spectral && !vars[VORTICITY].needed ) + vars[VORTICITY].spectral = FreeMemory(vars[VORTICITY].spectral); + + if ( vars[DIVERGENCE].spectral && !vars[DIVERGENCE].needed ) + vars[DIVERGENCE].spectral = FreeMemory(vars[DIVERGENCE].spectral); + + /* --------------------------- */ + /* Output of spectral fields */ + /* --------------------------- */ + + if ( globs->Type == 0 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].spectral ) + { + leveltype = zaxisInqType(vars[code].ozaxisID); + if ( (leveltype == ZAXIS_HYBRID) && (vars[code].ozaxisID != vars[code].izaxisID) ) + { + nlevel = zaxisInqSize(vars[code].ozaxisID); + for ( lindex = 0; lindex < nlevel; lindex++ ) + { + ilevel = (int) zaxisInqLevel(vars[code].ozaxisID, lindex); + offset = (ilevel-1)*globs->DimSP; + streamWriteVarSlice(globs->ostreamID, vars[code].ovarID, lindex, vars[code].spectral+offset, 0); + } + } + else + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].spectral, 0); + } + else + Error("Code %d not available on spectral space!", code); + } + + FreeSpectral(vars); + return; + } + + /* ------------------------------- */ + /* Computations in fourier space */ + /* ------------------------------- */ + + if ( globs->Type >= 10 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].spectral ) + { + if ( vars[code].fourier == NULL ) + { + fieldSize = vars[code].hlev * globs->DimFC; + vars[code].fourier = alloc_dp(fieldSize, + FieldName(code,"fourier")); + sp2fc(vars[code].spectral, vars[code].fourier, globs->poli, + vars[code].hlev, globs->Latitudes, globs->Fouriers, globs->Truncation); + } + if ( code != LNPS ) + vars[code].spectral = FreeMemory(vars[code].spectral); + } + + /* if (globs->Type < 60) globs->poli = FreeMemory(globs->poli); */ + /* if (globs->Type < 50) globs->pol2 = FreeMemory(globs->pol2); */ + /* if (globs->Type < 50) globs->pol3 = FreeMemory(globs->pol3); */ + + if ( vars[U_WIND].needed && vars[U_WIND].fourier ) + scaluv(vars[U_WIND].fourier, globs->rcoslat, globs->Latitudes, globs->Fouriers*globs->NumLevel); + if ( vars[V_WIND].needed && vars[V_WIND].fourier ) + scaluv(vars[V_WIND].fourier, globs->rcoslat, globs->Latitudes, globs->Fouriers*globs->NumLevel); + + if ( vars[DPSDX].needed ) + { + vars[DPSDX].hlev = 1; + vars[DPSDX].plev = 1; + vars[DPSDX].sfit = FALSE; + vars[DPSDX].fourier = alloc_dp(globs->DimFC, "vars[DPSDX].fourier"); + if ( vars[LNPS].fourier == NULL ) after_gp2sp(globs, vars, LNPS); + Derivate(vars[LNPS].fourier, vars[DPSDX].fourier, 1, globs->Waves, globs->Latitudes, globs->DerivationFactor); + } + if ( vars[DPSDY].needed ) + { + vars[DPSDY].hlev = 1; + vars[DPSDY].plev = 1; + vars[DPSDY].sfit = FALSE; + vars[DPSDY].fourier = alloc_dp(globs->DimFC, "vars[DPSDY].fourier"); + if ( vars[LNPS].spectral == NULL ) after_gp2sp(globs, vars, LNPS); + sp2fc(vars[LNPS].spectral, vars[DPSDY].fourier, globs->pdev, + vars[DPSDY].hlev, globs->Latitudes, globs->Fouriers, globs->Truncation); + } + } + + FreeSpectral(vars); + + /* -------------------------- */ + /* Output of fourier fields */ + /* -------------------------- */ + + if ( globs->Type == 10 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].fourier ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].fourier, 0); + else + Error("Code %d not available on fourier space!", code); + } + + FreeFourier(vars); + return; + } + + /* ----------------------- */ + /* Output of zonal means */ + /* ----------------------- */ + + if ( globs->Type == 11 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].fourier ) + { + leveltype = zaxisInqType(vars[code].ozaxisID); + if ( (leveltype == ZAXIS_HYBRID) && (vars[code].ozaxisID != vars[code].izaxisID) ) + { + nlevel = zaxisInqSize(vars[code].ozaxisID); + for ( lindex = 0; lindex < nlevel; lindex++ ) + { + ilevel = (int) zaxisInqLevel(vars[code].ozaxisID, lindex); + offset = (ilevel-1)*globs->DimFC; + streamWriteVarSlice(globs->ostreamID, vars[code].ovarID, lindex, vars[code].fourier+offset, 0); + } + } + else + { + nlevel = zaxisInqSize(vars[code].ozaxisID); + for ( lindex = 0; lindex < nlevel; lindex++ ) + { + offset = lindex*globs->DimFC; + streamWriteVarSlice(globs->ostreamID, vars[code].ovarID, lindex, vars[code].fourier+offset, 0); + } + } + } + else + Error("Code %d not available on zonal mean!", code); + } + + FreeFourier(vars); + return; + } + + /* ------------------------------ */ + /* Transformation to gridpoints */ + /* ------------------------------ */ + + if ( globs->Type >= 20 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].fourier ) + { + if ( vars[code].hybrid == NULL ) + { + fieldSize = globs->DimGP * vars[code].hlev; + vars[code].hybrid = alloc_dp(fieldSize, + FieldName(code,"hybrid")); + after_FC2GP(vars[code].fourier,vars[code].hybrid, + globs->Latitudes,globs->Longitudes,vars[code].hlev,globs->Fouriers); + } + vars[code].fourier = FreeMemory(vars[code].fourier); + } + + if ( vars[PS_PROG].comp && vars[PS_PROG].hybrid == NULL ) + { + vars[PS_PROG].hybrid = alloc_dp(globs->DimGP, "PS_PROG"); + if ( vars[LNPS].hybrid ) + { + for (l = 0; l < globs->DimGP; l++) vars[PS_PROG].hybrid[l] = exp(vars[LNPS].hybrid[l]); + } + else if ( vars[PS].hybrid ) + { + Warning("log surface pressure (code 152) not found - using surface pressure (code 134)!"); + after_copy_array(vars[PS_PROG].hybrid, vars[PS].hybrid, globs->DimGP); + } + else + { + Error("surface pressure not found!"); + } + } + vars[LNPS].needed = vars[LNPS].selected; + + if ( globs->Orography == NULL ) + { + globs-> Orography = alloc_dp(globs->DimGP , "Orography"); + if ( vars[GEOPOTENTIAL].hybrid ) + after_copy_array(globs->Orography, vars[GEOPOTENTIAL].hybrid, globs->DimGP); + else + { + if ( vars[GEOPOTENTIAL].selected || globs->Type >= 30 ) + { + Warning("Orography not found - using zero orography!"); + after_zero_array(globs->Orography, globs->DimGP); + } + } + } + vars[GEOPOTENTIAL].needed = vars[GEOPOTENTIAL].selected; + + after_EchamCompGP(globs, vars); + } + + FreeFourier(vars); + + if ( globs->Type == 20 ) + { + /* ----------------------- */ + /* Means on hybrid grids */ + /* ----------------------- */ + + if ( globs->Mean ) + { + for ( code = 0; code < MaxCodes; code++ ) + { + if ( vars[code].selected && vars[code].hybrid ) + { + fieldSize = globs->DimGP * vars[code].hlev; + + if ( vars[code].mean == NULL ) + vars[code].mean = alloc_dp(fieldSize, FieldName(code, "mean")); + + if ( globs->Mean > 1 && vars[code].variance == NULL ) + vars[code].variance = alloc_dp(fieldSize, FieldName(code, "variance")); + + if ( globs->MeanCount == 1 ) + { + after_copy_array(vars[code].mean, vars[code].hybrid, fieldSize); + if ( globs->Mean > 1 ) + IniQuaSum(vars[code].variance, vars[code].hybrid, fieldSize); + } + else + { + AddVector(vars[code].mean, vars[code].hybrid, fieldSize, + &vars[code].nmiss, vars[code].missval); + if ( globs->Mean > 1 ) + AddQuaSum(vars[code].variance, vars[code].hybrid, fieldSize); + } + + if ( globs->EndOfInterval ) + { + if ( vars[code].samp == NULL ) + MultVectorScalar(vars[code].hybrid, vars[code].mean, 1.0/globs->MeanCount, fieldSize, + vars[code].nmiss, vars[code].missval); + else + DivVectorIvector(vars[code].hybrid, vars[code].mean, vars[code].samp, fieldSize, + &vars[code].nmiss, vars[code].missval); + + if ( globs->Mean > 1 ) + VarQuaSum(vars[code].variance, vars[code].hybrid, fieldSize, globs->MeanCount); + } + } + } + } + + /* ---------------------------- */ + /* Output of hybrid level grids */ + /* ---------------------------- */ + + if ( globs->Mean == 0 || globs->EndOfInterval ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].hybrid == NULL ) + Error("Internal problem. Code %d not allocated!", code); + + leveltype = zaxisInqType(vars[code].ozaxisID); + if ( (leveltype == ZAXIS_HYBRID) && (vars[code].ozaxisID != vars[code].izaxisID) ) + { + nlevel = zaxisInqSize(vars[code].ozaxisID); + for ( lindex = 0; lindex < nlevel; lindex++ ) + { + ilevel = (int) zaxisInqLevel(vars[code].ozaxisID, lindex); + offset = (ilevel-1)*globs->DimGP; + if ( globs->Mean != 2 ) + streamWriteVarSlice(globs->ostreamID, vars[code].ovarID, lindex, + vars[code].hybrid+offset, vars[code].nmiss); + if ( globs->Mean >= 2 ) + streamWriteVarSlice(globs->ostreamID2, vars[code].ovarID2, lindex, + vars[code].variance+offset, vars[code].nmiss); + } + } + else + { + if ( globs->Mean != 2 ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].hybrid, vars[code].nmiss); + if ( globs->Mean >= 2 ) + streamWriteVar(globs->ostreamID2, vars[code].ovarID2, vars[code].variance, vars[code].nmiss); + } + } + + FreeSamp(vars); + } + + FreeHybrid(vars); + return; + } + + /* -------------------------------------- */ + /* Vertical interpolation / extrapolation */ + /* -------------------------------------- */ + + if ( globs->Type >= 30 ) + { + if ( globs->vert_index == NULL ) + globs->vert_index = (int *) malloc(globs->NumLevelRequest*globs->DimGP*sizeof(int)); + + if ( globs->unitsel ) + { + if ( globs->p_of_height == NULL ) globs->p_of_height = alloc_dp(globs->NumLevelRequest,"p_of_height"); + height2pressure(globs->p_of_height, globs->LevelRequest, globs->NumLevelRequest); + pressureLevel = globs->p_of_height; + } + else + { + pressureLevel = globs->LevelRequest; + } + + genind(globs->vert_index, pressureLevel, vars[FULL_PRESS].hybrid, globs->DimGP, globs->NumLevelRequest, globs->NumLevel); + + nmiss = 0; + if ( ! globs->Extrapolate ) + { + if ( globs->pnmiss == NULL ) globs->pnmiss = (int *) malloc(globs->NumLevelRequest*sizeof(int)); + genindmiss(globs->vert_index, pressureLevel, globs->DimGP, globs->NumLevelRequest, vars[PS_PROG].hybrid, globs->pnmiss); + for ( i = 0; i < globs->NumLevelRequest; i++ ) nmiss += globs->pnmiss[i]; + } + + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].hybrid ) + { + leveltype = zaxisInqType(vars[code].izaxisID); + if ( vars[code].hlev == 1 || leveltype != ZAXIS_HYBRID || (vars[code].hlev < globs->NumLevel) ) + { + if ( vars[code].grid ) FreeMemory(vars[code].grid); + vars[code].grid = vars[code].hybrid; + vars[code].hybrid = NULL; + } + else + { + if ( vars[code].grid == NULL ) + { + fieldSize = globs->DimGP * globs->NumLevelRequest; + vars[code].grid = alloc_dp(fieldSize, FieldName(code, "grid")); + } + + if ( code == TEMPERATURE ) + { + interp_T(globs->Orography, vars[TEMPERATURE].hybrid, vars[TEMPERATURE].grid, + vars[FULL_PRESS].hybrid, vars[HALF_PRESS].hybrid, globs->vert_index, + pressureLevel, globs->NumLevelRequest, globs->DimGP, globs->NumLevel, vars[code].missval); + } + else if ( code == GEOPOTHEIGHT ) + { + if ( vars[TEMPERATURE].hybrid == NULL ) Error("Code 130 not found!"); + interp_Z(globs->Orography, vars[GEOPOTHEIGHT].hybrid, vars[GEOPOTHEIGHT].grid, + vars[FULL_PRESS].hybrid, vars[HALF_PRESS].hybrid, globs->vert_index, + vars[TEMPERATURE].hybrid, + pressureLevel, globs->NumLevelRequest, globs->DimGP, globs->NumLevel, vars[code].missval); + } + else + { + interp_X(vars[code].hybrid, vars[code].grid, vars[FULL_PRESS].hybrid, + globs->vert_index, pressureLevel, globs->NumLevelRequest, globs->DimGP, globs->NumLevel, vars[code].missval); + } + + if ( ! globs->Extrapolate ) vars[code].nmiss = nmiss; + + if ( code != TEMPERATURE ) + vars[code].hybrid = FreeMemory(vars[code].hybrid); + } + } + } + + vars[TEMPERATURE].needed = vars[TEMPERATURE].selected; + FreeHybrid(vars); + if ( vars[HALF_PRESS].hybrid ) + vars[HALF_PRESS].hybrid = FreeMemory(vars[HALF_PRESS].hybrid); + + /* -------------------------------- */ + /* Output of pressure level grids */ + /* -------------------------------- */ + + if ( globs->Type == 30 && globs->Mean == 0 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected && vars[code].grid ) + { + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].grid, vars[code].nmiss); + } + + FreeGrid(vars); + return; + } + + /* ---------------------- */ + /* Computation of Means */ + /* ---------------------- */ + + if ( globs->Type >= 30 && globs->Mean ) + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].grid ) + { + fieldSize = globs->DimGP * vars[code].plev; + + if ( vars[code].mean == NULL ) + vars[code].mean = alloc_dp(fieldSize, FieldName(code, "mean")); + + if ( globs->MeanCount == 1 ) + after_copy_array(vars[code].mean, vars[code].grid, fieldSize); + else + AddVector(vars[code].mean, vars[code].grid, fieldSize, + &vars[code].nmiss, vars[code].missval); + + if ( globs->EndOfInterval ) + { + if ( vars[code].samp == NULL ) + MultVectorScalar(vars[code].mean, vars[code].mean, 1.0/globs->MeanCount, fieldSize, + vars[code].nmiss, vars[code].missval); + else + DivVectorIvector(vars[code].mean, vars[code].mean, vars[code].samp, fieldSize, + &vars[code].nmiss, vars[code].missval); + } + } + + /* -------------------------- */ + /* Computation of Variances */ + /* -------------------------- */ + + if ( globs->Type >= 30 && globs->Mean > 1 ) + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].mean ) + { + fieldSize = globs->DimGP * vars[code].plev; + + if (vars[code].variance == NULL) + vars[code].variance = alloc_dp(fieldSize, FieldName(code, "var")); + + if ( globs->MeanCount == 1 ) + IniQuaSum(vars[code].variance, vars[code].grid, fieldSize); + else + AddQuaSum(vars[code].variance, vars[code].grid, fieldSize); + + if ( globs->EndOfInterval ) + VarQuaSum(vars[code].variance, vars[code].mean, fieldSize, globs->MeanCount); + } + + if ( globs->Mean && !globs->EndOfInterval ) + { + FreeGrid(vars); + return; + } + + /* --------------------------------------------- */ + /* Output of pressure level means and variances */ + /* --------------------------------------------- */ + + if ( globs->Type == 30 && globs->Mean ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected && vars[code].mean ) + { + if ( globs->Mean != 2 ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].mean, vars[code].nmiss); + if ( globs->Mean >= 2 ) + streamWriteVar(globs->ostreamID2, vars[code].ovarID2, vars[code].variance, vars[code].nmiss); + } + + FreeSamp(vars); + FreeGrid(vars); + return; + } + + + /* ------------------ */ + /* Free mean fields */ + /* ------------------ */ + + if ( globs->Type >= 40 && globs->Mean ) + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].mean ) + { + if ( vars[code].variance ) vars[code].variance = FreeMemory(vars[code].variance); + if ( vars[code].grid ) vars[code].grid = FreeMemory(vars[code].grid); + vars[code].grid = vars[code].mean; + vars[code].mean = NULL; + } + + /* --------------------------------- */ + /* Transformation to fourier space */ + /* --------------------------------- */ + + if ( globs->Type >= 40 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].grid && (vars[code].sfit || globs->Type < 70) ) + { + if ( vars[code].nmiss > 0 ) + Error("Missing values for code %d unsupported with TYPE > 30!", code); + + if ( vars[code].fourier == NULL ) + { + fieldSize = globs->DimFC * vars[code].plev; + vars[code].fourier = alloc_dp(fieldSize,FieldName(code,"fourier")); + } + + after_GP2FC(vars[code].grid, vars[code].fourier, + globs->Latitudes, globs->Longitudes, vars[code].plev, globs->Fouriers); + + if ( vars[code].grid && (vars[code].sfit || globs->Type < 70) ) + vars[code].grid = FreeMemory(vars[code].grid); + } + } + + for (code = 0; code < MaxCodes; code++) + if (vars[code].grid && (vars[code].sfit || globs->Type < 70)) + vars[code].grid = FreeMemory(vars[code].grid); + + /* -------------------------- */ + /* Output of fourier fields */ + /* -------------------------- */ + + if ( globs->Type == 40 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].fourier ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].fourier, vars[code].nmiss); + else + Error("Code %d not available on fourier space!", code); + } + + FreeFourier(vars); + return; + } + + /* --------------------- */ + /* Output of zonal means */ + /* --------------------- */ + + if ( globs->Type == 41 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].fourier ) + { + nlevel = zaxisInqSize(vars[code].ozaxisID); + for ( lindex = 0; lindex < nlevel; lindex++ ) + { + offset = lindex*globs->DimFC; + streamWriteVarSlice(globs->ostreamID, vars[code].ovarID, lindex, vars[code].fourier+offset, vars[code].nmiss); + } + } + else + Error("Code %d not available on zonal mean!", code); + } + + FreeFourier(vars); + return; + } + + /* ---------------------------------- */ + /* Transformation to spectral space */ + /* ---------------------------------- */ + + if ( globs->Type >= 50 ) + { + if ( vars[U_WIND].needed && vars[U_WIND].fourier ) + scaluv(vars[U_WIND].fourier, globs->coslat, globs->Latitudes, globs->Fouriers*globs->NumLevelRequest); + if ( vars[V_WIND].needed && vars[V_WIND].fourier ) + scaluv(vars[V_WIND].fourier, globs->coslat, globs->Latitudes, globs->Fouriers*globs->NumLevelRequest); + + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].fourier ) + { + if ( vars[code].spectral == NULL ) + { + fieldSize = vars[code].plev * globs->DimSP; + vars[code].spectral = alloc_dp(fieldSize, FieldName(code,"spectral")); + } + + fc2sp(vars[code].fourier,vars[code].spectral, + globs->pold,vars[code].plev,globs->Latitudes,globs->Fouriers,globs->Truncation); + } + + if ( vars[DIVERGENCE].needed || vars[VORTICITY].needed || + vars[VELOPOT].needed || vars[STREAM].needed ) + { + if ( vars[DIVERGENCE].spectral == NULL ) + vars[DIVERGENCE].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, + "vars[DIVERGENCE].spectral"); + if ( vars[VORTICITY].spectral == NULL ) + vars[VORTICITY].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, + "vars[VORTICITY].spectral"); + if ( (vars[U_WIND].fourier == 0 || vars[V_WIND].fourier == 0) && globs->NumLevelRequest ) + Error("uwind or vwind missing!"); + uv2dv(vars[U_WIND].fourier, vars[V_WIND].fourier, + vars[DIVERGENCE].spectral, vars[VORTICITY].spectral, + globs->pol2, globs->pol3, globs->NumLevelRequest, globs->Latitudes, globs->Truncation); + } + + if ( vars[VELOPOT].needed ) + { + vars[VELOPOT].hlev = vars[DIVERGENCE].hlev; + vars[VELOPOT].plev = vars[DIVERGENCE].plev; + vars[VELOPOT].sfit = TRUE; + if ( vars[VELOPOT].spectral == NULL ) + vars[VELOPOT].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[VELOPOT].spectral"); + dv2ps(vars[DIVERGENCE].spectral, vars[VELOPOT].spectral, globs->NumLevelRequest, globs->Truncation); + } + + if ( vars[STREAM].needed ) + { + vars[STREAM].hlev = vars[VORTICITY].hlev; + vars[STREAM].plev = vars[VORTICITY].plev; + vars[STREAM].sfit = TRUE; + if ( vars[STREAM].spectral == NULL ) + vars[STREAM].spectral = alloc_dp(globs->DimSP*globs->NumLevelRequest, "vars[STREAM].spectral"); + dv2ps(vars[VORTICITY].spectral, vars[STREAM].spectral, globs->NumLevelRequest, globs->Truncation); + } + } + + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].fourier && (vars[code].sfit || globs->Type < 61) ) + vars[code].fourier = FreeMemory(vars[code].fourier); + + /* --------------------------- */ + /* Output of spectral fields */ + /* --------------------------- */ + + if ( globs->Type == 50 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected && vars[code].spectral ) + { + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].spectral, vars[code].nmiss); + } + + FreeSpectral(vars); + return; + } + + /* -------------------------------*/ + /* Computations in fourier space */ + /* -------------------------------*/ + + if ( globs->Type >= 60 ) + { + for (code = 0; code < MaxCodes; code++) + if (vars[code].needed && vars[code].spectral) + { + if (vars[code].fourier == NULL) { + fieldSize = vars[code].plev * globs->DimFC; + vars[code].fourier = alloc_dp(fieldSize, + FieldName(code,"fourier")); + } + sp2fc(vars[code].spectral,vars[code].fourier,globs->poli, + vars[code].plev,globs->Latitudes,globs->Fouriers,globs->Truncation); + } + if ( vars[U_WIND].needed && vars[U_WIND].fourier ) + scaluv(vars[U_WIND].fourier, globs->rcoslat, globs->Latitudes, globs->Fouriers*globs->NumLevelRequest); + if ( vars[V_WIND].needed && vars[V_WIND].fourier ) + scaluv(vars[V_WIND].fourier, globs->rcoslat, globs->Latitudes, globs->Fouriers*globs->NumLevelRequest); + } + + FreeSpectral(vars); + + /* -------------------------- */ + /* Output of fourier fields */ + /* -------------------------- */ + + if ( globs->Type == 60 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].fourier ) + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].fourier, 0); + else + Error("Code %d not available on fourier space!", code); + } + + FreeFourier(vars); + return; + } + + /* ----------------------- */ + /* Output of zonal means */ + /* ----------------------- */ + + if ( globs->Type == 61 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + if ( vars[code].fourier ) + { + nlevel = zaxisInqSize(vars[code].ozaxisID); + for ( lindex = 0; lindex < nlevel; lindex++ ) + { + offset = lindex*globs->DimFC; + streamWriteVarSlice(globs->ostreamID, vars[code].ovarID, lindex, vars[code].fourier+offset, vars[code].nmiss); + } + } + else + Error("Code %d not available on zonal mean!", code); + } + + FreeFourier(vars); + return; + } + + /* ------------------------------ */ + /* Transformation to gridpoints */ + /* ------------------------------ */ + + if ( globs->Type >= 70 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].needed && vars[code].fourier ) + { + fieldSize = vars[code].plev * globs->DimGP; + if ( vars[code].grid == NULL ) + vars[code].grid = alloc_dp(fieldSize, FieldName(code, "grid")); + + after_FC2GP(vars[code].fourier, vars[code].grid, + globs->Latitudes, globs->Longitudes, vars[code].plev, globs->Fouriers); + } + } + + FreeFourier(vars); + + /* -------------------------------- */ + /* Output of pressure level grids */ + /* -------------------------------- */ + + if ( globs->Type == 70 ) + { + for ( code = 0; code < MaxCodes; code++ ) + if ( vars[code].selected ) + { + streamWriteVar(globs->ostreamID, vars[code].ovarID, vars[code].grid, vars[code].nmiss); + } + + FreeSamp(vars); + FreeGrid(vars); + return; + } +} + +void after_AnalysisAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, int nmiss) +{ + long fieldSize; + int truncation; + int dataSize; + int dataOffset; + int nlevel; + int gridSize; + int gridtype, leveltype; + + gridtype = gridInqType(gridID); + leveltype = zaxisInqType(zaxisID); + nlevel = zaxisInqSize(zaxisID); + gridSize = gridInqSize(gridID); + dataSize = gridSize*nlevel; + dataOffset = gridSize*levelID; + + vars[code].nmiss0 += nmiss; + + if ( gridtype == GRID_SPECTRAL ) + { + vars[code].sfit = TRUE; + vars[code].hlev = globs->NumLevelRequest; + vars[code].plev = globs->NumLevelRequest; + if ( nlevel > 1 && leveltype == ZAXIS_PRESSURE ) + { + if ( code != U_WIND && code != V_WIND ) + { + fieldSize = globs->Dim3SP; + if (vars[code].spectral0 == NULL) + vars[code].spectral0 = alloc_dp(fieldSize, FieldName(code,"spectral")); + truncation = gridInqTrunc(gridID); + sp2sp(globs->Field, truncation, vars[code].spectral0+levelID*globs->DimSP, globs->Truncation); + } + else + { + fieldSize = globs->Dim3SP; + if (vars[code].spectral0 == NULL) + vars[code].spectral0 = alloc_dp(fieldSize, FieldName(code,"spectral")); + after_copy_array(vars[code].spectral0+levelID*globs->DimSP,globs->Field,globs->DimSP); + } + } + else + Error("Only pressure level data supported for spectral data!"); + } + else + { + if ( nlevel > 1 && leveltype == ZAXIS_PRESSURE ) + { + vars[code].sfit = TRUE; + fieldSize = globs->Dim3GP; + vars[code].hlev = globs->NumLevelRequest; + vars[code].plev = globs->NumLevelRequest; + if ( vars[code].grid0 == NULL ) + vars[code].grid0 = alloc_dp(fieldSize, FieldName(code,"grid0")); + after_copy_array(vars[code].grid0+levelID*globs->DimGP, globs->Field, globs->DimGP); + } + else + { + vars[code].sfit = FALSE; + fieldSize = globs->DimGP; + vars[code].hlev = 1; + vars[code].plev = 1; + if ( vars[code].grid0 == NULL ) + vars[code].grid0 = alloc_dp(fieldSize, FieldName(code,"grid0")); + after_copy_array(vars[code].grid0, globs->Field, globs->DimGP); + } + + if ( globs->Mean > 0 && (nmiss > 0 || vars[code].samp) ) + { + int i; + if ( vars[code].samp == NULL ) + { + vars[code].samp = (int *) malloc(dataSize*sizeof(int)); + for ( i = 0; i < dataSize; i++ ) vars[code].samp[i] = globs->MeanCount0; + } + + for ( i = 0; i < gridSize; i++ ) + if ( IS_NOT_EQUAL(globs->Field[i], vars[code].missval) ) vars[code].samp[i+dataOffset]++; + } + } +} + + +void after_EchamAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, int nmiss) +{ + int dataSize; + int dataOffset; + int nlevel; + int gridSize; + int gridtype, leveltype; + + gridtype = gridInqType(gridID); + leveltype = zaxisInqType(zaxisID); + nlevel = zaxisInqSize(zaxisID); + gridSize = gridInqSize(gridID); + dataSize = gridSize*nlevel; + dataOffset = gridSize*levelID; + + vars[code].nmiss0 += nmiss; + + if ( gridtype == GRID_SPECTRAL ) + { + /* ---------------------------------------------------------- */ + /* Found spectral field ! If needed, allocate memory and copy */ + /* ---------------------------------------------------------- */ + vars[code].sfit = TRUE; + vars[code].hlev = nlevel; + vars[code].plev = 1; + if ( nlevel > 1 && leveltype == ZAXIS_HYBRID ) + vars[code].plev = globs->NumLevelRequest; + + if ( gridInqTrunc(gridID) != globs->Truncation ) + Error("Resolution error. Required %d - Found %d", globs->Truncation, gridInqTrunc(gridID)); + + if ( vars[code].spectral0 == NULL ) + vars[code].spectral0 = alloc_dp(dataSize, FieldName(code, "spectral0")); + + after_copy_array(vars[code].spectral0+dataOffset, globs->Field, gridSize); + } + else + { + vars[code].hlev = nlevel; + vars[code].plev = nlevel; + vars[code].sfit = FALSE; + if ( nlevel > 1 && leveltype == ZAXIS_HYBRID && nlevel == globs->NumLevel ) + { + vars[code].plev = globs->NumLevelRequest; + vars[code].sfit = TRUE; + } + + if ( globs->Mean > 0 && (nmiss > 0 || vars[code].samp) ) + { + int i; + if ( vars[code].samp == NULL ) + { + vars[code].samp = (int *) malloc(dataSize*sizeof(int)); + for ( i = 0; i < dataSize; i++ ) vars[code].samp[i] = globs->MeanCount0; + } + + for ( i = 0; i < gridSize; i++ ) + if ( IS_NOT_EQUAL(globs->Field[i], vars[code].missval) ) vars[code].samp[i+dataOffset]++; + } + + if ( vars[code].hybrid0 == NULL ) + vars[code].hybrid0 = alloc_dp(dataSize, FieldName(code, "hybrid0")); + + after_copy_array(vars[code].hybrid0+dataOffset, globs->Field, gridSize); + } +} + +static +void MakeDependencies(struct Variable *vars, int varcode, int depcode) +{ + extern int afterDebug; + + if ( vars[varcode].needed && ! vars[varcode].detected ) + { + vars[depcode].needed = TRUE; + vars[varcode].comp = TRUE; + + if ( afterDebug ) + fprintf(stderr, "Needed code %d to compute code %d\n", depcode, varcode); + + if ( vars[depcode].ivarID == -1 ) + { + if ( depcode == U_WIND ) + { + MakeDependencies(vars, U_WIND, DIVERGENCE); + MakeDependencies(vars, U_WIND, VORTICITY); + } + if ( depcode == V_WIND ) + { + MakeDependencies(vars, V_WIND, DIVERGENCE); + MakeDependencies(vars, V_WIND, VORTICITY); + } + } + + if ( vars[varcode].ivarID == -1 ) + { + if ( vars[depcode].ivarID == -1 ) + { + Error("code %d undefined, needed to compute code %d", depcode, varcode); + } + else + { + vars[varcode].ivarID = vars[depcode].ivarID; + vars[varcode].igridID = vars[depcode].igridID; + vars[varcode].ogridID = vars[depcode].ogridID; + vars[varcode].izaxisID = vars[depcode].izaxisID; + vars[varcode].ozaxisID = vars[depcode].ozaxisID; + } + } + } +} + +static +void CheckDependencies(struct Variable *vars, int analysisdata) +{ + MakeDependencies(vars, VELOPOT, U_WIND); + MakeDependencies(vars, VELOPOT, V_WIND); + MakeDependencies(vars, VELOPOT, VORTICITY); + MakeDependencies(vars, VELOPOT, DIVERGENCE); + + MakeDependencies(vars, STREAM, U_WIND); + MakeDependencies(vars, STREAM, V_WIND); + MakeDependencies(vars, STREAM, VORTICITY); + MakeDependencies(vars, STREAM, DIVERGENCE); + + MakeDependencies(vars, VORTICITY, U_WIND); + MakeDependencies(vars, VORTICITY, V_WIND); + + MakeDependencies(vars, DIVERGENCE, U_WIND); + MakeDependencies(vars, DIVERGENCE, V_WIND); + + MakeDependencies(vars, U_WIND, VORTICITY); + MakeDependencies(vars, U_WIND, DIVERGENCE); + MakeDependencies(vars, U_WIND, V_WIND); + + MakeDependencies(vars, V_WIND, VORTICITY); + MakeDependencies(vars, V_WIND, DIVERGENCE); + MakeDependencies(vars, V_WIND, U_WIND); + + MakeDependencies(vars, WINDSPEED, U_WIND); + MakeDependencies(vars, WINDSPEED, V_WIND); + + if ( analysisdata ) + { + MakeDependencies(vars, RHUMIDITY, HUMIDITY); + MakeDependencies(vars, RHUMIDITY, TEMPERATURE); + MakeDependencies(vars, HUMIDITY, RHUMIDITY); + MakeDependencies(vars, HUMIDITY, TEMPERATURE); + MakeDependencies(vars, GEOPOTHEIGHT, GEOPOTENTIAL); + } + else + { + MakeDependencies(vars, THETAF, TEMPERATURE); + MakeDependencies(vars, SLP, TEMPERATURE); + } + + MakeDependencies(vars, SW_ATM, 176); + MakeDependencies(vars, SW_ATM, 178); + MakeDependencies(vars, LW_ATM, 177); + MakeDependencies(vars, LW_ATM, 179); + MakeDependencies(vars, NET_ATM, 176); + MakeDependencies(vars, NET_ATM, 177); + MakeDependencies(vars, NET_ATM, 178); + MakeDependencies(vars, NET_ATM, 179); + + MakeDependencies(vars, SW_BOT_CLF, 176); + MakeDependencies(vars, SW_BOT_CLF, 185); + MakeDependencies(vars, LW_BOT_CLF, 177); + MakeDependencies(vars, LW_BOT_CLF, 186); + MakeDependencies(vars, SW_TOP_CLF, 178); + MakeDependencies(vars, SW_TOP_CLF, 187); + MakeDependencies(vars, LW_TOP_CLF, 179); + MakeDependencies(vars, LW_TOP_CLF, 188); + MakeDependencies(vars, NET_TOP_CLF, 178); + MakeDependencies(vars, NET_TOP_CLF, 179); + MakeDependencies(vars, NET_TOP_CLF, 187); + MakeDependencies(vars, NET_TOP_CLF, 188); + + MakeDependencies(vars, ALL_WATER, 222); + MakeDependencies(vars, LOW_WATER, 222); + MakeDependencies(vars, MID_WATER, 222); + MakeDependencies(vars, HIH_WATER, 222); + + MakeDependencies(vars, LOW_CLOUD, 223); + MakeDependencies(vars, MID_CLOUD, 223); + MakeDependencies(vars, HIH_CLOUD, 223); + + if ( vars[LOW_CLOUD].comp || vars[MID_CLOUD].comp || vars[HIH_CLOUD].comp ) + { + static int zaxisID = -999; + if ( zaxisID == -999 ) zaxisID = zaxisCreate(ZAXIS_SURFACE, 1); + + vars[LOW_CLOUD].izaxisID = zaxisID; + vars[LOW_CLOUD].ozaxisID = zaxisID; + vars[MID_CLOUD].izaxisID = zaxisID; + vars[MID_CLOUD].ozaxisID = zaxisID; + vars[HIH_CLOUD].izaxisID = zaxisID; + vars[HIH_CLOUD].ozaxisID = zaxisID; + } +} + +void after_AnalysisDependencies(struct Variable *vars, int ncodes) +{ + int code; + + for ( code = 0; code < ncodes; code++ ) + vars[code].needed = vars[code].selected; + + MakeDependencies(vars, PS, LNPS); + + CheckDependencies(vars, 1); +} + +void after_EchamDependencies(struct Variable *vars, int ncodes, int type, int source) +{ + int code; + + for ( code = 0; code < ncodes; code++ ) + vars[code].needed = vars[code].selected; + + for ( code = 0; code < ncodes; code++ ) + if ( vars[code].detected == FALSE ) vars[code].ivarID = -1; + + if ( type >= 50 ) + { + vars[U_WIND].needed |= vars[DIVERGENCE].needed; + vars[V_WIND].needed |= vars[DIVERGENCE].needed; + vars[U_WIND].needed |= vars[VORTICITY].needed; + vars[V_WIND].needed |= vars[VORTICITY].needed; + vars[U_WIND].needed |= vars[VELOPOT].needed; + vars[V_WIND].needed |= vars[VELOPOT].needed; + vars[U_WIND].needed |= vars[STREAM].needed; + vars[V_WIND].needed |= vars[STREAM].needed; + } + + if ( type >= 30 ) vars[LNPS].needed = TRUE; + + if ( type >= 20 ) + { + MakeDependencies(vars, THETAF, LNPS); + MakeDependencies(vars, SLP, LNPS); + MakeDependencies(vars, SLP, GEOPOTENTIAL); + /* + MakeDependencies(vars, SLP, HALF_PRESS); + MakeDependencies(vars, SLP, FULL_PRESS); + */ + MakeDependencies(vars, RHUMIDITY, TEMPERATURE); + MakeDependencies(vars, RHUMIDITY, HUMIDITY); + MakeDependencies(vars, RHUMIDITY, LNPS); + MakeDependencies(vars, GEOPOTHEIGHT, TEMPERATURE); + MakeDependencies(vars, GEOPOTHEIGHT, HUMIDITY); + MakeDependencies(vars, GEOPOTHEIGHT, LNPS); + MakeDependencies(vars, OMEGA, DIVERGENCE); + MakeDependencies(vars, OMEGA, U_WIND); + MakeDependencies(vars, OMEGA, V_WIND); + MakeDependencies(vars, OMEGA, LNPS); + MakeDependencies(vars, OMEGA, DPSDX); + MakeDependencies(vars, OMEGA, DPSDY); + } + + MakeDependencies(vars, DPSDX, LNPS); + MakeDependencies(vars, HALF_PRESS, LNPS); + MakeDependencies(vars, PS, LNPS); + + MakeDependencies(vars, SURF_RUNOFF, 142); + MakeDependencies(vars, SURF_RUNOFF, 143); + MakeDependencies(vars, SURF_RUNOFF, 182); + MakeDependencies(vars, SURF_RUNOFF, 221); /* snow depth change */ + + MakeDependencies(vars, THETAF, TS); + + MakeDependencies(vars, FRESH_WATER, 142); + MakeDependencies(vars, FRESH_WATER, 143); + MakeDependencies(vars, FRESH_WATER, 182); + + MakeDependencies(vars, PRECIP, 142); + MakeDependencies(vars, PRECIP, 143); + + if ( source != S_ECHAM5 ) + { + MakeDependencies(vars, NET_WATER, 142); + MakeDependencies(vars, NET_WATER, 143); + MakeDependencies(vars, NET_WATER, 160); + MakeDependencies(vars, NET_WATER, 182); + + MakeDependencies(vars, NET_TOP, 178); + MakeDependencies(vars, NET_TOP, 179); + + MakeDependencies(vars, NET_BOT, 176); + MakeDependencies(vars, NET_BOT, 177); + + MakeDependencies(vars, NET_HEAT, 146); + MakeDependencies(vars, NET_HEAT, 147); + MakeDependencies(vars, NET_HEAT, 176); + MakeDependencies(vars, NET_HEAT, 177); + MakeDependencies(vars, NET_HEAT, 218); + /* + if ( source == S_ECHAM5 ) + { + MakeDependencies(vars, NET_HEAT, 206); + MakeDependencies(vars, NET_HEAT, 208); + MakeDependencies(vars, NET_HEAT, 209); + } + else + */ + { + MakeDependencies(vars, NET_HEAT, 220); + } + } + + MakeDependencies(vars, SW_CLF, 178); + MakeDependencies(vars, SW_CLF, 224); + + MakeDependencies(vars, LW_CLF, 179); + MakeDependencies(vars, LW_CLF, 225); + + MakeDependencies(vars, NET_CLF, 178); + MakeDependencies(vars, NET_CLF, 179); + MakeDependencies(vars, NET_CLF, 224); + MakeDependencies(vars, NET_CLF, 225); + + if ( vars[DPSDX].needed || vars[DPSDY].needed || + vars[GEOPOTHEIGHT].comp || vars[SLP].comp || vars[THETAF].needed || + vars[HALF_PRESS].needed || vars[RHUMIDITY].comp || vars[OMEGA].comp || + type >= 30 ) + vars[PS_PROG].comp = TRUE; + + CheckDependencies(vars, 0); +} diff --git a/src/specspace.c b/src/specspace.c index b3cbf06e5..81e32fc9b 100644 --- a/src/specspace.c +++ b/src/specspace.c @@ -22,6 +22,7 @@ void after_legini_full(int ntr, int nlat, double *restrict poli, double *restric double *restrict pol2, double *restrict pol3, double *restrict coslat); void after_legini(int ntr, int nlat, double *restrict poli, double *restrict pold, double *restrict coslat); + void grid2spec(SPTRANS *sptrans, int gridIDin, double *arrayIn, int gridIDout, double *arrayOut) { int nlev = 1; -- GitLab