/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! !! GNU General Public License !! !! !! !! This file is part of the Flexible Modeling System (FMS). !! !! !! !! FMS is free software; you can redistribute it and/or modify !! !! it and are expected to follow the terms of the GNU General Public !! !! License as published by the Free Software Foundation. !! !! !! !! FMS is distributed in the hope that it will be useful, !! !! but WITHOUT ANY WARRANTY; without even the implied warranty of !! !! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !! !! GNU General Public License for more details. !! !! !! !! You should have received a copy of the GNU General Public License !! !! along with FMS; if not, write to: !! !! Free Software Foundation, Inc. !! !! 59 Temple Place, Suite 330 !! !! Boston, MA 02111-1307 USA !! !! or see: !! !! http://www.gnu.org/licenses/gpl.txt !! !! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ #include #include #include #include #ifdef use_libMPI #include #endif #include "mosaic_util.h" #include "constant.h" #define HPI (0.5*M_PI) #define TPI (2.0*M_PI) #define TOLORENCE (1.e-6) #define EPSLN (1.e-10) /*********************************************************** void error_handler(char *str) error handler: will print out error message and then abort ***********************************************************/ void error_handler(const char *msg) { fprintf(stderr, "FATAL Error: %s\n", msg ); #ifdef use_libMPI MPI_Abort(MPI_COMM_WORLD, -1); #else exit(1); #endif }; /* error_handler */ /********************************************************************* int nearest_index(double value, const double *array, int ia) return index of nearest data point within "array" corresponding to "value". if "value" is outside the domain of "array" then nearest_index = 0 or = size(array)-1 depending on whether array(0) or array(ia-1) is closest to "value" Arguments: value: arbitrary data...same units as elements in "array" array: array of data points (must be monotonically increasing) ia : size of array. ********************************************************************/ int nearest_index(double value, const double *array, int ia) { int index, i; int keep_going; for(i=1; i array[ia-1]) index = ia-1; else { i=0; keep_going = 1; while (i < ia && keep_going) { i = i+1; if (value <= array[i]) { index = i; if (array[i]-value > value-array[i-1]) index = i-1; keep_going = 0; } } } return index; }; /******************************************************************/ void tokenize(const char * const string, const char *tokens, unsigned int varlen, unsigned int maxvar, char * pstring, unsigned int * const nstr) { size_t i, j, nvar, len, ntoken; int found, n; nvar = 0; j = 0; len = strlen(string); ntoken = strlen(tokens); /* here we use the fact that C array [][] is contiguous in memory */ if(string[0] == 0)error_handler("Error from tokenize: to-be-parsed string is empty"); for(i = 0; i < len; i ++){ if(string[i] != ' ' && string[i] != '\t'){ found = 0; for(n=0; n= maxvar) error_handler("Error from tokenize: number of variables exceeds limit"); } } else { *(pstring + nvar*varlen + j++) = string[i]; if(j >= varlen ) error_handler("error from tokenize: variable name length exceeds limit during tokenization"); } } } *(pstring + nvar*varlen + j) = 0; *nstr = ++nvar; } /******************************************************************************* double maxval_double(int size, double *data) get the maximum value of double array *******************************************************************************/ double maxval_double(int size, const double *data) { int n; double maxval; maxval = data[0]; for(n=1; n maxval ) maxval = data[n]; } return maxval; }; /* maxval_double */ /******************************************************************************* double minval_double(int size, double *data) get the minimum value of double array *******************************************************************************/ double minval_double(int size, const double *data) { int n; double minval; minval = data[0]; for(n=1; n M_PI) dx = dx - 2.0*M_PI; if(dx < -M_PI) dx = dx + 2.0*M_PI; return (dx*(sin(ur_lat)-sin(ll_lat))*RADIUS*RADIUS ) ; }; /* box_area */ /*------------------------------------------------------------------------------ double poly_area(const x[], const y[], int n) obtains area of input polygon by line integrating -sin(lat)d(lon) Vertex coordinates must be in degrees. Vertices must be listed counter-clockwise around polygon. grid is in radians. ----------------------------------------------------------------------------*/ double poly_area(const double x[], const double y[], int n) { double area = 0.0; int i; for (i=0;i M_PI) dx = dx - 2.0*M_PI; if(dx < -M_PI) dx = dx + 2.0*M_PI; if (dx==0.0) continue; if ( fabs(lat1-lat2) < SMALL_VALUE) /* cheap area calculation along latitude */ area -= dx*sin(0.5*(lat1+lat2)); else { #ifdef fix_truncate dy = 0.5*(lat1-lat2); dat = sin(dy)/dy; area -= dx*sin(0.5*(lat1+lat2))*dat; #else area += dx*(cos(lat1)-cos(lat2))/(lat1-lat2); #endif } } return area*RADIUS*RADIUS; }; /* poly_area */ double poly_area_no_adjust(const double x[], const double y[], int n) { double area = 0.0; int i; for (i=0;i=n_ins;i--) { x[i+1] = x[i]; y[i+1] = y[i]; } x[n_ins] = lon_in; y[n_ins] = lat_in; return (n+1); } /* insert_vtx */ void v_print(double x[], double y[], int n) { int i; for (i=0;i=HPI-TOLORENCE) pole = 1; if (0&&pole) { printf("fixing pole cell\n"); v_print(x, y, nn); printf("---------"); } /* all pole points must be paired */ for (i=0;i=HPI-TOLORENCE) { int im=(i+nn-1)%nn, ip=(i+1)%nn; if (y[im]==y[i] && y[ip]==y[i]) { nn = delete_vtx(x, y, nn, i); i--; } else if (y[im]!=y[i] && y[ip]!=y[i]) { nn = insert_vtx(x, y, nn, i, x[i], y[i]); i++; } } /* first of pole pair has longitude of previous vertex */ /* second of pole pair has longitude of subsequent vertex */ for (i=0;i=HPI-TOLORENCE) { int im=(i+nn-1)%nn, ip=(i+1)%nn; if (y[im]!=y[i]) x[i] = x[im]; if (y[ip]!=y[i]) x[i] = x[ip]; } if (nn) x_sum = x[0]; else return(0); for (i=1;i M_PI) dx = dx - TPI; x_sum += (x[i] = x[i-1] + dx); } dx = (x_sum/nn)-tlon; if (dx < -M_PI) for (i=0;i M_PI) for (i=0;i angle \ \ p2 -----------------------------------------------------------------------------*/ double spherical_angle(const double *v1, const double *v2, const double *v3) { double angle; double px, py, pz, qx, qy, qz, ddd; /* vector product between v1 and v2 */ px = v1[1]*v2[2] - v1[2]*v2[1]; py = v1[2]*v2[0] - v1[0]*v2[2]; pz = v1[0]*v2[1] - v1[1]*v2[0]; /* vector product between v1 and v3 */ qx = v1[1]*v3[2] - v1[2]*v3[1]; qy = v1[2]*v3[0] - v1[0]*v3[2]; qz = v1[0]*v3[1] - v1[1]*v3[0]; /* angle between p and q */ ddd = sqrt( (px*px+py*py+pz*pz)*(qx*qx+qy*qy+qz*qz) ); if (ddd > 0) { angle = acos((px*qx+py*qy+pz*qz)/ddd); } else angle = 0.; return angle; }; /* spherical_angle */ /*------------------------------------------------------------------------------ double spherical_excess_area(p_lL, p_uL, p_lR, p_uR) get the surface area of a cell defined as a quadrilateral on the sphere. Area is computed as the spherical excess [area units are m^2] ----------------------------------------------------------------------------*/ double spherical_excess_area(const double* p_ll, const double* p_ul, const double* p_lr, const double* p_ur, double radius) { double area, ang1, ang2, ang3, ang4; double v1[3], v2[3], v3[3]; /* S-W: 1 */ latlon2xyz(1, p_ll, p_ll+1, v1, v1+1, v1+2); latlon2xyz(1, p_lr, p_lr+1, v2, v2+1, v2+2); latlon2xyz(1, p_ul, p_ul+1, v3, v3+1, v3+2); ang1 = spherical_angle(v1, v2, v3); /* S-E: 2 */ latlon2xyz(1, p_lr, p_lr+1, v1, v1+1, v1+2); latlon2xyz(1, p_ur, p_ur+1, v2, v2+1, v2+2); latlon2xyz(1, p_ll, p_ll+1, v3, v3+1, v3+2); ang2 = spherical_angle(v1, v2, v3); /* N-E: 3 */ latlon2xyz(1, p_ur, p_ur+1, v1, v1+1, v1+2); latlon2xyz(1, p_ul, p_ul+1, v2, v2+1, v2+2); latlon2xyz(1, p_lr, p_lr+1, v3, v3+1, v3+2); ang3 = spherical_angle(v1, v2, v3); /* N-W: 4 */ latlon2xyz(1, p_ul, p_ul+1, v1, v1+1, v1+2); latlon2xyz(1, p_ur, p_ur+1, v2, v2+1, v2+2); latlon2xyz(1, p_ll, p_ll+1, v3, v3+1, v3+2); ang4 = spherical_angle(v1, v2, v3); area = (ang1 + ang2 + ang3 + ang4 - 2.*M_PI) * radius* radius; return area; }; /* spherical_excess_area */ /*---------------------------------------------------------------------- void vect_cross(e, p1, p2) Perform cross products of 3D vectors: e = P1 X P2 -------------------------------------------------------------------*/ void vect_cross(const double *p1, const double *p2, double *e ) { e[0] = p1[1]*p2[2] - p1[2]*p2[1]; e[1] = p1[2]*p2[0] - p1[0]*p2[2]; e[2] = p1[0]*p2[1] - p1[1]*p2[0]; }; /* vect_cross */ /* ---------------------------------------------------------------- make a unit vector --------------------------------------------------------------*/ void normalize_vect(double *e) { double pdot; int k; pdot = e[0]*e[0] + e[1] * e[1] + e[2] * e[2]; pdot = sqrt( pdot ); for(k=0; k<3; k++) e[k] /= pdot; }; /*------------------------------------------------------------------ void unit_vect_latlon(int size, lon, lat, vlon, vlat) calculate unit vector for latlon in cartesian coordinates ---------------------------------------------------------------------*/ void unit_vect_latlon(int size, const double *lon, const double *lat, double *vlon, double *vlat) { double sin_lon, cos_lon, sin_lat, cos_lat; int n; for(n=0; n