/* * ?---p0---p1---p2---p3--- ---pm'---? * | | | | | ... | | * | r0 | r1 | r2 | r3 | ... rm'| rm | * | | | | | ... | | * ?---n0---n1---n2---n3--- ---nm'---? */ void interpolate_line(size_t m, float const *p, float const *n, float *r) { size_t i; r[0] = extrapolate_point(p[0], n[0], p[1], n[1]); r[m] = extrapolate_point(p[m-1], n[m-1], p[m-2], n[m-2]); for (i = 0; i < m-1; i++) { r[i+1] = interpolate_point(p[i], n[i], p[i+1], n[i+1]); } }
// update particle position using 4th order Runge-Kutta method void update_particle_position_rk4( e *E, double* cart_pos, double* vel, double dt, int dim){ int d; double accumPos[DIM_MAX]; // where the pos[] solution vector is accumulated double pos[DIM_MAX]; // position in longitude, latitude double posPred[DIM_MAX]; // position in meters double k1[DIM_MAX]; int whereILive; double fac; fac = 1.0/6.0; for( d=0; d<dim; d++ ) { accumPos[d] = cart_pos[d]; // initial step k1[d] = dt * vel[d]; posPred[d] = cart_pos[d] + 0.5 * k1[d]; accumPos[d] = accumPos[d] + fac * k1[d]; // first step ( + 1/6 k1 ) } // convert posPred back to lon lat so we can call get_owner_element pos[1] = r2d(posPred[1]/R); // calc lat first pos[0] = r2d(posPred[0] / (R*cos(d2r(pos[1])))); // now lon // find out which element containts this position whereILive = get_owner_element(E, pos); // update weights calculate_interpolation_weights(&E->el[whereILive], E->xi, E->eta, pos); // interpolate the nodal velocity to the current point interpolate_point(&E->el[whereILive], vel); /* Reuse k1. Here k1 = k2 */ for( d=0; d<dim; d++ ) { k1[d] = dt * vel[d]; posPred[d] = cart_pos[d] + 0.5 * k1[d]; accumPos[d] = accumPos[d] + 2.0*fac*k1[d]; /* second step ( + 1/3 k2 ) */ } /* Put positions back in posPred */ //for( d=0; d<dim; d++ ) { // posPred[d] = cart_pos[d] + 0.5 * k1[d]; //} // convert cart_pos back to lon lat pos[1] = r2d(posPred[1]/R); // calc lat first pos[0] = r2d(posPred[0] / (R*cos(d2r(pos[1])))); // now lon // find out which element containts this position //printf("\t\t2: posPred[0] = %f, posPred[1] = %f\n", posPred[0], posPred[1]); //printf("\t\t2: pos[0] = %f, pos[1] = %f\n", pos[0], pos[1]); whereILive = get_owner_element(E, pos); calculate_interpolation_weights(&E->el[whereILive], E->xi, E->eta, pos); // interpolate the nodal velocity to the current point interpolate_point(&E->el[whereILive], vel); /* Reuse k1. Here k1 = k3 */ for( d=0; d<dim; d++ ) { k1[d] = dt * vel[d]; posPred[d] = cart_pos[d] + k1[d]; accumPos[d] = accumPos[d] + 2.0*fac*k1[d]; /* third step ( + 1/3 k3 ) */ } /* Put positions back in posPred */ //for( d=0; d<dim; d++ ) { // posPred[d] = cart_pos[d] + k1[d]; //} // convert cart_pos back to lon lat pos[1] = r2d(posPred[1]/R); // calc lat first pos[0] = r2d(posPred[0] / (R*cos(d2r(pos[1])))); // now lon // find out which element containts this position whereILive = get_owner_element(E, pos); calculate_interpolation_weights(&E->el[whereILive], E->xi, E->eta, pos); // interpolate the nodal velocity to the current point interpolate_point(&E->el[whereILive], vel); /* Reuse k1. Here k1 = k4 */ for( d=0; d<dim; d++ ) { k1[d] = dt * vel[d]; accumPos[d] = accumPos[d] + fac*k1[d]; /* fourth step ( + 1/6 k4 ) */ // get new position cart_pos[d] = accumPos[d]; } //printf("done\n"); fflush(stdout); }
void interp_bathy_on_grid(e *E){ int i,j; int el; double pos[2]; //double interp_value; // setup the interpolation source grid data structures E->nx = E->b.nlon-1; //E->nc.x-1; E->ny = E->b.nlat-1; //E->nc.y-1; E->nElements = E->nx*E->ny ; E->ele = malloc(E->nElements*sizeof(element)); E->nodesPerEl = 4; E->msh.x = malloc((E->nx+1) * sizeof(double)); E->msh.y = malloc((E->ny+1) * sizeof(double)); init_xi_eta(E); el = 0; for(i=0;i<E->ny;i++){ for(j=0;j<E->nx;j++){ // set positions for this element // element node numbering is anti-clockwise E->ele[el].node_coord[0][0] = E->b.lon[j]; E->ele[el].node_coord[0][1] = E->b.lat[i]; // 0 E->ele[el].node_coord[1][0] = E->b.lon[j+1]; E->ele[el].node_coord[1][1] = E->b.lat[i]; // 1 E->ele[el].node_coord[2][0] = E->b.lon[j+1]; E->ele[el].node_coord[2][1] = E->b.lat[i+1]; // 2 E->ele[el].node_coord[3][0] = E->b.lon[j]; E->ele[el].node_coord[3][1] = E->b.lat[i+1]; // 3 // now set the nodal value for this element E->ele[el].node_value[0] = -E->b.field[i][j]; E->ele[el].node_value[1] = -E->b.field[i][j+1]; E->ele[el].node_value[2] = -E->b.field[i+1][j+1]; E->ele[el].node_value[3] = -E->b.field[i+1][j]; el++; } } // the store_mesh call is required for the function get_owner_element store_mesh(E, E->nx, E->ny); //print_elements(E); // for each rho grid point for(i=0;i<E->g.nY;i++){ for(j=0;j<E->g.nX;j++){ // get pos of grid point pos[0] = E->lon_rho[i][j]; pos[1] = E->lat_rho[i][j]; // find out which element this lies within el = get_owner_element(E, pos); calculate_interpolation_weights(&E->ele[el], E->xi, E->eta, pos); interpolate_point(&E->ele[el], &E->h[i][j]); } } }
int main(int argc, char* argv[]) { char* bathyfname = NULL; int nbathy = -1; point* pbathy = NULL; char* gridfname = NULL; NODETYPE nt = NT_DD; gridnodes* gn = NULL; gridmap* gm = NULL; char* maskfname = NULL; int** mask = NULL; int ppe = PPE_DEF; double zmin = ZMIN_DEF; double zmax = ZMAX_DEF; delaunay* d = NULL; void (*interpolate_point) (void*, point *) = NULL; void* interpolator = NULL; int i = -1, j = -1; parse_commandline(argc, argv, &bathyfname, &gridfname, &maskfname, &nt, &ppe, &zmin, &zmax, &i, &j); /* * sanity check */ if (bathyfname == NULL) quit("no input bathymetry data specified"); if (gridfname == NULL) quit("no input grid data specified"); if (ppe <= 0 || ppe > PPE_MAX) quit("number of points per edge specified = %d greater than %d", ppe, PPE_MAX); if (zmin >= zmax) quit("min depth = %.3g > max depth = %.3g", zmin, zmax); if (nt != NT_DD && nt != NT_COR) quit("unsupported node type"); /* * read bathymetry */ points_read(bathyfname, 3, &nbathy, &pbathy); if (gu_verbose) fprintf(stderr, "## %d input bathymetry values", nbathy); if (nbathy < 3) quit("less than 3 input bathymetry values"); /* * read and validate grid */ gn = gridnodes_read(gridfname, nt); gridnodes_validate(gn); /* * read mask */ if (maskfname != NULL) { int nx = gridnodes_getnce1(gn); int ny = gridnodes_getnce2(gn); mask = gu_readmask(maskfname, nx, ny); } /* * transform grid nodes to corner type */ if (nt != NT_COR) { gridnodes* newgn = gridnodes_transform(gn, NT_COR); gridnodes_destroy(gn); gn = newgn; } /* * build the grid map for physical <-> index space conversions */ gm = gridmap_build(gridnodes_getnce1(gn), gridnodes_getnce2(gn), gridnodes_getx(gn), gridnodes_gety(gn)); /* * convert bathymetry to index space if necessary */ if (indexspace) { point* newpbathy = malloc(nbathy * sizeof(point)); int newnbathy = 0; int ii; for (ii = 0; ii < nbathy; ++ii) { point* p = &pbathy[ii]; point* newp = &newpbathy[newnbathy]; double ic, jc; if (gridmap_xy2fij(gm, p->x, p->y, &ic, &jc)) { newp->x = ic; newp->y = jc; newp->z = p->z; newnbathy++; } } free(pbathy); pbathy = newpbathy; nbathy = newnbathy; } /* * create interpolator */ if (rule == CSA) { /* using libcsa */ interpolator = csa_create(); csa_addpoints(interpolator, nbathy, pbathy); csa_calculatespline(interpolator); interpolate_point = (void (*)(void*, point *)) csa_approximatepoint; } else if (rule == AVERAGE) { interpolator = ga_create(gm); ga_addpoints(interpolator, nbathy, pbathy); interpolate_point = (void (*)(void*, point *)) ga_getvalue; ppe = 1; } else { /* using libnn */ /* * triangulate */ if (gu_verbose) { fprintf(stderr, "## triangulating..."); fflush(stdout); } d = delaunay_build(nbathy, pbathy, 0, NULL, 0, NULL); if (gu_verbose) { fprintf(stderr, "done\n"); fflush(stderr); } if (rule == NN_SIBSON || rule == NN_NONSIBSONIAN) { interpolator = nnpi_create(d); if (rule == NN_SIBSON) nn_rule = SIBSON; else nn_rule = NON_SIBSONIAN; interpolate_point = (void (*)(void*, point *)) nnpi_interpolate_point; } else if (rule == LINEAR) { interpolator = lpi_build(d); interpolate_point = (void (*)(void*, point *)) lpi_interpolate_point; } } /* * main cycle -- over grid cells */ { double** gx = gridnodes_getx(gn); int jmin, jmax, imin, imax; if (i < 0) { imin = 0; imax = gridnodes_getnce1(gn) - 1; jmin = 0; jmax = gridnodes_getnce2(gn) - 1; } else { if (gu_verbose) fprintf(stderr, "## calculating depth for cell (%d,%d)\n", i, j); imin = i; imax = i; jmin = j; jmax = j; } for (j = jmin; j <= jmax; ++j) { for (i = imin; i <= imax; ++i) { double sum = 0.0; int count = 0; int ii, jj; if ((mask != NULL && mask[j][i] == 0) || isnan(gx[j][i]) || isnan(gx[j + 1][i + 1]) || isnan(gx[j][i + 1]) || isnan(gx[j + 1][i])) { printf("NaN\n"); continue; } for (ii = 0; ii < ppe; ++ii) { for (jj = 0; jj < ppe; ++jj) { double fi = (double) i + 0.5 / (double) ppe * (1.0 + 2.0 * (double) ii); double fj = (double) j + 0.5 / (double) ppe * (1.0 + 2.0 * (double) jj); point p; if (!indexspace) gridmap_fij2xy(gm, fi, fj, &p.x, &p.y); else { p.x = fi; p.y = fj; } interpolate_point(interpolator, &p); if (isnan(p.z)) continue; else if (p.z < zmin) p.z = zmin; else if (p.z > zmax) p.z = zmax; sum += p.z; count++; } } if (count == 0) printf("NaN\n"); else printf("%.2f\n", sum / (double) count); fflush(stdout); } } } /* * clean up, just because */ if (rule == CSA) csa_destroy(interpolator); else if (rule == AVERAGE) ga_destroy(interpolator); else { if (rule == NN_SIBSON || rule == NN_NONSIBSONIAN) nnpi_destroy(interpolator); else if (rule == LINEAR) lpi_destroy(interpolator); delaunay_destroy(d); } if (mask != NULL) gu_free2d(mask); gridmap_destroy(gm); gridnodes_destroy(gn); free(pbathy); return 0; }