/*
This file is part of EZRide.
Copyright 2007 Dwight Barkley,
Copyright 2010 Vadim Biktashev & Andrew Foulkes.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
This program 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 this program. If not, see .
*/
#include
#include
#include
#include "ezride.h"
/*---------------------------------------------------------------------------*
* These subroutines compute the location of the spiral tips. The tip (x,y) is
* defined implicitly by f1(x,y) = f2(x,y) = 0. The functions f1 and f2 are
* defined at the end of this file and can in principle be almost any
* functions. Currently they are such as to define the tip as the intersection
* of a pair of u,v contours. Newton iterations are used to find the root
* (x,y). Derivatives are determined by finite differencing. The u and v
* fields are approximated (interpolated) with polynomials of order
* N_ORDER. **THE CODE ASSUMES N_ORDER IS ODD.** N_ORDER=3 gives accurate
* results.
*
* Note that each time Find_tips () is called, the entire grid is searched for
* possible tips. This is a bit inefficient if there is only one tip. However
* timing tests show that it takes little time and allows for finding multiple
* tips.
*---------------------------------------------------------------------------*/
#define NORDER 3 /* interpolation order for fields (MUST BE ODD) */
#define DX 0.05 /* finite diff used for computing derivatives */
#define DY 0.05 /* finite diff used for computing derivatives */
#define TOL2 1.e-10 /* tol (squared) for newton convergence */
#define TOOBIG 10. /* max size of eps2 in newton (to prevent blowup) */
#define MXNWT 8 /* max number of newton iterations */
#define PRNT_WARN(verbose,level,message) if(verbose>=level) printf(message);
/*
* Private functions
* ----------------- */
static int Newton (Real *px, Real *py, Real *pth);
static Real Eval_func (Real (*f)(int i, int j), Real x, Real y, int new);
static Real hh (Real x_local, int i);
static Real f1 (int i, int j);
static Real f2 (int i, int j);
static inline double sq(double x) {return x*x;}
/* ========================================================================= */
Real x_tip,y_tip;
/* ========================================================================= */
void Tip_ini (void)
{
int max;
max=nsteps+NX+NY;
tip_x =(Real *) malloc((unsigned)(max)*sizeof(Real));
tip_y =(Real *) malloc((unsigned)(max)*sizeof(Real));
tip_x[0] = 0.;
tip_y[0] = 0.;
ntips = 0;
}
/* ========================================================================= */
void Find_tips (void)
{
Real x,y,theta=0;
Real R, R2;
Real f100, f101, f110, f111, f200, f201, f210, f211;
int i,j,count=0,imin,imax,jmin,jmax;/*,fact;*/
unsigned int uindex, vindex;
Real D2;
imin=2;
imax=NX-1;
jmin=2;
jmax=NY-1;
R=NX2-2;
if ((NY2-2) R2) continue;
}
f100=f1(i,j); f101=f1(i+1,j); f110=f1(i,j+1); f111=f1(i+1,j+1);
uindex=(f100>0.)|((f101>0.)<<1)|((f110>0.)<<2)|((f111>0.)<<3);
if ((uindex != 0) && (uindex != 15)) { /* non-trivial index for u */
f200=f2(i,j); f201=f2(i+1,j); f210=f2(i,j+1); f211=f2(i+1,j+1);
vindex=(f200>0.)|((f201>0.)<<1)|((f210>0.)<<2)|((f211>0.)<<3);
if ((vindex != 0) && (vindex != 15)) { /* non-trivial index for v */
/* Both u and v have non-trivial index. Possible tip. Take initial
guess to be center of this square */
x = (Real)i + 0.5;
y = (Real)j + 0.5;
/* Use Newton iteration to find tip. Do not do this if above guess
is too close to the last computed tip at this time step */
if( (ntips==0) || (count==0) || (sq(x-x_tip)+sq(y-y_tip)>4) ) {
if( Newton(&x, &y, &theta) ) {
x_tip=x;
y_tip=y; /* real grid coords of the tip, for plotting */
XX=i;
YY=j; /* integer grid coordinates of the tip, for the Mover */
X0=grid_h*(x-NX2);
Y0=grid_h*(y-NY2);
TH0 = theta; /* model coords of the tip, for output */
count++; /* number of tips at this time moment */
} /* newton successful */
} /* new tip is not too close */
} /* nontrivial index for v */
} /* nontrivial index for u */
} /* for j */
} /* for i */
if(verbose>=2) printf("number of tips in one field= %d\n", count);
if (count) {
tip_x[ntips]=x_tip;
tip_y[ntips]=y_tip; /* real grid coords of the tip, for plotting */
ntips++; /* number of tips to be plotted */
if (write_tip)
Write_tip_data (X0,Y0,TH0); /* model coords of the tip, for output */
}
}
/* ========================================================================= */
static int Newton (Real *px, Real *py, Real *pth)
{
Real x=*px, y=*py, theta=*pth, f1_val, f2_val, df1dx, df1dy, df2dx, df2dy, jac, nrm2;
int nwt=0, new=1, old=0; /* new & old determine whether new
* interpolating polynomials are
* generated */
while(nwtTOOBIG) return(0);
if(nrm2 MXNWT in Newton()\n");
return(0);
}
/* ========================================================================= */
void tips(Real x_tip, Real y_tip)
{
/* Purpose of this function is so that the allocation *
* of the tips is not wasted, by allocating the tips *
* to the arrays tip_x and tip_y more than once for *
* each time step. tips(c_tip,y_tip) can be called *
* upon only once during a loop. */
tip_x[ntips] = x_tip;
tip_y[ntips] = y_tip;
ntips++;
}
/* ========================================================================= */
Real Eval_func (Real (*f)(int i, int j), Real x, Real y, int new)
{
/* Uses Lagrangian interpolation to find value of function f at point
* (x,y). If new=1, then this is a new (x,y) point and new interpolating
* polynomials are computed. */
static Real x_local, y_local, hx[NORDER+1], hy[NORDER+1];
static int ix_0, iy_0;
Real sum=0.;
int i,j;
if(new) {
/* Generate new polynomials */
ix_0 = (int)x - ((NORDER+1)/2 -1);
iy_0 = (int)y - ((NORDER+1)/2 -1);
x_local = x - ix_0;
y_local = y - iy_0;
for(i=0;i<(NORDER+1);i++) {
hx[i] = hh(x_local,i);
hy[i] = hh(y_local,i);
}
}
/* Test for out of range */
if(ix_0<1||ix_0>NX-NORDER||iy_0<1||iy_0>NY-NORDER) {
PRNT_WARN(verbose,2,"Warning: (x,y) out of range in Eval_func() \n");
return(TOOBIG+1.);
}
/* Interpolate function */
for(i=0;i<(NORDER+1);i++) {
for(j=0;j<(NORDER+1);j++) {
sum += hx[i]*hy[j]*(*f)(ix_0+i,iy_0+j);
}
}
return(sum);
}
/* ========================================================================= */
Real hh (Real x_local, int i)
{
/* Computes the ith Lagrange interpolating polynomial at point x_local. */
Real product=1.;
int j;
for(j=0;j<(NORDER+1);j++)
if(j!=i) product *= (x_local-(Real)j)/(Real)(i-j);
return(product);
}
/* ========================================================================= */
/* Define Functions f1 and f2
*
* Here f1 and f2 are such as to define the spiral
* tip as the intersection of the contours:
* u=Utip and v=Vtip (defined in ezride.c)
* ----------------------------------------------- */
Real f1 (int i, int j)
{
return(U(i,j)-Utip);
}
/* ========================================================================= */
Real f2 (int i, int j)
{
return(V(i,j)-Vtip);
}
/* ========================================================================= */