A collection of diagnostic and interpolation routines for use with output from the Weather Research and Forecasting (WRF-ARW) Model.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

13253 lines
352 KiB

#include <stdio.h>
#include <strings.h>
#include <math.h>
#include "wrapper.h"
extern void NGCALLF(dcomputetk,DCOMPUTETK)(double *,double *,double *,int *);
extern void NGCALLF(dcomputetd,DCOMPUTETD)(double *,double *,double *,int *);
extern void NGCALLF(dcomputerh,DCOMPUTERH)(double *,double *,double *,
double *,int *);
extern void NGCALLF(dcomputeseaprs,DCOMPUTESEAPRS)(int *,int *,int *,
double *,double *,
double *,double *,
double *,double *,
double *,double *);
extern void NGCALLF(dinterp3dz,DINTERP3DZ)(double *,double *,double *,
double *,int *,int *, int*,
double *);
extern void NGCALLF(dinterp2dxy,DINTERP2DXY)(double *,double *,double *,
int *,int *,int *, int*);
extern void NGCALLF(dinterp1d,DINTERP1D)(double *,double *,double *,double *,
int *, int *, double *);
extern void NGCALLF(dfilter2d,DFILTER2D)(double *, double *, int *, int *,
int *, double *);
extern void NGCALLF(filter2d,FILTER2D)(float *, float *, int *, int *,
int *, float *);
extern void NGCALLF(dgetijlatlong,DGETIJLATLONG)(double *, double *, double *,
double *, int *, int *,
int *, int *, int *);
extern void NGCALLF(dcomputeuvmet,DCOMPUTEUVMET)(double *, double *, double *,
double *, double *, double *,
double *, double *, double *,
double *, int *, int *,
int *, int *, int *,
logical *,double *, double*,
double *);
extern void NGCALLF(dcomputeiclw,DCOMPUTEICLW)(double *, double *, double *,
int *, int *, int *);
extern void NGCALLF(dbint3d,DBINT3D)(double *,double *,double *, double *,
int *, int *, int *, int *,
int *, int *, int *);
extern void NGCALLF(dcomputepv,DCOMPUTEPV)(double *, double *, double *,
double *, double *, double *,
double *, double *, double *,
double *, double *, int *, int *,
int *, int *, int *);
extern void NGCALLF(dcomputeabsvort,DCOMPUTEABSVORT)(double *, double *,
double *, double *,
double *, double *,
double *, double *,
double *, int *, int *,
int *, int *, int *);
extern void NGCALLF(calcdbz,CALCDBZ)(double *, double *, double *, double *,
double *, double *, double *, int *,
int *, int *, int *, int *, int *);
extern void NGCALLF(dlltoij,DLLTOIJ)(int *, double *, double *, double *,
double *, double *, double *, double *,
double *, double *, double *, double *,
double *, double *, double *, double *,
double *);
extern void NGCALLF(dijtoll,DIJTOLL)(int *, double *, double *, double *,
double *, double *, double *, double *,
double *, double *, double *, double *,
double *, double *, double *, double *,
double *);
extern void NGCALLF(deqthecalc,DEQTHECALC)(double *, double *, double *,
double *, int *, int *, int *);
extern void NGCALLF(dcapecalc3d,DCAPECALC3D)(double *prs, double *tmk,
double *qvp, double *ght,
double *ter, double *sfp,
double *cape, double *cin,
double *cmsg,
int *miy, int *mjx, int *mkzh,
int *i3dflag, int *ter_follow,
char *,int);
extern void NGCALLF(dcalrelhl,DCALRELHL)(double *u, double *v, double *z,
double *ter, double *top,
double *sreh, int *miy, int *mjx,
int *mkzh);
extern void NGCALLF(dcalcuh,DCALCUH)(int *, int *, int *, int *, double *,
double *, double *, double *, double *,
double *, double *, double *, double *,
double *, double *, double *);
extern void NGCALLF(plotgrids_var,PLOTGRIDS_VAR)(char *fname, float *plotvar, int);
extern void NGCALLF(plotfmt_open,PLOTFMT_OPEN)(char *cfilename, int *istatus,
int);
extern void NGCALLF(plotfmt_close,PLOTFMT_CLOSE)();
extern void NGCALLF(plotfmt_rdhead,PLOTFMT_RDHEAD)(int *istatus,
float *rhead,
char *cfield,
char *chdate,
char *cunits,
char *cmapsc,
char *cdesc,
int,int,int,int,int);
extern void NGCALLF(plotfmt_rddata,PLOTFMT_RDDATA)(int *istatus,
int *nx, int *ny,
float *slab);
extern void NGCALLF(wetbulbcalc,WETBULBCALC)(double *prs,double *tmk,
double *qvp, double *twb,
int *nx, int *ny,int *nz,
char *,int);
extern void NGCALLF(omgcalc,OMGCALC)(double *qvp, double *tmk, double *www,
double *prs, double *omg,
int *mx,int *my, int *mz);
extern void NGCALLF(virtual_temp,VIRTUAL_TEMP)(double *temp,double *ratmix,
double *tv,int *,int *,int *);
extern NclDimRec *get_wrf_dim_info(int,int,int,ng_size_t*);
extern char *get_psa_file();
extern void var_zero(double *, ng_size_t);
extern void convert_to_hPa(double *, ng_size_t);
extern void flip_it(double *, double *, ng_size_t, ng_size_t);
NhlErrorTypes wrf_tk_W( void )
{
/*
* Input array variables
*/
void *p, *theta;
double *tmp_p = NULL;
double *tmp_theta = NULL;
int ndims_p, ndims_theta;
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_theta[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_p, type_theta;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Output variable and attributes.
*/
void *t;
NclQuark *description, *units;
char *cdescription, *cunits;
double *tmp_t = NULL;
int size_tt;
NclBasicDataTypes type_t;
NclObjClass type_obj_t;
/*
* Various
*/
ng_size_t i, nx, size_leftmost, index_p;
int inx;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
p = (void*)NclGetArgValue(
0,
2,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
theta = (void*)NclGetArgValue(
1,
2,
&ndims_theta,
dsizes_theta,
NULL,
NULL,
&type_theta,
DONT_CARE);
/*
* Error checking. Input variables must be same size.
*/
if(ndims_p != ndims_theta) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_tk: The p and theta arrays must have the same number of dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_p; i++) {
if(dsizes_p[i] != dsizes_theta[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_tk: p and theta must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Retrieve dimension names from the "theta" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(1,2,ndims_theta,dsizes_theta);
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_p-1; i++) size_leftmost *= dsizes_p[i];
nx = dsizes_p[ndims_p-1];
size_tt = size_leftmost * nx;
/*
* Test dimension sizes.
*/
if(nx > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_tk: nx = %ld is greater than INT_MAX", nx);
return(NhlFATAL);
}
inx = (int) nx;
/*
* Allocate space for coercing input arrays. If the input p or theta
* are already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the two input arrays
* are double.
*/
type_t = NCL_float;
type_obj_t = nclTypefloatClass;
if(type_p != NCL_double) {
tmp_p = (double *)calloc(nx,sizeof(double));
if(tmp_p == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_tk: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_t = NCL_double;
type_obj_t = nclTypedoubleClass;
}
if(type_theta != NCL_double) {
tmp_theta = (double *)calloc(nx,sizeof(double));
if(tmp_theta == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_tk: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_t = NCL_double;
type_obj_t = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
if(type_t == NCL_double) {
t = (double *)calloc(size_tt,sizeof(double));
if(t == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_tk: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
t = (float *)calloc(size_tt,sizeof(float));
tmp_t = (double *)calloc(nx,sizeof(double));
if(tmp_t == NULL || t == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_tk: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* one-dimensional subsection.
*/
index_p = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of p (tmp_p) to double if necessary.
*/
if(type_p != NCL_double) {
coerce_subset_input_double(p,tmp_p,index_p,type_p,nx,0,NULL,NULL);
}
else {
tmp_p = &((double*)p)[index_p];
}
/*
* Coerce subsection of theta (tmp_theta) to double if ncessary.
*/
if(type_theta != NCL_double) {
coerce_subset_input_double(theta,tmp_theta,index_p,type_theta,nx,
0,NULL,NULL);
}
else {
tmp_theta = &((double*)theta)[index_p];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_t == NCL_double) tmp_t = &((double*)t)[index_p];
/*
* Call Fortran routine.
*/
NGCALLF(dcomputetk,DCOMPUTETK)(tmp_t,tmp_p,tmp_theta,&inx);
/*
* Coerce output back to float if necessary.
*/
if(type_t == NCL_float) {
coerce_output_float_only(t,tmp_t,nx,index_p);
}
index_p += nx; /* Increment index */
}
/*
* Free up memory.
*/
if(type_p != NCL_double) NclFree(tmp_p);
if(type_theta != NCL_double) NclFree(tmp_theta);
if(type_t != NCL_double) NclFree(tmp_t);
/*
* Set up some attributes ("description" and "units") to return.
* Note that if the input arrays are anything but 2D, the units
* will be "Temperature", and "2m Temperature" otherwise.
*/
if(ndims_p != 2) {
cdescription = (char *)calloc(12,sizeof(char));
strcpy(cdescription,"Temperature");
}
else {
cdescription = (char *)calloc(15,sizeof(char));
strcpy(cdescription,"2m Temperature");
}
cunits = (char *)calloc(2,sizeof(char));
strcpy(cunits,"K");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cunits);
free(cdescription);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)t,
NULL,
ndims_p,
dsizes_p,
TEMPORARY,
NULL,
type_obj_t
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_td_W( void )
{
/*
* Input array variables
*/
void *p, *qv;
double *tmp_p, *tmp_qv;
int ndims_p, ndims_qv;
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_qv[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_p, type_qv;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Output variable and attributes.
*/
void *t;
NclQuark *description, *units;
char *cdescription, *cunits;
double *tmp_t = NULL;
int size_tt;
NclBasicDataTypes type_t;
NclObjClass type_obj_t;
/*
* Various
*/
ng_size_t i, np, nx, size_leftmost, index_p;
int inx;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
p = (void*)NclGetArgValue(
0,
2,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
qv = (void*)NclGetArgValue(
1,
2,
&ndims_qv,
dsizes_qv,
NULL,
NULL,
&type_qv,
DONT_CARE);
/*
* Error checking. Input variables must be same size.
*/
if(ndims_p != ndims_qv) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_td: The p and qv arrays must have the same number of dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_p; i++) {
if(dsizes_p[i] != dsizes_qv[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_td: p and qv must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Retrieve dimension names from the "qvapor" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(1,2,ndims_qv,dsizes_qv);
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_p-1; i++) size_leftmost *= dsizes_p[i];
nx = dsizes_p[ndims_p-1];
size_tt = size_leftmost * nx;
/*
* Test dimension sizes.
*/
if(nx > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_td: nx = %ld is greater than INT_MAX", nx);
return(NhlFATAL);
}
inx = (int) nx;
/*
* Allocate space for coercing input arrays. If the input p or qv
* are already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the two input arrays
* are double.
*/
type_t = NCL_float;
type_obj_t = nclTypefloatClass;
/*
* Allocate space for tmp_p no matter what, because we have to
* convert the values from hPa to Pa, and we don't want to do
* this to the original array.
*/
tmp_p = (double *)calloc(nx,sizeof(double));
if(tmp_p == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_td: Unable to allocate memory for coercing 't' to double");
return(NhlFATAL);
}
if(type_p == NCL_double) {
type_t = NCL_double;
type_obj_t = nclTypedoubleClass;
}
/*
* Allocate space for tmp_qv no matter what, because we want to set
* values of qv that are less than zero to zero, but we don't want
* these values retained when the function is done.
*/
tmp_qv = (double *)malloc(nx*sizeof(double));
if(tmp_qv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_td: Unable to allocate memory for coercing 'qv' to double");
return(NhlFATAL);
}
if(type_qv == NCL_double) {
type_t = NCL_double;
type_obj_t = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
if(type_t == NCL_double) {
t = (double *)calloc(size_tt,sizeof(double));
if(t == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_td: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
t = (float *)calloc(size_tt,sizeof(float));
tmp_t = (double *)calloc(nx,sizeof(double));
if(tmp_t == NULL || t == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_td: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* one-dimensional subsection.
*/
index_p = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of p (tmp_p) to double if necessary. Otherwise,
* just do a memcpy. Afterwards, convert the p values to Pa units,
* as they are coming in as hPa.
*/
if(type_p != NCL_double) {
coerce_subset_input_double(p,tmp_p,index_p,type_p,nx,0,NULL,NULL);
}
else {
(void *)memcpy((void*)((char*)tmp_p),
(void*)((char*)p + (index_p*sizeof(double))),
sizeof(double)*nx);
}
for(np = 0; np < nx; np++) tmp_p[np] *= 0.01;
/*
* Coerce subsection of qv (tmp_qv) to double if ncessary. Otherwise,
* just do a memcpy. Afterwards, set all values < 0 to 0.
*/
if(type_qv != NCL_double) {
coerce_subset_input_double(qv,tmp_qv,index_p,type_qv,nx,
0,NULL,NULL);
}
else {
(void *)memcpy((void*)((char*)tmp_qv),
(void*)((char*)qv + (index_p*sizeof(double))),
sizeof(double)*nx);
}
var_zero(tmp_qv, nx); /* Set all values < 0 to 0. */
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_t == NCL_double) tmp_t = &((double*)t)[index_p];
/*
* Call Fortran routine.
*/
NGCALLF(dcomputetd,DCOMPUTETD)(tmp_t,tmp_p,tmp_qv,&inx);
/*
* Coerce output back to float if necessary.
*/
if(type_t == NCL_float) {
coerce_output_float_only(t,tmp_t,nx,index_p);
}
index_p += nx; /* Increment index */
}
/*
* Free up memory.
*/
NclFree(tmp_qv);
NclFree(tmp_p);
if(type_t != NCL_double) NclFree(tmp_t);
/*
* Set up some attributes ("description" and "units") to return.
* Note that if the input arrays are anything but 2D, the units
* will be "Temperature", and "2m Temperature" otherwise.
*/
if(ndims_p != 2) {
cdescription = (char *)calloc(21,sizeof(char));
strcpy(cdescription,"Dewpoint Temperature");
}
else {
cdescription = (char *)calloc(24,sizeof(char));
strcpy(cdescription,"2m Dewpoint Temperature");
}
cunits = (char *)calloc(2,sizeof(char));
strcpy(cunits,"C");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cdescription);
free(cunits);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)t,
NULL,
ndims_p,
dsizes_p,
TEMPORARY,
NULL,
type_obj_t
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_rh_W( void )
{
/*
* Input array variables
*/
void *qv, *p, *t;
double *tmp_qv = NULL;
double *tmp_p = NULL;
double *tmp_t = NULL;
int ndims_qv, ndims_p, ndims_t;
ng_size_t dsizes_qv[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_t[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_qv, type_p, type_t;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Output variable and attributes.
*/
void *rh;
NclQuark *description, *units;
char *cdescription, *cunits;
double *tmp_rh = NULL;
int size_rh;
NclBasicDataTypes type_rh;
NclObjClass type_obj_rh;
/*
* Various
*/
ng_size_t i, nx, size_leftmost, index_qv;
int inx;
/*
* Variables for returning the output array with attributes and/or
* dimension names attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
qv = (void*)NclGetArgValue(
0,
3,
&ndims_qv,
dsizes_qv,
NULL,
NULL,
&type_qv,
DONT_CARE);
p = (void*)NclGetArgValue(
1,
3,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
t = (void*)NclGetArgValue(
2,
3,
&ndims_t,
dsizes_t,
NULL,
NULL,
&type_t,
DONT_CARE);
/*
* Error checking. Input variables must be same size.
*/
if(ndims_qv != ndims_t || ndims_p != ndims_t) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_rh: The qv, p, and t arrays must have the same number of dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_qv; i++) {
if(dsizes_qv[i] != dsizes_t[i] || dsizes_p[i] != dsizes_t[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_rh: qv, p, and t must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Retrieve dimension names from the "t" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(2,3,ndims_t,dsizes_t);
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_qv-1; i++) size_leftmost *= dsizes_qv[i];
nx = dsizes_qv[ndims_qv-1];
size_rh = size_leftmost * nx;
/*
* Test dimension sizes.
*/
if(nx > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_rh: nx = %ld is greater than INT_MAX", nx);
return(NhlFATAL);
}
inx = (int) nx;
/*
* Allocate space for coercing input arrays. If the input p or t
* are already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the two input arrays
* are double.
*/
type_rh = NCL_float;
type_obj_rh = nclTypefloatClass;
/*
* Allocate space for tmp_qv no matter what, because we want to set
* values of qv that are less than zero to zero, but we don't want
* these values retained when the function is done.
*/
tmp_qv = (double*)malloc(nx * sizeof(double));
if(tmp_qv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_rh: Unable to allocate memory for coercing 'qv' to double");
return(NhlFATAL);
}
if(type_qv == NCL_double) {
type_rh = NCL_double;
type_obj_rh = nclTypedoubleClass;
}
if(type_p != NCL_double) {
tmp_p = (double *)calloc(nx,sizeof(double));
if(tmp_p == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_rh: Unable to allocate memory for coercing 'p' to double");
return(NhlFATAL);
}
}
else {
type_rh = NCL_double;
type_obj_rh = nclTypedoubleClass;
}
if(type_t != NCL_double) {
tmp_t = (double *)calloc(nx,sizeof(double));
if(tmp_t == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_rh: Unable to allocate memory for coercing 't' to double");
return(NhlFATAL);
}
}
else {
type_rh = NCL_double;
type_obj_rh = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
if(type_rh == NCL_double) {
rh = (double *)calloc(size_rh,sizeof(double));
if(rh == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_rh: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
rh = (float *)calloc(size_rh,sizeof(float));
tmp_rh = (double *)calloc(nx,sizeof(double));
if(tmp_rh == NULL || rh == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_rh: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* one-dimensional subsection.
*/
index_qv = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of qv (tmp_qv) to double if necessary. Otherwise,
* just do a memcpy. Afterwards, set all values < 0 to 0.
*/
if(type_qv != NCL_double) {
coerce_subset_input_double(qv,tmp_qv,index_qv,type_qv,nx,0,NULL,NULL);
}
else {
(void *)memcpy((void*)((char*)tmp_qv),
(void*)((char*)qv + (index_qv*sizeof(double))),
sizeof(double)*nx);
}
var_zero(tmp_qv, nx); /* Set all values < 0 to 0. */
/*
* Coerce subsection of p (tmp_p) to double if necessary.
*/
if(type_p != NCL_double) {
coerce_subset_input_double(p,tmp_p,index_qv,type_p,nx,0,NULL,NULL);
}
else {
tmp_p = &((double*)p)[index_qv];
}
/*
* Coerce subsection of t (tmp_t) to double if ncessary.
*/
if(type_t != NCL_double) {
coerce_subset_input_double(t,tmp_t,index_qv,type_t,nx,
0,NULL,NULL);
}
else {
tmp_t = &((double*)t)[index_qv];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_rh == NCL_double) tmp_rh = &((double*)rh)[index_qv];
/*
* Call Fortran routine.
*/
NGCALLF(dcomputerh,DCOMPUTERH)(tmp_qv,tmp_p,tmp_t,tmp_rh,&inx);
/*
* Coerce output back to float if necessary.
*/
if(type_rh == NCL_float) {
coerce_output_float_only(rh,tmp_rh,nx,index_qv);
}
index_qv += nx; /* Increment index */
}
/*
* Free up memory.
*/
NclFree(tmp_qv);
if(type_p != NCL_double) NclFree(tmp_p);
if(type_t != NCL_double) NclFree(tmp_t);
if(type_rh != NCL_double) NclFree(tmp_rh);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(18,sizeof(char));
cunits = (char *)calloc(2,sizeof(char));
strcpy(cdescription,"Relative Humidity");
strcpy(cunits,"%");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cdescription);
free(cunits);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)rh,
NULL,
ndims_qv,
dsizes_qv,
TEMPORARY,
NULL,
type_obj_rh
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_slp_W( void )
{
/*
* Input array variables
*/
void *z, *t, *p, *q;
double *tmp_z = NULL;
double *tmp_t = NULL;
double *tmp_p = NULL;
double *tmp_q = NULL;
int ndims_z, ndims_t, ndims_p, ndims_q;
ng_size_t dsizes_z[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_t[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_q[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_z, type_t, type_p, type_q;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info = NULL;
NclDimRec *dim_info_t = NULL;
/*
* Output variable.
*/
void *slp;
NclQuark *description, *units;
char *cdescription, *cunits;
double *tmp_slp = NULL;
int ndims_slp;
ng_size_t *dsizes_slp;
ng_size_t size_slp;
NclBasicDataTypes type_slp;
NclObjClass type_obj_slp;
/*
* Various
*/
ng_size_t i, nx, ny, nz, nxy, nxyz, size_leftmost, index_nxy, index_nxyz;
double *tmp_t_sea_level, *tmp_t_surf, *tmp_level;
int inx, iny, inz;
/*
* Variables for returning the output array with attributes and/or
* dimension names attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
z = (void*)NclGetArgValue(
0,
4,
&ndims_z,
dsizes_z,
NULL,
NULL,
&type_z,
DONT_CARE);
t = (void*)NclGetArgValue(
1,
4,
&ndims_t,
dsizes_t,
NULL,
NULL,
&type_t,
DONT_CARE);
p = (void*)NclGetArgValue(
2,
4,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
q = (void*)NclGetArgValue(
3,
4,
&ndims_q,
dsizes_q,
NULL,
NULL,
&type_q,
DONT_CARE);
/*
* Error checking. Input variables must be same size, and must have at least
* 3 dimensions.
*/
if(ndims_z != ndims_t || ndims_z != ndims_p || ndims_z != ndims_q) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: The z, t, p, and q arrays must have the same number of dimensions");
return(NhlFATAL);
}
if(ndims_z < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: The z, t, p, and q arrays must have at least 3 dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_z; i++) {
if(dsizes_z[i] != dsizes_t[i] || dsizes_z[i] != dsizes_p[i] ||
dsizes_z[i] != dsizes_q[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: z, t, p, and q must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Allocate space to set dimension sizes.
*/
ndims_slp = ndims_z-1;
dsizes_slp = (ng_size_t*)calloc(ndims_slp,sizeof(ng_size_t));
if( dsizes_slp == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
/*
* Set sizes for output array and calculate size of leftmost dimensions.
* The output array will have one less dimension than the four input arrays.
*/
size_leftmost = 1;
for(i = 0; i < ndims_z-3; i++) {
dsizes_slp[i] = dsizes_z[i];
size_leftmost *= dsizes_z[i];
}
nx = dsizes_z[ndims_z-1];
ny = dsizes_z[ndims_z-2];
nz = dsizes_z[ndims_z-3];
dsizes_slp[ndims_slp-1] = nx;
dsizes_slp[ndims_slp-2] = ny;
nxy = nx * ny;
nxyz = nxy * nz;
size_slp = size_leftmost * nxy;
/*
* Test dimension sizes.
*/
if((nx > INT_MAX) || (ny > INT_MAX) || (nz > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: nx, ny, and/or nz is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
/*
* Get dimension info to see if we have named dimensions.
* This will be used for return variable.
*/
dim_info_t = get_wrf_dim_info(1,4,ndims_t,dsizes_t);
if(dim_info_t != NULL) {
dim_info = malloc(sizeof(NclDimRec)*ndims_slp);
if(dim_info == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for holding dimension information");
return(NhlFATAL);
}
for(i = 0; i < ndims_z-3; i++) {
dim_info[i] = dim_info_t[i];
}
dim_info[ndims_slp-1] = dim_info_t[ndims_t-1];
dim_info[ndims_slp-2] = dim_info_t[ndims_t-2];
}
/*
* Allocate space for coercing input arrays. If the input q, p, or t
* are already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the two input arrays
* are double.
*/
type_slp = NCL_float;
type_obj_slp = nclTypefloatClass;
/*
* Allocate space for tmp_q no matter what, because we want to set
* values of q that are less than zero to zero, but we don't want
* these values retained when the function is done.
*/
tmp_q = (double*)malloc(nxyz * sizeof(double));
if(tmp_q == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for coercing 'q' to double");
return(NhlFATAL);
}
if(type_q == NCL_double) {
type_slp = NCL_double;
type_obj_slp = nclTypedoubleClass;
}
if(type_z != NCL_double) {
tmp_z = (double *)calloc(nxyz,sizeof(double));
if(tmp_z == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for coercing 'z' to double");
return(NhlFATAL);
}
}
else {
type_slp = NCL_double;
type_obj_slp = nclTypedoubleClass;
}
if(type_t != NCL_double) {
tmp_t = (double *)calloc(nxyz,sizeof(double));
if(tmp_t == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for coercing 't' to double");
return(NhlFATAL);
}
}
else {
type_slp = NCL_double;
type_obj_slp = nclTypedoubleClass;
}
if(type_p != NCL_double) {
tmp_p = (double *)calloc(nxyz,sizeof(double));
if(tmp_p == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for coercing 'p' to double");
return(NhlFATAL);
}
}
else {
type_slp = NCL_double;
type_obj_slp = nclTypedoubleClass;
}
/*
* Allocate space for work arrays.
*/
tmp_t_sea_level = (double *)calloc(nxy,sizeof(double));
tmp_t_surf = (double *)calloc(nxy,sizeof(double));
tmp_level = (double *)calloc(nxy,sizeof(double));
if(tmp_t_sea_level == NULL || tmp_t_surf == NULL || tmp_level == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for temporary arrays");
return(NhlFATAL);
}
/*
* Allocate space for output array.
*/
if(type_slp == NCL_double) {
slp = (double *)calloc(size_slp,sizeof(double));
if(slp == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
slp = (float *)calloc(size_slp,sizeof(float));
tmp_slp = (double *)calloc(nxy,sizeof(double));
if(tmp_slp == NULL || slp == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_slp: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Loop across leftmost dimensions and call the Fortran routine
* for each three-dimensional subsection.
*/
index_nxy = index_nxyz = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of q (tmp_q) to double if necessary. Otherwise,
* just do a memcpy. Afterwards, set all values < 0 to 0.
*/
if(type_q != NCL_double) {
coerce_subset_input_double(q,tmp_q,index_nxyz,type_q,nxyz,0,NULL,NULL);
}
else {
(void *)memcpy((void*)((char*)tmp_q),
(void*)((char*)q + (index_nxyz*sizeof(double))),
sizeof(double)*nxyz);
}
var_zero(tmp_q, nxyz); /* Set all values < 0 to 0. */
/*
* Coerce subsection of z (tmp_z) to double if necessary.
*/
if(type_z != NCL_double) {
coerce_subset_input_double(z,tmp_z,index_nxyz,type_z,nxyz,0,NULL,NULL);
}
else {
tmp_z = &((double*)z)[index_nxyz];
}
/*
* Coerce subsection of p (tmp_p) to double if necessary.
*/
if(type_p != NCL_double) {
coerce_subset_input_double(p,tmp_p,index_nxyz,type_p,nxyz,0,NULL,NULL);
}
else {
tmp_p = &((double*)p)[index_nxyz];
}
/*
* Coerce subsection of t (tmp_t) to double if ncessary.
*/
if(type_t != NCL_double) {
coerce_subset_input_double(t,tmp_t,index_nxyz,type_t,nxyz,0,NULL,NULL);
}
else {
tmp_t = &((double*)t)[index_nxyz];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_slp == NCL_double) tmp_slp = &((double*)slp)[index_nxy];
/*
* Call Fortran routine.
*/
NGCALLF(dcomputeseaprs,DCOMPUTESEAPRS)(&inx,&iny,&inz,tmp_z,tmp_t,tmp_p,
tmp_q,tmp_slp,tmp_t_sea_level,
tmp_t_surf,tmp_level);
/*
* Coerce output back to float if necessary.
*/
if(type_slp == NCL_float) {
coerce_output_float_only(slp,tmp_slp,nxy,index_nxy);
}
index_nxyz += nxyz; /* Increment indices */
index_nxy += nxy;
}
/*
* Free up memory.
*/
NclFree(tmp_q);
if(type_p != NCL_double) NclFree(tmp_p);
if(type_t != NCL_double) NclFree(tmp_t);
if(type_z != NCL_double) NclFree(tmp_z);
if(type_slp != NCL_double) NclFree(tmp_slp);
NclFree(tmp_t_sea_level);
NclFree(tmp_t_surf);
NclFree(tmp_level);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(19,sizeof(char));
cunits = (char *)calloc(4,sizeof(char));
strcpy(cdescription,"Sea Level Pressure");
strcpy(cunits,"hPa");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cdescription);
free(cunits);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)slp,
NULL,
ndims_slp,
dsizes_slp,
TEMPORARY,
NULL,
type_obj_slp
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_slp);
if(dim_info != NULL) NclFree(dim_info);
NclFree(dim_info_t);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_interp_3d_z_W( void )
{
/*
* Input array variables
*/
void *v3d, *z, *loc;
double *tmp_v3d = NULL;
double *tmp_z = NULL;
double *tmp_loc = NULL;
int ndims_v3d, ndims_z;
ng_size_t dsizes_v3d[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_z[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_v3d, type_z, type_loc;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info_v3d;
NclDimRec *dim_info = NULL;
/*
* Variables for retrieving attributes from "v3d".
*/
NclAttList *attr_list;
NclAtt attr_obj;
NclStackEntry stack_entry;
NrmQuark *description, *units;
char *cdesc = NULL;
char *cunits = NULL;
logical found_desc = False, found_units = False;
/*
* Output variable.
*/
void *v2d;
double *tmp_v2d = NULL;
int ndims_v2d;
ng_size_t *dsizes_v2d;
ng_size_t size_v2d;
NclBasicDataTypes type_v2d;
NclObjClass type_obj_v2d;
NclScalar missing_v2d;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
NclQuark *qdesc, *qunits;
/*
* Various
*/
ng_size_t i, nx, ny, nz, nxy, nxyz, size_leftmost, index_v3d, index_v2d;
int inx, iny, inz;
double vmsg;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
v3d = (void*)NclGetArgValue(
0,
3,
&ndims_v3d,
dsizes_v3d,
NULL,
NULL,
&type_v3d,
DONT_CARE);
z = (void*)NclGetArgValue(
1,
3,
&ndims_z,
dsizes_z,
NULL,
NULL,
&type_z,
DONT_CARE);
loc = (void*)NclGetArgValue(
2,
3,
NULL,
NULL,
NULL,
NULL,
&type_loc,
DONT_CARE);
/*
* Error checking. First two input variables must be same size.
*/
if(ndims_v3d < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: The v3d and z arrays must have at least 3 dimensions");
return(NhlFATAL);
}
if(ndims_v3d != ndims_z) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: The v3d and z arrays must have the same number of dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_v3d; i++) {
if(dsizes_v3d[i] != dsizes_z[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: v3d and z must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Check if v3d has any attributes, namely "description" or "units".
* These attributes will be attached to the return variable v2d.
*/
stack_entry = _NclGetArg(0, 3, DONT_CARE);
switch (stack_entry.kind) {
case NclStk_VAR:
if (stack_entry.u.data_var->var.att_id != -1) {
attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id);
if (attr_obj == NULL) {
break;
}
}
else {
/*
* att_id == -1 ==> no optional args given.
*/
break;
}
/*
* Get optional arguments. If none are specified, then return
* missing values.
*/
if (attr_obj->att.n_atts == 0) {
break;
}
else {
/*
* Get list of attributes.
*/
attr_list = attr_obj->att.att_list;
/*
* Loop through attributes and check them.
*/
while (attr_list != NULL) {
if ((strcmp(attr_list->attname, "description")) == 0) {
description = (NrmQuark *) attr_list->attvalue->multidval.val;
cdesc = NrmQuarkToString(*description);
found_desc = True;
}
if ((strcmp(attr_list->attname, "units")) == 0) {
units = (NrmQuark *) attr_list->attvalue->multidval.val;
cunits = NrmQuarkToString(*units);
found_units = True;
}
attr_list = attr_list->next;
}
}
default:
break;
}
/*
* Calculate size of leftmost dimensions and set dimension sizes for
* output array.
*
* The output array will have one less dimension than v3d/z input arrays.
*/
nx = dsizes_v3d[ndims_v3d-1];
ny = dsizes_v3d[ndims_v3d-2];
nz = dsizes_v3d[ndims_v3d-3];
nxy = nx * ny;
nxyz = nxy * nz;
/*
* Test dimension sizes.
*/
if((nx > INT_MAX) || (ny > INT_MAX) || (nz > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: nx, ny, and/or nz is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
ndims_v2d = ndims_v3d-1;
dsizes_v2d = (ng_size_t*)calloc(ndims_v2d,sizeof(ng_size_t));
if( dsizes_v2d == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
size_leftmost = 1;
for(i = 0; i < ndims_v3d-3; i++) {
dsizes_v2d[i] = dsizes_v3d[i];
size_leftmost *= dsizes_v3d[i];
}
dsizes_v2d[ndims_v2d-2] = ny;
dsizes_v2d[ndims_v2d-1] = nx;
size_v2d = size_leftmost * nxy;
/*
* Retrieve dimension names from the "v3d" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info_v3d = get_wrf_dim_info(0,3,ndims_v3d,dsizes_v3d);
if(dim_info_v3d != NULL) {
dim_info = malloc(sizeof(NclDimRec)*ndims_v2d);
if(dim_info == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: Unable to allocate memory for holding dimension information");
return(NhlFATAL);
}
for(i = 0; i < ndims_v3d-3; i++) {
dim_info[i] = dim_info_v3d[i];
}
dim_info[ndims_v2d-1] = dim_info_v3d[ndims_v3d-1];
dim_info[ndims_v2d-2] = dim_info_v3d[ndims_v3d-2];
}
/*
* Allocate space for coercing input arrays. If the input v3d or z
* are already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the two input arrays
* are double.
*/
type_v2d = NCL_float;
type_obj_v2d = nclTypefloatClass;
if(type_v3d != NCL_double) {
tmp_v3d = (double *)calloc(nxyz,sizeof(double));
if(tmp_v3d == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_v2d = NCL_double;
type_obj_v2d = nclTypedoubleClass;
}
if(type_z != NCL_double) {
tmp_z = (double *)calloc(nxyz,sizeof(double));
if(tmp_z == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_v2d = NCL_double;
type_obj_v2d = nclTypedoubleClass;
}
/*
* Coerce loc (tmp_loc) to double if ncessary.
*/
tmp_loc = coerce_input_double(loc,type_loc,1,0,NULL,NULL);
/*
* Allocate space for output array.
*/
if(type_v2d == NCL_double) {
v2d = (double *)calloc(size_v2d,sizeof(double));
if(v2d == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: Unable to allocate memory for output array");
return(NhlFATAL);
}
missing_v2d.doubleval = ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis.doubleval;
vmsg = missing_v2d.doubleval;
}
else {
v2d = (float *)calloc(size_v2d,sizeof(float));
tmp_v2d = (double *)calloc(nxy,sizeof(double));
if(tmp_v2d == NULL || v2d == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_3d_z: Unable to allocate memory for output array");
return(NhlFATAL);
}
missing_v2d.floatval = ((NclTypeClass)nclTypefloatClass)->type_class.default_mis.floatval;
vmsg = (double)missing_v2d.floatval;
}
/*
* Loop across leftmost dimensions and call the Fortran routine
* for each three-dimensional subsection.
*/
index_v2d = index_v3d = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of v3d (tmp_v3d) to double if necessary.
*/
if(type_v3d != NCL_double) {
coerce_subset_input_double(v3d,tmp_v3d,index_v3d,type_v3d,nxyz,
0,NULL,NULL);
}
else {
tmp_v3d = &((double*)v3d)[index_v3d];
}
/*
* Coerce subsection of z (tmp_z) to double if necessary.
*/
if(type_z != NCL_double) {
coerce_subset_input_double(z,tmp_z,index_v3d,type_z,nxyz,0,NULL,NULL);
}
else {
tmp_z = &((double*)z)[index_v3d];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_v2d == NCL_double) tmp_v2d = &((double*)v2d)[index_v2d];
/*
* Call Fortran routine.
*/
NGCALLF(dinterp3dz,DINTERP3DZ)(tmp_v3d,tmp_v2d,tmp_z,tmp_loc,
&inx,&iny,&inz,&vmsg);
/*
* Coerce output back to float if necessary.
*/
if(type_v2d == NCL_float) {
coerce_output_float_only(v2d,tmp_v2d,nxy,index_v2d);
}
index_v3d += nxyz;
index_v2d += nxy;
}
/*
* Free up memory.
*/
if(type_v3d != NCL_double) NclFree(tmp_v3d);
if(type_z != NCL_double) NclFree(tmp_z);
if(type_loc != NCL_double) NclFree(tmp_loc);
if(type_v2d != NCL_double) NclFree(tmp_v2d);
/*
* If v3d had a "description" or units attribute, return them with
* the output variable as an attribute. Otherwise, return a
* blank string for description, and nothing for units.
*/
if(!found_desc) {
cdesc = (char *)calloc(2,sizeof(char));
strcpy(cdesc," ");
}
/*
* I don't think we can return "description" or "units" here, because
* they are attached to an NCL input parameter. It could screw things up
* if we try to return it as an attribute with the output variable.
* Instead, create a new description and units "quark" variable.
*/
qdesc = (NclQuark*)NclMalloc(sizeof(NclQuark));
*qdesc = NrmStringToQuark(cdesc);
if (!found_desc)
free(cdesc);
if(found_units) {
qunits = (NclQuark*)NclMalloc(sizeof(NclQuark));
*qunits = NrmStringToQuark(cunits);
}
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)v2d,
&missing_v2d,
ndims_v2d,
dsizes_v2d,
TEMPORARY,
NULL,
type_obj_v2d
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)qdesc,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
if(found_units) {
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)qunits,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
}
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_v2d);
if(dim_info != NULL) NclFree(dim_info);
NclFree(dim_info_v3d);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_interp_2d_xy_W( void )
{
/*
* Input array variables
*/
void *v3d, *xy;
double *tmp_v3d = NULL;
double *tmp_xy = NULL;
int ndims_v3d, ndims_xy;
ng_size_t dsizes_v3d[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_xy[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_v3d, type_xy;
/*
* Variables for retrieving attributes from "v3d".
*/
NclAttList *attr_list;
NclAtt attr_obj;
NclStackEntry stack_entry;
NrmQuark *description, *units;
char *cdesc = NULL;
char *cunits = NULL;
logical found_desc = False, found_units = False;
/*
* Output variable.
*/
void *v2d;
double *tmp_v2d = NULL;
int ndims_v2d;
ng_size_t *dsizes_v2d, size_v2d;
NclBasicDataTypes type_v2d;
NclObjClass type_obj_v2d;
NclScalar missing_v2d;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
NclQuark *qdesc, *qunits;
/*
* Various
*/
ng_size_t i, nx, ny, nz, nxnynz, nxy, nxy_nz , nxy_2, size_leftmost;
ng_size_t index_v3d, index_v2d, index_xy;
int inx, iny, inz, inxy;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
v3d = (void*)NclGetArgValue(
0,
2,
&ndims_v3d,
dsizes_v3d,
NULL,
NULL,
&type_v3d,
DONT_CARE);
xy = (void*)NclGetArgValue(
1,
2,
&ndims_xy,
dsizes_xy,
NULL,
NULL,
&type_xy,
DONT_CARE);
/*
* Error checking.
*/
if(ndims_v3d < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: The v3d array must be at least 3-dimensional");
return(NhlFATAL);
}
if(ndims_v3d != (ndims_xy+1)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: The v3d array must have one more dimension than the xy array");
return(NhlFATAL);
}
if(dsizes_xy[ndims_xy-1] != 2) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: The rightmost dimension of xy must be 2");
return(NhlFATAL);
}
nz = dsizes_v3d[ndims_v3d-3];
ny = dsizes_v3d[ndims_v3d-2];
nx = dsizes_v3d[ndims_v3d-1];
nxy = dsizes_xy[ndims_xy-2];
nxnynz = nx * ny * nz;
nxy_nz = nxy * nz;
nxy_2 = nxy * 2;
/*
* Test dimension sizes.
*/
if((nxy > INT_MAX) || (nx > INT_MAX) || (ny > INT_MAX) || (nz > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: one or more dimension sizes is greater than INT_MAX", nxy);
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
inxy = (int) nxy;
/*
* Check leftmost dimensions, if any, and calculate their size.
* Also set dimension sizes for output array.
*/
ndims_v2d = ndims_xy; /* leftmost dims x nz x nxy */
dsizes_v2d = (ng_size_t*)calloc(ndims_v2d,sizeof(ng_size_t));
if( dsizes_v2d == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
size_leftmost = 1;
for(i = 0; i < ndims_v3d-3; i++) {
if(dsizes_v3d[i] != dsizes_xy[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: The leftmost dimensions of v3d and xy must be the same");
return(NhlFATAL);
}
dsizes_v2d[i] = dsizes_v3d[i];
size_leftmost *= dsizes_v3d[i];
}
dsizes_v2d[ndims_v2d-2] = nz;
dsizes_v2d[ndims_v2d-1] = nxy;
size_v2d = size_leftmost * nxy_nz;
/*
* Check if v3d has any attributes, namely "description" or "units".
* These attributes will be attached to the return variable v2d.
*/
stack_entry = _NclGetArg(0, 2, DONT_CARE);
switch (stack_entry.kind) {
case NclStk_VAR:
if (stack_entry.u.data_var->var.att_id != -1) {
attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id);
if (attr_obj == NULL) {
break;
}
}
else {
/*
* att_id == -1 ==> no optional args given.
*/
break;
}
/*
* Get optional arguments. If none are specified, then return
* missing values.
*/
if (attr_obj->att.n_atts == 0) {
break;
}
else {
/*
* Get list of attributes.
*/
attr_list = attr_obj->att.att_list;
/*
* Loop through attributes and check them.
*/
while (attr_list != NULL) {
if ((strcmp(attr_list->attname, "description")) == 0) {
description = (NrmQuark *) attr_list->attvalue->multidval.val;
cdesc = NrmQuarkToString(*description);
found_desc = True;
}
if ((strcmp(attr_list->attname, "units")) == 0) {
units = (NrmQuark *) attr_list->attvalue->multidval.val;
cunits = NrmQuarkToString(*units);
found_units = True;
}
attr_list = attr_list->next;
}
}
default:
break;
}
/*
* Allocate space for coercing input arrays. If the input v3d or xy
* are already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the two input arrays
* are double.
*/
type_v2d = NCL_float;
type_obj_v2d = nclTypefloatClass;
if(type_v3d != NCL_double) {
tmp_v3d = (double *)calloc(nxnynz,sizeof(double));
if(tmp_v3d == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_v2d = NCL_double;
type_obj_v2d = nclTypedoubleClass;
}
if(type_xy != NCL_double) {
tmp_xy = (double *)calloc(nxy_2,sizeof(double));
if(tmp_xy == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_v2d = NCL_double;
type_obj_v2d = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
if(type_v2d == NCL_double) {
v2d = (double *)calloc(size_v2d,sizeof(double));
if(v2d == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: Unable to allocate memory for output array");
return(NhlFATAL);
}
missing_v2d.doubleval = ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis.doubleval;
}
else {
v2d = (float *)calloc(size_v2d,sizeof(float));
tmp_v2d = (double *)calloc(nxy_nz,sizeof(double));
if(tmp_v2d == NULL || v2d == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_2d_xy: Unable to allocate memory for output array");
return(NhlFATAL);
}
missing_v2d.floatval = ((NclTypeClass)nclTypefloatClass)->type_class.default_mis.floatval;
}
/*
* Loop across leftmost dimensions and call the Fortran routine
* for reach three-dimensional subsection.
*/
index_v3d = index_v2d = index_xy = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of v3d (tmp_v3d) to double if necessary.
*/
if(type_v3d != NCL_double) {
coerce_subset_input_double(v3d,tmp_v3d,index_v3d,type_v3d,nxnynz,
0,NULL,NULL);
}
else {
tmp_v3d = &((double*)v3d)[index_v3d];
}
/*
* Coerce subsection of xy (tmp_xy) to double if necessary.
*/
if(type_xy != NCL_double) {
coerce_subset_input_double(xy,tmp_xy,index_xy,type_xy,nxy_2,0,NULL,NULL);
}
else {
tmp_xy = &((double*)xy)[index_xy];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_v2d == NCL_double) tmp_v2d = &((double*)v2d)[index_v2d];
/*
* Call Fortran routine.
*/
NGCALLF(dinterp2dxy,DINTERP2DXY)(tmp_v3d,tmp_v2d,tmp_xy,&inx,&iny,&inz,&inxy);
/*
* Coerce output back to float if necessary.
*/
if(type_v2d == NCL_float) {
coerce_output_float_only(v2d,tmp_v2d,nxy_nz,index_v2d);
}
index_v3d += nxnynz; /* Increment indices */
index_v2d += nxy_nz;
index_xy += nxy_2;
}
/*
* Free up memory.
*/
if(type_v3d != NCL_double) NclFree(tmp_v3d);
if(type_xy != NCL_double) NclFree(tmp_xy);
if(type_v2d != NCL_double) NclFree(tmp_v2d);
/*
* If v3d had a "description" or units attribute, return them with
* the output variable as an attribute. Otherwise, return a
* blank string for description, and nothing for units.
*/
if(!found_desc) {
cdesc = (char *)calloc(2,sizeof(char));
strcpy(cdesc," ");
}
/*
* I don't think we can return "description" or "units" here, because
* they are attached to an NCL input parameter. It could screw things up
* if we try to return it as an attribute with the output variable.
* Instead, create a new description and units "quark" variable.
*/
qdesc = (NclQuark*)NclMalloc(sizeof(NclQuark));
*qdesc = NrmStringToQuark(cdesc);
if (!found_desc)
free(cdesc);
if(found_units) {
qunits = (NclQuark*)NclMalloc(sizeof(NclQuark));
*qunits = NrmStringToQuark(cunits);
}
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)v2d,
&missing_v2d,
ndims_v2d,
dsizes_v2d,
TEMPORARY,
NULL,
type_obj_v2d
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)qdesc,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
if(found_units) {
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)qunits,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
}
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
NULL,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_v2d);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_interp_1d_W( void )
{
/*
* Input array variables
*/
void *v_in, *z_in, *z_out;
double *tmp_v_in = NULL;
double *tmp_z_in = NULL;
double *tmp_z_out = NULL;
int ndims_v_in, ndims_z_in, ndims_z_out;
ng_size_t dsizes_v_in[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_z_in[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_z_out[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_v_in, type_z_in, type_z_out;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Variables for retrieving attributes from "v3d".
*/
NclAttList *attr_list;
NclAtt attr_obj;
NclStackEntry stack_entry;
NrmQuark *description, *units;
char *cdesc = NULL;
char *cunits = NULL;
logical found_desc = False, found_units = False;
/*
* Output variable.
*/
void *v_out;
double *tmp_v_out = NULL;
double v_out_msg;
ng_size_t *dsizes_v_out, size_v_out;
NclBasicDataTypes type_v_out;
NclObjClass type_obj_v_out;
NclScalar missing_v_out;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
NclQuark *qdesc, *qunits;
/*
* Various
*/
ng_size_t i, nz_in, nz_out, size_leftmost, index_v_in, index_v_out;
int inz_in, inz_out;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
v_in = (void*)NclGetArgValue(
0,
3,
&ndims_v_in,
dsizes_v_in,
NULL,
NULL,
&type_v_in,
DONT_CARE);
z_in = (void*)NclGetArgValue(
1,
3,
&ndims_z_in,
dsizes_z_in,
NULL,
NULL,
&type_z_in,
DONT_CARE);
z_out = (void*)NclGetArgValue(
2,
3,
&ndims_z_out,
dsizes_z_out,
NULL,
NULL,
&type_z_out,
DONT_CARE);
/*
* Error checking.
*/
if(ndims_v_in != ndims_z_in || ndims_v_in != ndims_z_out) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: The v_in, z_in, and z_out arrays must be the same number of dimensions");
return(NhlFATAL);
}
nz_in = dsizes_z_in[ndims_z_in-1];
nz_out = dsizes_z_out[ndims_z_out-1];
if(dsizes_v_in[ndims_v_in-1] != nz_in) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: The rightmost dimension of v_in and z_in must be the same");
return(NhlFATAL);
}
/*
* Test dimension sizes.
*/
if((nz_in > INT_MAX) || (nz_out > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: nz_in and/or nz_out is greater than INT_MAX");
return(NhlFATAL);
}
inz_in = (int) nz_in;
inz_out = (int) nz_out;
/*
* Retrieve dimension names from the "v3d" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(0,3,ndims_v_in,dsizes_v_in);
/*
* Check if v_in has any attributes, namely "description" or "units".
* These attributes will be attached to the return variable v_out.
*/
stack_entry = _NclGetArg(0, 3, DONT_CARE);
switch (stack_entry.kind) {
case NclStk_VAR:
if (stack_entry.u.data_var->var.att_id != -1) {
attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id);
if (attr_obj == NULL) {
break;
}
}
else {
/*
* att_id == -1 ==> no optional args given.
*/
break;
}
/*
* Get optional arguments. If none are specified, then return
* missing values.
*/
if (attr_obj->att.n_atts == 0) {
break;
}
else {
/*
* Get list of attributes.
*/
attr_list = attr_obj->att.att_list;
/*
* Loop through attributes and check them.
*/
while (attr_list != NULL) {
if ((strcmp(attr_list->attname, "description")) == 0) {
description = (NrmQuark *) attr_list->attvalue->multidval.val;
cdesc = NrmQuarkToString(*description);
found_desc = True;
}
if ((strcmp(attr_list->attname, "units")) == 0) {
units = (NrmQuark *) attr_list->attvalue->multidval.val;
cunits = NrmQuarkToString(*units);
found_units = True;
}
attr_list = attr_list->next;
}
}
default:
break;
}
/*
* Calculate leftmost dimensions, if any, and check their sizes.
* Also set dimension sizes for output array.
*/
dsizes_v_out = (ng_size_t*)calloc(ndims_z_out,sizeof(ng_size_t));
if( dsizes_v_out == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
size_leftmost = 1;
for(i = 0; i < ndims_v_in-1; i++ ) {
if(dsizes_v_in[i] != dsizes_z_in[i] ||
dsizes_v_in[i] != dsizes_z_out[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: The input arrays must be the same dimensionality");
return(NhlFATAL);
}
dsizes_v_out[i] = dsizes_v_in[i];
size_leftmost *= dsizes_v_in[i];
}
dsizes_v_out[ndims_v_in-1] = nz_out;
size_v_out = size_leftmost * nz_out;
/*
* Allocate space for coercing input arrays. If the input arrays
* are already double, then we don't need to allocate space for the
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the two input arrays
* are double.
*/
type_v_out = NCL_float;
type_obj_v_out = nclTypefloatClass;
if(type_v_in != NCL_double) {
tmp_v_in = (double *)calloc(nz_in,sizeof(double));
if(tmp_v_in == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_v_out = NCL_double;
type_obj_v_out = nclTypedoubleClass;
}
if(type_z_in != NCL_double) {
tmp_z_in = (double *)calloc(nz_in,sizeof(double));
if(tmp_z_in == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_v_out = NCL_double;
type_obj_v_out = nclTypedoubleClass;
}
if(type_z_out != NCL_double) {
tmp_z_out = (double *)calloc(nz_out,sizeof(double));
if(tmp_z_out == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_v_out = NCL_double;
type_obj_v_out = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
if(type_v_out == NCL_double) {
v_out = (double *)calloc(size_v_out,sizeof(double));
if(v_out == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: Unable to allocate memory for output array");
return(NhlFATAL);
}
v_out_msg = missing_v_out.doubleval = ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis.doubleval;
}
else {
v_out = (float *)calloc(size_v_out,sizeof(float));
tmp_v_out = (double *)calloc(nz_out,sizeof(double));
if(tmp_v_out == NULL || v_out == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_interp_1d: Unable to allocate memory for output array");
return(NhlFATAL);
}
v_out_msg = (double)((NclTypeClass)nclTypefloatClass)->type_class.default_mis.floatval;
missing_v_out.floatval = ((NclTypeClass)nclTypefloatClass)->type_class.default_mis.floatval;
}
/*
* Loop across leftmost dimensions and call the Fortran routine
* for reach one-dimensional subsection.
*/
index_v_out = index_v_in = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of v_in (tmp_v_in) to double if necessary.
*/
if(type_v_in != NCL_double) {
coerce_subset_input_double(v_in,tmp_v_in,index_v_in,type_v_in,nz_in,
0,NULL,NULL);
}
else {
tmp_v_in = &((double*)v_in)[index_v_in];
}
/*
* Coerce subsection of z_in (tmp_z_in) to double if necessary.
*/
if(type_z_in != NCL_double) {
coerce_subset_input_double(z_in,tmp_z_in,index_v_in,type_z_in,nz_in,
0,NULL,NULL);
}
else {
tmp_z_in = &((double*)z_in)[index_v_in];
}
/*
* Coerce subsection of z_out (tmp_z_out) to double if necessary.
*/
if(type_z_out != NCL_double) {
coerce_subset_input_double(z_out,tmp_z_out,index_v_out,type_z_out,
nz_out,0,NULL,NULL);
}
else {
tmp_z_out = &((double*)z_out)[index_v_out];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_v_out == NCL_double) tmp_v_out = &((double*)v_out)[index_v_out];
/*
* Call Fortran routine.
*/
NGCALLF(dinterp1d,DINTERP1D)(tmp_v_in,tmp_v_out,tmp_z_in,tmp_z_out,&inz_in,
&inz_out,&v_out_msg);
/*
* Coerce output back to float if necessary.
*/
if(type_v_out == NCL_float) {
coerce_output_float_only(v_out,tmp_v_out,nz_out,index_v_out);
}
index_v_in += nz_in;
index_v_out += nz_out;
}
/*
* Free up memory.
*/
if(type_v_in != NCL_double) NclFree(tmp_v_in);
if(type_z_in != NCL_double) NclFree(tmp_z_in);
if(type_z_out != NCL_double) NclFree(tmp_z_out);
if(type_v_out != NCL_double) NclFree(tmp_v_out);
/*
* If v3d had a "description" or units attribute, return them with
* the output variable as an attribute. Otherwise, return a
* blank string for description, and nothing for units.
*/
if(!found_desc) {
cdesc = (char *)calloc(2,sizeof(char));
strcpy(cdesc," ");
}
/*
* I don't think we can return "description" or "units" here, because
* they are attached to an NCL input parameter. It could screw things up
* if we try to return it as an attribute with the output variable.
* Instead, create a new description and units "quark" variable.
*/
qdesc = (NclQuark*)NclMalloc(sizeof(NclQuark));
*qdesc = NrmStringToQuark(cdesc);
if (!found_desc)
free(cdesc);
if(found_units) {
qunits = (NclQuark*)NclMalloc(sizeof(NclQuark));
*qunits = NrmStringToQuark(cunits);
}
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)v_out,
&missing_v_out,
ndims_z_out,
dsizes_v_out,
TEMPORARY,
NULL,
type_obj_v_out
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)qdesc,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
if(found_units) {
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)qunits,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
}
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_v_out);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_smooth_2d_W( void )
{
/*
* Input variables
*
*/
void *a;
int has_missing_a, ndims_a;
ng_size_t dsizes_a[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_a;
NclScalar missing_a;
int *it;
/*
* Various
*/
double *db = NULL;
float *fb = NULL;
ng_size_t i, index_a, size_leftmost;
int ny, nx, nynx;
double d_missing;
float f_missing;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
a = (void*)NclGetArgValue(
0,
2,
&ndims_a,
dsizes_a,
&missing_a,
&has_missing_a,
&type_a,
1);
/*
* Check dimension sizes and input type.
*/
if(ndims_a < 2) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_smooth_2d: The 'a' array must have at least 2 dimensions");
return(NhlFATAL);
}
if(type_a != NCL_double && type_a != NCL_float) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_smooth_2d: The 'a' array must be float or double");
return(NhlFATAL);
}
ny = dsizes_a[ndims_a-2];
nx = dsizes_a[ndims_a-1];
nynx = ny * nx;
/*
* Get argument # 1
*/
it = (int*)NclGetArgValue(
1,
2,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_a-2; i++) size_leftmost *= dsizes_a[i];
/*
* Allocate space for "b", which "a" will be copied to inside
* Fortran routine.
*/
if(type_a == NCL_double) {
db = (double *)malloc(nynx*sizeof(double));
if(db == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_smooth_2d: Unable to allocate memory for temporary array");
return(NhlFATAL);
}
d_missing = has_missing_a ? missing_a.doubleval : ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis.doubleval;
}
else {
fb = (float *)malloc(nynx*sizeof(float));
if(fb == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_smooth_2d: Unable to allocate memory for temporary array");
return(NhlFATAL);
}
f_missing = has_missing_a ? missing_a.floatval : ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis.floatval;
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* two-dimensional subsection.
*/
index_a = 0;
for(i = 0; i < size_leftmost; i++) {
if(type_a == NCL_double) {
NGCALLF(dfilter2d,DFILTER2D)(&((double*)a)[index_a], db, &nx, &ny, it,
&d_missing);
}
else {
NGCALLF(filter2d,FILTER2D)(&((float*)a)[index_a], fb, &nx, &ny, it,
&f_missing);
}
index_a += nynx;
}
if(type_a == NCL_double) {
NclFree(db);
}
else {
NclFree(fb);
}
/*
* This is a procedure, so no values are returned.
*/
return(NhlNOERROR);
}
NhlErrorTypes wrf_latlon_to_ij_W( void )
{
/*
* Input variables
*/
void *lat_array, *lon_array, *lat_loc, *lon_loc;
double *tmp_lat_array = NULL;
double *tmp_lon_array = NULL;
double *tmp_lat_loc = NULL;
double *tmp_lon_loc = NULL;
int ndims_lat_array;
ng_size_t dsizes_lat_array[NCL_MAX_DIMENSIONS];
int ndims_lon_array;
ng_size_t dsizes_lon_array[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_lat_loc[1];
ng_size_t dsizes_lon_loc[1];
NclBasicDataTypes type_lat_array, type_lon_array;
NclBasicDataTypes type_lat_loc, type_lon_loc;
int is_scalar_latlon_loc;
/*
* Return variable
*/
int iret, *ret;
int ndims_ret;
ng_size_t *dsizes_ret;
NclScalar missing_ret;
/*
* Various
*/
ng_size_t ny, nx, nynx, nretlocs;
ng_size_t index_array, index_ret;
ng_size_t i, j, ndims_leftmost, size_leftmost, size_output;
int inx, iny;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
lat_array = (void*)NclGetArgValue(
0,
4,
&ndims_lat_array,
dsizes_lat_array,
NULL,
NULL,
&type_lat_array,
DONT_CARE);
/*
* Get argument # 1
*/
lon_array = (void*)NclGetArgValue(
1,
4,
&ndims_lon_array,
dsizes_lon_array,
NULL,
NULL,
&type_lon_array,
DONT_CARE);
/*
* Check dimension sizes of lat,lon arrays and calculate size of
* leftmost dimensions.
*/
if(ndims_lat_array < 2 || ndims_lon_array < 2 ||
ndims_lon_array != ndims_lat_array) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: The lat,lon arrays must have at least two dimensions and the same number of dimensions as each other");
return(NhlFATAL);
}
ny = dsizes_lat_array[ndims_lat_array-2];
nx = dsizes_lat_array[ndims_lat_array-1];
nynx = ny * nx;
/*
* Test dimension sizes.
*/
if((nx > INT_MAX) || (ny > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: nx and/or ny is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
size_leftmost = 1;
ndims_leftmost = ndims_lat_array-2;
for(i = 0; i < ndims_lon_array; i++) {
if(dsizes_lon_array[i] != dsizes_lat_array[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: The dimension sizes of the lat,lon arrays must be the same");
return(NhlFATAL);
}
if(i < ndims_leftmost) size_leftmost *= dsizes_lat_array[i];
}
/*
* Get argument # 2
*/
lat_loc = (void*)NclGetArgValue(
2,
4,
NULL,
dsizes_lat_loc,
NULL,
NULL,
&type_lat_loc,
DONT_CARE);
/*
* Get argument # 3
*/
lon_loc = (void*)NclGetArgValue(
3,
4,
NULL,
dsizes_lon_loc,
NULL,
NULL,
&type_lon_loc,
DONT_CARE);
/*
* Check dimension sizes of lat,lon locations.
*/
if(dsizes_lon_loc[0] != dsizes_lat_loc[0]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: The lat,lon locations must be the same length");
return(NhlFATAL);
}
if(dsizes_lon_loc[0] == 1) {
is_scalar_latlon_loc = 1;
}
else {
is_scalar_latlon_loc = 0;
}
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* Allocate space for tmp_lat_array.
*/
if(type_lat_array != NCL_double) {
tmp_lat_array = (double *)calloc(nynx,sizeof(double));
if(tmp_lat_array == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_lon_array.
*/
if(type_lon_array != NCL_double) {
tmp_lon_array = (double *)calloc(nynx,sizeof(double));
if(tmp_lon_array == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_lat_loc.
*/
if(type_lat_loc != NCL_double) {
tmp_lat_loc = (double *)calloc(1,sizeof(double));
if(tmp_lat_loc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_lon_loc.
*/
if(type_lon_loc != NCL_double) {
tmp_lon_loc = (double *)calloc(1,sizeof(double));
if(tmp_lon_loc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
/*
* Calculate size of output array. The output array will have dimension
* sizes equal to the leftmost dimensions of the lat,lon arrays (minus
* the last two dimensions), the length of the lat,lon locations
* (if not a scalar), and the last dimension will be 2, which holds the
* i,j location on the grid.
*/
nretlocs = size_leftmost * dsizes_lat_loc[0];
size_output = 2 * nretlocs;
/*
* Allocate space for output array.
*/
ret = (int*)calloc(size_output, sizeof(int));
if(ret == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Allocate space for output dimension sizes and set them. The last dimension
* will always be 2, in order to hold the i,j locations. Some examples:
*
* Lat,lon array are 90 x 180, lat,lon locations are scalars:
* Output will be array with 2 elements.
*
* Lat,lon array are 5 x 90 x 180, lat,lon locations are scalars:
* Output will be array of length 5 x 2.
*
* Lat,lon array are 5 x 90 x 180, lat,lon locations are length 10:
* Output will be array of length 5 x 10 x 2.
*
* Lat,lon array are 3 x 5 x 90 x 180, lat,lon locations are length 4:
* Output will be array of length 3 x 5 x 4 x 2.
*/
if(is_scalar_latlon_loc) {
ndims_ret = ndims_leftmost + 1;
}
else {
ndims_ret = ndims_leftmost + 2;
}
dsizes_ret = (ng_size_t*)calloc(ndims_ret,sizeof(ng_size_t));
if( dsizes_ret == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_latlon_to_ij: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
/*
* Fill in dimension sizes for output array. See above examples.
*/
for(i = 0; i < ndims_leftmost; i++) {
dsizes_ret[i] = dsizes_lat_array[i];
}
if(!is_scalar_latlon_loc) {
dsizes_ret[ndims_leftmost] = dsizes_lat_loc[0];
}
dsizes_ret[ndims_ret-1] = 2;
/*
* Loop across leftmost dimensions of lat,lon array, the lat,lon locations,
* and call the Fortran routine for each subsection of the input arrays.
*/
index_array = index_ret = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of lat_array (tmp_lat_array) to double if necessary.
*/
if(type_lat_array != NCL_double) {
coerce_subset_input_double(lat_array,tmp_lat_array,index_array,
type_lat_array,nynx,0,NULL,NULL);
}
else {
tmp_lat_array = &((double*)lat_array)[index_array];
}
/*
* Coerce subsection of lon_array (tmp_lon_array) to double if necessary.
*/
if(type_lon_array != NCL_double) {
coerce_subset_input_double(lon_array,tmp_lon_array,index_array,
type_lon_array,nynx,0,NULL,NULL);
}
else {
tmp_lon_array = &((double*)lon_array)[index_array];
}
/*
* Get default integer missing value.
*/
missing_ret.intval = ((NclTypeClass)nclTypeintClass)->type_class.default_mis.intval;
/*
* Loop across lat,lon locations.
*/
for(j = 0; j < dsizes_lat_loc[0]; j++) {
/*
* Coerce subsection of lat_loc (tmp_lat_loc) to double if necessary.
*/
if (type_lat_loc != NCL_double) {
coerce_subset_input_double(lat_loc,tmp_lat_loc,j,type_lat_loc,1,0,
NULL,NULL);
}
else {
tmp_lat_loc = &((double*)lat_loc)[j];
}
/*
* Coerce subsection of lon_loc (tmp_lon_loc) to double if necessary.
*/
if(type_lon_loc != NCL_double) {
coerce_subset_input_double(lon_loc,tmp_lon_loc,j,type_lon_loc,1,0,
NULL,NULL);
}
else {
tmp_lon_loc = &((double*)lon_loc)[j];
}
/*
* Call the Fortran routine. Make sure you return the i,j index
* swapped, since we are going from Fortran to C.
*/
NGCALLF(dgetijlatlong,DGETIJLATLONG)(tmp_lat_array, tmp_lon_array,
tmp_lat_loc, tmp_lon_loc,
&ret[index_ret+1],
&ret[index_ret], &inx, &iny,
&missing_ret.intval);
index_ret+=2;
}
index_array += nynx;
}
/*
* Free unneeded memory.
*/
if(type_lat_array != NCL_double) NclFree(tmp_lat_array);
if(type_lon_array != NCL_double) NclFree(tmp_lon_array);
if(type_lat_loc != NCL_double) NclFree(tmp_lat_loc);
if(type_lon_loc != NCL_double) NclFree(tmp_lon_loc);
iret = NclReturnValue(ret,ndims_ret,dsizes_ret,&missing_ret,NCL_int,0);
NclFree(dsizes_ret);
return(iret);
}
NhlErrorTypes wrf_uvmet_W( void )
{
/*
* Input variables
*/
/*
* Argument # 0
*/
void *u;
double *tmp_u = NULL;
int ndims_u;
ng_size_t dsizes_u[NCL_MAX_DIMENSIONS];
int has_missing_u;
NclBasicDataTypes type_u;
NclScalar missing_u, missing_du;
/*
* Argument # 1
*/
void *v;
double *tmp_v = NULL;
int ndims_v;
ng_size_t dsizes_v[NCL_MAX_DIMENSIONS];
int has_missing_v;
NclBasicDataTypes type_v;
NclScalar missing_v, missing_dv;
/*
* Argument # 2
*/
void *lat;
double *tmp_lat = NULL;
int ndims_lat;
ng_size_t dsizes_lat[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_lat;
/*
* Argument # 3
*/
void *lon;
double *tmp_lon = NULL;
int ndims_lon;
ng_size_t dsizes_lon[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_lon;
/*
* Argument # 4
*/
void *cenlon;
double *tmp_cenlon;
NclBasicDataTypes type_cenlon;
/*
* Argument # 5
*/
void *cone;
double *tmp_cone;
NclBasicDataTypes type_cone;
/*
* Return variable and attributes.
*/
void *uvmet;
double *tmp_uvmet, tmp_uvmet_msg;
int ndims_uvmet;
ng_size_t *dsizes_uvmet;
int has_missing;
NclScalar missing_uvmet;
NclBasicDataTypes type_uvmet;
NclObjClass type_obj_uvmet;
NclQuark *description, *units;
char *cdescription, *cunits;
NclDimRec *dim_info = NULL;
NclDimRec *dim_info_u, *dim_info_v;
/*
* Various
*/
ng_size_t nx, ny, nz, nxp1, nynxp1, nyp1, nyp1nx, nynx, twonynx;
ng_size_t index_u, index_v, index_latlon, index_uvmet_u, index_uvmet_v;
ng_size_t i, j;
ng_size_t size_leftmost, size_leftmost_uvmet, size_uvmet, size_output;
double rpd, *longca, *longcb;
int istag, ndims_leftmost;
int inx, iny, inxp1, inyp1;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
u = (void*)NclGetArgValue(
0,
6,
&ndims_u,
dsizes_u,
&missing_u,
&has_missing_u,
&type_u,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_u < 2) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: The u array must have at least 2 dimensions");
return(NhlFATAL);
}
ny = dsizes_u[ndims_u-2];
nxp1 = dsizes_u[ndims_u-1];
nynxp1 = ny * nxp1;
/*
* Get argument # 1
*/
v = (void*)NclGetArgValue(
1,
6,
&ndims_v,
dsizes_v,
&missing_v,
&has_missing_v,
&type_v,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_v != ndims_u) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: The u and v arrays must have the same number of dimensions");
return(NhlFATAL);
}
nyp1 = dsizes_v[ndims_v-2];
nx = dsizes_v[ndims_v-1];
nyp1nx = nyp1 * nx;
/*
* Test dimension sizes.
*/
if((nxp1 > INT_MAX) || (nyp1 > INT_MAX) || (nx > INT_MAX) || (ny > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inxp1 = (int) nxp1;
inyp1 = (int) nyp1;
/*
* Coerce the missing values.
*/
coerce_missing(type_u,has_missing_u,&missing_u,&missing_du,NULL);
coerce_missing(type_v,has_missing_v,&missing_v,&missing_dv,NULL);
if(has_missing_u || has_missing_v) {
has_missing = True;
/*fprintf(stderr, "\n\nfile: %s, line: %d\n", __FILE__, __LINE__);*/
/* fprintf(stderr, "\tu or v has missing.\n");*/
}
else {
has_missing = False;
}
/*
* Check whether we have staggered or unstaggered grids.
*
* If unstaggered:
* - The rightmost two dimensions of u and v must be the same.
*
* If staggered:
* - The rightmost dimension of u must be one more than the
* rightmost dimension of v.
* - The second rightmost dimension of v must be one more
* than the second rightmost dimension of u.
*/
if(nxp1 == nx && nyp1 == ny) istag = 0;
else istag = 1;
/*
* Get argument # 2
*/
lat = (void*)NclGetArgValue(
2,
6,
&ndims_lat,
dsizes_lat,
NULL,
NULL,
&type_lat,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_lat != 2 && ndims_lat != ndims_u &&
(ndims_u > 2 && ndims_lat != (ndims_u-1))) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: The lat array must either be 2D, the same dimensions as u,v, or one fewer dimensions than u,v");
return(NhlFATAL);
}
if(dsizes_lat[ndims_lat-2] != ny || dsizes_lat[ndims_lat-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: The rightmost 2 dimensions of lat must be ny x nx");
return(NhlFATAL);
}
nynx = ny * nx;
/*
* Check dimension sizes for lat. It can be:
* - 2D (ny x nx)
* - Same dimensionality as U,V (but with rightmost dimemsions ny x nx)
* - One fewer dimension than U,V, with all leftmost up to the third
* rightmost dimensions the same as U,V.
*/
if(ndims_lat > 2) {
if(ndims_lat == ndims_u) {
for(i = 0; i < ndims_u-2; i++) {
if(dsizes_lat[i] != dsizes_u[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: if u and lat have the same number of dimensions, then all but the rightmost 2 dimensions must be the same");
return(NhlFATAL);
}
}
}
else {
for(i = 0; i < ndims_u-3; i++) {
if(dsizes_lat[i] != dsizes_u[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: if lat has one fewer dimensions than u, then all but the rightmost 3 dimensions must be the same");
return(NhlFATAL);
}
}
}
}
/*
* Get argument # 3
*/
lon = (void*)NclGetArgValue(
3,
6,
&ndims_lon,
dsizes_lon,
NULL,
NULL,
&type_lon,
DONT_CARE);
/*
* Check dimension sizes for lon. This should be easier than lat,
* since we've done all the work for lat, and the lat,lon have to be
* exactly the same dimensions.
*/
if(ndims_lon != ndims_lat) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: The lat,lon arrays must have the same number of dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_lat; i++) {
if(dsizes_lat[i] != dsizes_lon[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: The lat,lon arrays must have the same dimension sizes");
return(NhlFATAL);
}
}
/*
* Get argument # 4
*/
cenlon = (void*)NclGetArgValue(
4,
6,
NULL,
NULL,
NULL,
NULL,
&type_cenlon,
DONT_CARE);
/*
* Get argument # 5
*/
cone = (void*)NclGetArgValue(
5,
6,
NULL,
NULL,
NULL,
NULL,
&type_cone,
DONT_CARE);
/*
* Calculate size of leftmost dimensions. Note that u, v can have an
* extra leftmost dimension over lat, lon, so we need to separate these
* out. The third-from-the-rightmost dimension will be called "nz".
*/
size_leftmost = 1;
if(ndims_lat > 2 && ndims_lat == (ndims_u-1)) {
nz = dsizes_u[ndims_u-3];
ndims_leftmost = ndims_u-3;
for(i = 0; i < ndims_leftmost; i++) size_leftmost *= dsizes_u[i];
}
else {
nz = 1;
ndims_leftmost = ndims_u-2;
for(i = 0; i < ndims_leftmost; i++) size_leftmost *= dsizes_u[i];
}
/*
* The output type defaults to float, unless this input array is double.
*/
type_uvmet = NCL_float;
type_obj_uvmet = nclTypefloatClass;
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* Allocate space for tmp_u.
*/
if(type_u != NCL_double) {
tmp_u = (double *)calloc(nynxp1,sizeof(double));
if(tmp_u == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_uvmet = NCL_double;
type_obj_uvmet = nclTypedoubleClass;
}
/*
* Allocate space for tmp_v.
*/
if(type_v != NCL_double) {
tmp_v = (double *)calloc(nyp1nx,sizeof(double));
if(tmp_v == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_uvmet = NCL_double;
type_obj_uvmet = nclTypedoubleClass;
}
/*
* Allocate space for tmp_lat and tmp_lon, depending on whether
* they are 2D or not.
*/
if(ndims_lat == 2) {
tmp_lat = coerce_input_double(lat,type_lat,nynx,0,NULL,NULL);
tmp_lon = coerce_input_double(lon,type_lon,nynx,0,NULL,NULL);
}
else {
/*
* Allocate space for tmp_lat
*/
if(type_lat != NCL_double) {
tmp_lat = (double *)calloc(nynx,sizeof(double));
if(tmp_lat == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_lon.
*/
if(type_lon != NCL_double) {
tmp_lon = (double *)calloc(nynx,sizeof(double));
if(tmp_lon == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
}
/*
* Allocate space for tmp_cenlon.
*/
tmp_cenlon = coerce_input_double(cenlon,type_cenlon,1,0,NULL,NULL);
if(tmp_cenlon == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
/*
* Allocate space for tmp_cone.
*/
tmp_cone = coerce_input_double(cone,type_cone,1,0,NULL,NULL);
if(tmp_cone == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
/*
* Calculate size of output array.
*/
twonynx = 2 * ny * nx;
size_leftmost_uvmet = size_leftmost * nz;
size_uvmet = size_leftmost_uvmet * nynx;
size_output = 2 * size_uvmet;
/*
* Allocate space for output array.
*/
tmp_uvmet = (double *)calloc(twonynx,sizeof(double));
if(type_uvmet != NCL_double) {
uvmet = (void *)calloc(size_output, sizeof(float));
missing_uvmet.floatval = ((NclTypeClass)nclTypefloatClass)->type_class.default_mis.floatval;
tmp_uvmet_msg = (double)missing_uvmet.floatval;
}
else {
uvmet = (void *)calloc(size_output, sizeof(double));
missing_uvmet.doubleval = ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis.doubleval;
tmp_uvmet_msg = missing_uvmet.doubleval;
}
if(uvmet == NULL || tmp_uvmet == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Allocate space for some dummy arrays.
*/
longca = (double*)calloc(nynx,sizeof(double));
longcb = (double*)calloc(nynx,sizeof(double));
if( longca == NULL || longcb == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for output arrays");
return(NhlFATAL);
}
/*
* Allocate space for output dimension sizes and set them.
*/
ndims_uvmet = ndims_u + 1;
dsizes_uvmet = (ng_size_t*)calloc(ndims_uvmet,sizeof(ng_size_t));
if( dsizes_uvmet == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
dsizes_uvmet[0] = 2;
for(i = 1; i < ndims_uvmet-2; i++) dsizes_uvmet[i] = dsizes_u[i-1];
dsizes_uvmet[ndims_uvmet-2] = ny;
dsizes_uvmet[ndims_uvmet-1] = nx;
/*
* Loop across leftmost dimensions *and* nz, and call the Fortran
* routine for each subsection of the input arrays.
*
* The input lat, lon arrays don't have the "nz" dimension,
* so they have to be taken care of outside the nz loop.
*/
index_u = index_v = index_latlon = index_uvmet_u = 0;
index_uvmet_v = size_uvmet;
rpd = 3.14159265/180.;
for(i = 0; i < size_leftmost; i++) {
if(ndims_lat > 2) {
/*
* Coerce subsection of lat (tmp_lat) to double if necessary.
*/
if(type_lat != NCL_double) {
coerce_subset_input_double(lat,tmp_lat,index_latlon,type_lat,nynx,
0,NULL,NULL);
}
else {
tmp_lat = &((double*)lat)[index_latlon];
}
/*
* Coerce subsection of lon (tmp_lon) to double if necessary.
*/
if(type_lon != NCL_double) {
coerce_subset_input_double(lon,tmp_lon,index_latlon,type_lon,nynx,
0,NULL,NULL);
}
else {
tmp_lon = &((double*)lon)[index_latlon];
}
}
for(j = 0; j < nz; j++) {
/*
* Coerce subsection of u (tmp_u) to double if necessary.
*/
if(type_u != NCL_double) {
coerce_subset_input_double(u,tmp_u,index_u,type_u,nynxp1,0,NULL,NULL);
}
else {
tmp_u = &((double*)u)[index_u];
}
/*
* Coerce subsection of v (tmp_v) to double if necessary.
*/
if(type_v != NCL_double) {
coerce_subset_input_double(v,tmp_v,index_v,type_v,nyp1nx,0,NULL,NULL);
}
else {
tmp_v = &((double*)v)[index_v];
}
/*
* Call the Fortran routine.
*/
NGCALLF(dcomputeuvmet,DCOMPUTEUVMET)(tmp_u, tmp_v, tmp_uvmet, longca,
longcb, tmp_lon, tmp_lat,
tmp_cenlon, tmp_cone, &rpd,
&inx, &iny, &inxp1, &inyp1, &istag,
&has_missing,&missing_du.doubleval,
&missing_du.doubleval,
&tmp_uvmet_msg);
/*
* Coerce output back to float if necessary.
*/
coerce_output_float_or_double(uvmet,&tmp_uvmet[0],type_uvmet,nynx,
index_uvmet_u);
coerce_output_float_or_double(uvmet,&tmp_uvmet[nynx],type_uvmet,nynx,
index_uvmet_v);
index_u += nynxp1;
index_v += nyp1nx;
index_uvmet_u += nynx;
index_uvmet_v += nynx;
}
if(ndims_lat > 2) {
index_latlon += nynx;
}
}
/*
* Free unneeded memory.
*/
if(type_u != NCL_double) NclFree(tmp_u);
if(type_v != NCL_double) NclFree(tmp_v);
if(type_lat != NCL_double) NclFree(tmp_lat);
if(type_lon != NCL_double) NclFree(tmp_lon);
if(type_cenlon != NCL_double) NclFree(tmp_cenlon);
if(type_cone != NCL_double) NclFree(tmp_cone);
NclFree(tmp_uvmet);
NclFree(longca);
NclFree(longcb);
/*
* Set up some attributes ("description" and "units") to return.
* Note that if the input arrays are anything but 2D, the units
* will be "Temperature", and "2m Temperature" otherwise.
*/
cdescription = (char *)calloc(17,sizeof(char));
strcpy(cdescription,"u,v met velocity");
cunits = (char *)calloc(4,sizeof(char));
strcpy(cunits,"m/s");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cdescription);
free(cunits);
/*
* Get dimension info of U and V to see if we have named dimensions.
* This will be used for return variable. The return value's
* dimension names will
*/
dim_info_u = get_wrf_dim_info(0,6,ndims_u,dsizes_u);
dim_info_v = get_wrf_dim_info(1,6,ndims_v,dsizes_v);
if(dim_info_u != NULL && dim_info_v != NULL) {
dim_info = malloc(sizeof(NclDimRec)*ndims_uvmet);
if(dim_info == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_uvmet: Unable to allocate memory for holding dimension information");
return(NhlFATAL);
}
for(i = 0; i < ndims_uvmet; i++ ) {
dim_info[i].dim_num = i;
dim_info[i].dim_size = dsizes_uvmet[i];
if(i != 0) dim_info[i].dim_quark = dim_info_u[i-1].dim_quark;
else dim_info[0].dim_quark = NrmStringToQuark("u_v");
}
/*
* Just the rightmost dimension is different from u's named dimensions.
*/
dim_info[ndims_uvmet-1].dim_quark = dim_info_v[ndims_v-1].dim_quark;
}
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)uvmet,
&missing_uvmet,
ndims_uvmet,
dsizes_uvmet,
TEMPORARY,
NULL,
type_obj_uvmet
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_uvmet);
NclFree(dim_info);
NclFree(dim_info_u);
NclFree(dim_info_v);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_dbz_W( void )
{
/*
* Input variables
*/
/*
* Argument # 0
*/
void *prs;
double *tmp_prs = NULL;
int ndims_prs;
ng_size_t dsizes_prs[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_prs;
/*
* Argument # 1
*/
void *tmk;
double *tmp_tmk = NULL;
int ndims_tmk;
ng_size_t dsizes_tmk[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_tmk;
/*
* Argument # 2
*/
void *qvp;
double *tmp_qvp = NULL;
int ndims_qvp;
ng_size_t dsizes_qvp[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_qvp;
/*
* Argument # 3
*/
void *qra;
double *tmp_qra = NULL;
int ndims_qra;
ng_size_t dsizes_qra[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_qra;
/*
* Argument # 4
*/
void *qsn;
double *tmp_qsn;
double *tmp1_qsn = NULL;
int is_scalar_qsn, ndims_qsn;
ng_size_t dsizes_qsn[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_qsn;
/*
* Argument # 5
*/
void *qgr;
double *tmp_qgr = NULL;
double *tmp1_qgr = NULL;
int is_scalar_qgr, ndims_qgr;
ng_size_t dsizes_qgr[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_qgr;
/*
* Argument # 6
*/
int *ivarint;
/*
* Argument # 7
*/
int *iliqskin;
/*
* Return variable
*/
void *dbz;
double *tmp_dbz = NULL;
NclBasicDataTypes type_dbz;
NclObjClass type_obj_dbz;
NclQuark *description, *units;
char *cdescription, *cunits;
/*
* Variables for returning the output array with dimension names attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData return_md, att_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Various
*/
ng_size_t btdim, sndim, wedim, nbtsnwe, index_dbz;
ng_size_t i, j, size_leftmost, size_output;
int sn0 = 0, iwedim, isndim, ibtdim;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
prs = (void*)NclGetArgValue(
0,
8,
&ndims_prs,
dsizes_prs,
NULL,
NULL,
&type_prs,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_prs < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: The prs array must have at least 3 dimensions");
return(NhlFATAL);
}
btdim = dsizes_prs[ndims_prs-3];
sndim = dsizes_prs[ndims_prs-2];
wedim = dsizes_prs[ndims_prs-1];
nbtsnwe = btdim * sndim * wedim;
/*
* Test dimension sizes.
*/
if((wedim > INT_MAX) || (sndim > INT_MAX) || (btdim > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
iwedim = (int) wedim;
isndim = (int) sndim;
ibtdim = (int) btdim;
/*
* Get argument # 1
*/
tmk = (void*)NclGetArgValue(
1,
8,
&ndims_tmk,
dsizes_tmk,
NULL,
NULL,
&type_tmk,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_tmk != ndims_prs) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: The tmk array must have the same number of dimensions as the prs array");
return(NhlFATAL);
}
/*
* Get argument # 2
*/
qvp = (void*)NclGetArgValue(
2,
8,
&ndims_qvp,
dsizes_qvp,
NULL,
NULL,
&type_qvp,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_qvp != ndims_prs) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: The qv array must have the same number of dimensions as the prs array");
return(NhlFATAL);
}
/*
* Get argument # 3
*/
qra = (void*)NclGetArgValue(
3,
8,
&ndims_qra,
dsizes_qra,
NULL,
NULL,
&type_qra,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_qra != ndims_prs) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: The qr array must have the same number of dimensions as the prs array");
return(NhlFATAL);
}
/*
* Get argument # 4
*/
qsn = (void*)NclGetArgValue(
4,
8,
&ndims_qsn,
dsizes_qsn,
NULL,
NULL,
&type_qsn,
DONT_CARE);
/*
* Check dimension sizes.
*/
is_scalar_qsn = is_scalar(ndims_qsn,dsizes_qsn);
if(!is_scalar_qsn && ndims_qsn != ndims_prs) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: qs must either be a scalar or have the same number of dimensions as the prs array");
return(NhlFATAL);
}
/*
* Get argument # 5
*/
qgr = (void*)NclGetArgValue(
5,
8,
&ndims_qgr,
dsizes_qgr,
NULL,
NULL,
&type_qgr,
DONT_CARE);
/*
* Check dimension sizes.
*/
is_scalar_qgr = is_scalar(ndims_qgr,dsizes_qgr);
if(!is_scalar_qgr && ndims_qgr != ndims_prs) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: qg must either be a scalar or have the same number of dimensions as the prs array");
return(NhlFATAL);
}
/*
* Check that the first 6 input arrays all have the same dimensionality.
*/
for(i = 0; i < ndims_prs; i++) {
if(dsizes_tmk[i] != dsizes_prs[i] || dsizes_qvp[i] != dsizes_prs[i] ||
dsizes_qra[i] != dsizes_prs[i] ||
(!is_scalar_qsn && dsizes_qsn[i] != dsizes_prs[i]) ||
(!is_scalar_qgr && dsizes_qgr[i] != dsizes_prs[i])) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: The prs, tmk, qv, qr, qs, and qg arrays must have the same dimensions (qs and qg can be scalars)");
return(NhlFATAL);
}
}
/*
* Get argument # 6
*/
ivarint = (int*)NclGetArgValue(
6,
8,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Get argument # 7
*/
iliqskin = (int*)NclGetArgValue(
7,
8,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_prs-3; i++) size_leftmost *= dsizes_prs[i];
/*
* The output type defaults to float, unless this input array is double.
*/
type_dbz = NCL_float;
type_obj_dbz = nclTypefloatClass;
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*/
/*
* Allocate space for tmp_prs.
*/
if(type_prs != NCL_double) {
tmp_prs = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_prs == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_dbz = NCL_double;
type_obj_dbz = nclTypedoubleClass;
}
/*
* Allocate space for tmp_tmk.
*/
if(type_tmk != NCL_double) {
tmp_tmk = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_tmk == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_dbz = NCL_double;
type_obj_dbz = nclTypedoubleClass;
}
/*
* Allocate space for tmp_qvp.
*/
if(type_qvp != NCL_double) {
tmp_qvp = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_qvp == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_dbz = NCL_double;
type_obj_dbz = nclTypedoubleClass;
}
/*
* Allocate space for tmp_qra no matter what, because qra might be
* changed by the Fortran routine, and we don't want those changes
* to propagate back here.
*/
tmp_qra = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_qra == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
if(type_qra == NCL_double) {
type_dbz = NCL_double;
type_obj_dbz = nclTypedoubleClass;
}
/*
* Allocate space for tmp_qsn no matter what, because qsn might be
* changed by the Fortran routine, and we don't want those changes
* to propagate back here.
*
* qsn could be a scalar. If so, we'll need to propagate it to a full
* array. We'll do this later inside the do loop where the Fortran
* routine is called.
*/
tmp_qsn = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_qsn == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
if(is_scalar_qsn) {
if(type_qsn != NCL_double) {
tmp1_qsn = coerce_input_double(qsn,type_qsn,1,0,NULL,NULL);
}
else {
tmp1_qsn = (double*)malloc(sizeof(double));
*tmp1_qsn = ((double*)qsn)[0];
}
}
if(type_qsn == NCL_double) {
type_dbz = NCL_double;
type_obj_dbz = nclTypedoubleClass;
}
/*
* Allocate space for tmp_qgr.
*
* If it is a scalar, then propagate the scalar to an array.
*/
if(is_scalar_qgr || type_qgr != NCL_double) {
tmp_qgr = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_qgr == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
if(is_scalar_qgr) {
tmp1_qgr = coerce_input_double(qgr,type_qgr,1,0,NULL,NULL);
for(i = 0; i < nbtsnwe; i++) tmp_qgr[i] = *tmp1_qgr;
}
if(type_qgr == NCL_double) {
type_dbz = NCL_double;
type_obj_dbz = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
size_output = size_leftmost * nbtsnwe;
if(type_dbz != NCL_double) {
dbz = (void *)calloc(size_output, sizeof(float));
tmp_dbz = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_dbz == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: Unable to allocate memory for temporary output array");
return(NhlFATAL);
}
}
else {
dbz = (void *)calloc(size_output, sizeof(double));
}
if(dbz == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_dbz: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* subsection of the input arrays.
*/
index_dbz = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of prs (tmp_prs) to double if necessary.
*/
if(type_prs != NCL_double) {
coerce_subset_input_double(prs,tmp_prs,index_dbz,type_prs,nbtsnwe,
0,NULL,NULL);
}
else {
tmp_prs = &((double*)prs)[index_dbz];
}
/*
* Coerce subsection of tmk (tmp_tmk) to double if necessary.
*/
if(type_tmk != NCL_double) {
coerce_subset_input_double(tmk,tmp_tmk,index_dbz,type_tmk,nbtsnwe,
0,NULL,NULL);
}
else {
tmp_tmk = &((double*)tmk)[index_dbz];
}
/*
* Coerce subsection of qvp (tmp_qvp) to double if necessary.
*/
if(type_qvp != NCL_double) {
coerce_subset_input_double(qvp,tmp_qvp,index_dbz,type_qvp,nbtsnwe,
0,NULL,NULL);
}
else {
tmp_qvp = &((double*)qvp)[index_dbz];
}
/*
* If qsn is a scalar, then propagate it to a full array.
*/
if(is_scalar_qsn) {
for(j = 0; j < nbtsnwe; j++) tmp_qsn[j] = *tmp1_qsn;
if(*tmp1_qsn == 0.) {
sn0 = 0;
}
}
else {
/*
* Force the coercion of qsn to tmp_qsn, because the original arrays may
* get changed by the Fortran routine, and we don't want those changes to
* propagate back here.
*/
coerce_subset_input_double(qsn,tmp_qsn,index_dbz,type_qsn,nbtsnwe,
0,NULL,NULL);
/*
* Check values for qsn array. If all zero, then set sn0 to 0. Otherwise
* set sn0 to 1.
*/
j = 0;
sn0 = 0;
while( (j < nbtsnwe) && !sn0) {
if(tmp_qsn[j] != 0.) sn0 = 1;
j++;
}
}
/*
* Force the coercion of qra to tmp_qra, because the original arrays may
* get changed by the Fortran routine, and we don't want those changes to
* propagate back here.
*/
coerce_subset_input_double(qra,tmp_qra,index_dbz,type_qra,nbtsnwe,
0,NULL,NULL);
/*
* Coerce subsection of qgr (tmp_qgr) to double if necessary.
*/
if(!is_scalar_qgr) {
double *tmp_qgr_save = tmp_qgr;
if(type_qgr != NCL_double) {
coerce_subset_input_double(qgr,tmp_qgr,index_dbz,type_qgr,nbtsnwe,
0,NULL,NULL);
}
else {
tmp_qgr = &((double*)qgr)[index_dbz];
}
if (tmp_qgr_save != NULL && tmp_qgr_save != tmp_qgr)
NclFree(tmp_qgr);
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_dbz == NCL_double) tmp_dbz = &((double*)dbz)[index_dbz];
/*
* Call the Fortran routine.
*/
NGCALLF(calcdbz,CALCDBZ)(tmp_dbz, tmp_prs, tmp_tmk, tmp_qvp, tmp_qra,
tmp_qsn, tmp_qgr, &iwedim, &isndim, &ibtdim,
&sn0, ivarint, iliqskin);
/*
* Coerce output back to float if necessary.
*/
if(type_dbz == NCL_float) {
coerce_output_float_only(dbz,tmp_dbz,nbtsnwe,index_dbz);
}
index_dbz += nbtsnwe;
}
/*
* Free unneeded memory.
*/
if(type_prs != NCL_double) NclFree(tmp_prs);
if(type_tmk != NCL_double) NclFree(tmp_tmk);
if(type_qvp != NCL_double) NclFree(tmp_qvp);
NclFree(tmp_qra);
NclFree(tmp_qsn);
if(type_qgr != NCL_double) NclFree(tmp_qgr);
if(type_dbz != NCL_double) NclFree(tmp_dbz);
if(is_scalar_qsn) NclFree(tmp1_qsn);
if(is_scalar_qgr && type_qgr != NCL_double) NclFree(tmp1_qgr);
/*
* Retrieve dimension names from the "tmk" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(1,8,ndims_tmk,dsizes_tmk);
/*
* Set up return value.
*/
/*
* Return value back to NCL script.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)dbz,
NULL,
ndims_tmk,
dsizes_tmk,
TEMPORARY,
NULL,
type_obj_dbz
);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(13,sizeof(char));
strcpy(cdescription,"Reflectivity");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
free(cdescription);
cunits = (char *)calloc(4,sizeof(char));
strcpy(cunits,"dBZ");
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*units = NrmStringToQuark(cunits);
free(cunits);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_pvo_W( void )
{
/*
* Input variables
*
* Argument # 0
*/
void *u;
double *tmp_u = NULL;
int ndims_u;
ng_size_t dsizes_u[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_u;
/*
* Argument # 1
*/
void *v;
double *tmp_v = NULL;
int ndims_v;
ng_size_t dsizes_v[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_v;
/*
* Argument # 2
*/
void *th;
double *tmp_th = NULL;
int ndims_th;
ng_size_t dsizes_th[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_th;
/*
* Argument # 3
*/
void *p;
double *tmp_p = NULL;
int ndims_p;
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_p;
/*
* Argument # 4
*/
void *msfu;
double *tmp_msfu = NULL;
int ndims_msfu;
ng_size_t dsizes_msfu[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_msfu;
/*
* Argument # 5
*/
void *msfv;
double *tmp_msfv = NULL;
int ndims_msfv;
ng_size_t dsizes_msfv[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_msfv;
/*
* Argument # 6
*/
void *msft;
double *tmp_msft = NULL;
int ndims_msft;
ng_size_t dsizes_msft[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_msft;
/*
* Argument # 7
*/
void *cor;
double *tmp_cor = NULL;
int ndims_cor;
ng_size_t dsizes_cor[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_cor;
/*
* Argument # 8
*/
void *dx;
double *tmp_dx = NULL;
NclBasicDataTypes type_dx;
/*
* Argument # 9
*/
void *dy;
double *tmp_dy = NULL;
NclBasicDataTypes type_dy;
/*
* Argument # 10
*/
int *opt;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Return variable
*/
void *pv;
double *tmp_pv = NULL;
int att_id;
NclBasicDataTypes type_pv;
NclObjClass type_obj_pv;
NclQuark *description, *units;
char *cdescription, *cunits;
/*
* Various
*/
ng_size_t nx, ny, nz, nxp1, nyp1;
ng_size_t nznynxp1, nznyp1nx, nznynx, nynxp1, nyp1nx, nynx;
ng_size_t i, size_pv, size_leftmost;
ng_size_t index_u, index_v, index_th, index_msfu, index_msfv, index_msft;
int inx, iny, inz, inxp1, inyp1;
/*
* Variables for returning the output array with dimension names attached.
*/
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
u = (void*)NclGetArgValue(
0,
11,
&ndims_u,
dsizes_u,
NULL,
NULL,
&type_u,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_u < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: u must have at least 3 dimensions");
return(NhlFATAL);
}
nz = dsizes_u[ndims_u-3];
ny = dsizes_u[ndims_u-2];
nxp1 = dsizes_u[ndims_u-1];
/*
* Get argument # 1
*/
v = (void*)NclGetArgValue(
1,
11,
&ndims_v,
dsizes_v,
NULL,
NULL,
&type_v,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_v != ndims_u) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: u, v, th, and p must have the same number of dimensions");
return(NhlFATAL);
}
if(dsizes_v[ndims_v-3] != nz) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The third-from-the-right dimension of v must be the same as the third-from-the-right dimension of u");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes.
*/
for(i = 0; i < ndims_u-3; i++) {
if(dsizes_u[i] != dsizes_v[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The leftmost dimensions of u and v must be the same");
return(NhlFATAL);
}
}
nyp1 = dsizes_v[ndims_v-2];
nx = dsizes_v[ndims_v-1];
/*
* Get argument # 2
*/
th = (void*)NclGetArgValue(
2,
11,
&ndims_th,
dsizes_th,
NULL,
NULL,
&type_th,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_th != ndims_u) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: u, v, th, and p must have the same number of dimensions");
return(NhlFATAL);
}
if(dsizes_th[ndims_th-3] != nz || dsizes_th[ndims_th-2] != ny ||
dsizes_th[ndims_th-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The rightmost dimensions of th must be a combination of the dimensions of u and v (see documentation)");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes.
*/
for(i = 0; i < ndims_u-3; i++) {
if(dsizes_th[i] != dsizes_u[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The leftmost dimensions of th and u must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 3
*/
p = (void*)NclGetArgValue(
3,
11,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_p != ndims_u) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: u, v, th, and p must have the same number of dimensions");
return(NhlFATAL);
}
/*
* Error checking on dimension sizes.
*/
for(i = 0; i < ndims_th; i++) {
if(dsizes_p[i] != dsizes_th[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The dimensions of p and th must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 4
*/
msfu = (void*)NclGetArgValue(
4,
11,
&ndims_msfu,
dsizes_msfu,
NULL,
NULL,
&type_msfu,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_msfu < 2) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: msfu must have at least 2 dimensions");
return(NhlFATAL);
}
if(ndims_msfu !=2 && ndims_msfu != (ndims_u-1)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: msfu must be 2D or have one fewer dimensions than u");
return(NhlFATAL);
}
if(dsizes_msfu[ndims_msfu-2] != ny || dsizes_msfu[ndims_msfu-1] != nxp1) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The rightmost 2 dimensions of msfu must be the same as the rightmost 2 dimensions of u");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes. msfu, msfv, msft, and
* cor can be 2D or nD. If they are nD, they must have same leftmost
* dimensions as other input arrays.
*/
if(ndims_msfu > 2) {
for(i = 0; i < ndims_u-3; i++) {
if(dsizes_msfu[i] != dsizes_u[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: If msfu is not 2-dimensional, then the leftmost dimensions of msfu and u must be the same");
return(NhlFATAL);
}
}
}
/*
* Get argument # 5
*/
msfv = (void*)NclGetArgValue(
5,
11,
&ndims_msfv,
dsizes_msfv,
NULL,
NULL,
&type_msfv,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_msfv != ndims_msfu) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: msfu, msfv, msft, and cor must have the same number of dimensions");
return(NhlFATAL);
}
if(dsizes_msfv[ndims_msfv-2] != nyp1 || dsizes_msfv[ndims_msfv-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The rightmost 2 dimensions of msfv must be the same as the rightmost 2 dimensions of v");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes.
*/
for(i = 0; i < ndims_msfu-2; i++) {
if(dsizes_msfv[i] != dsizes_msfu[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The leftmost dimensions of msfv and msfu must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 6
*/
msft = (void*)NclGetArgValue(
6,
11,
&ndims_msft,
dsizes_msft,
NULL,
NULL,
&type_msft,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_msft != ndims_msfu) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: msfu, msfv, msft, and cor must have the same number of dimensions");
return(NhlFATAL);
}
if(dsizes_msft[ndims_msft-2] != ny || dsizes_msft[ndims_msft-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The rightmost 2 dimensions of msft must be the same as the rightmost 2 dimensions of th");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes.
*/
for(i = 0; i < ndims_msfu-2; i++) {
if(dsizes_msft[i] != dsizes_msfu[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The leftmost dimensions of msft and msfu must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 7
*/
cor = (void*)NclGetArgValue(
7,
11,
&ndims_cor,
dsizes_cor,
NULL,
NULL,
&type_cor,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_cor != ndims_msft) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: msfu, msfv, msft, and cor must have the same number of dimensions");
return(NhlFATAL);
}
/*
* Error checking on dimension sizes.
*/
for(i = 0; i < ndims_msft; i++) {
if(dsizes_cor[i] != dsizes_msft[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: The dimensions of cor and msft must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 8
*/
dx = (void*)NclGetArgValue(
8,
11,
NULL,
NULL,
NULL,
NULL,
&type_dx,
DONT_CARE);
tmp_dx = coerce_input_double(dx,type_dx,1,0,NULL,NULL);
/*
* Get argument # 9
*/
dy = (void*)NclGetArgValue(
9,
11,
NULL,
NULL,
NULL,
NULL,
&type_dy,
DONT_CARE);
tmp_dy = coerce_input_double(dy,type_dy,1,0,NULL,NULL);
/*
* Get argument # 10
*/
opt = (int*)NclGetArgValue(
10,
11,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
nynx = ny * nx;
nznynx = nz * nynx;
nynxp1 = ny * nxp1;
nyp1nx = nyp1 * nx;
nznynxp1 = nz * nynxp1;
nznyp1nx = nz * nyp1nx;
/*
* Test dimension sizes.
*/
if((nxp1 > INT_MAX) || (nyp1 > INT_MAX) || (nz > INT_MAX) ||
(nx > INT_MAX) ||(ny > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
inxp1 = (int) nxp1;
inyp1 = (int) nyp1;
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_u-3; i++) size_leftmost *= dsizes_u[i];
size_pv = size_leftmost * nznynx;
/*
* Retrieve dimension names from the "th" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(2,11,ndims_th,dsizes_th);
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*/
/*
* Allocate space for tmp_u.
*/
if(type_u != NCL_double) {
tmp_u = (double *)calloc(nznynxp1,sizeof(double));
if(tmp_u == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for coercing u to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_v.
*/
if(type_v != NCL_double) {
tmp_v = (double *)calloc(nznyp1nx,sizeof(double));
if(tmp_v == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for coercing v to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_th.
*/
if(type_th != NCL_double) {
tmp_th = (double *)calloc(nznynx,sizeof(double));
if(tmp_th == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for coercing th to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_p.
*/
if(type_p != NCL_double) {
tmp_p = (double *)calloc(nznynx,sizeof(double));
if(tmp_p == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for coercing p to double");
return(NhlFATAL);
}
}
/*
* Allocate space for coercing msfu, msfv, and cor to double precision.
* These arrays can be 2D or nD, so take this into account. If one of
* them is 2D, then all three of them have to be 2D.
*/
if(ndims_msfu == 2) {
tmp_msfu = coerce_input_double(msfu,type_msfu,nynxp1,0,NULL,NULL);
tmp_msfv = coerce_input_double(msfv,type_msfv,nyp1nx,0,NULL,NULL);
tmp_msft = coerce_input_double(msft,type_msft,nynx,0,NULL,NULL);
tmp_cor = coerce_input_double(cor,type_cor,nynx,0,NULL,NULL);
}
else {
/*
* Allocate space for tmp_msfu.
*/
if(type_msfu != NCL_double) {
tmp_msfu = (double*)calloc(nynxp1,sizeof(double));
if(tmp_msfu == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for coercing msfu to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_msfv.
*/
if(type_msfv != NCL_double) {
tmp_msfv = (double*)calloc(nyp1nx,sizeof(double));
if(tmp_msfv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for coercing msfv to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_msft.
*/
if(type_msft != NCL_double) {
tmp_msft = (double*)calloc(nynx,sizeof(double));
if(tmp_msft == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for coercing msft to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_cor.
*/
if(type_cor != NCL_double) {
tmp_cor = (double *)calloc(nynx,sizeof(double));
if(tmp_cor == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for coercing cor to double");
return(NhlFATAL);
}
}
}
/*
* The output type defaults to float, unless any input arrays are double.
*/
if(type_u == NCL_double || type_v == NCL_double ||
type_th == NCL_double || type_p == NCL_double ||
type_msfu == NCL_double || type_msfv == NCL_double ||
type_msft == NCL_double || type_cor == NCL_double) {
type_pv = NCL_double;
type_obj_pv = nclTypedoubleClass;
}
else {
type_pv = NCL_float;
type_obj_pv = nclTypefloatClass;
}
/*
* Allocate space for output array.
*/
if(type_pv != NCL_double) {
pv = (void *)calloc(size_pv, sizeof(float));
tmp_pv = (double *)calloc(nznynx,sizeof(double));
if(pv == NULL || tmp_pv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
pv = (void *)calloc(size_pv, sizeof(double));
if(pv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_pvo: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Call the Fortran routine.
*/
index_u = index_v = index_th = index_msfu = index_msfv = index_msft = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of u (tmp_u) to double if necessary.
*/
if(type_u != NCL_double) {
coerce_subset_input_double(u,tmp_u,index_u,type_u,nznynxp1,0,NULL,NULL);
}
else {
tmp_u = &((double*)u)[index_u];
}
/*
* Coerce subsection of v (tmp_v) to double if necessary.
*/
if(type_v != NCL_double) {
coerce_subset_input_double(v,tmp_v,index_v,type_v,nznyp1nx,0,NULL,NULL);
}
else {
tmp_v = &((double*)v)[index_v];
}
/*
* Coerce subsection of th (tmp_th) to double if necessary.
*/
if(type_th != NCL_double) {
coerce_subset_input_double(th,tmp_th,index_th,type_th,nznynx,0,NULL,NULL);
}
else {
tmp_th = &((double*)th)[index_th];
}
/*
* Coerce subsection of p (tmp_p) to double if necessary.
*/
if(type_p != NCL_double) {
coerce_subset_input_double(p,tmp_p,index_th,type_p,nznynx,0,NULL,NULL);
}
else {
tmp_p = &((double*)p)[index_th];
}
/*
* msfu, msfv, msft, and cor can be 2D or nD, so account
* for that here. If they are 2D, they've already been coerced
* before the loop.
*/
if(ndims_msfu > 2) {
/*
* Coerce subsection of msfu (tmp_msfu) to double if necessary.
*/
if(type_msfu != NCL_double) {
coerce_subset_input_double(msfu,tmp_msfu,index_msfu,type_msfu,nynxp1,0,NULL,NULL);
}
else {
tmp_msfu = &((double*)msfu)[index_msfu];
}
/*
* Coerce subsection of msfv (tmp_msfv) to double if necessary.
*/
if(type_msfv != NCL_double) {
coerce_subset_input_double(msfv,tmp_msfv,index_msfv,type_msfv,nyp1nx,0,NULL,NULL);
}
else {
tmp_msfv = &((double*)msfv)[index_msfv];
}
/*
* Coerce subsection of msft (tmp_msft) to double if necessary.
*/
if(type_msft != NCL_double) {
coerce_subset_input_double(msft,tmp_msft,index_msft,type_msft,nynx,0,NULL,NULL);
}
else {
tmp_msft = &((double*)msft)[index_msft];
}
/*
* Coerce subsection of cor (tmp_cor) to double if necessary.
*/
if(type_cor != NCL_double) {
coerce_subset_input_double(cor,tmp_cor,index_msft,type_cor,nynx,0,NULL,NULL);
}
else {
tmp_cor = &((double*)cor)[index_msft];
}
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_pv == NCL_double) tmp_pv = &((double*)pv)[index_th];
NGCALLF(dcomputepv,DCOMPUTEPV)(tmp_pv, tmp_u, tmp_v, tmp_th, tmp_p,
tmp_msfu, tmp_msfv, tmp_msft, tmp_cor,
tmp_dx, tmp_dy, &inx, &iny, &inz, &inxp1, &inyp1);
if(type_pv != NCL_double) {
coerce_output_float_only(pv,tmp_pv,nznynx,index_th);
}
index_u += nznynxp1;
index_v += nznyp1nx;
index_th += nznynx;
if(ndims_msfu > 2) {
index_msfu += nynxp1;
index_msfv += nyp1nx;
index_msft += nynx;
}
}
/*
* Free unneeded memory.
*/
if(type_u != NCL_double) NclFree(tmp_u);
if(type_v != NCL_double) NclFree(tmp_v);
if(type_th != NCL_double) NclFree(tmp_th);
if(type_p != NCL_double) NclFree(tmp_p);
if(type_msfu != NCL_double) NclFree(tmp_msfu);
if(type_msfv != NCL_double) NclFree(tmp_msfv);
if(type_msft != NCL_double) NclFree(tmp_msft);
if(type_cor != NCL_double) NclFree(tmp_cor);
if(type_pv != NCL_double) NclFree(tmp_pv);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)pv,
NULL,
ndims_th,
dsizes_th,
TEMPORARY,
NULL,
type_obj_pv
);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(20,sizeof(char));
strcpy(cdescription,"Potential Vorticity");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
free(cdescription);
cunits = (char *)calloc(4,sizeof(char));
strcpy(cunits,"PVU");
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*units = NrmStringToQuark(cunits);
free(cunits);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_avo_W( void )
{
/*
* Input variables
*
* Argument # 0
*/
void *u;
double *tmp_u = NULL;
int ndims_u;
ng_size_t dsizes_u[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_u;
/*
* Argument # 1
*/
void *v;
double *tmp_v = NULL;
int ndims_v;
ng_size_t dsizes_v[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_v;
/*
* Argument # 2
*/
void *msfu;
double *tmp_msfu = NULL;
int ndims_msfu;
ng_size_t dsizes_msfu[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_msfu;
/*
* Argument # 3
*/
void *msfv;
double *tmp_msfv = NULL;
int ndims_msfv;
ng_size_t dsizes_msfv[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_msfv;
/*
* Argument # 4
*/
void *msft;
double *tmp_msft = NULL;
int ndims_msft;
ng_size_t dsizes_msft[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_msft;
/*
* Argument # 5
*/
void *cor;
double *tmp_cor = NULL;
int ndims_cor;
ng_size_t dsizes_cor[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_cor;
/*
* Argument # 6
*/
void *dx;
double *tmp_dx = NULL;
NclBasicDataTypes type_dx;
/*
* Argument # 7
*/
void *dy;
double *tmp_dy = NULL;
NclBasicDataTypes type_dy;
/*
* Argument # 8
*/
int *opt;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info, *dim_info_v;
/*
* Return variable
*/
void *av;
double *tmp_av = NULL;
int att_id;
ng_size_t *dsizes_av;
NclBasicDataTypes type_av;
NclObjClass type_obj_av;
NclQuark *description, *units;
char *cdescription, *cunits;
/*
* Various
*/
ng_size_t nx, ny, nz, nxp1, nyp1;
ng_size_t nznynxp1, nznyp1nx, nznynx, nynxp1, nyp1nx, nynx;
ng_size_t i, size_av, size_leftmost;
ng_size_t index_u, index_v, index_msfu, index_msfv, index_msft, index_av;
int inx, iny, inz, inxp1, inyp1;
/*
* Variables for returning the output array with dimension names attached.
*/
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
u = (void*)NclGetArgValue(
0,
9,
&ndims_u,
dsizes_u,
NULL,
NULL,
&type_u,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_u < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: u must have at least 3 dimensions");
return(NhlFATAL);
}
nz = dsizes_u[ndims_u-3];
ny = dsizes_u[ndims_u-2];
nxp1 = dsizes_u[ndims_u-1];
/*
* Get argument # 1
*/
v = (void*)NclGetArgValue(
1,
9,
&ndims_v,
dsizes_v,
NULL,
NULL,
&type_v,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_v != ndims_u) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: u and v must have the same number of dimensions");
return(NhlFATAL);
}
if(dsizes_v[ndims_v-3] != nz) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: The third-from-the-right dimension of v must be the same as the third-from-the-right dimension of u");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes.
*/
for(i = 0; i < ndims_u-3; i++) {
if(dsizes_u[i] != dsizes_v[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: The leftmost dimensions of u and v must be the same");
return(NhlFATAL);
}
}
nyp1 = dsizes_v[ndims_v-2];
nx = dsizes_v[ndims_v-1];
/*
* Get argument # 2
*/
msfu = (void*)NclGetArgValue(
2,
9,
&ndims_msfu,
dsizes_msfu,
NULL,
NULL,
&type_msfu,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_msfu < 2) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: msfu must have at least 2 dimensions");
return(NhlFATAL);
}
if(ndims_msfu !=2 && ndims_msfu != (ndims_u-1)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: msfu must be 2D or have one fewer dimensions than u");
return(NhlFATAL);
}
if(dsizes_msfu[ndims_msfu-2] != ny || dsizes_msfu[ndims_msfu-1] != nxp1) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: The rightmost 2 dimensions of msfu must be the same as the rightmost 2 dimensions of u");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes. msfu, msfv, msft, and
* cor can be 2D or nD. If they are nD, they must have same leftmost
* dimensions as other input arrays.
*/
if(ndims_msfu > 2) {
for(i = 0; i < ndims_u-3; i++) {
if(dsizes_msfu[i] != dsizes_u[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: If msfu is not 2-dimensional, then the leftmost dimensions of msfu and u must be the same");
return(NhlFATAL);
}
}
}
/*
* Get argument # 3
*/
msfv = (void*)NclGetArgValue(
3,
9,
&ndims_msfv,
dsizes_msfv,
NULL,
NULL,
&type_msfv,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_msfv != ndims_msfu) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: msfu, msfv, msft, and cor must have the same number of dimensions");
return(NhlFATAL);
}
if(dsizes_msfv[ndims_msfv-2] != nyp1 || dsizes_msfv[ndims_msfv-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: The rightmost 2 dimensions of msfv must be the same as the rightmost 2 dimensions of v");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes.
*/
for(i = 0; i < ndims_msfu-2; i++) {
if(dsizes_msfv[i] != dsizes_msfu[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: The leftmost dimensions of msfv and msfu must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 4
*/
msft = (void*)NclGetArgValue(
4,
9,
&ndims_msft,
dsizes_msft,
NULL,
NULL,
&type_msft,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_msft != ndims_msfu) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: msfu, msfv, msft, and cor must have the same number of dimensions");
return(NhlFATAL);
}
if(dsizes_msft[ndims_msft-2] != ny || dsizes_msft[ndims_msft-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: The rightmost 2 dimensions of msft must be the same as the rightmost 2 dimensions of th");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes.
*/
for(i = 0; i < ndims_msfu-2; i++) {
if(dsizes_msft[i] != dsizes_msfu[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: The leftmost dimensions of msft and msfu must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 5
*/
cor = (void*)NclGetArgValue(
5,
9,
&ndims_cor,
dsizes_cor,
NULL,
NULL,
&type_cor,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_cor != ndims_msft) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: msfu, msfv, msft, and cor must have the same number of dimensions");
return(NhlFATAL);
}
/*
* Error checking on dimension sizes.
*/
for(i = 0; i < ndims_msft; i++) {
if(dsizes_cor[i] != dsizes_msft[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: The dimensions of cor and msft must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 6
*/
dx = (void*)NclGetArgValue(
6,
9,
NULL,
NULL,
NULL,
NULL,
&type_dx,
DONT_CARE);
tmp_dx = coerce_input_double(dx,type_dx,1,0,NULL,NULL);
/*
* Get argument # 7
*/
dy = (void*)NclGetArgValue(
7,
9,
NULL,
NULL,
NULL,
NULL,
&type_dy,
DONT_CARE);
tmp_dy = coerce_input_double(dy,type_dy,1,0,NULL,NULL);
/*
* Get argument # 8
*/
opt = (int*)NclGetArgValue(
8,
9,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
nynx = ny * nx;
nznynx = nz * nynx;
nynxp1 = ny * nxp1;
nyp1nx = nyp1 * nx;
nznynxp1 = nz * nynxp1;
nznyp1nx = nz * nyp1nx;
/*
* Test dimension sizes.
*/
if((nxp1 > INT_MAX) || (nyp1 > INT_MAX) || (nz > INT_MAX) ||
(nx > INT_MAX) ||(ny > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
inxp1 = (int) nxp1;
inyp1 = (int) nyp1;
/*
* Calculate size of leftmost dimensions, and set
* dimension sizes for output array.
*/
dsizes_av = (ng_size_t*)calloc(ndims_u,sizeof(ng_size_t));
if( dsizes_av == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
size_leftmost = 1;
for(i = 0; i < ndims_u-3; i++) {
size_leftmost *= dsizes_u[i];
dsizes_av[i] = dsizes_u[i];
}
size_av = size_leftmost * nznynx;
dsizes_av[ndims_u-1] = nx;
dsizes_av[ndims_u-2] = ny;
dsizes_av[ndims_u-3] = nz;
/*
* Retrieve dimension names from the "u" and "v" variables, if any.
*
* U's dimension names will be used for the output, except for the
* rightmost dimension which will be replaced by V's rightmost dimension
* name.
*/
dim_info = get_wrf_dim_info(0,9,ndims_u,dsizes_u);
dim_info_v = get_wrf_dim_info(1,9,ndims_v,dsizes_v);
dim_info[ndims_u-1].dim_size = nx;
dim_info[ndims_u-2].dim_size = ny;
dim_info[ndims_u-3].dim_size = nz;
dim_info[ndims_u-1].dim_quark = dim_info_v[ndims_v-1].dim_quark;
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*/
/*
* Allocate space for tmp_u.
*/
if(type_u != NCL_double) {
tmp_u = (double *)calloc(nznynxp1,sizeof(double));
if(tmp_u == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for coercing u to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_v.
*/
if(type_v != NCL_double) {
tmp_v = (double *)calloc(nznyp1nx,sizeof(double));
if(tmp_v == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for coercing v to double");
return(NhlFATAL);
}
}
/*
* Allocate space for coercing msfu, msfv, and cor to double precision.
* These arrays can be 2D or nD, so take this into account. If one of
* them is 2D, then all three of them have to be 2D.
*/
if(ndims_msfu == 2) {
tmp_msfu = coerce_input_double(msfu,type_msfu,nynxp1,0,NULL,NULL);
tmp_msfv = coerce_input_double(msfv,type_msfv,nyp1nx,0,NULL,NULL);
tmp_msft = coerce_input_double(msft,type_msft,nynx,0,NULL,NULL);
tmp_cor = coerce_input_double(cor,type_cor,nynx,0,NULL,NULL);
}
else {
/*
* Allocate space for tmp_msfu.
*/
if(type_msfu != NCL_double) {
tmp_msfu = (double*)calloc(nynxp1,sizeof(double));
if(tmp_msfu == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for coercing msfu to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_msfv.
*/
if(type_msfv != NCL_double) {
tmp_msfv = (double*)calloc(nyp1nx,sizeof(double));
if(tmp_msfv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for coercing msfv to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_msft.
*/
if(type_msft != NCL_double) {
tmp_msft = (double*)calloc(nynx,sizeof(double));
if(tmp_msft == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for coercing msft to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_cor.
*/
if(type_cor != NCL_double) {
tmp_cor = (double *)calloc(nynx,sizeof(double));
if(tmp_cor == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for coercing cor to double");
return(NhlFATAL);
}
}
}
/*
* The output type defaults to float, unless any input arrays are double.
*/
if(type_u == NCL_double || type_v == NCL_double ||
type_msfu == NCL_double || type_msfv == NCL_double ||
type_msft == NCL_double || type_cor == NCL_double) {
type_av = NCL_double;
type_obj_av = nclTypedoubleClass;
}
else {
type_av = NCL_float;
type_obj_av = nclTypefloatClass;
}
/*
* Allocate space for output array.
*/
if(type_av != NCL_double) {
av = (void *)calloc(size_av, sizeof(float));
tmp_av = (double *)calloc(nznynx,sizeof(double));
if(av == NULL || tmp_av == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
av = (void *)calloc(size_av, sizeof(double));
if(av == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_avo: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Call the Fortran routine.
*/
index_u = index_v = index_msfu = index_msfv = index_msft = index_av = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of u (tmp_u) to double if necessary.
*/
if(type_u != NCL_double) {
coerce_subset_input_double(u,tmp_u,index_u,type_u,nznynxp1,0,NULL,NULL);
}
else {
tmp_u = &((double*)u)[index_u];
}
/*
* Coerce subsection of v (tmp_v) to double if necessary.
*/
if(type_v != NCL_double) {
coerce_subset_input_double(v,tmp_v,index_v,type_v,nznyp1nx,0,NULL,NULL);
}
else {
tmp_v = &((double*)v)[index_v];
}
/*
* msfu, msfv, msft, and cor can be 2D or nD, so account
* for that here. If they are 2D, they've already been coerced
* before the loop.
*/
if(ndims_msfu > 2) {
/*
* Coerce subsection of msfu (tmp_msfu) to double if necessary.
*/
if(type_msfu != NCL_double) {
coerce_subset_input_double(msfu,tmp_msfu,index_msfu,type_msfu,nynxp1,0,NULL,NULL);
}
else {
tmp_msfu = &((double*)msfu)[index_msfu];
}
/*
* Coerce subsection of msfv (tmp_msfv) to double if necessary.
*/
if(type_msfv != NCL_double) {
coerce_subset_input_double(msfv,tmp_msfv,index_msfv,type_msfv,nyp1nx,0,NULL,NULL);
}
else {
tmp_msfv = &((double*)msfv)[index_msfv];
}
/*
* Coerce subsection of msft (tmp_msft) to double if necessary.
*/
if(type_msft != NCL_double) {
coerce_subset_input_double(msft,tmp_msft,index_msft,type_msft,nynx,0,NULL,NULL);
}
else {
tmp_msft = &((double*)msft)[index_msft];
}
/*
* Coerce subsection of cor (tmp_cor) to double if necessary.
*/
if(type_cor != NCL_double) {
coerce_subset_input_double(cor,tmp_cor,index_msft,type_cor,nynx,0,NULL,NULL);
}
else {
tmp_cor = &((double*)cor)[index_msft];
}
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_av == NCL_double) tmp_av = &((double*)av)[index_av];
NGCALLF(dcomputeabsvort,DCOMPUTEABSVORT)(tmp_av, tmp_u, tmp_v, tmp_msfu,
tmp_msfv, tmp_msft, tmp_cor,
tmp_dx, tmp_dy, &inx, &iny, &inz,
&inxp1, &inyp1);
if(type_av != NCL_double) {
coerce_output_float_only(av,tmp_av,nznynx,index_av);
}
index_u += nznynxp1;
index_v += nznyp1nx;
index_av += nznynx;
if(ndims_msfu > 2) {
index_msfu += nynxp1;
index_msfv += nyp1nx;
index_msft += nynx;
}
}
/*
* Free unneeded memory.
*/
if(type_u != NCL_double) NclFree(tmp_u);
if(type_v != NCL_double) NclFree(tmp_v);
if(type_msfu != NCL_double) NclFree(tmp_msfu);
if(type_msfv != NCL_double) NclFree(tmp_msfv);
if(type_msft != NCL_double) NclFree(tmp_msft);
if(type_cor != NCL_double) NclFree(tmp_cor);
if(type_av != NCL_double) NclFree(tmp_av);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)av,
NULL,
ndims_u,
dsizes_av,
TEMPORARY,
NULL,
type_obj_av
);
NclFree(dsizes_av);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(19,sizeof(char));
strcpy(cdescription,"Absolute Vorticity");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
free(cdescription);
cunits = (char *)calloc(9,sizeof(char));
strcpy(cunits,"10-5 s-1");
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*units = NrmStringToQuark(cunits);
free(cunits);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
/*
* Return output grid and attributes to NCL.
*/
NclFree(dim_info);
NclFree(dim_info_v);
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_helicity_W( void )
{
/*
* Input variables
*
* Argument # 0
*/
void *u;
double *tmp_u = NULL;
int ndims_u;
ng_size_t dsizes_u[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_u;
/*
* Argument # 1
*/
void *v;
double *tmp_v = NULL;
int ndims_v;
ng_size_t dsizes_v[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_v;
/*
* Argument # 2
*/
void *z;
double *tmp_z = NULL;
int ndims_z;
ng_size_t dsizes_z[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_z;
/*
* Argument # 3
*/
void *ter;
double *tmp_ter = NULL;
int ndims_ter;
ng_size_t dsizes_ter[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_ter;
/*
* Argument # 4
*/
void *top;
double *tmp_top = NULL;
NclBasicDataTypes type_top;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Return variable
*/
void *sreh;
double *tmp_sreh = NULL;
int att_id;
NclBasicDataTypes type_sreh;
NclObjClass type_obj_sreh;
NclQuark *description, *units;
char *cdescription, *cunits;
/*
* Various
*/
ng_size_t i, miy, mjx, mkzh, mxy, mxyz;
ng_size_t size_sreh, size_leftmost, index_u, index_ter;
int imiy, imjx, imkzh;
/*
* Variables for returning the output array with dimension names attached.
*/
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
u = (void*)NclGetArgValue(
0,
5,
&ndims_u,
dsizes_u,
NULL,
NULL,
&type_u,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_u < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: u must have at least 3 dimensions");
return(NhlFATAL);
}
mkzh = dsizes_u[ndims_u-3];
mjx = dsizes_u[ndims_u-2];
miy = dsizes_u[ndims_u-1];
/*
* Get argument # 1
*/
v = (void*)NclGetArgValue(
1,
5,
&ndims_v,
dsizes_v,
NULL,
NULL,
&type_v,
DONT_CARE);
/*
* Get argument # 2
*/
z = (void*)NclGetArgValue(
2,
5,
&ndims_z,
dsizes_z,
NULL,
NULL,
&type_z,
DONT_CARE);
/*
* Error checking on dimension sizes.
*/
if(ndims_u != ndims_v || ndims_u != ndims_z) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: u, v, and z must have the same dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_u; i++) {
if(dsizes_u[i] != dsizes_v[i] || dsizes_u[i] != dsizes_z[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: u, v, and z must have the same dimensions");
return(NhlFATAL);
}
}
/*
* Get argument # 3
*/
ter = (void*)NclGetArgValue(
3,
5,
&ndims_ter,
dsizes_ter,
NULL,
NULL,
&type_ter,
DONT_CARE);
/*
* Error checking on dimensions.
*/
if(ndims_ter != (ndims_u-1)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: ter must have one fewer dimension sizes than u, v, z");
return(NhlFATAL);
}
if(dsizes_ter[ndims_ter-2] != mjx || dsizes_ter[ndims_ter-1] != miy) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: The rightmost two dimensions of ter must be the same as the rightmost two dimensions of u, v, z");
return(NhlFATAL);
}
/*
* Error checking on leftmost dimension sizes.
*/
for(i = 0; i < ndims_ter-2; i++) {
if(dsizes_ter[i] != dsizes_u[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: The leftmost dimensions of ter and u, v, z must be the same");
return(NhlFATAL);
}
}
/*
* Get argument # 4
*/
top = (void*)NclGetArgValue(
4,
5,
NULL,
NULL,
NULL,
NULL,
&type_top,
DONT_CARE);
tmp_top = coerce_input_double(top,type_top,1,0,NULL,NULL);
mxy = mjx * miy;
mxyz = mxy * mkzh;
if((miy > INT_MAX) || (mjx > INT_MAX) || (mkzh > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
imiy = (int) miy;
imjx = (int) mjx;
imkzh = (int) mkzh;
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_ter-2; i++) size_leftmost *= dsizes_ter[i];
size_sreh = size_leftmost * mxy;
/*
* Retrieve dimension names from the "ter", if any.
*
* ter's dimension names will be used for the output.
*/
dim_info = get_wrf_dim_info(3,5,ndims_ter,dsizes_ter);
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*/
/*
* Allocate space for tmp_u.
*/
if(type_u != NCL_double) {
tmp_u = (double *)calloc(mxyz,sizeof(double));
if(tmp_u == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: Unable to allocate memory for coercing u to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_v.
*/
if(type_v != NCL_double) {
tmp_v = (double *)calloc(mxyz,sizeof(double));
if(tmp_v == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: Unable to allocate memory for coercing v to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_z.
*/
if(type_z != NCL_double) {
tmp_z = (double *)calloc(mxyz,sizeof(double));
if(tmp_z == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: Unable to allocate memory for coercing z to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_ter.
*/
if(type_ter != NCL_double) {
tmp_ter = (double *)calloc(mxy,sizeof(double));
if(tmp_ter == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: Unable to allocate memory for coercing ter to double");
return(NhlFATAL);
}
}
/*
* The output type defaults to float, unless any input arrays are double.
*/
if(type_u == NCL_double || type_v == NCL_double ||
type_z == NCL_double || type_ter == NCL_double) {
type_sreh = NCL_double;
type_obj_sreh = nclTypedoubleClass;
}
else {
type_sreh = NCL_float;
type_obj_sreh = nclTypefloatClass;
}
/*
* Allocate space for output array.
*/
if(type_sreh != NCL_double) {
sreh = (void *)calloc(size_sreh, sizeof(float));
tmp_sreh = (double *)calloc(mxy,sizeof(double));
if(sreh == NULL || tmp_sreh == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
sreh = (void *)calloc(size_sreh, sizeof(double));
if(sreh == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_helicity: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Call the Fortran routine.
*/
index_u = index_ter = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of u (tmp_u) to double if necessary.
*/
if(type_u != NCL_double) {
coerce_subset_input_double(u,tmp_u,index_u,type_u,mxyz,0,NULL,NULL);
}
else {
tmp_u = &((double*)u)[index_u];
}
/*
* Coerce subsection of v (tmp_v) to double if necessary.
*/
if(type_v != NCL_double) {
coerce_subset_input_double(v,tmp_v,index_u,type_v,mxyz,0,NULL,NULL);
}
else {
tmp_v = &((double*)v)[index_u];
}
/*
* Coerce subsection of z (tmp_z) to double if necessary.
*/
if(type_z != NCL_double) {
coerce_subset_input_double(z,tmp_z,index_u,type_z,mxyz,0,NULL,NULL);
}
else {
tmp_z = &((double*)z)[index_u];
}
/*
* Coerce subsection of ter (tmp_ter) to double if necessary.
*/
if(type_ter != NCL_double) {
coerce_subset_input_double(ter,tmp_ter,index_ter,type_ter,mxy,0,NULL,NULL);
}
else {
tmp_ter = &((double*)ter)[index_ter];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_sreh == NCL_double) tmp_sreh = &((double*)sreh)[index_ter];
NGCALLF(dcalrelhl,DCALRELHL)(tmp_u, tmp_v, tmp_z, tmp_ter, tmp_top,
tmp_sreh, &imiy, &imjx, &imkzh);
if(type_sreh != NCL_double) {
coerce_output_float_only(sreh,tmp_sreh,mxy,index_ter);
}
index_u += mxyz;
index_ter += mxy;
}
/*
* Free unneeded memory.
*/
if(type_u != NCL_double) NclFree(tmp_u);
if(type_v != NCL_double) NclFree(tmp_v);
if(type_z != NCL_double) NclFree(tmp_z);
if(type_ter != NCL_double) NclFree(tmp_ter);
if(type_sreh != NCL_double) NclFree(tmp_sreh);
if(type_top != NCL_double) NclFree(tmp_top);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)sreh,
NULL,
ndims_ter,
dsizes_ter,
TEMPORARY,
NULL,
type_obj_sreh
);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(24,sizeof(char));
strcpy(cdescription,"Storm Relative Helicity");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
free(cdescription);
cunits = (char *)calloc(8,sizeof(char));
strcpy(cunits,"m-2/s-2");
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*units = NrmStringToQuark(cunits);
free(cunits);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_updraft_helicity_W( void )
{
/*
* Input variables
*/
/*
* Argument # 0
*/
void *zp;
double *tmp_zp = NULL;
int ndims_zp;
ng_size_t dsizes_zp[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_zp;
/*
* Argument # 1
*/
void *mapfct;
double *tmp_mapfct = NULL;
int ndims_mapfct;
ng_size_t dsizes_mapfct[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_mapfct;
/*
* Argument # 2
*/
void *dx;
double *tmp_dx = NULL;
NclBasicDataTypes type_dx;
/*
* Argument # 3
*/
void *dy;
double *tmp_dy = NULL;
NclBasicDataTypes type_dy;
/*
* Argument # 4
*/
void *us;
double *tmp_us = NULL;
int ndims_us;
ng_size_t dsizes_us[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_us;
/*
* Argument # 5
*/
void *vs;
double *tmp_vs = NULL;
int ndims_vs;
ng_size_t dsizes_vs[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_vs;
/*
* Argument # 6
*/
void *w;
double *tmp_w = NULL;
int ndims_w;
ng_size_t dsizes_w[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_w;
/*
* Argument # 7
*/
logical *opt;
/*
* Possible attributes.
*/
void *uhmnhgt = NULL;
void *uhmxhgt = NULL;
double *tmp_uhmnhgt, *tmp_uhmxhgt;
logical set_uhmnhgt, set_uhmxhgt;
NclBasicDataTypes type_uhmnhgt = NCL_none;
NclBasicDataTypes type_uhmxhgt = NCL_none;
/*
* Variables for retrieving attributes from "opt".
*/
NclAttList *attr_list;
NclAtt attr_obj;
NclStackEntry stack_entry;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info = NULL;
NclDimRec *dim_info_us;
/*
* Return variable
*/
void *uh;
double *tmp_uh = NULL;
int ndims_uh;
ng_size_t *dsizes_uh;
NclBasicDataTypes type_uh;
NclObjClass type_obj_uh;
int att_id;
NclQuark *description, *units;
char *cdescription, *cunits;
/*
* Various
*/
ng_size_t nx, ny, nzp1, nzp1nynx, nynx, nz, nznynx;
ng_size_t index_zp, index_uh, index_us;
double *tem1, *tem2;
ng_size_t i, ndims_leftmost, size_leftmost, size_output;
int inx, iny, inz, inzp1;
/*
* Variables for returning the output array with dimension names attached.
*/
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
zp = (void*)NclGetArgValue(
0,
8,
&ndims_zp,
dsizes_zp,
NULL,
NULL,
&type_zp,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_zp < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The zp array must have at least 3 dimensions");
return(NhlFATAL);
}
nzp1 = dsizes_zp[ndims_zp-3];
ny = dsizes_zp[ndims_zp-2];
nx = dsizes_zp[ndims_zp-1];
nynx = ny * nx;
nzp1nynx = nynx * nzp1;
/*
* Get argument # 1
*/
mapfct = (void*)NclGetArgValue(
1,
8,
&ndims_mapfct,
dsizes_mapfct,
NULL,
NULL,
&type_mapfct,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_mapfct != 2 && ndims_mapfct != (ndims_zp-1)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The mapfct array must either be two-dimensional or have one fewer dimensions than zp");
return(NhlFATAL);
}
if(dsizes_mapfct[ndims_mapfct-2] != ny ||
dsizes_mapfct[ndims_mapfct-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The rightmost dimensions of mapfct must be ny x nx");
return(NhlFATAL);
}
/*
* Get argument # 2
*/
us = (void*)NclGetArgValue(
2,
8,
&ndims_us,
dsizes_us,
NULL,
NULL,
&type_us,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_us != ndims_zp) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The us array must have the same number of dimensions as zp");
return(NhlFATAL);
}
if(dsizes_us[ndims_us-2] != ny || dsizes_us[ndims_us-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The rightmost dimensions of us must be nz x ny x ny");
return(NhlFATAL);
}
nz = dsizes_us[ndims_us-3];
nznynx = nz * nynx;
/*
* Test dimension sizes.
*/
if((nx > INT_MAX) || (ny > INT_MAX) || (nzp1 > INT_MAX) || (nz > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
inzp1 = (int) nzp1;
/*
* Get argument # 3
*/
vs = (void*)NclGetArgValue(
3,
8,
&ndims_vs,
dsizes_vs,
NULL,
NULL,
&type_vs,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_vs != ndims_us) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The vs array must have the same number of dimensions as us");
return(NhlFATAL);
}
if(dsizes_vs[ndims_vs-3] != nz || dsizes_vs[ndims_vs-2] != ny ||
dsizes_vs[ndims_vs-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The rightmost dimensions of vs must be nz x ny x ny");
return(NhlFATAL);
}
/*
* Get argument # 4
*/
w = (void*)NclGetArgValue(
4,
8,
&ndims_w,
dsizes_w,
NULL,
NULL,
&type_w,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_w != ndims_zp || (dsizes_w[ndims_w-3] != nzp1 ||
dsizes_w[ndims_w-2] != ny ||
dsizes_w[ndims_w-1] != nx)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The w array must be the same dimensionality as zp");
return(NhlFATAL);
}
/*
* Get argument # 5
*/
dx = (void*)NclGetArgValue(
5,
8,
NULL,
NULL,
NULL,
NULL,
&type_dx,
DONT_CARE);
/*
* Get argument # 6
*/
dy = (void*)NclGetArgValue(
6,
8,
NULL,
NULL,
NULL,
NULL,
&type_dy,
DONT_CARE);
/*
* Get argument # 7
*/
opt = (logical*)NclGetArgValue(
7,
8,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Start checking for attributes attached to "opt"
*/
set_uhmnhgt = set_uhmxhgt = False;
stack_entry = _NclGetArg(7, 8, DONT_CARE);
switch (stack_entry.kind) {
case NclStk_VAR:
if (stack_entry.u.data_var->var.att_id != -1) {
attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id);
if (attr_obj == NULL) {
break;
}
}
else {
/*
* att_id == -1 ==> no optional args given.
*/
break;
}
/*
* Get optional arguments.
*/
if (attr_obj->att.n_atts > 0) {
/*
* Get list of attributes.
*/
attr_list = attr_obj->att.att_list;
/*
* Loop through attributes and check them. We are looking for:
*
* uhmnhgt or uhmxhgt
*/
while (attr_list != NULL) {
if(!strcasecmp(attr_list->attname, "uhmnhgt")) {
uhmnhgt = attr_list->attvalue->multidval.val;
type_uhmnhgt = attr_list->attvalue->multidval.data_type;
set_uhmnhgt = True;
}
else if(!strcasecmp(attr_list->attname, "uhmxhgt")) {
uhmxhgt = attr_list->attvalue->multidval.val;
type_uhmxhgt = attr_list->attvalue->multidval.data_type;
set_uhmxhgt = True;
}
attr_list = attr_list->next;
}
default:
break;
}
}
if(set_uhmnhgt) {
tmp_uhmnhgt = coerce_input_double(uhmnhgt,type_uhmnhgt,1,0,NULL,NULL);
}
else {
type_uhmnhgt = NCL_double;
tmp_uhmnhgt = (double *)calloc(1,sizeof(double));
*tmp_uhmnhgt = 2000.;
}
if(set_uhmxhgt) {
tmp_uhmxhgt = coerce_input_double(uhmxhgt,type_uhmxhgt,1,0,NULL,NULL);
}
else {
type_uhmxhgt = NCL_double;
tmp_uhmxhgt = (double *)calloc(1,sizeof(double));
*tmp_uhmxhgt = 5000.;
}
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
ndims_leftmost = ndims_zp-3;
for(i = 0; i < ndims_leftmost; i++) {
if(dsizes_us[i] != dsizes_zp[i] || dsizes_vs[i] != dsizes_zp[i] ||
dsizes_w[i] != dsizes_zp[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: The leftmost dimensions of zp, us, vs, and w must be the same");
return(NhlFATAL);
}
if(ndims_mapfct > 2 && dsizes_mapfct[i] != dsizes_zp[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: mapfct must either be two-dimensional or have the same leftmost dimensions as zp");
return(NhlFATAL);
}
size_leftmost *= dsizes_zp[i];
}
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* Allocate space for tmp_zp.
*/
if(type_zp != NCL_double) {
type_uh = NCL_float;
type_obj_uh = nclTypefloatClass;
tmp_zp = (double *)calloc(nzp1nynx,sizeof(double));
if(tmp_zp == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_uh = NCL_double;
type_obj_uh = nclTypedoubleClass;
}
/*
* Allocate space for tmp_mapfct. This array can be 2D or nD. If it
* is 2D, go ahead and coerce the values now. Otherwise, create a temp
* 2D array and we'll coerce the values in the loop below along with
* everybody else.
*/
if(ndims_mapfct == 2) {
tmp_mapfct = coerce_input_double(mapfct,type_mapfct,nynx,0,NULL,NULL);
}
else {
if(type_mapfct != NCL_double) {
tmp_mapfct = (double *)calloc(nynx,sizeof(double));
if(tmp_mapfct == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
}
/*
* Allocate space for tmp_dx.
*/
tmp_dx = coerce_input_double(dx,type_dx,1,0,NULL,NULL);
if(tmp_dx == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
/*
* Allocate space for tmp_dy.
*/
tmp_dy = coerce_input_double(dy,type_dy,1,0,NULL,NULL);
if(tmp_dy == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
/*
* Allocate space for tmp_us.
*/
if(type_us != NCL_double) {
tmp_us = (double *)calloc(nznynx,sizeof(double));
if(tmp_us == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_vs.
*/
if(type_vs != NCL_double) {
tmp_vs = (double *)calloc(nznynx,sizeof(double));
if(tmp_vs == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
/*
* Allocate space for tmp_w.
*/
if(type_w != NCL_double) {
tmp_w = (double *)calloc(nzp1nynx,sizeof(double));
if(tmp_w == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
/*
* Calculate size of output array.
*/
size_output = size_leftmost * nynx;
/*
* Allocate space for output array.
*/
if(type_uh != NCL_double) {
uh = (void *)calloc(size_output, sizeof(float));
tmp_uh = (double *)calloc(nynx,sizeof(double));
if(tmp_uh == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for temporary output array");
return(NhlFATAL);
}
}
else {
uh = (void *)calloc(size_output, sizeof(double));
}
if(uh == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Allocate space for work arrays.
*/
tem1 = (void *)calloc(nznynx, sizeof(double));
tem2 = (void *)calloc(nznynx, sizeof(double));
if( tem1 == NULL || tem2 == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for work arrays");
return(NhlFATAL);
}
/*
* Allocate space for output dimension sizes and set them.
*/
ndims_uh = ndims_leftmost + 2;
dsizes_uh = (ng_size_t*)calloc(ndims_uh,sizeof(ng_size_t));
if( dsizes_uh == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
for(i = 0; i < ndims_uh-2; i++) dsizes_uh[i] = dsizes_zp[i];
dsizes_uh[ndims_uh-2] = ny;
dsizes_uh[ndims_uh-1] = nx;
/*
* Retrieve dimension names from "u", if any.
*
* u's dimension names will be used for the output.
*/
dim_info_us = get_wrf_dim_info(2,8,ndims_us,dsizes_us);
if(dim_info_us != NULL) {
dim_info = malloc(sizeof(NclDimRec)*ndims_uh);
if(dim_info == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_updraft_helicity: Unable to allocate memory for holding dimension information");
return(NhlFATAL);
}
for(i = 0; i < ndims_uh-2; i++) dim_info[i] = dim_info_us[i];
dim_info[ndims_uh-1] = dim_info_us[ndims_us-1];
dim_info[ndims_uh-2] = dim_info_us[ndims_us-2];
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* subsection of the input arrays.
*/
index_zp = index_uh = index_us = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of zp (tmp_zp) to double if necessary.
*/
if(type_zp != NCL_double) {
coerce_subset_input_double(zp,tmp_zp,index_zp,type_zp,nzp1nynx,
0,NULL,NULL);
}
else {
tmp_zp = &((double*)zp)[index_zp];
}
/*
* Coerce subsection of mapfct (tmp_mapfct) to double if necessary.
*/
if(ndims_mapfct > 2) {
if(type_mapfct != NCL_double) {
coerce_subset_input_double(mapfct,tmp_mapfct,index_uh,
type_mapfct,nynx,0,NULL,NULL);
}
else {
tmp_mapfct = &((double*)mapfct)[index_uh];
}
}
/*
* Coerce subsection of us (tmp_us) to double if necessary.
*/
if(type_us != NCL_double) {
coerce_subset_input_double(us,tmp_us,index_us,type_us,nznynx,
0,NULL,NULL);
}
else {
tmp_us = &((double*)us)[index_us];
}
/*
* Coerce subsection of vs (tmp_vs) to double if necessary.
*/
if(type_vs != NCL_double) {
coerce_subset_input_double(vs,tmp_vs,index_us,type_vs,nznynx,
0,NULL,NULL);
}
else {
tmp_vs = &((double*)vs)[index_us];
}
/*
* Coerce subsection of w (tmp_w) to double if necessary.
*/
if(type_w != NCL_double) {
coerce_subset_input_double(w,tmp_w,index_zp,type_w,nzp1nynx,0,NULL,NULL);
}
else {
tmp_w = &((double*)w)[index_zp];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_uh == NCL_double) tmp_uh = &((double*)uh)[index_uh];
/*
* Call the Fortran routine.
*/
NGCALLF(dcalcuh,DCALCUH)(&inx, &iny, &inz, &inzp1, tmp_zp, tmp_mapfct,
tmp_dx, tmp_dy, tmp_uhmnhgt, tmp_uhmxhgt,
tmp_us, tmp_vs, tmp_w, tmp_uh, tem1, tem2);
/*
* Coerce output back to float if necessary.
*/
if(type_uh == NCL_float) {
coerce_output_float_only(uh,tmp_uh,nynx,index_uh);
}
index_zp += nzp1nynx;
index_uh += nynx;
index_us += nznynx;
}
/*
* Free unneeded memory.
*/
if(type_zp != NCL_double) NclFree(tmp_zp);
if(type_mapfct != NCL_double) NclFree(tmp_mapfct);
if(type_dx != NCL_double) NclFree(tmp_dx);
if(type_dy != NCL_double) NclFree(tmp_dy);
if(type_us != NCL_double) NclFree(tmp_us);
if(type_vs != NCL_double) NclFree(tmp_vs);
if(type_w != NCL_double) NclFree(tmp_w);
if(type_uh != NCL_double) NclFree(tmp_uh);
if(type_uhmnhgt != NCL_double || ! set_uhmnhgt) NclFree(tmp_uhmnhgt);
if(type_uhmxhgt != NCL_double || ! set_uhmxhgt) NclFree(tmp_uhmxhgt);
NclFree(tem1);
NclFree(tem2);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)uh,
NULL,
ndims_uh,
dsizes_uh,
TEMPORARY,
NULL,
type_obj_uh
);
NclFree(dsizes_uh);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(17,sizeof(char));
strcpy(cdescription,"Updraft Helicity");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
free(cdescription);
cunits = (char *)calloc(8,sizeof(char));
strcpy(cunits,"m-2/s-2");
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*units = NrmStringToQuark(cunits);
free(cunits);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
NclFree(dim_info_us);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_ll_to_ij_W( void )
{
/*
* Input variables
*/
/*
* Argument # 0
*/
void *lon;
double *tmp_lon = NULL;
int ndims_lon;
ng_size_t dsizes_lon[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_lon;
/*
* Argument # 1
*/
void *lat;
double *tmp_lat = NULL;
int ndims_lat;
ng_size_t dsizes_lat[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_lat;
/*
* Argument # 2
*/
logical *opt;
/*
* Variables for retrieving attributes from "opt".
*/
NclAttList *attr_list;
NclAtt attr_obj;
NclStackEntry stack_entry;
/*
* Variables that can be set via attributes.
*/
int map_proj;
void *truelat1 = NULL;
void *truelat2 = NULL;
void *stand_lon = NULL;
void *ref_lat = NULL;
void *ref_lon = NULL;
void *pole_lat = NULL;
void *pole_lon = NULL;
void *knowni = NULL;
void *knownj = NULL;
void *dx = NULL;
void *dy = NULL;
void *latinc = NULL;
void *loninc = NULL;
double *tmp_truelat1, *tmp_truelat2, *tmp_stand_lon;
double *tmp_ref_lat, *tmp_ref_lon, *tmp_pole_lat, *tmp_pole_lon;
double *tmp_knowni, *tmp_knownj, *tmp_dx, *tmp_dy, *tmp_latinc, *tmp_loninc;
NclBasicDataTypes type_truelat1 = NCL_none;
NclBasicDataTypes type_truelat2 = NCL_none;
NclBasicDataTypes type_stand_lon = NCL_none;
NclBasicDataTypes type_ref_lat = NCL_none;
NclBasicDataTypes type_ref_lon = NCL_none;
NclBasicDataTypes type_pole_lat = NCL_none;
NclBasicDataTypes type_pole_lon = NCL_none;
NclBasicDataTypes type_knowni = NCL_none;
NclBasicDataTypes type_knownj = NCL_none;
NclBasicDataTypes type_dx = NCL_none;
NclBasicDataTypes type_dy = NCL_none;
NclBasicDataTypes type_latinc = NCL_none;
NclBasicDataTypes type_loninc = NCL_none;
logical set_map_proj, set_truelat1, set_truelat2, set_stand_lon, set_ref_lat;
logical set_ref_lon, set_pole_lat, set_pole_lon, set_knowni, set_knownj;
logical set_dx, set_dy, set_latinc, set_loninc;
/*
* Return variable
*/
void *loc;
double *tmp_loc;
int ndims_loc;
ng_size_t *dsizes_loc;
NclBasicDataTypes type_loc;
NclObjClass type_obj_loc;
/*
* Variables for returning the output array with attributes attached.
*/
NclMultiDValData return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Various
*/
int npts, i;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
lon = (void*)NclGetArgValue(
0,
3,
&ndims_lon,
dsizes_lon,
NULL,
NULL,
&type_lon,
DONT_CARE);
/*
* Get argument # 1
*/
lat = (void*)NclGetArgValue(
1,
3,
&ndims_lat,
dsizes_lat,
NULL,
NULL,
&type_lat,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_lon != ndims_lat) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: lat and lon must have the same number of dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_lat; i++) {
if(dsizes_lon[i] != dsizes_lat[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: lat and lon must have the same dimension sizes");
return(NhlFATAL);
}
}
/*
* Get argument # 2
*/
opt = (logical*)NclGetArgValue(
2,
3,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Calculate size of lat/lon dimensions.
*/
npts = 1;
for(i = 0; i < ndims_lat; i++) npts *= dsizes_lat[i];
/*
* Start checking for attributes attached to "opt". Some are optional,
* and some are not. We'll check them later.
*/
set_map_proj = set_truelat1 = set_truelat2 = set_stand_lon = False;
set_ref_lat = set_ref_lon = set_pole_lat = set_pole_lon = False;
set_knowni = set_knownj = set_dx = set_dy = set_latinc = set_loninc = False;
stack_entry = _NclGetArg(2, 3, DONT_CARE);
switch (stack_entry.kind) {
case NclStk_VAR:
if (stack_entry.u.data_var->var.att_id != -1) {
attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id);
if (attr_obj == NULL) {
break;
}
}
else {
/*
* att_id == -1 ==> no optional args given.
*/
break;
}
/*
* Get optional arguments.
*/
if (attr_obj->att.n_atts > 0) {
/*
* Get list of attributes.
*/
attr_list = attr_obj->att.att_list;
/*
* Loop through attributes and check them. We are looking for:
*
* map_proj
* truelat1, truelat2
* stand_lon
* ref_lat, ref_lon
* pole_lat, pole_lon
* knowni, knownj
* dx, dy
* latinc, loninc
*/
while (attr_list != NULL) {
if(!strcasecmp(attr_list->attname, "map_proj")) {
map_proj = *(int *)attr_list->attvalue->multidval.val;
set_map_proj = True;
}
else if(!strcasecmp(attr_list->attname, "truelat1")) {
truelat1 = attr_list->attvalue->multidval.val;
type_truelat1 = attr_list->attvalue->multidval.data_type;
set_truelat1 = True;
}
else if(!strcasecmp(attr_list->attname, "truelat2")) {
truelat2 = attr_list->attvalue->multidval.val;
type_truelat2 = attr_list->attvalue->multidval.data_type;
set_truelat2 = True;
}
else if(!strcasecmp(attr_list->attname, "stand_lon")) {
stand_lon = attr_list->attvalue->multidval.val;
type_stand_lon = attr_list->attvalue->multidval.data_type;
set_stand_lon = True;
}
else if(!strcasecmp(attr_list->attname, "ref_lat")) {
ref_lat = attr_list->attvalue->multidval.val;
type_ref_lat = attr_list->attvalue->multidval.data_type;
set_ref_lat = True;
}
else if(!strcasecmp(attr_list->attname, "ref_lon")) {
ref_lon = attr_list->attvalue->multidval.val;
type_ref_lon = attr_list->attvalue->multidval.data_type;
set_ref_lon = True;
}
else if(!strcasecmp(attr_list->attname, "pole_lat")) {
pole_lat = attr_list->attvalue->multidval.val;
type_pole_lat = attr_list->attvalue->multidval.data_type;
set_pole_lat = True;
}
else if(!strcasecmp(attr_list->attname, "pole_lon")) {
pole_lon = attr_list->attvalue->multidval.val;
type_pole_lon = attr_list->attvalue->multidval.data_type;
set_pole_lon = True;
}
else if(!strcasecmp(attr_list->attname, "knowni")) {
knowni = attr_list->attvalue->multidval.val;
type_knowni = attr_list->attvalue->multidval.data_type;
set_knowni = True;
}
else if(!strcasecmp(attr_list->attname, "knownj")) {
knownj = attr_list->attvalue->multidval.val;
type_knownj = attr_list->attvalue->multidval.data_type;
set_knownj = True;
}
else if(!strcasecmp(attr_list->attname, "dx")) {
dx = attr_list->attvalue->multidval.val;
type_dx = attr_list->attvalue->multidval.data_type;
set_dx = True;
}
else if(!strcasecmp(attr_list->attname, "dy")) {
dy = attr_list->attvalue->multidval.val;
type_dy = attr_list->attvalue->multidval.data_type;
set_dy = True;
}
else if(!strcasecmp(attr_list->attname, "latinc")) {
latinc = attr_list->attvalue->multidval.val;
type_latinc = attr_list->attvalue->multidval.data_type;
set_latinc = True;
}
else if(!strcasecmp(attr_list->attname, "loninc")) {
loninc = attr_list->attvalue->multidval.val;
type_loninc = attr_list->attvalue->multidval.data_type;
set_loninc = True;
}
attr_list = attr_list->next;
}
default:
break;
}
}
/*
* Check for attributes that need to be set, or set to a certain value.
*
* Check MAP_PROJ. Must be set.
*/
if(!set_map_proj) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The MAP_PROJ attribute must be set");
return(NhlFATAL);
}
else if(map_proj != 1 && map_proj != 2 && map_proj != 3 && map_proj != 6) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The MAP_PROJ attribute must be set to 1, 2, 3, or 6");
return(NhlFATAL);
}
/*
* Check TRUELAT1. Must be set in some cases.
*/
if( (map_proj == 1 || map_proj == 2 || map_proj == 3) && !set_truelat1) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The TRUELAT1 attribute must be set if MAP_PROJ is 1, 2, or 3");
return(NhlFATAL);
}
if(set_truelat1) {
tmp_truelat1 = coerce_input_double(truelat1,type_truelat1,1,0,NULL,NULL);
}
else {
tmp_truelat1 = (double *)calloc(1,sizeof(double));
*tmp_truelat1 = 0.;
}
/*
* Check TRUELAT2. Must be set in some cases.
*/
if( map_proj == 1 && !set_truelat2) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The TRUELAT2 attribute must be set if MAP_PROJ is 1");
return(NhlFATAL);
}
if(set_truelat2) {
tmp_truelat2 = coerce_input_double(truelat2,type_truelat2,1,0,NULL,NULL);
}
else {
tmp_truelat2 = (double *)calloc(1,sizeof(double));
*tmp_truelat2 = 0.;
}
/*
* Check STAND_LON. Must be set.
*/
if(!set_stand_lon) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The STAND_LON attribute must be set");
return(NhlFATAL);
}
else {
tmp_stand_lon = coerce_input_double(stand_lon,type_stand_lon,1,0,NULL,NULL);
}
/*
* Check REF_LAT/REF_LON. Must be set.
*/
if(!set_ref_lat || !set_ref_lon) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The REF_LAT/REF_LON attributes must be set");
return(NhlFATAL);
}
else {
tmp_ref_lat = coerce_input_double(ref_lat,type_ref_lat,1,0,NULL,NULL);
tmp_ref_lon = coerce_input_double(ref_lon,type_ref_lon,1,0,NULL,NULL);
}
/*
* Check POLE_LAT/POLE_LON.
*/
if(set_pole_lat) {
tmp_pole_lat = coerce_input_double(pole_lat,type_pole_lat,1,0,NULL,NULL);
}
else {
tmp_pole_lat = (double *)calloc(1,sizeof(double));
*tmp_pole_lat = 90.;
}
if(set_pole_lon) {
tmp_pole_lon = coerce_input_double(pole_lon,type_pole_lon,1,0,NULL,NULL);
}
else {
tmp_pole_lon = (double *)calloc(1,sizeof(double));
*tmp_pole_lon = 0.;
}
/*
* Check KNOWNI/KNOWNJ. Must be set.
*/
if(!set_knowni || !set_knownj) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The KNOWNI/KNOWNJ attributes must be set");
return(NhlFATAL);
}
else {
tmp_knowni = coerce_input_double(knowni,type_knowni,1,0,NULL,NULL);
tmp_knownj = coerce_input_double(knownj,type_knownj,1,0,NULL,NULL);
}
/*
* Check DX/DY. Must be set in some cases.
*/
if( (map_proj == 1 || map_proj == 2 || map_proj == 3) &&
(!set_dx || !set_dy)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The DX/DY attributes must be set if MAP_PROJ is 1, 2, or 3");
return(NhlFATAL);
}
if(set_dx) {
tmp_dx = coerce_input_double(dx,type_dx,1,0,NULL,NULL);
}
else {
tmp_dx = (double *)calloc(1,sizeof(double));
*tmp_dx = 0.;
}
if(set_dy) {
tmp_dy = coerce_input_double(dy,type_dy,1,0,NULL,NULL);
}
else {
tmp_dy = (double *)calloc(1,sizeof(double));
*tmp_dy = 0.;
}
/*
* Check LATINC/LONINC. Must be set in some cases.
*/
if( map_proj == 6 && (!set_latinc || !set_loninc)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: The LATINC/LONINC attributes must be set if MAP_PROJ is 6");
return(NhlFATAL);
}
if(set_latinc) {
tmp_latinc = coerce_input_double(latinc,type_latinc,1,0,NULL,NULL);
}
else {
tmp_latinc = (double *)calloc(1,sizeof(double));
*tmp_latinc = 0.;
}
if(set_loninc) {
tmp_loninc = coerce_input_double(loninc,type_loninc,1,0,NULL,NULL);
}
else {
tmp_loninc = (double *)calloc(1,sizeof(double));
*tmp_loninc = 0.;
}
/*
* The output type defaults to float, unless either of the lat/lon arrays
* are double.
*/
type_loc = NCL_float;
type_obj_loc = nclTypefloatClass;
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*/
/*
* Allocate space for tmp_lat.
*/
if(type_lat != NCL_double) {
tmp_lat = (double *)calloc(npts,sizeof(double));
if(tmp_lat == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_loc = NCL_double;
type_obj_loc = nclTypedoubleClass;
}
/*
* Allocate space for tmp_lon.
*/
if(type_lon != NCL_double) {
tmp_lon = (double *)calloc(npts,sizeof(double));
if(tmp_lon == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_loc = NCL_double;
type_obj_loc = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
tmp_loc = (double *)calloc(2,sizeof(double));
if(type_loc != NCL_double) loc = (void *)calloc(2*npts, sizeof(float));
else loc = (void *)calloc(2*npts, sizeof(double));
if(loc == NULL || tmp_loc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Allocate space for output dimension sizes and set them.
*/
if(is_scalar(ndims_lat,dsizes_lat)) {
ndims_loc = 1;
}
else {
ndims_loc = ndims_lat + 1;
}
dsizes_loc = (ng_size_t*)calloc(ndims_loc,sizeof(ng_size_t));
if( dsizes_loc == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ll_to_ij: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
for(i = 0; i < ndims_loc-1; i++) dsizes_loc[i+1] = dsizes_lat[i];
dsizes_loc[0] = 2;
/*
* Loop across all lat/lon points and call the Fortran routine for each
* point.
*/
for(i = 0; i < npts; i++) {
/*
* Coerce subsection of lat (tmp_lat) to double if necessary.
*/
if(type_lat != NCL_double) {
coerce_subset_input_double(lat,tmp_lat,i,type_lat,1,0,NULL,NULL);
}
else {
tmp_lat = &((double*)lat)[i];
}
/*
* Coerce subsection of lon (tmp_lon) to double if necessary.
*/
if(type_lon != NCL_double) {
coerce_subset_input_double(lon,tmp_lon,i,type_lon,1,0,NULL,NULL);
}
else {
tmp_lon = &((double*)lon)[i];
}
/*
* Call the Fortran routine.
*/
NGCALLF(dlltoij,DLLTOIJ)(&map_proj, tmp_truelat1, tmp_truelat2,
tmp_stand_lon, tmp_ref_lat, tmp_ref_lon,
tmp_pole_lat, tmp_pole_lon, tmp_knowni,
tmp_knownj, tmp_dx, tmp_dy, tmp_latinc,
tmp_loninc, tmp_lat, tmp_lon, tmp_loc);
/*
* Coerce output back to float or double. What's returned is in
* j,i order, so be sure to return i,j order.
*/
coerce_output_float_or_double(loc,&tmp_loc[1],type_loc,1,i);
coerce_output_float_or_double(loc,&tmp_loc[0],type_loc,1,i+npts);
}
/*
* Free unneeded memory.
*/
if(type_lat != NCL_double) NclFree(tmp_lat);
if(type_lon != NCL_double) NclFree(tmp_lon);
if(type_truelat1 != NCL_double) NclFree(tmp_truelat1);
if(type_truelat2 != NCL_double) NclFree(tmp_truelat2);
if(type_stand_lon != NCL_double) NclFree(tmp_stand_lon);
if(type_ref_lat != NCL_double) NclFree(tmp_ref_lat);
if(type_ref_lon != NCL_double) NclFree(tmp_ref_lon);
if(type_pole_lat != NCL_double) NclFree(tmp_pole_lat);
if(type_pole_lon != NCL_double) NclFree(tmp_pole_lon);
if(type_knowni != NCL_double) NclFree(tmp_knowni);
if(type_knownj != NCL_double) NclFree(tmp_knownj);
if(type_dx != NCL_double) NclFree(tmp_dx);
if(type_dy != NCL_double) NclFree(tmp_dy);
if(type_latinc != NCL_double) NclFree(tmp_latinc);
if(type_loninc != NCL_double) NclFree(tmp_loninc);
NclFree(tmp_loc);
dim_info = malloc(sizeof(NclDimRec)*ndims_loc);
if(dim_info == NULL) {
NhlPError(NhlWARNING,NhlEUNKNOWN,"wrf_ll_to_ij: Unable to allocate memory for setting dimension names");
return(NhlFATAL);
}
for(i = 0; i < ndims_loc; i++ ) {
dim_info[i].dim_num = i;
dim_info[i].dim_quark = -1;
dim_info[i].dim_size = dsizes_loc[i];
}
dim_info[0].dim_quark = NrmStringToQuark("i_j_location");
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)loc,
NULL,
ndims_loc,
dsizes_loc,
TEMPORARY,
NULL,
type_obj_loc
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
-1,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_loc);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_ij_to_ll_W( void )
{
/*
* Input variables
*/
/*
* Argument # 0
*/
void *iloc;
double *tmp_iloc = NULL;
int ndims_iloc;
ng_size_t dsizes_iloc[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_iloc;
/*
* Argument # 1
*/
void *jloc;
double *tmp_jloc = NULL;
int ndims_jloc;
ng_size_t dsizes_jloc[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_jloc;
/*
* Argument # 2
*/
logical *opt;
/*
* Variables for retrieving attributes from "opt".
*/
NclAttList *attr_list;
NclAtt attr_obj;
NclStackEntry stack_entry;
/*
* Variables that can be set via attributes.
*/
int map_proj;
void *truelat1 = NULL;
void *truelat2 = NULL;
void *stand_lon = NULL;
void *ref_lat = NULL;
void *ref_lon = NULL;
void *pole_lat = NULL;
void *pole_lon = NULL;
void *knowni = NULL;
void *knownj = NULL;
void *dx = NULL;
void *dy = NULL;
void *latinc = NULL;
void *loninc = NULL;
double *tmp_truelat1 = NULL;
double *tmp_truelat2 = NULL;
double *tmp_stand_lon = NULL;
double *tmp_ref_lat = NULL;
double *tmp_ref_lon = NULL;
double *tmp_pole_lat = NULL;
double *tmp_pole_lon = NULL;
double *tmp_knowni = NULL;
double *tmp_knownj = NULL;
double *tmp_dx = NULL;
double *tmp_dy = NULL;
double *tmp_latinc = NULL;
double *tmp_loninc = NULL;
NclBasicDataTypes type_truelat1 = NCL_none;
NclBasicDataTypes type_truelat2 = NCL_none;
NclBasicDataTypes type_stand_lon = NCL_none;
NclBasicDataTypes type_ref_lat = NCL_none;
NclBasicDataTypes type_ref_lon = NCL_none;
NclBasicDataTypes type_pole_lat = NCL_none;
NclBasicDataTypes type_pole_lon = NCL_none;
NclBasicDataTypes type_knowni = NCL_none;
NclBasicDataTypes type_knownj = NCL_none;
NclBasicDataTypes type_dx = NCL_none;
NclBasicDataTypes type_dy = NCL_none;
NclBasicDataTypes type_latinc = NCL_none;
NclBasicDataTypes type_loninc = NCL_none;
logical set_map_proj, set_truelat1, set_truelat2, set_stand_lon, set_ref_lat;
logical set_ref_lon, set_pole_lat, set_pole_lon, set_knowni, set_knownj;
logical set_dx, set_dy, set_latinc, set_loninc;
/*
* Return variable
*/
void *loc;
double *tmp_loc;
int ndims_loc;
ng_size_t *dsizes_loc;
NclBasicDataTypes type_loc;
NclObjClass type_obj_loc;
/*
* Variables for returning the output array with attributes attached.
*/
NclMultiDValData return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Various
*/
int npts, i;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
iloc = (void*)NclGetArgValue(
0,
3,
&ndims_iloc,
dsizes_iloc,
NULL,
NULL,
&type_iloc,
DONT_CARE);
/*
* Get argument # 1
*/
jloc = (void*)NclGetArgValue(
1,
3,
&ndims_jloc,
dsizes_jloc,
NULL,
NULL,
&type_jloc,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_jloc != ndims_iloc) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: lat and lon must have the same number of dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_iloc; i++) {
if(dsizes_jloc[i] != dsizes_iloc[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: lat and lon must have the same dimensionality");
return(NhlFATAL);
}
}
/*
* Get argument # 2
*/
opt = (logical*)NclGetArgValue(
2,
3,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Calculate size of i/j dimensions.
*/
npts = 1;
for(i = 0; i < ndims_iloc; i++) npts *= dsizes_iloc[i];
/*
* Start checking for attributes attached to "opt". Some are optional,
* and some are not. We'll check them later.
*/
set_map_proj = set_truelat1 = set_truelat2 = set_stand_lon = False;
set_ref_lat = set_ref_lon = set_pole_lat = set_pole_lon = False;
set_knowni = set_knownj = set_dx = set_dy = set_latinc = set_loninc = False;
stack_entry = _NclGetArg(2, 3, DONT_CARE);
switch (stack_entry.kind) {
case NclStk_VAR:
if (stack_entry.u.data_var->var.att_id != -1) {
attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id);
if (attr_obj == NULL) {
break;
}
}
else {
/*
* att_id == -1 ==> no optional args given.
*/
break;
}
/*
* Get optional arguments.
*/
if (attr_obj->att.n_atts > 0) {
/*
* Get list of attributes.
*/
attr_list = attr_obj->att.att_list;
/*
* Loop through attributes and check them. We are looking for:
*
* map_proj
* truelat1, truelat2
* stand_lon
* ref_lat, ref_lon
* pole_lat, pole_lon
* knowni, knownj
* dx, dy
* latinc, loninc
*/
while (attr_list != NULL) {
if(!strcasecmp(attr_list->attname, "map_proj")) {
map_proj = *(int *)attr_list->attvalue->multidval.val;
set_map_proj = True;
}
else if(!strcasecmp(attr_list->attname, "truelat1")) {
truelat1 = attr_list->attvalue->multidval.val;
type_truelat1 = attr_list->attvalue->multidval.data_type;
set_truelat1 = True;
}
else if(!strcasecmp(attr_list->attname, "truelat2")) {
truelat2 = attr_list->attvalue->multidval.val;
type_truelat2 = attr_list->attvalue->multidval.data_type;
set_truelat2 = True;
}
else if(!strcasecmp(attr_list->attname, "stand_lon")) {
stand_lon = attr_list->attvalue->multidval.val;
type_stand_lon = attr_list->attvalue->multidval.data_type;
set_stand_lon = True;
}
else if(!strcasecmp(attr_list->attname, "ref_lat")) {
ref_lat = attr_list->attvalue->multidval.val;
type_ref_lat = attr_list->attvalue->multidval.data_type;
set_ref_lat = True;
}
else if(!strcasecmp(attr_list->attname, "ref_lon")) {
ref_lon = attr_list->attvalue->multidval.val;
type_ref_lon = attr_list->attvalue->multidval.data_type;
set_ref_lon = True;
}
else if(!strcasecmp(attr_list->attname, "pole_lat")) {
pole_lat = attr_list->attvalue->multidval.val;
type_pole_lat = attr_list->attvalue->multidval.data_type;
set_pole_lat = True;
}
else if(!strcasecmp(attr_list->attname, "pole_lon")) {
pole_lon = attr_list->attvalue->multidval.val;
type_pole_lon = attr_list->attvalue->multidval.data_type;
set_pole_lon = True;
}
else if(!strcasecmp(attr_list->attname, "knowni")) {
knowni = attr_list->attvalue->multidval.val;
type_knowni = attr_list->attvalue->multidval.data_type;
set_knowni = True;
}
else if(!strcasecmp(attr_list->attname, "knownj")) {
knownj = attr_list->attvalue->multidval.val;
type_knownj = attr_list->attvalue->multidval.data_type;
set_knownj = True;
}
else if(!strcasecmp(attr_list->attname, "dx")) {
dx = attr_list->attvalue->multidval.val;
type_dx = attr_list->attvalue->multidval.data_type;
set_dx = True;
}
else if(!strcasecmp(attr_list->attname, "dy")) {
dy = attr_list->attvalue->multidval.val;
type_dy = attr_list->attvalue->multidval.data_type;
set_dy = True;
}
else if(!strcasecmp(attr_list->attname, "latinc")) {
latinc = attr_list->attvalue->multidval.val;
type_latinc = attr_list->attvalue->multidval.data_type;
set_latinc = True;
}
else if(!strcasecmp(attr_list->attname, "loninc")) {
loninc = attr_list->attvalue->multidval.val;
type_loninc = attr_list->attvalue->multidval.data_type;
set_loninc = True;
}
attr_list = attr_list->next;
}
default:
break;
}
}
/*
* Check for attributes that need to be set, or set to a certain value.
*
* Check MAP_PROJ. Must be set.
*/
if(!set_map_proj) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The MAP_PROJ attribute must be set");
return(NhlFATAL);
}
else if(map_proj != 1 && map_proj != 2 && map_proj != 3 && map_proj != 6) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The MAP_PROJ attribute must be set to 1, 2, 3, or 6");
return(NhlFATAL);
}
/*
* Check TRUELAT1. Must be set in some cases.
*/
if( (map_proj == 1 || map_proj == 2 || map_proj == 3) && !set_truelat1) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The TRUELAT1 attribute must be set if MAP_PROJ is 1, 2, or 3");
return(NhlFATAL);
}
if(set_truelat1) {
tmp_truelat1 = coerce_input_double(truelat1,type_truelat1,1,0,NULL,NULL);
}
else {
tmp_truelat1 = (double *)calloc(1,sizeof(double));
*tmp_truelat1 = 0.;
}
/*
* Check TRUELAT2. Must be set in some cases.
*/
if( map_proj == 1 && !set_truelat2) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The TRUELAT2 attribute must be set if MAP_PROJ is 1");
return(NhlFATAL);
}
if(set_truelat2) {
tmp_truelat2 = coerce_input_double(truelat2,type_truelat2,1,0,NULL,NULL);
}
else {
tmp_truelat2 = (double *)calloc(1,sizeof(double));
*tmp_truelat2 = 0.;
}
/*
* Check STAND_LON. Must be set.
*/
if(!set_stand_lon) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The STAND_LON attribute must be set");
return(NhlFATAL);
}
else {
tmp_stand_lon = coerce_input_double(stand_lon,type_stand_lon,1,0,NULL,NULL);
}
/*
* Check REF_LAT/REF_LON. Must be set.
*/
if(!set_ref_lat || !set_ref_lon) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The REF_LAT/REF_LON attributes must be set");
return(NhlFATAL);
}
else {
tmp_ref_lat = coerce_input_double(ref_lat,type_ref_lat,1,0,NULL,NULL);
tmp_ref_lon = coerce_input_double(ref_lon,type_ref_lon,1,0,NULL,NULL);
}
/*
* Check POLE_LAT/POLE_LON.
*/
if(set_pole_lat) {
tmp_pole_lat = coerce_input_double(pole_lat,type_pole_lat,1,0,NULL,NULL);
}
else {
tmp_pole_lat = (double *)calloc(1,sizeof(double));
*tmp_pole_lat = 90.;
}
if(set_pole_lon) {
tmp_pole_lon = coerce_input_double(pole_lon,type_pole_lon,1,0,NULL,NULL);
}
else {
tmp_pole_lon = (double *)calloc(1,sizeof(double));
*tmp_pole_lon = 0.;
}
/*
* Check KNOWNI/KNOWNJ. Must be set.
*/
if(!set_knowni || !set_knownj) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The KNOWNI/KNOWNJ attributes must be set");
return(NhlFATAL);
}
else {
tmp_knowni = coerce_input_double(knowni,type_knowni,1,0,NULL,NULL);
tmp_knownj = coerce_input_double(knownj,type_knownj,1,0,NULL,NULL);
}
/*
* Check DX/DY. Must be set in some cases.
*/
if( (map_proj == 1 || map_proj == 2 || map_proj == 3) &&
(!set_dx || !set_dy)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The DX/DY attributes must be set if MAP_PROJ is 1, 2, or 3");
return(NhlFATAL);
}
if(set_dx) {
tmp_dx = coerce_input_double(dx,type_dx,1,0,NULL,NULL);
}
else {
tmp_dx = (double *)calloc(1,sizeof(double));
*tmp_dx = 0.;
}
if(set_dy) {
tmp_dy = coerce_input_double(dy,type_dy,1,0,NULL,NULL);
}
else {
tmp_dy = (double *)calloc(1,sizeof(double));
*tmp_dy = 0.;
}
/*
* Check LATINC/LONINC. Must be set in some cases.
*/
if( map_proj == 6 && (!set_latinc || !set_loninc)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: The LATINC/LONINC attributes must be set if MAP_PROJ is 6");
return(NhlFATAL);
}
if(set_latinc) {
tmp_latinc = coerce_input_double(latinc,type_latinc,1,0,NULL,NULL);
}
else {
tmp_latinc = (double *)calloc(1,sizeof(double));
*tmp_latinc = 0.;
}
if(set_loninc) {
tmp_loninc = coerce_input_double(loninc,type_loninc,1,0,NULL,NULL);
}
else {
tmp_loninc = (double *)calloc(1,sizeof(double));
*tmp_loninc = 0.;
}
/*
* The output type defaults to float, unless either of the lat/lon arrays
* are double.
*/
type_loc = NCL_float;
type_obj_loc = nclTypefloatClass;
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*/
/*
* Allocate space for tmp_iloc.
*/
if(type_iloc != NCL_double) {
tmp_iloc = (double *)calloc(npts,sizeof(double));
if(tmp_iloc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_loc = NCL_double;
type_obj_loc = nclTypedoubleClass;
}
/*
* Allocate space for tmp_jloc.
*/
if(type_jloc != NCL_double) {
tmp_jloc = (double *)calloc(npts,sizeof(double));
if(tmp_jloc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_loc = NCL_double;
type_obj_loc = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
tmp_loc = (double *)calloc(2,sizeof(double));
if(type_loc != NCL_double) loc = (void *)calloc(2*npts, sizeof(float));
else loc = (void *)calloc(2*npts, sizeof(double));
if(loc == NULL || tmp_loc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Allocate space for output dimension sizes and set them.
*/
if(is_scalar(ndims_iloc,dsizes_iloc)) {
ndims_loc = 1;
}
else {
ndims_loc = ndims_iloc + 1;
}
dsizes_loc = (ng_size_t*)calloc(ndims_loc,sizeof(ng_size_t));
if( dsizes_loc == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ij_to_ll: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
for(i = 0; i < ndims_loc-1; i++) dsizes_loc[i+1] = dsizes_iloc[i];
dsizes_loc[0] = 2;
/*
* Loop across all lat/lon points and call the Fortran routine for each
* point.
*/
for(i = 0; i < npts; i++) {
/*
* Coerce subsection of iloc (tmp_iloc) to double if necessary.
*/
if(type_iloc != NCL_double) {
coerce_subset_input_double(iloc,tmp_iloc,i,type_iloc,1,0,NULL,NULL);
}
else {
tmp_iloc = &((double*)iloc)[i];
}
/*
* Coerce subsection of lon (tmp_jloc) to double if necessary.
*/
if(type_jloc != NCL_double) {
coerce_subset_input_double(jloc,tmp_jloc,i,type_jloc,1,0,NULL,NULL);
}
else {
tmp_jloc = &((double*)jloc)[i];
}
/*
* Call the Fortran routine.
*/
NGCALLF(dijtoll,DIJTOLL)(&map_proj, tmp_truelat1, tmp_truelat2,
tmp_stand_lon, tmp_ref_lat, tmp_ref_lon,
tmp_pole_lat, tmp_pole_lon, tmp_knowni,
tmp_knownj, tmp_dx, tmp_dy, tmp_latinc,
tmp_loninc, tmp_iloc, tmp_jloc, tmp_loc);
/*
* Coerce output back to float or double. What's returned is in
* lat,lon (j,i) order, so be sure to return lon,lat (i,j) order.
*/
coerce_output_float_or_double(loc,&tmp_loc[1],type_loc,1,i);
coerce_output_float_or_double(loc,&tmp_loc[0],type_loc,1,i+npts);
}
/*
* Free unneeded memory.
*/
if(type_iloc != NCL_double) NclFree(tmp_iloc);
if(type_jloc != NCL_double) NclFree(tmp_jloc);
if(type_truelat1 != NCL_double) NclFree(tmp_truelat1);
if(type_truelat2 != NCL_double) NclFree(tmp_truelat2);
if(type_stand_lon != NCL_double) NclFree(tmp_stand_lon);
if(type_ref_lat != NCL_double) NclFree(tmp_ref_lat);
if(type_ref_lon != NCL_double) NclFree(tmp_ref_lon);
if(type_pole_lat != NCL_double) NclFree(tmp_pole_lat);
if(type_pole_lon != NCL_double) NclFree(tmp_pole_lon);
if(type_knowni != NCL_double) NclFree(tmp_knowni);
if(type_knownj != NCL_double) NclFree(tmp_knownj);
if(type_dx != NCL_double) NclFree(tmp_dx);
if(type_dy != NCL_double) NclFree(tmp_dy);
if(type_latinc != NCL_double) NclFree(tmp_latinc);
if(type_loninc != NCL_double) NclFree(tmp_loninc);
NclFree(tmp_loc);
dim_info = malloc(sizeof(NclDimRec)*ndims_loc);
if(dim_info == NULL) {
NhlPError(NhlWARNING,NhlEUNKNOWN,"wrf_ij_to_ll: Unable to allocate memory for setting dimension names");
return(NhlFATAL);
}
for(i = 0; i < ndims_loc; i++ ) {
dim_info[i].dim_num = i;
dim_info[i].dim_quark = -1;
dim_info[i].dim_size = dsizes_loc[i];
}
dim_info[0].dim_quark = NrmStringToQuark("lon_lat_location");
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)loc,
NULL,
ndims_loc,
dsizes_loc,
TEMPORARY,
NULL,
type_obj_loc
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
-1,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_loc);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
/*
* Function for calculating cape (from the RIP code). This function
* depends on the "psadilookup.dat" file, which by default will be
* searched for in $NCARG_ROOT/lib/ncarg/data/asc/), unless
* NCARG_PSADILOOKUP is set to the location of this file.
*/
/*
* The wrf_cape_3d wrapper is for the case where I3DFLAG is set to
* 1 in the Fortran rip_cape.f file. This wrapper is similar to
* rip_cape_3d except it will flip the first four input arrays if
* the pressure values are not decreasing. It will also multiple the
* pressure values by 0.01 to convert from hPa to Pa.
*
*/
NhlErrorTypes wrf_cape_3d_W( void )
{
/*
* Input array variables
*/
void *p, *t, *q, *z, *zsfc, *psfc;
logical *ter_follow;
double *tmp_p = NULL;
double *tmp_t = NULL;
double *tmp_q = NULL;
double *tmp_z = NULL;
double *tmp_zsfc = NULL;
double *tmp_psfc = NULL;
double *tmp_p_orig = NULL;
double *tmp_t_orig = NULL;
double *tmp_q_orig = NULL;
double *tmp_z_orig = NULL;
int ndims_p, ndims_t, ndims_q, ndims_z, ndims_zsfc, ndims_psfc;
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_t[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_q[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_z[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_zsfc[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_psfc[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_p, type_t, type_q, type_z, type_zsfc, type_psfc;
/*
* Output array variables
*/
void *cape;
double *tmp_cape_orig, *tmp_cin_orig, cmsg;
double *tmp_cape, *tmp_cin;
NclBasicDataTypes type_cape;
NclObjClass type_obj_cape;
int ndims_cape;
NclScalar missing_cape;
ng_size_t *dsizes_cape;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info = NULL;
NclDimRec *dim_info_t;
/*
* Variables for returning the output array with attributes and/or
* dimension names attached.
*/
NclMultiDValData return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Declare various variables for random purposes.
*/
ng_size_t i;
ng_size_t miy = 0;
ng_size_t mjx = 0;
ng_size_t mkzh = 0;
ng_size_t ntime = 0;
ng_size_t nz = 0;
ng_size_t size_cape, size_output, size_zsfc;
int i3dflag=1, scalar_zsfc;
ng_size_t index_cape, index_zsfc, index_cin;
int iter;
logical flip;
int imiy, imjx, imkzh;
char *psa_file;
/*
* Retrieve parameters
*
* Note that any of the pointer parameters can be set to NULL,
* which implies you don't care about its value.
*
*/
p = (void*)NclGetArgValue(
0,
7,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
t = (void*)NclGetArgValue(
1,
7,
&ndims_t,
dsizes_t,
NULL,
NULL,
&type_t,
DONT_CARE);
q = (void*)NclGetArgValue(
2,
7,
&ndims_q,
dsizes_q,
NULL,
NULL,
&type_q,
DONT_CARE);
z = (void*)NclGetArgValue(
3,
7,
&ndims_z,
dsizes_z,
NULL,
NULL,
&type_z,
DONT_CARE);
zsfc = (void*)NclGetArgValue(
4,
7,
&ndims_zsfc,
dsizes_zsfc,
NULL,
NULL,
&type_zsfc,
DONT_CARE);
psfc = (void*)NclGetArgValue(
5,
7,
&ndims_psfc,
dsizes_psfc,
NULL,
NULL,
&type_psfc,
DONT_CARE);
ter_follow = (logical*)NclGetArgValue(
6,
7,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
if(*ter_follow) iter = 1;
else iter = 0;
/*
* Check the input dimension sizes. There are four possible cases
* for the input dimension sizes:
*
* - p,t,q,z (nz,time,lev,lat,lon) and psfc,zsfc (nz,time,lat,lon)
* - p,t,q,z (time,lev,lat,lon) and psfc,zsfc (time,lat,lon)
* - p,t,q,z (lev,lat,lon) and psfc,zsfc (lat,lon)
* - p,t,q,z (lev) and psfc,zsfc (scalars)
*/
if(ndims_p != ndims_t || ndims_p != ndims_q || ndims_p != ndims_z) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: The p, t, q, and z arrays must all have the same number of dimensions");
return(NhlFATAL);
}
if(ndims_p != 1 && ndims_p != 3 && ndims_p != 4 && ndims_p != 5) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: The p, t, q, and z arrays must be 1-, 3-, 4-, or 5-dimensional\n");
return(NhlFATAL);
}
/*
* zsfc and psfc can be scalars, if the other input arrays are 1D.
*/
scalar_zsfc = is_scalar(ndims_zsfc,dsizes_zsfc);
if((ndims_zsfc != ndims_psfc) || (scalar_zsfc && ndims_p != 1) ||
(!scalar_zsfc && ndims_zsfc != ndims_p-1)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: The zsfc and psfc arrays must have the same number of dimensions, and either be scalars or one less dimension than the other input arrays");
return(NhlFATAL);
}
/*
* Now check that the dimension sizes are equal to each other.
*/
for(i = 0; i < ndims_p; i++) {
if(dsizes_p[i] != dsizes_t[i] || dsizes_p[i] != dsizes_q[i] ||
dsizes_p[i] != dsizes_z[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: p, t, q, and z must be the same dimensionality");
return(NhlFATAL);
}
}
for(i = 0; i < ndims_psfc; i++) {
if(dsizes_psfc[i] != dsizes_zsfc[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: psfc and zsfc must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Get sizes of input arrays.
*/
if(ndims_p == 5) {
nz = dsizes_p[0]; /* nz, serves as leftmost dimension */
ntime = dsizes_p[1]; /* time, also serves as leftmost dimension */
mkzh = dsizes_p[2]; /* lev */
mjx = dsizes_p[3]; /* lat */
miy = dsizes_p[4]; /* lon */
}
else if(ndims_p == 4) {
nz = 1;
ntime = dsizes_p[0]; /* time, serves as a leftmost dimension */
mkzh = dsizes_p[1]; /* lev */
mjx = dsizes_p[2]; /* lat */
miy = dsizes_p[3]; /* lon */
}
else if(ndims_p == 3) {
nz = 1;
ntime = 1;
mkzh = dsizes_p[0]; /* lev */
mjx = dsizes_p[1]; /* lat */
miy = dsizes_p[2]; /* lon */
}
else if(ndims_p == 1) {
nz = 1;
ntime = 1;
mkzh = dsizes_p[0]; /* lev */
mjx = 1; /* lat */
miy = 1; /* lon */
}
/*
* Test input dimension sizes.
*/
if((miy > INT_MAX) || (mjx > INT_MAX) || (mkzh > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
imiy = (int) miy;
imjx = (int) mjx;
imkzh = (int) mkzh;
/*
* Check some more dimension sizes.
*/
if(ndims_p == 5) {
if(dsizes_psfc[0] != nz || dsizes_psfc[1] != ntime ||
dsizes_psfc[2] != mjx || dsizes_psfc[3] != miy) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: If p,q,t,z are 4-dimensional (time x lev x lat x lon), psfc,zsfc must be 3-dimensional (time x lat x lon)");
return(NhlFATAL);
}
}
else if(ndims_p == 4) {
if(dsizes_psfc[0] != ntime || dsizes_psfc[1] != mjx ||
dsizes_psfc[2] != miy) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: If p,q,t,z are 4-dimensional (time x lev x lat x lon), psfc,zsfc must be 3-dimensional (time x lat x lon)");
return(NhlFATAL);
}
}
else if(ndims_p == 3) {
if(dsizes_psfc[0] != mjx || dsizes_psfc[1] != miy) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: If p,q,t,z are 3-dimensional (time x lev x lat x lon), psfc,zsfc must be 2-dimensional (lat x lon)");
return(NhlFATAL);
}
}
/*
* Calculate size of output array. The output array size depends on
* the size of p,t,q,z:
*
* - p,t,q,z (nz,time,lev,lat,lon) and psfc,zsfc (nz,time,lat,lon)
* output array: (2,nz,time,lev,lat,lon)
* - p,t,q,z (time,lev,lat,lon) and psfc,zsfc (time,lat,lon)
* output array: (2,time,lev,lat,lon)
* - p,t,q,z (lev,lat,lon) and psfc,zsfc (lat,lon)
* output array: (2,lev,lat,lon)
* - p,t,q,z (lev) and psfc,zsfc (scalars)
* output array: (2,lev)
*/
ndims_cape = ndims_p+1;
dsizes_cape = (ng_size_t *)calloc(ndims_cape,sizeof(ng_size_t));
if(dsizes_cape == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for array dimensionality");
return(NhlFATAL);
}
dsizes_cape[0] = 2; /* 0 = cape, 1 = cin */
for(i = 0; i < ndims_p; i++ ) {
dsizes_cape[i+1] = dsizes_p[i];
}
size_zsfc = mjx * miy;
size_cape = mkzh * size_zsfc; /* Also size of cin array */
size_output = 2 * size_cape * ntime * nz;
/*
* Allocate space for output arrays. We are allocating space for
* tmp_cape_orig and tmp_cin_orig even if the output will be double,
* because we may also need to flip the values before we're done.
*
* The addition of missing values was added in V6.1.0.
*/
if(type_p == NCL_double || type_t == NCL_double || type_q == NCL_double ||
type_z == NCL_double) {
type_cape = NCL_double;
type_obj_cape = nclTypedoubleClass;
cape = (double *)calloc(size_output,sizeof(double));
missing_cape.doubleval = ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis.doubleval;
cmsg = missing_cape.doubleval;
}
else {
type_cape = NCL_float;
type_obj_cape = nclTypefloatClass;
cape = (float *)calloc(size_output,sizeof(float));
missing_cape.floatval = ((NclTypeClass)nclTypefloatClass)->type_class.default_mis.floatval;
cmsg = (double)missing_cape.floatval;
}
tmp_cape_orig = (double *)calloc(size_cape,sizeof(double));
tmp_cin_orig = (double *)calloc(size_cape,sizeof(double));
if(cape == NULL || tmp_cape_orig == NULL || tmp_cin_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for output arrays");
return(NhlFATAL);
}
/*
* Allocate memory for coercing input arrays to double, if necessary.
* Force a copy of variable p, because we need to multiply it by 0.01,
* and we don't want this to propagate back to the NCL script.
*/
tmp_p_orig = (double *)calloc(size_cape,sizeof(double));
if(tmp_p_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
if(type_t != NCL_double) {
tmp_t_orig = (double *)calloc(size_cape,sizeof(double));
if(tmp_t_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
if(type_q != NCL_double) {
tmp_q_orig = (double *)calloc(size_cape,sizeof(double));
if(tmp_q_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
if(type_z != NCL_double) {
tmp_z_orig = (double *)calloc(size_cape,sizeof(double));
if(tmp_z_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
if(type_zsfc != NCL_double) {
tmp_zsfc = (double *)calloc(size_zsfc,sizeof(double));
if(tmp_zsfc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
if(type_psfc != NCL_double) {
tmp_psfc = (double *)calloc(size_zsfc,sizeof(double));
if(tmp_psfc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
/*
* We need to coerce the pressure array once outside the loop to
* check if the values are in ascending order.
*
* If not, we need to flip the leftmost dimension (p = p(::-1,:,:) in
* NCL-ese), *and* flip the other 3 input arrays in the same fashion.
*/
coerce_subset_input_double(p,tmp_p_orig,0,type_p,size_cape,0,NULL,NULL);
if(tmp_p_orig[0] > tmp_p_orig[(mkzh-1)*size_zsfc] ) {
flip = True;
tmp_p = (double *)calloc(size_cape,sizeof(double));
tmp_t = (double *)calloc(size_cape,sizeof(double));
tmp_q = (double *)calloc(size_cape,sizeof(double));
tmp_z = (double *)calloc(size_cape,sizeof(double));
tmp_cape = (double *)calloc(size_cape,sizeof(double));
tmp_cin = (double *)calloc(size_cape,sizeof(double));
if(tmp_p == NULL || tmp_t == NULL || tmp_q == NULL || tmp_z == NULL ||
tmp_cape == NULL || tmp_cin == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for flipping arrays");
return(NhlFATAL);
}
}
else {
flip = False;
tmp_p = tmp_p_orig;
tmp_t = tmp_t_orig;
tmp_q = tmp_q_orig;
tmp_z = tmp_z_orig;
tmp_cape = tmp_cape_orig;
tmp_cin = tmp_cin_orig;
}
/*
* Get path to psadilookup.dat file required by this routine.
*/
psa_file = get_psa_file();
/*
* Loop through time,nz and call the Fortran routine.
*/
index_cape = index_zsfc = 0;
index_cin = ntime * nz * size_cape; /* Second half of output array */
for(i = 0; i < ntime*nz; i++) {
/*
* Coerce subset of input arrays to double if necessary.
*/
if(i > 0) {
coerce_subset_input_double(p,tmp_p_orig,index_cape,type_p,
size_cape,0,NULL,NULL);
}
/*
* Multiple pressure values by 0.01 to convert from Pa to hPa.
* The assumption is that pressure values come in as Pa.
*/
convert_to_hPa(tmp_p_orig,size_cape);
if(type_t != NCL_double) {
coerce_subset_input_double(t,tmp_t_orig,index_cape,type_t,
size_cape,0,NULL,NULL);
}
else {
/*
* Point tmp_t_orig to appropriate location in t.
*/
tmp_t_orig = &((double*)t)[index_cape];
}
if(type_q != NCL_double) {
coerce_subset_input_double(q,tmp_q_orig,index_cape,type_q,
size_cape,0,NULL,NULL);
}
else {
/*
* Point tmp_q_orig to appropriate location in q.
*/
tmp_q_orig = &((double*)q)[index_cape];
}
if(type_z != NCL_double) {
coerce_subset_input_double(z,tmp_z_orig,index_cape,type_z,
size_cape,0,NULL,NULL);
}
else {
/*
* Point tmp_z_orig to appropriate location in z.
*/
tmp_z_orig = &((double*)z)[index_cape];
}
if(type_psfc != NCL_double) {
coerce_subset_input_double(psfc,tmp_psfc,index_zsfc,type_psfc,
size_zsfc,0,NULL,NULL);
}
else {
/*
* Point tmp_psfc to appropriate location in psfc.
*/
tmp_psfc = &((double*)psfc)[index_zsfc];
}
if(type_zsfc != NCL_double) {
coerce_subset_input_double(zsfc,tmp_zsfc,index_zsfc,type_zsfc,
size_zsfc,0,NULL,NULL);
}
else {
/*
* Point tmp_zsfc to appropriate location in zsfc.
*/
tmp_zsfc = &((double*)zsfc)[index_zsfc];
}
/*
* If the pressure values need to be flipped, we also need to flip
* the z, q, and t values in the same fashion.
*/
if(flip) {
flip_it(tmp_p_orig,tmp_p,mkzh,size_zsfc);
flip_it(tmp_t_orig,tmp_t,mkzh,size_zsfc);
flip_it(tmp_q_orig,tmp_q,mkzh,size_zsfc);
flip_it(tmp_z_orig,tmp_z,mkzh,size_zsfc);
}
else {
tmp_p = tmp_p_orig;
tmp_t = tmp_t_orig;
tmp_q = tmp_q_orig;
tmp_z = tmp_z_orig;
}
/*
* Call Fortran routine.
*/
NGCALLF(dcapecalc3d,DCAPECALC3D)(tmp_p, tmp_t, tmp_q, tmp_z, tmp_zsfc,
tmp_psfc, tmp_cape_orig, tmp_cin_orig,
&cmsg,&imiy, &imjx, &imkzh, &i3dflag,
&iter,psa_file,strlen(psa_file));
/*
* If we flipped arrays before going into the Fortran routine, we need
* to flip the output values as well.
*/
if(flip) {
flip_it(tmp_cape_orig,tmp_cape,mkzh,size_zsfc);
flip_it(tmp_cin_orig,tmp_cin,mkzh,size_zsfc);
}
else {
tmp_cape = tmp_cape_orig;
tmp_cin = tmp_cin_orig;
}
/*
* If the output is to be float, then do the coercion here.
*/
coerce_output_float_or_double(cape,tmp_cape,type_cape,size_cape,index_cape);
coerce_output_float_or_double(cape,tmp_cin,type_cape,size_cape,index_cin);
/*
* Implement the pointers into the arrays.
*/
index_cape += size_cape;
index_cin += size_cape;
index_zsfc += size_zsfc;
}
/*
* Free memory.
*/
NclFree(tmp_p_orig);
NclFree(tmp_cape_orig);
NclFree(tmp_cin_orig);
if(type_t != NCL_double) NclFree(tmp_t_orig);
if(type_q != NCL_double) NclFree(tmp_q_orig);
if(type_z != NCL_double) NclFree(tmp_z_orig);
if(type_zsfc != NCL_double) NclFree(tmp_zsfc);
if(type_psfc != NCL_double) NclFree(tmp_psfc);
if(flip) {
NclFree(tmp_p);
NclFree(tmp_t);
NclFree(tmp_q);
NclFree(tmp_z);
NclFree(tmp_cape);
NclFree(tmp_cin);
}
NclFree(psa_file);
/*
* Get dimension info to see if we have named dimensions.
* This will be used for return variable.
*/
dim_info_t = get_wrf_dim_info(1,7,ndims_t,dsizes_t);
if(dim_info_t != NULL) {
dim_info = malloc(sizeof(NclDimRec)*ndims_cape);
if(dim_info == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_3d: Unable to allocate memory for holding dimension information");
return(NhlFATAL);
}
for(i = 0; i < ndims_cape; i++ ) {
dim_info[i].dim_num = i;
dim_info[i].dim_size = dsizes_cape[i];
if(i != 0) dim_info[i].dim_quark = dim_info_t[i-1].dim_quark;
else dim_info[0].dim_quark = NrmStringToQuark("cape_cin");
}
}
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)cape,
&missing_cape,
ndims_cape,
dsizes_cape,
TEMPORARY,
NULL,
type_obj_cape
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
-1,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_cape);
if(dim_info != NULL) NclFree(dim_info);
NclFree(dim_info_t);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
/*
* The wrf_cape_2d wrapper is for the case where I3DFLAG is set to
* 0 in the Fortran rip_cape.f file. In this case, 4 2D arrays
* are returned: cape, cin, lcl, and lfc, but they are all returned
* in one big array whose leftmost dimension is 4:
*
* This wrapper is similar to rip_cape_2d except it will flip the first
* four input arrays if the pressure values are not decreasing.
* It will also multiple the pressure values by 0.01 to convert
* from hPa to Pa.
*
* index 0 = cape
* index 1 = cin
* index 2 = lcl
* index 3 = lfc
*/
NhlErrorTypes wrf_cape_2d_W( void )
{
/*
* Input array variables
*/
void *p, *t, *q, *z, *zsfc, *psfc;
logical *ter_follow;
double *tmp_p = NULL;
double *tmp_t = NULL;
double *tmp_q = NULL;
double *tmp_z = NULL;
double *tmp_zsfc = NULL;
double *tmp_psfc = NULL;
double *tmp_p_orig = NULL;
double *tmp_t_orig = NULL;
double *tmp_q_orig = NULL;
double *tmp_z_orig = NULL;
int ndims_p, ndims_t, ndims_q, ndims_z, ndims_zsfc, ndims_psfc;
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_t[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_q[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_z[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_zsfc[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_psfc[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_p, type_t, type_q, type_z, type_zsfc, type_psfc;
/*
* Output array variables
*/
void *cape;
double *tmp_cape, *tmp_cin, cmsg;
NclBasicDataTypes type_cape;
NclObjClass type_obj_cape;
int ndims_cape = 0;
NclScalar missing_cape;
ng_size_t *dsizes_cape;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info = NULL;
NclDimRec *dim_info_t;
/*
* Variables for returning the output array with attributes and/or
* dimension names attached.
*/
NclMultiDValData return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Declare various variables for random purposes.
*/
ng_size_t i;
ng_size_t miy = 0;
ng_size_t mjx = 0;
ng_size_t mkzh = 0;
ng_size_t ntime = 0;
ng_size_t nz = 0;
ng_size_t size_cape, size_output, size_zsfc;
ng_size_t size_left_zsfc;
ng_size_t index_cape, index_zsfc;
ng_size_t index_output_cape, index_output_cin, index_output_lcl;
ng_size_t index_output_lfc, mkzh0_index, mkzh1_index, mkzh2_index;
int imiy, imjx, imkzh, iter, i3dflag=0;
char *psa_file;
logical flip;
/*
* Retrieve parameters
*
* Note that any of the pointer parameters can be set to NULL,
* which implies you don't care about its value.
*
*/
p = (void*)NclGetArgValue(
0,
7,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
t = (void*)NclGetArgValue(
1,
7,
&ndims_t,
dsizes_t,
NULL,
NULL,
&type_t,
DONT_CARE);
q = (void*)NclGetArgValue(
2,
7,
&ndims_q,
dsizes_q,
NULL,
NULL,
&type_q,
DONT_CARE);
z = (void*)NclGetArgValue(
3,
7,
&ndims_z,
dsizes_z,
NULL,
NULL,
&type_z,
DONT_CARE);
zsfc = (void*)NclGetArgValue(
4,
7,
&ndims_zsfc,
dsizes_zsfc,
NULL,
NULL,
&type_zsfc,
DONT_CARE);
psfc = (void*)NclGetArgValue(
5,
7,
&ndims_psfc,
dsizes_psfc,
NULL,
NULL,
&type_psfc,
DONT_CARE);
ter_follow = (logical*)NclGetArgValue(
6,
7,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
if(*ter_follow) iter = 1;
else iter = 0;
/*
* Check the input dimension sizes. There are three possible cases
* for the input dimension sizes:
*
* - p,t,q,z (nz,time,lev,lat,lon) and psfc,zsfc (nz,time,lat,lon)
* - p,t,q,z (time,lev,lat,lon) and psfc,zsfc (time,lat,lon)
* - p,t,q,z (lev,lat,lon) and psfc,zsfc (lat,lon)
*/
if(ndims_p != ndims_t || ndims_p != ndims_q || ndims_p != ndims_z) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: The p, t, q, and z arrays must all have the same number of dimensions");
return(NhlFATAL);
}
if(ndims_p != 3 && ndims_p != 4 && ndims_p != 5) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: The p, t, q, and z arrays must be 3-, 4- or 5-dimensional\n");
return(NhlFATAL);
}
/*
* Check zsfc and psfc dimension sizes.
*/
if((ndims_zsfc != ndims_psfc) || (ndims_zsfc != ndims_p-1)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: The zsfc and psfc arrays must have the same number of dimensions and be one less dimension than the other input arrays");
return(NhlFATAL);
}
/*
* Now check that the dimension sizes are equal to each other.
*/
for(i = 0; i < ndims_p; i++) {
if(dsizes_p[i] != dsizes_t[i] || dsizes_p[i] != dsizes_q[i] ||
dsizes_p[i] != dsizes_z[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: p, t, q, and z must be the same dimensionality");
return(NhlFATAL);
}
}
for(i = 0; i < ndims_psfc; i++) {
if(dsizes_psfc[i] != dsizes_zsfc[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: psfc and zsfc must be the same dimensionality");
return(NhlFATAL);
}
}
if(ndims_p == 5) {
/*
* Store dimension sizes.
*/
nz = dsizes_p[0]; /* nz */
ntime = dsizes_p[1]; /* time */
mkzh = dsizes_p[2]; /* lev */
mjx = dsizes_p[3]; /* lat */
miy = dsizes_p[4]; /* lon */
ndims_cape = 5;
if(dsizes_psfc[0] != nz || dsizes_psfc[1] != ntime ||
dsizes_psfc[2] != mjx || dsizes_psfc[3] != miy) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: If p,q,t,z are 5-dimensional (nz x time x lev x lat x lon), psfc,zsfc must be 4-dimensional (nz x time x lat x lon)");
return(NhlFATAL);
}
}
else if(ndims_p == 4) {
/*
* Store dimension sizes.
*/
nz = 1;
ntime = dsizes_p[0]; /* time */
mkzh = dsizes_p[1]; /* lev */
mjx = dsizes_p[2]; /* lat */
miy = dsizes_p[3]; /* lon */
ndims_cape = 4;
if(dsizes_psfc[0] != ntime || dsizes_psfc[1] != mjx ||
dsizes_psfc[2] != miy) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: If p,q,t,z are 4-dimensional (time x lev x lat x lon), psfc,zsfc must be 3-dimensional (time x lat x lon)");
return(NhlFATAL);
}
}
else if(ndims_p == 3) {
/*
* Store dimension sizes.
*/
nz = 1;
ntime = 1;
mkzh = dsizes_p[0]; /* lev */
mjx = dsizes_p[1]; /* lat */
miy = dsizes_p[2]; /* lon */
ndims_cape = 3;
if(dsizes_psfc[0] != mjx || dsizes_psfc[1] != miy) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: If p,q,t,z are 3-dimensional (time x lev x lat x lon), psfc,zsfc must be 2-dimensional (lat x lon)");
return(NhlFATAL);
}
}
/*
* If mkzh is not at least size 3, then this dimension won't be big
* enough to contain the cin, lcl, and lfc values.
*/
if(mkzh < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: The level dimension must have at least 3 elements");
return(NhlFATAL);
}
/*
* Test input dimension sizes.
*/
if((miy > INT_MAX) || (mjx > INT_MAX) || (mkzh > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
imiy = (int) miy;
imjx = (int) mjx;
imkzh = (int) mkzh;
/*
* Calculate size of output array. The output array size depends on
* the size of p,t,q,z:
*
* - p,t,q,z (nz,time,lev,lat,lon) and psfc,zsfc (nz,time,lat,lon)
* output array: (4,nz,time,lat,lon)
* - p,t,q,z (time,lev,lat,lon) and psfc,zsfc (time,lat,lon)
* output array: (4,time,lat,lon)
* - p,t,q,z (lev,lat,lon) and psfc,zsfc (lat,lon)
* output array: (4,lat,lon)
*/
dsizes_cape = (ng_size_t *)calloc(ndims_cape,sizeof(ng_size_t));
if(dsizes_cape == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for array dimensionality");
return(NhlFATAL);
}
/* 0=cape, 1=cin, 2=lcl, 3=lfc */
if(ndims_cape == 5) {
dsizes_cape[0] = 4; /* To hold the 4 different variables. */
dsizes_cape[1] = nz;
dsizes_cape[2] = ntime;
dsizes_cape[3] = mjx;
dsizes_cape[4] = miy;
}
else if(ndims_cape == 4) {
dsizes_cape[0] = 4; /* To hold the 4 different variables. */
dsizes_cape[1] = ntime;
dsizes_cape[2] = mjx;
dsizes_cape[3] = miy;
}
else if(ndims_cape == 3) {
dsizes_cape[0] = 4; /* To hold the 4 different variables. */
dsizes_cape[1] = mjx;
dsizes_cape[2] = miy;
}
size_zsfc = mjx * miy;
size_cape = mkzh * size_zsfc;
mkzh0_index = (mkzh-1) * size_zsfc; /* Indexes into cin array for */
mkzh1_index = (mkzh-2) * size_zsfc; /* returning cin, lcl, and lfc */
mkzh2_index = (mkzh-3) * size_zsfc; /* respectively. */
size_left_zsfc = size_zsfc * ntime * nz;
size_output = 4 * size_left_zsfc;
/*
* Allocate space for output and temporary arrays. Even if the input
* arrays are already double, go ahead and allocate some space for
* them b/c we have to copy the values back to 4 different locations.
*
* The addition of missing values was added in V6.1.0.
*/
if(type_p == NCL_double || type_t == NCL_double || type_q == NCL_double ||
type_z == NCL_double) {
type_cape = NCL_double;
type_obj_cape = nclTypedoubleClass;
cape = (double *)calloc(size_output,sizeof(double));
missing_cape.doubleval = ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis.doubleval;
cmsg = missing_cape.doubleval;
}
else {
type_cape = NCL_float;
type_obj_cape = nclTypefloatClass;
cape = (float *)calloc(size_output,sizeof(float));
missing_cape.floatval = ((NclTypeClass)nclTypefloatClass)->type_class.default_mis.floatval;
cmsg = (double)missing_cape.floatval;
}
tmp_cape = (double *)calloc(size_cape,sizeof(double));
tmp_cin = (double *)calloc(size_cape,sizeof(double));
if(cape == NULL || tmp_cape == NULL || tmp_cin == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for output arrays");
return(NhlFATAL);
}
/*
* Allocate memory for coercing input arrays to double, if necessary.
*
* Force a copy of variable p, because we need to multiply it by 0.01,
* and we don't want this to propagate back to the NCL script.
*/
tmp_p_orig = (double *)calloc(size_cape,sizeof(double));
if(tmp_p_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
if(type_t != NCL_double) {
tmp_t_orig = (double *)calloc(size_cape,sizeof(double));
if(tmp_t_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
if(type_q != NCL_double) {
tmp_q_orig = (double *)calloc(size_cape,sizeof(double));
if(tmp_q_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
if(type_z != NCL_double) {
tmp_z_orig = (double *)calloc(size_cape,sizeof(double));
if(tmp_z_orig == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
if(type_zsfc != NCL_double) {
tmp_zsfc = (double *)calloc(size_zsfc,sizeof(double));
if(tmp_zsfc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
if(type_psfc != NCL_double) {
tmp_psfc = (double *)calloc(size_zsfc,sizeof(double));
if(tmp_psfc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for coercing input arrays to double");
return(NhlFATAL);
}
}
/*
* We need to coerce the pressure array once outside the loop to
* check if the values are in ascending order.
*
* If not, we need to flip the leftmost dimension (p = p(::-1,:,:) in
* NCL-ese), *and* flip the other 3 input arrays in the same fashion.
*/
coerce_subset_input_double(p,tmp_p_orig,0,type_p,size_cape,0,NULL,NULL);
if(tmp_p_orig[0] > tmp_p_orig[(mkzh-1)*size_zsfc] ) {
flip = True;
tmp_p = (double *)calloc(size_cape,sizeof(double));
tmp_t = (double *)calloc(size_cape,sizeof(double));
tmp_q = (double *)calloc(size_cape,sizeof(double));
tmp_z = (double *)calloc(size_cape,sizeof(double));
if(tmp_p == NULL || tmp_t == NULL || tmp_q == NULL || tmp_z == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for flipping arrays");
return(NhlFATAL);
}
}
else {
flip = False;
tmp_p = tmp_p_orig;
tmp_t = tmp_t_orig;
tmp_q = tmp_q_orig;
tmp_z = tmp_z_orig;
}
/*
* Get path to psadilookup.dat file required by this routine.
*/
psa_file = get_psa_file();
/*
* Loop through time,nz and call the Fortran routine.
*/
index_cape = index_zsfc = 0;
index_output_cape = 0;
index_output_cin = size_left_zsfc;
index_output_lcl = 2 * size_left_zsfc;
index_output_lfc = 3 * size_left_zsfc;
for(i = 0; i < ntime*nz; i++) {
/*
* Coerce subset of input arrays to double if necessary.
*/
if(i > 0) {
coerce_subset_input_double(p,tmp_p_orig,index_cape,type_p,
size_cape,0,NULL,NULL);
}
/*
* Multiple pressure values by 0.01 to convert from Pa to hPa.
* The assumption is that pressure values come in as Pa.
*/
convert_to_hPa(tmp_p_orig,size_cape);
if(type_t != NCL_double) {
coerce_subset_input_double(t,tmp_t_orig,index_cape,type_t,
size_cape,0,NULL,NULL);
}
else {
/*
* Point tmp_t_orig to appropriate location in t.
*/
tmp_t_orig = &((double*)t)[index_cape];
}
if(type_q != NCL_double) {
coerce_subset_input_double(q,tmp_q_orig,index_cape,type_q,
size_cape,0,NULL,NULL);
}
else {
/*
* Point tmp_q_orig to appropriate location in q.
*/
tmp_q_orig = &((double*)q)[index_cape];
}
if(type_z != NCL_double) {
coerce_subset_input_double(z,tmp_z_orig,index_cape,type_z,
size_cape,0,NULL,NULL);
}
else {
/*
* Point tmp_z_orig to appropriate location in z.
*/
tmp_z_orig = &((double*)z)[index_cape];
}
if(type_psfc != NCL_double) {
coerce_subset_input_double(psfc,tmp_psfc,index_zsfc,type_psfc,
size_zsfc,0,NULL,NULL);
}
else {
/*
* Point tmp_psfc to appropriate location in psfc.
*/
tmp_psfc = &((double*)psfc)[index_zsfc];
}
if(type_zsfc != NCL_double) {
coerce_subset_input_double(zsfc,tmp_zsfc,index_zsfc,type_zsfc,
size_zsfc,0,NULL,NULL);
}
else {
/*
* Point tmp_zsfc to appropriate location in zsfc.
*/
tmp_zsfc = &((double*)zsfc)[index_zsfc];
}
/*
* If the pressure values need to be flipped, we also need to flip
* the z, q, and t values in the same fashion.
*/
if(flip) {
flip_it(tmp_p_orig,tmp_p,mkzh,size_zsfc);
flip_it(tmp_t_orig,tmp_t,mkzh,size_zsfc);
flip_it(tmp_q_orig,tmp_q,mkzh,size_zsfc);
flip_it(tmp_z_orig,tmp_z,mkzh,size_zsfc);
}
else {
tmp_p = tmp_p_orig;
tmp_t = tmp_t_orig;
tmp_q = tmp_q_orig;
tmp_z = tmp_z_orig;
}
/*
* Call Fortran routine.
*/
NGCALLF(dcapecalc3d,DCAPECALC3D)(tmp_p, tmp_t, tmp_q, tmp_z, tmp_zsfc,
tmp_psfc, tmp_cape, tmp_cin, &cmsg,
&imiy, &imjx, &imkzh, &i3dflag, &iter,
psa_file,strlen(psa_file));
/*
* Even if we flipped arrays before going into the Fortran routine, do
* NOT flip them on the output.
*
* Copy the values back out to the correct places in the "cape" array.
*
* This is a bit whacky, because the Fortran code is doing something
* fancy to save memory. The "tmp_cin" array contains the cin values in
* the last mkzh section, the lcl values in the 2nd-to-last mkzh
* section, and the lfc values in the 3rd-to-last mkzh section.
*
* The "tmp_cape" array contains its values in the last mkzh section
* of the tmp_cape array.
*/
coerce_output_float_or_double(cape,&tmp_cape[mkzh0_index],type_cape,
size_zsfc,index_output_cape);
coerce_output_float_or_double(cape,&tmp_cin[mkzh0_index],type_cape,
size_zsfc,index_output_cin);
coerce_output_float_or_double(cape,&tmp_cin[mkzh1_index],type_cape,
size_zsfc,index_output_lcl);
coerce_output_float_or_double(cape,&tmp_cin[mkzh2_index],type_cape,
size_zsfc,index_output_lfc);
/*
* Implement the pointers into the arrays.
*/
index_cape += size_cape;
index_zsfc += size_zsfc;
index_output_cape += size_zsfc;
index_output_cin += size_zsfc;
index_output_lcl += size_zsfc;
index_output_lfc += size_zsfc;
}
/*
* Free memory.
*/
NclFree(tmp_p_orig);
if(type_t != NCL_double) NclFree(tmp_t_orig);
if(type_q != NCL_double) NclFree(tmp_q_orig);
if(type_z != NCL_double) NclFree(tmp_z_orig);
if(type_zsfc != NCL_double) NclFree(tmp_zsfc);
if(type_psfc != NCL_double) NclFree(tmp_psfc);
NclFree(tmp_cape);
NclFree(tmp_cin);
if(flip) {
NclFree(tmp_p);
NclFree(tmp_t);
NclFree(tmp_q);
NclFree(tmp_z);
}
NclFree(psa_file);
/*
* Get dimension info to see if we have named dimensions.
* This will be used for return variable.
*/
dim_info_t = get_wrf_dim_info(1,7,ndims_t,dsizes_t);
if(dim_info_t != NULL) {
dim_info = malloc(sizeof(NclDimRec)*ndims_cape);
if(dim_info == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_cape_2d: Unable to allocate memory for holding dimension information");
return(NhlFATAL);
}
for(i = 0; i < ndims_cape; i++ ) {
dim_info[i].dim_num = i;
dim_info[i].dim_size = dsizes_cape[i];
}
dim_info[0].dim_quark = NrmStringToQuark("mcape_mcin_lcl_lfc");
for(i = 0; i < ndims_t-3; i++) {
dim_info[i+1].dim_quark = dim_info_t[i].dim_quark;
}
dim_info[ndims_cape-2].dim_quark = dim_info_t[ndims_t-2].dim_quark;
dim_info[ndims_cape-1].dim_quark = dim_info_t[ndims_t-1].dim_quark;
}
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)cape,
&missing_cape,
ndims_cape,
dsizes_cape,
TEMPORARY,
NULL,
type_obj_cape
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
-1,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_cape);
if(dim_info != NULL) NclFree(dim_info);
NclFree(dim_info_t);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
/*
* Retrieve the dimension name info of a particular
* input argument to a WRF NCL function. If there are
* no named dimensions, *and* you have at least a 2D
* array, then set the last two dimension names to
* "south_north" x "west_east".
*/
NclDimRec *get_wrf_dim_info(int arg_num,int num_args,int ndims_arg,ng_size_t *dsizes_arg)
{
NclDimRec *dim_info;
int i, is_named;
/* this is now separately malloced */
dim_info = get_dim_info(arg_num,num_args);
is_named = 0;
if(ndims_arg >= 2) {
if(dim_info != NULL) {
/*
* Check if we actually have any named dimensions.
*/
i = 0;
while(i < ndims_arg && !is_named ) {
if(dim_info[i++].dim_quark != -1) is_named = 1;
}
}
if(!is_named) {
/*
* If we are here, then we know we have no named dimensions,
* and hence need to create some.
*/
if(dim_info == NULL) {
dim_info = malloc(sizeof(NclDimRec)*ndims_arg);
if(dim_info == NULL) {
NhlPError(NhlWARNING,NhlEUNKNOWN,"wrf_get_dim_info: Unable to allocate memory for setting dimension names");
return(NULL);
}
}
for(i = 0; i < ndims_arg; i++ ) {
dim_info[i].dim_num = i;
dim_info[i].dim_quark = -1;
dim_info[i].dim_size = dsizes_arg[i];
}
dim_info[ndims_arg-2].dim_quark = NrmStringToQuark("south_north");
dim_info[ndims_arg-1].dim_quark = NrmStringToQuark("west_east");
}
}
return(dim_info);
}
NhlErrorTypes wrf_eth_W( void )
{
/*
* Input variables
*/
/*
* Argument # 0
*/
void *qv;
double *tmp_qv = NULL;
int ndims_qv;
ng_size_t dsizes_qv[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_qv;
/*
* Argument # 1
*/
void *t;
double *tmp_t = NULL;
int ndims_t;
ng_size_t dsizes_t[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_t;
/*
* Argument # 2
*/
void *p;
double *tmp_p = NULL;
int ndims_p;
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_p;
/*
* Return variable
*/
void *eth;
double *tmp_eth = NULL;
NclBasicDataTypes type_eth;
NclObjClass type_obj_eth;
NclQuark *description, *units;
char *cdescription, *cunits;
/*
* Variables for returning the output array with dimension names attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData return_md, att_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Various
*/
int btdim, sndim, wedim, nbtsnwe;
ng_size_t index_eth, i, size_leftmost, size_eth;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
qv = (void*)NclGetArgValue(
0,
3,
&ndims_qv,
dsizes_qv,
NULL,
NULL,
&type_qv,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_qv < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: The qv array must have at least 3 dimensions");
return(NhlFATAL);
}
btdim = dsizes_qv[ndims_qv-3];
sndim = dsizes_qv[ndims_qv-2];
wedim = dsizes_qv[ndims_qv-1];
nbtsnwe = btdim * sndim * wedim;
/*
* Get argument # 1
*/
t = (void*)NclGetArgValue(
1,
3,
&ndims_t,
dsizes_t,
NULL,
NULL,
&type_t,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_t != ndims_qv) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: The qv and t arrays must have the same number of dimensions");
return(NhlFATAL);
}
/*
* Get argument # 2
*/
p = (void*)NclGetArgValue(
2,
3,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_p != ndims_qv) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: The p and t arrays must have the same number of dimensions");
return(NhlFATAL);
}
for(i = 0; i < ndims_qv; i++) {
if(dsizes_t[i] != dsizes_qv[i] || dsizes_p[i] != dsizes_qv[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: The qv, t, and p arrays must have the same dimension sizes");
return(NhlFATAL);
}
}
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_qv-3; i++) size_leftmost *= dsizes_qv[i];
/*
* The output type defaults to float, unless any input arrays are double.
*/
type_eth = NCL_float;
type_obj_eth = nclTypefloatClass;
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* Allocate space for tmp_qv.
*/
if(type_qv != NCL_double) {
tmp_qv = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_qv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_eth = NCL_double;
type_obj_eth = nclTypedoubleClass;
}
/*
* Allocate space for tmp_t.
*/
if(type_t != NCL_double) {
tmp_t = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_t == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_eth = NCL_double;
type_obj_eth = nclTypedoubleClass;
}
/*
* Allocate space for tmp_p.
*/
if(type_p != NCL_double) {
tmp_p = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_p == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_eth = NCL_double;
type_obj_eth = nclTypedoubleClass;
}
/*
* Calculate size of output array and allocate space for it.
*/
size_eth = size_leftmost * nbtsnwe;
if(type_eth != NCL_double) {
eth = (void *)calloc(size_eth, sizeof(float));
tmp_eth = (double *)calloc(nbtsnwe,sizeof(double));
if(tmp_eth == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: Unable to allocate memory for temporary output array");
return(NhlFATAL);
}
}
else {
eth = (void *)calloc(size_eth, sizeof(double));
}
if(eth == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_eth: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* subsection of the input arrays.
*/
index_eth = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of qv (tmp_qv) to double if necessary.
*/
if(type_qv != NCL_double) {
coerce_subset_input_double(qv,tmp_qv,index_eth,type_qv,nbtsnwe,
0,NULL,NULL);
}
else {
tmp_qv = &((double*)qv)[index_eth];
}
/*
* Coerce subsection of t (tmp_t) to double if necessary.
*/
if(type_t != NCL_double) {
coerce_subset_input_double(t,tmp_t,index_eth,type_t,nbtsnwe,
0,NULL,NULL);
}
else {
tmp_t = &((double*)t)[index_eth];
}
/*
* Coerce subsection of p (tmp_p) to double if necessary.
*/
if(type_p != NCL_double) {
coerce_subset_input_double(p,tmp_p,index_eth,type_p,nbtsnwe,
0,NULL,NULL);
}
else {
tmp_p = &((double*)p)[index_eth];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_eth == NCL_double) tmp_eth = &((double*)eth)[index_eth];
/*
* Call the Fortran routine.
*/
NGCALLF(deqthecalc,DEQTHECALC)(tmp_qv, tmp_t, tmp_p, tmp_eth,
&wedim, &sndim, &btdim);
/*
* Coerce output back to float if necessary.
*/
if(type_eth == NCL_float) {
coerce_output_float_only(eth,tmp_eth,nbtsnwe,index_eth);
}
index_eth += nbtsnwe;
}
/*
* Free unneeded memory.
*/
if(type_qv != NCL_double) NclFree(tmp_qv);
if(type_t != NCL_double) NclFree(tmp_t);
if(type_p != NCL_double) NclFree(tmp_p);
if(type_eth != NCL_double) NclFree(tmp_eth);
/*
* Retrieve dimension names from the "t" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(1,3,ndims_t,dsizes_t);
/*
* Set up return value.
*/
/*
* Return value back to NCL script.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)eth,
NULL,
ndims_t,
dsizes_t,
TEMPORARY,
NULL,
type_obj_eth
);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(33,sizeof(char));
strcpy(cdescription,"Equivalent Potential Temperature");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
free(cdescription);
cunits = (char *)calloc(2,sizeof(char));
strcpy(cunits,"K");
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*units = NrmStringToQuark(cunits);
free(cunits);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
/*
* The wrf_wps_xxx_int functions that follow are for reading
* WRF WPS intermediate files. You can use wrf_wps_read_int
* as an "all-in-one" function that creates one 3D variable
* with all the data and attributes attached, or you can
* use the three individual functions, wrf_wps_open_int,
* wrf_wps_rdhead_int, and wrf_wps_rddata_int that allows you
* to read the data in one 2D slab at a time.
*/
/*
* This function simply opens the WRF/WPS intermediate file
* and returns a status.
*/
NhlErrorTypes wrf_wps_open_int_W( void )
{
/*
* Argument # 0
*/
NrmQuark *filename;
char *cfilename;
/*
* Return variable
*/
int *istatus;
/*
* Various
*/
int ret, ndims;
ng_size_t dsizes[1];
/*
* Get argument # 0
*/
filename = (NrmQuark *)NclGetArgValue(
0,
1,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Convert to character string.
*/
cfilename = NrmQuarkToString(*filename);
/*
* Allocate space for output array.
*/
ndims = 1;
dsizes[0] = 1;
/*
* Allocate return integer
*/
istatus = (int*)calloc(1, sizeof(int));
/*
* Call the Fortran routine.
*/
NGCALLF(plotfmt_open,PLOTFMT_open)(cfilename, istatus,
strlen(cfilename));
if(*istatus != 0) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wps_open_int: The input file '%s' could not be opened.\nCheck that it exists and is spelled correctly",cfilename);
return(NhlFATAL);
}
/*
* Return value back to NCL script.
*/
ret = NclReturnValue(istatus,ndims,dsizes,NULL,NCL_int,0);
return(ret);
}
/*
* This function simply closes a WRF/WPS intermediate file
* that was opened with wrf_wps_open/rddata/rhead_int.
* Note that nothing is currently done with the istatus
* variable. This might change if we decide that
* istatus can contain a "unit" attribute that indicates
* which Fortran unit was used to open the file.
*/
NhlErrorTypes wrf_wps_close_int_W( void )
{
int *istatus;
istatus = (int *)NclGetArgValue(
0,
1,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
NGCALLF(plotfmt_close,PLOTFMT_CLOSE)();
return(NhlNOERROR);
}
/*
* This function takes an open WRF/WPS intermediate file,
* and reads header information. This header information
* then gives you the info needed to read the slab via
* wrf_wps_rddata_int.
*/
NhlErrorTypes wrf_wps_rdhead_int_W( void )
{
/*
* Argument # 0
*/
int *istatus;
/*
* Argument # 1
*/
void *head;
float *rhead;
NclBasicDataTypes type_head;
ng_size_t dsizes_head[1];
/*
* Argument # 2
*/
NrmQuark *field;
char *cfield;
int FIELD_LEN=9;
/*
* Argument # 3
*/
NrmQuark *hdate;
char *chdate;
int HDATE_LEN=24;
/*
* Argument # 4
*/
NrmQuark *units;
char *cunits;
int UNITS_LEN=25;
/*
* Argument # 5
*/
NrmQuark *mapsc;
char *cmapsc;
int MAPSC_LEN=32;
/*
* Argument # 6
*/
NrmQuark *desc;
char *cdesc;
int DESC_LEN=46;
/*
* Various
*/
int i;
/*
* Get argument #0
*/
istatus = (int *)NclGetArgValue(
0,
7,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Get arguments # 1-6
*/
head = (void *)NclGetArgValue(
1,
7,
NULL,
dsizes_head,
NULL,
NULL,
&type_head,
DONT_CARE);
rhead = coerce_input_float(head, type_head, dsizes_head[0], 0,
NULL, NULL);
field = (NrmQuark *)NclGetArgValue(
2,
7,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
hdate = (NrmQuark *)NclGetArgValue(
3,
7,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
units = (NrmQuark *)NclGetArgValue(
4,
7,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
mapsc = (NrmQuark *)NclGetArgValue(
5,
7,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
desc = (NrmQuark *)NclGetArgValue(
6,
7,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Allocate space needed for each string
*/
cfield = (char *)malloc((FIELD_LEN+1)*sizeof(char));
chdate = (char *)malloc((HDATE_LEN+1)*sizeof(char));
cunits = (char *)malloc((UNITS_LEN+1)*sizeof(char));
cmapsc = (char *)malloc((MAPSC_LEN+1)*sizeof(char));
cdesc = (char *)malloc((DESC_LEN+1)*sizeof(char));
/*
* Call the Fortran routine.
*/
NGCALLF(plotfmt_rdhead,PLOTFMT_RDHEAD)(istatus,rhead,cfield,chdate,
cunits,cmapsc,cdesc,
FIELD_LEN,HDATE_LEN,
UNITS_LEN,MAPSC_LEN,
DESC_LEN);
/*
* Strip off potential white space at end of each string.
*/
i = FIELD_LEN-1;
while(i >=0 && (cfield[i] == ' ' || cfield[i] == '\t')) i--;
cfield[i+1] = '\0';
i = HDATE_LEN-1;
while(i >= 0 && (chdate[i] == ' ' || chdate[i] == '\t')) i--;
chdate[i+1] = '\0';
i = UNITS_LEN-1;
while( i >= 0 && (cunits[i] == ' ' || cunits[i] == '\t')) i--;
cunits[i+1] = '\0';
i = MAPSC_LEN-1;
while( i >= 0 && (cmapsc[i] == ' ' || cmapsc[i] == '\t')) i--;
cmapsc[i+1] = '\0';
i = DESC_LEN-1;
while( i >= 0 && (cdesc[i] == ' ' || cdesc[i] == '\t')) i--;
cdesc[i+1] = '\0';
*field = NrmStringToQuark(cfield);
*hdate = NrmStringToQuark(chdate);
*units = NrmStringToQuark(cunits);
*mapsc = NrmStringToQuark(cmapsc);
*desc = NrmStringToQuark(cdesc);
return(NhlNOERROR);
}
/*
* This function takes an open WRF/WPS intermediate file,
* and reads a 2D slab.
*/
NhlErrorTypes wrf_wps_rddata_int_W( void )
{
/*
* Argument # 0
*/
int *istatus;
/*
* Arguments #1-2
*/
void *tmp_nx, *tmp_ny;
ng_size_t *nx, *ny;
NclBasicDataTypes type_nx, type_ny;
int inx, iny;
/*
* Return
*/
float *slab;
ng_size_t dsizes[2];
int ret;
/*
* Get argument #0
*/
istatus = (int *)NclGetArgValue(
0,
3,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Get arguments #1-2
*/
tmp_nx = (void *)NclGetArgValue(
1,
3,
NULL,
NULL,
NULL,
NULL,
&type_nx,
DONT_CARE);
tmp_ny = (void *)NclGetArgValue(
2,
3,
NULL,
NULL,
NULL,
NULL,
&type_ny,
DONT_CARE);
/*
* Convert the input dimensions to ng_size_t.
*/
nx = get_dimensions(tmp_nx,1,type_nx,"wrf_wps_rddata_int");
ny = get_dimensions(tmp_ny,1,type_ny,"wrf_wps_rddata_int");
if(nx == NULL || ny == NULL)
return(NhlFATAL);
if((*nx > INT_MAX) || (*ny > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wps_rddata_int: nx and/or ny is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) *nx;
iny = (int) *ny;
slab = (float*)calloc(inx*iny,sizeof(float));
if(slab == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wps_rddata_int: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Call the Fortran routine.
*/
NGCALLF(plotfmt_rddata,PLOTFMT_RDDATA)(istatus,&inx,&iny,slab);
/*
* Return value back to NCL script.
*/
dsizes[0] = *ny;
dsizes[1] = *nx;
ret = NclReturnValue(slab,2,dsizes,NULL,NCL_float,0);
return(ret);
}
/*
* This function is a "3-in-1" function that does the
* work of wrf_wps_open_int, wrf_wps_rdhead_int, and
* wrf_wps_rddata_int. It returns a 3D float array
* that contains all the necessary data and attributes.
*
*/
NhlErrorTypes wrf_wps_read_int_W( void )
{
/*
* Argument # 0
*/
NrmQuark *filename;
char *cfilename;
/*
* Return values. The slab will be returned, along with a bunch
* of attributes depending on the projection.
*/
int NHEAD=14, FIELD_LEN=9, HDATE_LEN=24, UNITS_LEN=25;
int MAPSC_LEN=32, DESCR_LEN=46;
float *slab, *rhead, *slab_s;
float rhead_s[NHEAD];
ng_size_t dsizes_slab[3], dsizes_rhead[2], dsizes_field[1], dsizes_hdate[1];
ng_size_t dsizes_units[1], dsizes_mapsc[1], dsizes_descr[1];
NrmQuark *field, *hdate, *units, *mapsc, *descr;
char *cfield, *chdate, *cunits, *cmapsc, *cdescr;
NclScalar missing_slab;
/*
* Various
*/
int i, j, n, istatus, nx, ny, nxny, max_nx, max_ny, nfields;
int index_slab, index_rhead;
/*
* Attribute variables
*/
int att_id;
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Get argument #0
*/
filename = (NrmQuark *)NclGetArgValue(
0,
1,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Convert to character string.
*/
cfilename = NrmQuarkToString(*filename);
/*
* Call the Fortran routine to open the file
*/
NGCALLF(plotfmt_open,PLOTFMT_open)(cfilename, &istatus,
strlen(cfilename));
if(istatus != 0) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wps_read_int: The input file '%s' could not be opened.\nCheck that it exists and is spelled correctly",cfilename);
return(NhlFATAL);
}
cfield = (char *)malloc((FIELD_LEN+1)*sizeof(char));
chdate = (char *)malloc((HDATE_LEN+1)*sizeof(char));
cunits = (char *)malloc((UNITS_LEN+1)*sizeof(char));
cmapsc = (char *)malloc((MAPSC_LEN+1)*sizeof(char));
cdescr = (char *)malloc((DESCR_LEN+1)*sizeof(char));
/*
* Read each field so we can count how many there are.
*/
nfields = 0;
while (istatus == 0) {
/* Read the header */
NGCALLF(plotfmt_rdhead,PLOTFMT_RDHEAD)(&istatus,&rhead_s[0],cfield,
chdate,cunits,cmapsc,cdescr,
FIELD_LEN,HDATE_LEN,
UNITS_LEN,MAPSC_LEN,
DESCR_LEN);
if(istatus == 0) {
nx = (int)rhead_s[3];
ny = (int)rhead_s[4];
slab_s = (float*)calloc(nx*ny,sizeof(float));
if(slab_s == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wps_read_int: Unable to allocate memory for output array");
return(NhlFATAL);
}
if(nfields == 0) {
max_nx = nx;
max_ny = ny;
}
else {
max_nx = max(max_nx,nx);
max_ny = max(max_ny,ny);
}
/* Read the data */
NGCALLF(plotfmt_rddata,PLOTFMT_RDDATA)(&istatus,&nx,&ny,slab_s);
NclFree(slab_s);
if(istatus == 0) nfields++;
}
}
nxny = max_nx * max_ny;
/* Allocate the return arrays */
rhead = (float*)calloc(nfields*NHEAD,sizeof(float));
slab = (float*)calloc(nfields*nxny,sizeof(float));
field = (NclQuark*)NclMalloc(nfields*sizeof(NclQuark));
hdate = (NclQuark*)NclMalloc(nfields*sizeof(NclQuark));
units = (NclQuark*)NclMalloc(nfields*sizeof(NclQuark));
mapsc = (NclQuark*)NclMalloc(nfields*sizeof(NclQuark));
descr = (NclQuark*)NclMalloc(nfields*sizeof(NclQuark));
if(rhead == NULL || slab == NULL || field == NULL || hdate == NULL ||
units == NULL || mapsc == NULL || descr == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wps_read_int: Unable to allocate memory for output array and attributes");
return(NhlFATAL);
}
/* Close and reopen file. */
NGCALLF(plotfmt_close,PLOTFMT_CLOSE)();
NGCALLF(plotfmt_open,PLOTFMT_open)(cfilename, &istatus,
strlen(cfilename));
missing_slab.floatval = -1e30;
index_slab = index_rhead = 0;
/* Now loop through again and fill up the output arrays */
for(n = 0; n < nfields; n++) {
/* Read the header into allocated arrays */
NGCALLF(plotfmt_rdhead,PLOTFMT_RDHEAD)(&istatus,&rhead[index_rhead],
cfield,chdate,cunits,
cmapsc,cdescr,
FIELD_LEN,HDATE_LEN,
UNITS_LEN,MAPSC_LEN,
DESCR_LEN);
/*
* Strip off potential white space at end of each string.
*/
i = FIELD_LEN-1;
while(i >=0 && (cfield[i] == ' ' ||
cfield[i] == '\t')) i--;
cfield[i+1] = '\0';
i = HDATE_LEN-1;
while(i >= 0 && (chdate[i] == ' ' ||
chdate[i] == '\t')) i--;
chdate[i+1] = '\0';
i = UNITS_LEN-1;
while( i >= 0 && (cunits[i] == ' ' ||
cunits[i] == '\t')) i--;
cunits[i+1] = '\0';
i = MAPSC_LEN-1;
while( i >= 0 && (cmapsc[i] == ' ' ||
cmapsc[i] == '\t')) i--;
cmapsc[i+1] = '\0';
i = DESCR_LEN-1;
while( i >= 0 && (cdescr[i] == ' ' ||
cdescr[i] == '\t')) i--;
cdescr[i+1] = '\0';
field[n] = NrmStringToQuark(cfield);
hdate[n] = NrmStringToQuark(chdate);
units[n] = NrmStringToQuark(cunits);
mapsc[n] = NrmStringToQuark(cmapsc);
descr[n] = NrmStringToQuark(cdescr);
/*
* We have to get nx and ny every time in the loop, because they
* can be different sizes.
*/
nx = (int)rhead[index_rhead+3];
ny = (int)rhead[index_rhead+4];
slab_s = (float*)calloc(nx*ny,sizeof(float));
if(slab_s == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wps_read_int: Unable to allocate memory for output array");
return(NhlFATAL);
}
/* Read data into temporary array */
NGCALLF(plotfmt_rddata,PLOTFMT_RDDATA)(&istatus,&nx,&ny,&slab_s[0]);
/* Copy slab subset back out to big slab array */
for(i = 0; i < ny; i++) {
for(j = 0; j < nx; j++) {
slab[index_slab+(i*max_nx)+j] = slab_s[(i*nx)+j];
}
/* Fill rest with missing values */
for(j = nx; j < max_nx; j++) {
slab[index_slab+(i*max_nx)+j] = missing_slab.floatval;
}
}
/* For next time through loop */
index_slab += nxny;
index_rhead += NHEAD;
}
/* Close the file. */
NGCALLF(plotfmt_close,PLOTFMT_CLOSE)();
/* Free memory */
free(slab_s);
free(cfield);
free(chdate);
free(cunits);
free(cmapsc);
free(cdescr);
/*
* Return slab and attributes back to NCL script.
*/
dsizes_slab[0] = nfields;
dsizes_slab[1] = max_ny;
dsizes_slab[2] = max_nx;
dsizes_rhead[0] = nfields;
dsizes_rhead[1] = NHEAD;
dsizes_field[0] = nfields;
dsizes_hdate[0] = nfields;
dsizes_units[0] = nfields;
dsizes_mapsc[0] = nfields;
dsizes_descr[0] = nfields;
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)slab,
&missing_slab,
3,
dsizes_slab,
TEMPORARY,
NULL,
nclTypefloatClass
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)field,
NULL,
1,
dsizes_field,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"field",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)hdate,
NULL,
1,
dsizes_hdate,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"hdate",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes_units,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)mapsc,
NULL,
1,
dsizes_mapsc,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"map_source",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)descr,
NULL,
1,
dsizes_descr,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)rhead,
NULL,
2,
dsizes_rhead,
TEMPORARY,
NULL,
nclTypefloatClass
);
_NclAddAtt(
att_id,
"rhead",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
NULL,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
/*
* This next section contains wrappers for wrf_bint and wrf_iclw.
* These wrappers have never been tested or documented, and are
* not registered in wrapper.c. I've let them here in case we need
* to resuscitate them.
*/
NhlErrorTypes wrf_wps_read_nml_W( void )
{
/*
* Argument # 0
*/
NrmQuark *namelist;
char *cnamelist;
/*
* Return variable
*/
float *pgrids_var;
int size_output, ndims_output;
ng_size_t dsizes_output[2];
NclScalar missing_output;
/*
* Various
*/
int NVAR=19, MAX_DOMAINS=21;
int ret;
/*
* Get argument # 0
*/
namelist = (NrmQuark *)NclGetArgValue(
0,
1,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Convert to character string.
*/
cnamelist = NrmQuarkToString(*namelist);
/*
* Allocate space for output array.
*/
ndims_output = 2;
dsizes_output[0] = MAX_DOMAINS;
dsizes_output[1] = NVAR;
size_output = NVAR*MAX_DOMAINS;
pgrids_var = (float*)calloc(size_output, sizeof(float));
if(pgrids_var == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wps_read_nml: Unable to allocate memory for output array");
return(NhlFATAL);
}
missing_output.floatval = -999.;
/*
* Call the Fortran routine.
*/
NGCALLF(plotgrids_var,PLOTGRIDS_VAR)(cnamelist, pgrids_var,
strlen(cnamelist));
/*
* Return value back to NCL script.
*/
ret = NclReturnValue(pgrids_var,ndims_output,dsizes_output,
&missing_output,NCL_float,0);
return(ret);
}
NhlErrorTypes wrf_bint_W( void )
{
/*
* Input array variables
*/
void *data_in, *obsii, *obsjj;
double *tmp_data_in = NULL;
double *tmp_obsii = NULL;
double *tmp_obsjj = NULL;
int *icrs, *jcrs;
int ndims_data_in, ndims_obsii, ndims_obsjj;
ng_size_t dsizes_data_in[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_obsii[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_obsjj[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_data_in, type_obsii, type_obsjj;
/*
* Output variable.
*/
void *data_out;
double *tmp_data_out = NULL;
ng_size_t *dsizes_data_out, size_data_out;
NclBasicDataTypes type_data_out;
/*
* Various
*/
int ret;
ng_size_t i, nx, ny, nz, nobsicrs, nobsjcrs, size_leftmost;
ng_size_t nxyz, nobsij, nobsijz, index_data_in, index_data_out, index_nobsij;
int inx, iny, inz, inobsicrs, inobsjcrs;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
data_in = (void*)NclGetArgValue(
0,
5,
&ndims_data_in,
dsizes_data_in,
NULL,
NULL,
&type_data_in,
DONT_CARE);
obsii = (void*)NclGetArgValue(
1,
5,
&ndims_obsii,
dsizes_obsii,
NULL,
NULL,
&type_obsii,
DONT_CARE);
obsjj = (void*)NclGetArgValue(
2,
5,
&ndims_obsjj,
dsizes_obsjj,
NULL,
NULL,
&type_obsjj,
DONT_CARE);
icrs = (int*)NclGetArgValue(
3,
5,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
jcrs = (int*)NclGetArgValue(
4,
5,
NULL,
NULL,
NULL,
NULL,
NULL,
DONT_CARE);
/*
* Error checking.
*/
if(ndims_data_in < 2 || ndims_obsii < 2 || ndims_obsjj < 2) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: The data_in, obsii, and obsjj arrays must have at least two dimensions");
return(NhlFATAL);
}
if(ndims_obsii != ndims_obsjj) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: The obsii and obsjj arrays must have the same number of dimensions");
return(NhlFATAL);
}
if((ndims_data_in == 2 && ndims_obsii != 2) ||
(ndims_data_in > 2 && ndims_data_in != (ndims_obsii+1))) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: The data_in, obsii, and obsjj arrays must all be two-dimensional, or data_in must be greater than two dimensions and have one more dimension than obsii and obsjj");
return(NhlFATAL);
}
for(i = 0; i < ndims_obsii; i++) {
if(dsizes_obsii[i] != dsizes_obsjj[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: The obsii and obsjj arrays must be the same dimension sizes");
return(NhlFATAL);
}
}
/*
* If data_in is greater than 3 dimensions, then check that these
* extra dimensions are all the same length in the three input
* arrays.
*
* While we're here, calculate the size of the leftmost dimensions.
*/
size_leftmost = 1;
if(ndims_data_in > 3) {
for(i = 0; i < ndims_data_in-3; i++) {
if(dsizes_data_in[i] != dsizes_obsii[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: The rightmost dimensions of data_in, obsii, obsjj must be the same");
return(NhlFATAL);
}
size_leftmost *= dsizes_data_in[i];
}
}
/*
* Store some dimension sizes and output data array sizes.
*/
nx = dsizes_data_in[ndims_data_in-1];
ny = dsizes_data_in[ndims_data_in-2];
if(ndims_data_in > 2) {
nz = dsizes_data_in[ndims_data_in-3];
}
else {
nz = 1;
}
nobsicrs = dsizes_obsii[ndims_obsii-1];
nobsjcrs = dsizes_obsii[ndims_obsii-2];
nxyz = nx * ny * nz;
nobsij = nobsicrs * nobsjcrs;
nobsijz = nobsij * nz;
size_data_out = size_leftmost * nobsijz;
/*
* Test input dimension sizes.
*/
if((nx > INT_MAX) || (ny > INT_MAX) || (nobsicrs > INT_MAX) ||
(nobsjcrs > INT_MAX) || (nz > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: one or more dimension sizes is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
inobsicrs = (int) nobsicrs;
inobsjcrs = (int) nobsjcrs;
/*
* Allocate space for coercing input arrays. If the input data_in, obsii,
* or obsjj are already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the input arrays
* are double.
*/
type_data_out = NCL_float;
if(type_data_in != NCL_double) {
tmp_data_in = (double *)calloc(nxyz,sizeof(double));
if(tmp_data_in == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_data_out = NCL_double;
}
if(type_obsii != NCL_double) {
tmp_obsii = (double *)calloc(nobsij,sizeof(double));
if(tmp_obsii == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_data_out = NCL_double;
}
if(type_obsjj != NCL_double) {
tmp_obsjj = (double *)calloc(nobsij,sizeof(double));
if(tmp_obsjj == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_data_out = NCL_double;
}
/*
* Allocate space for output array.
*/
if(type_data_out == NCL_double) {
data_out = (double *)calloc(size_data_out,sizeof(double));
if(data_out == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
data_out = (float *)calloc(size_data_out,sizeof(float));
tmp_data_out = (double *)calloc(nobsijz,sizeof(double));
if(tmp_data_out == NULL || data_out == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Create dimension sizes for output array.
*/
dsizes_data_out = (ng_size_t*)calloc(ndims_data_in,sizeof(ng_size_t));
if( dsizes_data_out == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_bint: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
for(i = 1; i < ndims_data_in-2; i++) dsizes_data_out[i] = dsizes_data_in[i];
dsizes_data_out[ndims_data_in-2] = nobsjcrs;
dsizes_data_out[ndims_data_in-1] = nobsicrs;
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* one-dimensional subsection.
*/
index_data_in = index_data_out = index_nobsij = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of data_in (tmp_data_in) to double if necessary.
*/
if(type_data_in != NCL_double) {
coerce_subset_input_double(data_in,tmp_data_in,index_data_in,
type_data_in,nxyz,0,NULL,NULL);
}
else {
tmp_data_in = &((double*)data_in)[index_data_in];
}
/*
* Coerce subsection of obsii (tmp_obsii) to double if ncessary.
*/
if(type_obsii != NCL_double) {
coerce_subset_input_double(obsii,tmp_obsii,index_nobsij,type_obsii,
nobsij,0,NULL,NULL);
}
else {
tmp_obsii = &((double*)obsii)[index_nobsij];
}
/*
* Coerce subsection of obsjj (tmp_obsjj) to double if ncessary.
*/
if(type_obsjj != NCL_double) {
coerce_subset_input_double(obsjj,tmp_obsjj,index_nobsij,type_obsjj,
nobsij,0,NULL,NULL);
}
else {
tmp_obsjj = &((double*)obsjj)[index_nobsij];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_data_out == NCL_double) {
tmp_data_out = &((double*)data_out)[index_data_out];
}
/*
* Call Fortran routine.
*/
NGCALLF(dbint3d,DBINT3D)(tmp_data_out,tmp_obsii,tmp_obsjj,tmp_data_in,
&inx,&iny,&inz,&inobsicrs,&inobsjcrs,icrs,jcrs);
/*
* Coerce output back to float if necessary.
*/
if(type_data_out == NCL_float) {
coerce_output_float_only(data_out,tmp_data_out,nobsijz,index_data_out);
}
/*
* Increment indices.
*/
index_data_in += nxyz;
index_data_out += nobsijz;
index_nobsij += nobsij;
}
/*
* Free up memory.
*/
if(type_data_in != NCL_double) NclFree(tmp_data_in);
if(type_obsii != NCL_double) NclFree(tmp_obsii);
if(type_obsjj != NCL_double) NclFree(tmp_obsjj);
if(type_data_out != NCL_double) NclFree(tmp_data_out);
ret = NclReturnValue(data_out,ndims_data_in,dsizes_data_out,NULL,
type_data_out,0);
NclFree(dsizes_data_out);
return(ret);
}
NhlErrorTypes wrf_iclw_W( void )
{
/*
* Input variables
*/
/*
* Argument # 0
*/
void *p;
double *tmp_p = NULL;
int ndims_p;
ng_size_t dsizes_p[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_p;
/*
* Argument # 1
*/
void *qc;
double *tmp_qc = NULL;
int ndims_qc;
ng_size_t dsizes_qc[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_qc;
/*
* Return variable
*/
void *iclw;
NclQuark *description, *units;
char *cdescription, *cunits;
double *tmp_iclw = NULL;
int ndims_iclw;
ng_size_t *dsizes_iclw;
NclBasicDataTypes type_iclw;
NclObjClass type_obj_iclw;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Various
*/
ng_size_t nz, ny, nx, nznynx, nynx;
ng_size_t index_p, index_iclw;
ng_size_t i, ndims_leftmost, size_leftmost, size_output;
int inx, iny, inz;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
/*
* Get argument # 0
*/
p = (void*)NclGetArgValue(
0,
2,
&ndims_p,
dsizes_p,
NULL,
NULL,
&type_p,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_p < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: The p array must have at least 3 dimensions");
return(NhlFATAL);
}
nz = dsizes_p[ndims_p-3];
ny = dsizes_p[ndims_p-2];
nx = dsizes_p[ndims_p-1];
nynx = ny * nx;
nznynx = nz * nynx;
/*
* Test dimension sizes.
*/
if((nx > INT_MAX) || (ny > INT_MAX) || (nz > INT_MAX)) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: nx, ny and/or is greater than INT_MAX");
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
/*
* Get argument # 1
*/
qc = (void*)NclGetArgValue(
1,
2,
&ndims_qc,
dsizes_qc,
NULL,
NULL,
&type_qc,
DONT_CARE);
/*
* Check dimension sizes.
*/
if(ndims_qc < 3) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: The qc array must have at least 3 dimensions");
return(NhlFATAL);
}
if(dsizes_qc[ndims_qc-3] != nz ||
dsizes_qc[ndims_qc-2] != ny ||
dsizes_qc[ndims_qc-1] != nx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: The rightmost dimensions of qc must be nz x ny x nx");
return(NhlFATAL);
}
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
ndims_leftmost = ndims_p-3;
for(i = 0; i < ndims_leftmost; i++) {
if(dsizes_qc[i] != dsizes_p[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: The leftmost dimensions of p and qc must be the same");
return(NhlFATAL);
}
size_leftmost *= dsizes_p[i];
}
/*
* The output type defaults to float, unless either input array is double.
*/
type_iclw = NCL_float;
type_obj_iclw = nclTypefloatClass;
/*
* Allocate space for coercing input arrays. If any of the input
* is already double, then we don't need to allocate space for
* temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*/
/*
* Allocate space for tmp_p.
*/
if(type_p != NCL_double) {
tmp_p = (double *)calloc(nznynx,sizeof(double));
if(tmp_p == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_iclw = NCL_double;
type_obj_iclw = nclTypedoubleClass;
}
/*
* Allocate space for tmp_qc.
*/
if(type_qc != NCL_double) {
tmp_qc = (double *)calloc(nznynx,sizeof(double));
if(tmp_qc == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: Unable to allocate memory for coercing input array to double");
return(NhlFATAL);
}
}
else {
type_iclw = NCL_double;
type_obj_iclw = nclTypedoubleClass;
}
/*
* Calculate size of output array.
*/
size_output = size_leftmost * nynx;
/*
* Allocate space for output array.
*/
if(type_iclw != NCL_double) {
iclw = (void *)calloc(size_output, sizeof(float));
tmp_iclw = (double *)calloc(nynx,sizeof(double));
if(tmp_iclw == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: Unable to allocate memory for temporary output array");
return(NhlFATAL);
}
}
else {
iclw = (void *)calloc(size_output, sizeof(double));
}
if(iclw == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: Unable to allocate memory for output array");
return(NhlFATAL);
}
/*
* Allocate space for output dimension sizes and set them.
*/
ndims_iclw = ndims_leftmost + 2;
dsizes_iclw = (ng_size_t*)calloc(ndims_iclw,sizeof(ng_size_t));
if( dsizes_iclw == NULL ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_iclw: Unable to allocate memory for holding dimension sizes");
return(NhlFATAL);
}
for(i = 0; i < ndims_iclw-2; i++) dsizes_iclw[i] = dsizes_p[i];
dsizes_iclw[ndims_iclw-2] = ny;
dsizes_iclw[ndims_iclw-1] = nx;
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* subsection of the input arrays..
*/
index_p = index_iclw = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of p (tmp_p) to double if necessary.
*/
if(type_p != NCL_double) {
coerce_subset_input_double(p,tmp_p,index_p,type_p,nznynx,0,NULL,NULL);
}
else {
tmp_p = &((double*)p)[index_p];
}
/*
* Coerce subsection of qc (tmp_qc) to double if necessary.
*/
if(type_qc != NCL_double) {
coerce_subset_input_double(qc,tmp_qc,index_p,type_qc,nznynx,0,NULL,NULL);
}
else {
tmp_qc = &((double*)qc)[index_p];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_iclw == NCL_double) tmp_iclw = &((double*)iclw)[index_iclw];
/*
* Call the Fortran routine.
*/
NGCALLF(dcomputeiclw,DCOMPUTEICLW)(tmp_iclw, tmp_p, tmp_qc, &inx, &iny, &inz);
/*
* Coerce output back to float if necessary.
*/
if(type_iclw == NCL_float) {
coerce_output_float_only(iclw,tmp_iclw,nynx,index_iclw);
}
index_p += nznynx;
index_iclw += nynx;
}
/*
* Free unneeded memory.
*/
if(type_p != NCL_double) NclFree(tmp_p);
if(type_qc != NCL_double) NclFree(tmp_qc);
if(type_iclw != NCL_double) NclFree(tmp_iclw);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(16,sizeof(char));
cunits = (char *)calloc(3,sizeof(char));
strcpy(cdescription,"Int Cloud Water");
strcpy(cunits,"mm");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cdescription);
free(cunits);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)iclw,
NULL,
ndims_iclw,
dsizes_iclw,
TEMPORARY,
NULL,
type_obj_iclw
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
NULL,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dsizes_iclw);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_wetbulb_W( void )
{
/*
* Input array variables
*/
void *prs, *tmk, *qvp;
double *tmp_prs = NULL;
double *tmp_tmk = NULL;
double *tmp_qvp = NULL;
int ndims_prs, ndims_tmk, ndims_qvp;
ng_size_t dsizes_prs[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_tmk[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_qvp[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_prs, type_tmk, type_qvp;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Output variable and attributes.
*/
void *twb;
NclQuark *description, *units;
char *cdescription, *cunits;
double *tmp_twb = NULL;
NclBasicDataTypes type_twb;
NclObjClass type_obj_twb;
/*
* Various
*/
ng_size_t i, nx, ny, nz, nxyz, size_leftmost, index_prs, size_twb;
int inx, iny, inz;
char *psa_file;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
prs = (void*)NclGetArgValue(
0,
3,
&ndims_prs,
dsizes_prs,
NULL,
NULL,
&type_prs,
DONT_CARE);
tmk = (void*)NclGetArgValue(
1,
3,
&ndims_tmk,
dsizes_tmk,
NULL,
NULL,
&type_tmk,
DONT_CARE);
qvp = (void*)NclGetArgValue(
2,
3,
&ndims_qvp,
dsizes_qvp,
NULL,
NULL,
&type_qvp,
DONT_CARE);
/*
* Error checking. Input variables must be same size.
*/
if(ndims_prs < 3 || ndims_prs != ndims_tmk || ndims_prs != ndims_qvp ) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: The prs, tmk, and qvp arrays must have at least 3 dimensions and have the same number of dimensions as each other");
return(NhlFATAL);
}
for(i = 0; i < ndims_prs; i++) {
if(dsizes_prs[i] != dsizes_tmk[i] || dsizes_prs[i] != dsizes_qvp[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: prs, tmk, and qvp must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Test dimension sizes.
*/
nz = dsizes_prs[ndims_prs-1];
ny = dsizes_prs[ndims_prs-2];
nx = dsizes_prs[ndims_prs-3];
if(nx > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: nx = %ld is greater than INT_MAX", nx);
return(NhlFATAL);
}
if(ny > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: ny = %ld is greater than INT_MAX", ny);
return(NhlFATAL);
}
if(nz > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: nz = %ld is greater than INT_MAX", nz);
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
/*
* Retrieve dimension names from the "tmk" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(1,3,ndims_tmk,dsizes_tmk);
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_prs-3; i++) size_leftmost *= dsizes_prs[i];
nxyz = nx * ny * nz;
size_twb = size_leftmost * nxyz;
/*
* Allocate space for coercing input arrays. If the input prs, tmk,
* or qvp are already double, then we don't need to allocate space
* for temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the input arrays
* are double.
*/
type_twb = NCL_float;
type_obj_twb = nclTypefloatClass;
if(type_prs != NCL_double) {
tmp_prs = (double *)calloc(nxyz,sizeof(double));
if(tmp_prs == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: Unable to allocate memory for coercing 'prs' array to double");
return(NhlFATAL);
}
}
else {
type_twb = NCL_double;
type_obj_twb = nclTypedoubleClass;
}
if(type_tmk != NCL_double) {
tmp_tmk = (double *)calloc(nxyz,sizeof(double));
if(tmp_tmk == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: Unable to allocate memory for coercing 'tmk' to double");
return(NhlFATAL);
}
}
else {
type_twb = NCL_double;
type_obj_twb = nclTypedoubleClass;
}
if(type_qvp != NCL_double) {
tmp_qvp = (double *)calloc(nxyz,sizeof(double));
if(tmp_qvp == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: Unable to allocate memory for coercing 'qvp' to double");
return(NhlFATAL);
}
}
else {
type_twb = NCL_double;
type_obj_twb = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
if(type_twb == NCL_double) {
twb = (double *)calloc(size_twb,sizeof(double));
if(twb == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
twb = (float *)calloc(size_twb,sizeof(float));
tmp_twb = (double *)calloc(nxyz,sizeof(double));
if(tmp_twb == NULL || twb == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_wetbulb: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Get path to psadilookup.dat file required by this routine.
*/
psa_file = get_psa_file();
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* three-dimensional subsection.
*/
index_prs = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of p (tmp_prs) to double if necessary.
*/
if(type_prs != NCL_double) {
coerce_subset_input_double(prs,tmp_prs,index_prs,type_prs,
nxyz,0,NULL,NULL);
}
else {
tmp_prs = &((double*)prs)[index_prs];
}
/*
* Coerce subsection of tmk (tmp_tmk) to double if ncessary.
*/
if(type_tmk != NCL_double) {
coerce_subset_input_double(tmk,tmp_tmk,index_prs,type_tmk,
nxyz,0,NULL,NULL);
}
else {
tmp_tmk = &((double*)tmk)[index_prs];
}
/*
* Coerce subsection of qvp (tmp_qvp) to double if ncessary.
*/
if(type_qvp != NCL_double) {
coerce_subset_input_double(qvp,tmp_qvp,index_prs,type_qvp,
nxyz,0,NULL,NULL);
}
else {
tmp_qvp = &((double*)qvp)[index_prs];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_twb == NCL_double) tmp_twb = &((double*)twb)[index_prs];
/*
* Call Fortran routine.
*/
NGCALLF(wetbulbcalc,WETBULBCALC)(tmp_prs,tmp_tmk,tmp_qvp,tmp_twb,
&inx,&iny,&inz,psa_file,
strlen(psa_file));
/*
* Coerce output back to float if necessary.
*/
if(type_twb == NCL_float) {
coerce_output_float_only(twb,tmp_twb,nxyz,index_prs);
}
index_prs += nxyz; /* Increment index */
}
/*
* Free up memory.
*/
if(type_prs != NCL_double) NclFree(tmp_prs);
if(type_tmk != NCL_double) NclFree(tmp_tmk);
if(type_qvp != NCL_double) NclFree(tmp_qvp);
if(type_twb != NCL_double) NclFree(tmp_twb);
NclFree(psa_file);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(21,sizeof(char));
strcpy(cdescription,"Wet Bulb Temperature");
cunits = (char *)calloc(2,sizeof(char));
strcpy(cunits,"C");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cunits);
free(cdescription);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)twb,
NULL,
ndims_prs,
dsizes_prs,
TEMPORARY,
NULL,
type_obj_twb
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_omega_W( void )
{
/*
* Input array variables
*/
void *qvp, *tmk, *www, *prs;
double *tmp_qvp = NULL;
double *tmp_tmk = NULL;
double *tmp_www = NULL;
double *tmp_prs = NULL;
int ndims_qvp, ndims_tmk, ndims_www, ndims_prs;
ng_size_t dsizes_qvp[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_tmk[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_www[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_prs[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_qvp, type_tmk, type_www, type_prs;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Output variable and attributes.
*/
void *omg;
NclQuark *description, *units;
char *cdescription, *cunits;
double *tmp_omg = NULL;
NclBasicDataTypes type_omg;
NclObjClass type_obj_omg;
/*
* Various
*/
ng_size_t i, nx, ny, nz, nxyz, size_leftmost, index_qvp, size_omg;
int inx, iny, inz;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
qvp = (void*)NclGetArgValue(
0,
3,
&ndims_qvp,
dsizes_qvp,
NULL,
NULL,
&type_qvp,
DONT_CARE);
tmk = (void*)NclGetArgValue(
1,
4,
&ndims_tmk,
dsizes_tmk,
NULL,
NULL,
&type_tmk,
DONT_CARE);
www = (void*)NclGetArgValue(
2,
4,
&ndims_www,
dsizes_www,
NULL,
NULL,
&type_www,
DONT_CARE);
prs = (void*)NclGetArgValue(
3,
4,
&ndims_prs,
dsizes_prs,
NULL,
NULL,
&type_prs,
DONT_CARE);
/*
* Error checking. Input variables must be same size.
*/
if(ndims_qvp < 3 || ndims_qvp != ndims_tmk || ndims_qvp != ndims_www ||
ndims_qvp != ndims_prs) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: qvp, tmk, www, and prs must have at least 3 dimensions and have the same number of dimensions as each other");
return(NhlFATAL);
}
for(i = 0; i < ndims_qvp; i++) {
if(dsizes_qvp[i] != dsizes_tmk[i] || dsizes_qvp[i] != dsizes_prs[i] || dsizes_qvp[i] != dsizes_www[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: qvp, tmk, www, and prs must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Test dimension sizes.
*/
nz = dsizes_qvp[ndims_qvp-1];
ny = dsizes_qvp[ndims_qvp-2];
nx = dsizes_qvp[ndims_qvp-3];
if(nx > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: nx = %ld is greater than INT_MAX", nx);
return(NhlFATAL);
}
if(ny > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: ny = %ld is greater than INT_MAX", ny);
return(NhlFATAL);
}
if(nz > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: nz = %ld is greater than INT_MAX", nz);
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
/*
* Retrieve dimension names from the "tmk" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(1,3,ndims_tmk,dsizes_tmk);
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_qvp-3; i++) size_leftmost *= dsizes_qvp[i];
nz = dsizes_qvp[ndims_qvp-1];
ny = dsizes_qvp[ndims_qvp-2];
nx = dsizes_qvp[ndims_qvp-3];
nxyz = nx * ny * nz;
size_omg = size_leftmost * nxyz;
/*
* Allocate space for coercing input arrays. If the input qvp, tmk,
* www, prs are already double, then we don't need to allocate space
* for temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the input arrays
* are double.
*/
type_omg = NCL_float;
type_obj_omg = nclTypefloatClass;
if(type_qvp != NCL_double) {
tmp_qvp = (double *)calloc(nxyz,sizeof(double));
if(tmp_qvp == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: Unable to allocate memory for coercing 'qvp' to double");
return(NhlFATAL);
}
}
else {
type_omg = NCL_double;
type_obj_omg = nclTypedoubleClass;
}
if(type_tmk != NCL_double) {
tmp_tmk = (double *)calloc(nxyz,sizeof(double));
if(tmp_tmk == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: Unable to allocate memory for coercing 'tmk' to double");
return(NhlFATAL);
}
}
else {
type_omg = NCL_double;
type_obj_omg = nclTypedoubleClass;
}
if(type_www != NCL_double) {
tmp_www = (double *)calloc(nxyz,sizeof(double));
if(tmp_www == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: Unable to allocate memory for coercing 'www' to double");
return(NhlFATAL);
}
}
else {
type_omg = NCL_double;
type_obj_omg = nclTypedoubleClass;
}
if(type_prs != NCL_double) {
tmp_prs = (double *)calloc(nxyz,sizeof(double));
if(tmp_prs == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: Unable to allocate memory for coercing 'prs' array to double");
return(NhlFATAL);
}
}
else {
type_omg = NCL_double;
type_obj_omg = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
if(type_omg == NCL_double) {
omg = (double *)calloc(size_omg,sizeof(double));
if(omg == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
omg = (float *)calloc(size_omg,sizeof(float));
tmp_omg = (double *)calloc(nxyz,sizeof(double));
if(tmp_omg == NULL || omg == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_omega: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* three-dimensional subsection.
*/
index_qvp = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of qvp (tmp_qvp) to double if ncessary.
*/
if(type_qvp != NCL_double) {
coerce_subset_input_double(qvp,tmp_qvp,index_qvp,type_qvp,
nxyz,0,NULL,NULL);
}
else {
tmp_qvp = &((double*)qvp)[index_qvp];
}
/*
* Coerce subsection of tmk (tmp_tmk) to double if ncessary.
*/
if(type_tmk != NCL_double) {
coerce_subset_input_double(tmk,tmp_tmk,index_qvp,type_tmk,
nxyz,0,NULL,NULL);
}
else {
tmp_tmk = &((double*)tmk)[index_qvp];
}
/*
* Coerce subsection of www (tmp_www) to double if ncessary.
*/
if(type_www != NCL_double) {
coerce_subset_input_double(www,tmp_www,index_qvp,type_www,
nxyz,0,NULL,NULL);
}
else {
tmp_www = &((double*)www)[index_qvp];
}
/*
* Coerce subsection of p (tmp_prs) to double if necessary.
*/
if(type_prs != NCL_double) {
coerce_subset_input_double(prs,tmp_prs,index_qvp,type_prs,
nxyz,0,NULL,NULL);
}
else {
tmp_prs = &((double*)prs)[index_qvp];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_omg == NCL_double) tmp_omg = &((double*)omg)[index_qvp];
/*
* Call Fortran routine.
*/
NGCALLF(omgcalc,OMGCALC)(tmp_qvp,tmp_tmk,tmp_www,tmp_prs,tmp_omg,
&inx,&iny,&inz);
/*
* Coerce output back to float if necessary.
*/
if(type_omg == NCL_float) {
coerce_output_float_only(omg,tmp_omg,nxyz,index_qvp);
}
index_qvp += nxyz; /* Increment index */
}
/*
* Free up memory.
*/
if(type_qvp != NCL_double) NclFree(tmp_qvp);
if(type_tmk != NCL_double) NclFree(tmp_tmk);
if(type_www != NCL_double) NclFree(tmp_www);
if(type_prs != NCL_double) NclFree(tmp_prs);
if(type_omg != NCL_double) NclFree(tmp_omg);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(6,sizeof(char));
strcpy(cdescription,"Omega");
cunits = (char *)calloc(5,sizeof(char));
strcpy(cunits,"Pa/s");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cunits);
free(cdescription);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)omg,
NULL,
ndims_qvp,
dsizes_qvp,
TEMPORARY,
NULL,
type_obj_omg
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
NhlErrorTypes wrf_virtual_temp_W( void )
{
/*
* Input array variables
*/
void *temp, *ratmx;
double *tmp_temp = NULL;
double *tmp_ratmx = NULL;
int ndims_temp, ndims_ratmx;
ng_size_t dsizes_temp[NCL_MAX_DIMENSIONS];
ng_size_t dsizes_ratmx[NCL_MAX_DIMENSIONS];
NclBasicDataTypes type_temp, type_ratmx;
/*
* Variable for getting/setting dimension name info.
*/
NclDimRec *dim_info;
/*
* Output variable and attributes.
*/
void *tv;
NclQuark *description, *units;
char *cdescription, *cunits;
double *tmp_tv = NULL;
NclBasicDataTypes type_tv;
NclObjClass type_obj_tv;
/*
* Various
*/
ng_size_t i, nx, ny, nz, nxyz, size_leftmost, index_temp, size_tv;
int inx, iny, inz;
/*
* Variables for returning the output array with attributes attached.
*/
int att_id;
ng_size_t dsizes[1];
NclMultiDValData att_md, return_md;
NclVar tmp_var;
NclStackEntry return_data;
/*
* Retrieve parameters.
*
* Note any of the pointer parameters can be set to NULL, which
* implies you don't care about its value.
*/
temp = (void*)NclGetArgValue(
0,
2,
&ndims_temp,
dsizes_temp,
NULL,
NULL,
&type_temp,
DONT_CARE);
ratmx = (void*)NclGetArgValue(
1,
2,
&ndims_ratmx,
dsizes_ratmx,
NULL,
NULL,
&type_ratmx,
DONT_CARE);
/*
* Error checking. Input variables must be same size.
*/
if(ndims_temp < 3 || ndims_temp != ndims_ratmx) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: The temp and ratmx arrays must have at least 3 dimensions and have the same number of dimensions as each other");
return(NhlFATAL);
}
for(i = 0; i < ndims_temp; i++) {
if(dsizes_temp[i] != dsizes_ratmx[i]) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: temp and ratmx must be the same dimensionality");
return(NhlFATAL);
}
}
/*
* Test dimension sizes.
*/
nx = dsizes_temp[ndims_temp-1];
ny = dsizes_temp[ndims_temp-2];
nz = dsizes_temp[ndims_temp-3];
if(nx > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: nx = %ld is greater than INT_MAX", nx);
return(NhlFATAL);
}
if(ny > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: ny = %ld is greater than INT_MAX", ny);
return(NhlFATAL);
}
if(nz > INT_MAX) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: nz = %ld is greater than INT_MAX", nz);
return(NhlFATAL);
}
inx = (int) nx;
iny = (int) ny;
inz = (int) nz;
/*
* Retrieve dimension names from the "temp" variable, if any.
* These dimension names will later be attached to the output variable.
*/
dim_info = get_wrf_dim_info(1,3,ndims_temp,dsizes_temp);
/*
* Calculate size of leftmost dimensions.
*/
size_leftmost = 1;
for(i = 0; i < ndims_temp-3; i++) size_leftmost *= dsizes_temp[i];
nxyz = nx * ny * nz;
size_tv = size_leftmost * nxyz;
/*
* Allocate space for coercing input arrays. If the input temp
* or ratmx are already double, then we don't need to allocate space
* for temporary arrays, because we'll just change the pointer into
* the void array appropriately.
*
* The output type defaults to float, unless any of the input arrays
* are double.
*/
type_tv = NCL_float;
type_obj_tv = nclTypefloatClass;
if(type_temp != NCL_double) {
tmp_temp = (double *)calloc(nxyz,sizeof(double));
if(tmp_temp == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: Unable to allocate memory for coercing 'temp' to double");
return(NhlFATAL);
}
}
else {
type_tv = NCL_double;
type_obj_tv = nclTypedoubleClass;
}
if(type_ratmx != NCL_double) {
tmp_ratmx = (double *)calloc(nxyz,sizeof(double));
if(tmp_ratmx == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: Unable to allocate memory for coercing 'ratmx' to double");
return(NhlFATAL);
}
}
else {
type_tv = NCL_double;
type_obj_tv = nclTypedoubleClass;
}
/*
* Allocate space for output array.
*/
if(type_tv == NCL_double) {
tv = (double *)calloc(size_tv,sizeof(double));
if(tv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
else {
tv = (float *)calloc(size_tv,sizeof(float));
tmp_tv = (double *)calloc(nxyz,sizeof(double));
if(tmp_tv == NULL || tv == NULL) {
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_virtual_temp: Unable to allocate memory for output array");
return(NhlFATAL);
}
}
/*
* Loop across leftmost dimensions and call the Fortran routine for each
* three-dimensional subsection.
*/
index_temp = 0;
for(i = 0; i < size_leftmost; i++) {
/*
* Coerce subsection of temp (tmp_temp) to double if ncessary.
*/
if(type_temp != NCL_double) {
coerce_subset_input_double(temp,tmp_temp,index_temp,type_temp,
nxyz,0,NULL,NULL);
}
else {
tmp_temp = &((double*)temp)[index_temp];
}
/*
* Coerce subsection of ratmx (tmp_ratmx) to double if ncessary.
*/
if(type_ratmx != NCL_double) {
coerce_subset_input_double(ratmx,tmp_ratmx,index_temp,type_ratmx,
nxyz,0,NULL,NULL);
}
else {
tmp_ratmx = &((double*)ratmx)[index_temp];
}
/*
* Point temporary output array to void output array if appropriate.
*/
if(type_tv == NCL_double) tmp_tv = &((double*)tv)[index_temp];
/*
* Call Fortran routine.
*/
NGCALLF(virtual_temp,VIRTUAL_TEMP)(tmp_temp,tmp_ratmx,tmp_tv,
&inx,&iny,&inz);
/*
* Coerce output back to float if necessary.
*/
if(type_tv == NCL_float) {
coerce_output_float_only(tv,tmp_tv,nxyz,index_temp);
}
index_temp += nxyz; /* Increment index */
}
/*
* Free up memory.
*/
if(type_temp != NCL_double) NclFree(tmp_temp);
if(type_ratmx != NCL_double) NclFree(tmp_ratmx);
if(type_tv != NCL_double) NclFree(tmp_tv);
/*
* Set up some attributes ("description" and "units") to return.
*/
cdescription = (char *)calloc(20,sizeof(char));
strcpy(cdescription,"Virtual Temperature");
cunits = (char *)calloc(2,sizeof(char));
strcpy(cunits,"K");
description = (NclQuark*)NclMalloc(sizeof(NclQuark));
units = (NclQuark*)NclMalloc(sizeof(NclQuark));
*description = NrmStringToQuark(cdescription);
*units = NrmStringToQuark(cunits);
free(cunits);
free(cdescription);
/*
* Set up return value.
*/
return_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)tv,
NULL,
ndims_temp,
dsizes_temp,
TEMPORARY,
NULL,
type_obj_tv
);
/*
* Set up attributes to return.
*/
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL);
dsizes[0] = 1;
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)description,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"description",
att_md,
NULL
);
att_md = _NclCreateVal(
NULL,
NULL,
Ncl_MultiDValData,
0,
(void*)units,
NULL,
1,
dsizes,
TEMPORARY,
NULL,
(NclObjClass)nclTypestringClass
);
_NclAddAtt(
att_id,
"units",
att_md,
NULL
);
tmp_var = _NclVarCreate(
NULL,
NULL,
Ncl_Var,
0,
NULL,
return_md,
dim_info,
att_id,
NULL,
RETURNVAR,
NULL,
TEMPORARY
);
NclFree(dim_info);
/*
* Return output grid and attributes to NCL.
*/
return_data.kind = NclStk_VAR;
return_data.u.data_var = tmp_var;
_NclPlaceReturn(return_data);
return(NhlNOERROR);
}
/*
* This routine gets the path to the psadilookup.dat file
* required by some WRF routines.
*
* The default is to use $NCARG_ROOT/lib/ncarg/data/asc/psadilookup.dat
* for the input data file, unless PSADILOOKUP_PATH is set by the
* user, then it will try to use this path.
*/
char *get_psa_file()
{
const char *path = NULL;
char *psa_file;
int path_len;
path = getenv("PSADILOOKUP_PATH");
if ((void *)path == (void *)NULL) {
path = _NGGetNCARGEnv("data");
if ((void *)path != (void *)NULL) {
path_len = strlen(path) + 21; /* 21 = "/asc/psadilookup.dat\0" */
psa_file = malloc(path_len*sizeof(char));
strcpy(psa_file,path);
strcat(psa_file,_NhlPATHDELIMITER);
strcat(psa_file,"asc");
}
}
else {
strcpy(psa_file,path);
path_len = strlen(path) + 17; /* 17 = "/psadilookup.dat\0" */
psa_file = malloc(path_len*sizeof(char));
}
strcat(psa_file,_NhlPATHDELIMITER);
strcat(psa_file,"psadilookup.dat");
strcat(psa_file,"\0");
return(psa_file);
}
/*
* This routine sets all values of var < 0 to 0.0. This is
* so you don't have to do this in the NCL script. It's the
* equivalent of:
*
* tmp_var = tmp_var > 0.0
*
*/
void var_zero(double *tmp_var, ng_size_t n)
{
ng_size_t i;
for(i = 0; i < n; i++) {
if(tmp_var[i] < 0.0) tmp_var[i] = 0.0;
}
}
/* Converts from hPa to Pa. */
void convert_to_hPa(double *pp, ng_size_t np)
{
ng_size_t i;
for(i = 0; i < np; i++) pp[i] *= 0.01;
}
/*
* This procedure flips the given double array in the
* leftmost dimension, given the size of the leftmost
* dimension, and the product of the rightmost two dimensions.
*/
void flip_it(double *tmp_from, double *tmp_to, ng_size_t nz, ng_size_t nynx)
{
ng_size_t i, index_from, index_to, size_copy;
size_copy = nynx*sizeof(double);
for(i = 0; i < nz; i++) {
index_from = (i * nynx) * sizeof(double);
index_to = ((nz-1-i) * nynx) * sizeof(double);
(void *)memcpy((void*)((char*)tmp_to) + index_to,
(void*)((char*)tmp_from) + index_from,size_copy);
}
}