Esempio n. 1
0
// Draws the first passage time from the propensity function.
// Uses the help routine drawT_f and structure drawT_params for some technical
// reasons related to the way to input a function and parameters required by
// the GSL library.
Real
GreensFunction1DAbsAbs::drawTime (Real rnd) const
{
    THROW_UNLESS( std::invalid_argument, 0.0 <= rnd && rnd < 1.0 );

    const Real a(this->geta());
    const Real sigma(this->getsigma());
    const Real L(this->geta() - this->getsigma());
    const Real r0(this->getr0());
    const Real D(this->getD());
    const Real v(this->getv());
    
    if (D == 0.0 )
    {
	return INFINITY;
    }
    else if ( L < 0.0 || fabs(a-r0) < EPSILON*L || fabs(r0-sigma) > (1.0 - EPSILON)*L )
    {
	// if the domain had zero size
	return 0.0;
    }

    const Real expo(-D/(L*L));
    const Real r0s_L((r0-sigma)/L);
    // some abbreviations for terms appearing in the sums with drift<>0
    const Real sigmav2D(sigma*v/2.0/D);
    const Real av2D(a*v/2.0/D);
    const Real Lv2D(L*v/2.0/D);
    // exponent of the prefactor present in case of v<>0; has to be split because it has a t-dep. and t-indep. part
    const Real vexpo_t(-v*v/4.0/D);
    const Real vexpo_pref(-v*r0/2.0/D);

    // the structure to store the numbers to calculate the numbers for 1-S
    struct drawT_params parameters;
    Real Xn, exponent, prefactor;
    
    Real nPI;
    
    // Construct the coefficients and the terms in the exponent and put them 
    // into the params structure
    int n = 0;
    // a simpler sum has to be computed for the case w/o drift, so distinguish here
    if(v==0)
    {
      do
      {
	  nPI = ((Real)(n+1))*M_PI;	// why n+1 : this loop starts at n=0 (1st index of the arrays), while the sum starts at n=1 !
	  Xn = sin(nPI*r0s_L) * (1.0 - cos(nPI)) / nPI; 
	  exponent = nPI*nPI*expo;
	  
	  // store the coefficients in the structure
	  parameters.Xn[n] = Xn;	
	  // also store the values for the exponent
	  parameters.exponent[n]=exponent;
	  n++;
      }
      // TODO: Modify this later to include a cutoff when changes are small
      while (n<MAX_TERMS);
    }
    else	// case with drift<>0
    {
     do
      {
	  nPI = ((Real)(n+1))*M_PI;	// why n+1 : this loop starts at n=0 (1st index of the arrays), while the sum starts at n=1 !
	  Xn = (exp(sigmav2D) - cos(nPI)*exp(av2D)) * nPI/(Lv2D*Lv2D+nPI*nPI) * sin(nPI*r0s_L);
	  exponent = nPI*nPI*expo + vexpo_t;
	  
	  // store the coefficients in the structure
	  parameters.Xn[n] = Xn;	
	  // also store the values for the exponent
	  parameters.exponent[n]=exponent;
	  n++;
      }
       // TODO: Modify this later to include a cutoff when changes are small
      while (n<MAX_TERMS);
    }

    // the prefactor of the sum is also different in case of drift<>0 :
    if(v==0)	prefactor = 2.0*exp(vexpo_pref);
    else	prefactor = 2.0;
    parameters.prefactor = prefactor;
    
    parameters.rnd = rnd;
    parameters.terms = MAX_TERMS;
    parameters.tscale = this->t_scale;

    gsl_function F;
    F.function = &drawT_f;
    F.params = &parameters;

    // Find a good interval to determine the first passage time in
    const Real dist( std::min(r0-sigma, a-r0) );

    // construct a guess: MSD = sqrt (2*d*D*t)
    Real t_guess( dist * dist / ( 2.0 * D ) );
    // A different guess has to be made in case of nonzero drift to account for the displacement due to it
    // When drifting towards the closest boundary...
    if( ( r0-sigma >= L/2.0 && v > 0.0 ) || ( r0-sigma <= L/2.0 && v < 0.0 ) )	t_guess = sqrt(D*D/(v*v*v*v)+dist*dist/(v*v)) - D/(v*v);
    // When drifting away from the closest boundary...
    if( ( r0-sigma  < L/2.0 && v > 0.0 ) || ( r0-sigma  > L/2.0 && v < 0.0 ) )	t_guess = D/(v*v) - sqrt(D*D/(v*v*v*v)-dist*dist/(v*v));
    
    
    Real value( GSL_FN_EVAL( &F, t_guess ) );
    Real low( t_guess );
    Real high( t_guess );

    if( value < 0.0 )
    {
	// scale the interval around the guess such that the function 
	// straddles if the guess was too low
	do
	{
	    // keep increasing the upper boundary until the 
	    // function straddles
	    high *= 10.0;
	    value = GSL_FN_EVAL( &F, high );

	    if( fabs( high ) >= t_guess * 1e6 )
	    {
		std::cerr << "Couldn't adjust high. F(" << high << ") = "
		          << value << std::endl;
		throw std::exception();
	    }
	}
	while ( value <= 0.0 );
    }
    else
    {
	// if the guess was too high initialize with 2 so the test 
	// below survives the first iteration
	Real value_prev( 2.0 );
	do
	{
	    if( fabs( low ) <= t_guess * 1.0e-6 ||
	        fabs(value-value_prev) < EPSILON*this->t_scale )
	    {
		std::cerr << "Couldn't adjust low. F(" << low << ") = "
		          << value << " t_guess: " << t_guess << " diff: "
		          << (value - value_prev) << " value: " << value
		          << " value_prev: " << value_prev << " t_scale: "
		          << this->t_scale << std::endl;
		return low;
	    }

	    value_prev = value;
	    // keep decreasing the lower boundary until the 
	    // function straddles
	    low *= 0.1;
	    // get the accompanying value
	    value = GSL_FN_EVAL( &F, low );

	}
	while ( value >= 0.0 );
    }

    // find the intersection on the y-axis between the random number and 
    // the function
    // define a new solver type brent
    const gsl_root_fsolver_type* solverType( gsl_root_fsolver_brent );
    // make a new solver instance
    // TODO: incl typecast?
    gsl_root_fsolver* solver( gsl_root_fsolver_alloc( solverType ) );
    const Real t( findRoot( F, solver, low, high, EPSILON*t_scale, EPSILON,
                            "GreensFunction1DAbsAbs::drawTime" ) );

    // return the drawn time
    return t;
}
Esempio n. 2
0
// Draws the first passage time from the survival probability,
// using an assistance function drawT_f that casts the math. function
// into the form needed by the GSL root solver.
Real
GreensFunction1DRadAbs::drawTime (Real rnd) const
{
    THROW_UNLESS( std::invalid_argument, 0.0 <= rnd && rnd < 1.0 );
  
    const Real sigma(this->getsigma());
    const Real a(this->geta());
    const Real L(this->geta()-this->getsigma());
    const Real r0(this->getr0());
    const Real k(this->getk());
    const Real D(this->getD());
    const Real v(this->getv());
    const Real h((this->getk()+this->getv()/2.0)/this->getD());
    

    if ( D == 0.0 || L == INFINITY )
    {
	return INFINITY;
    }

    if ( rnd <= EPSILON || L < 0.0 || fabs(a-r0) < EPSILON*L )
    {
	return 0.0;
    }

    const Real v2D(v/2.0/D);
    const Real exp_av2D(exp(a*v2D));
    const Real exp_sigmav2D(exp(sigma*v2D));
    // exponent of the prefactor present in case of v<>0; has to be split because it has a t-dep. and t-indep. part
    const Real vexpo_t(-v*v/4.0/D);
    const Real vexpo_pref(-v*r0/2.0/D);

    // the structure to store the numbers to calculate the numbers for 1-S
    struct drawT_params parameters;
    // some temporary variables
    double root_n = 0;
    double root_n2, root_n_r0_s, root_n_L, h_root_n;
    double Xn, exponent, prefactor;


    // produce the coefficients and the terms in the exponent and put them
    // in the params structure. This is not very efficient at this point,
    // coefficients should be calculated on demand->TODO
    for (int n=0; n<MAX_TERMS; n++)
    {
	root_n = this->root_n(n+1);	// get the n-th root of tan(root*a)=root/-h (Note: root numbering starts at n=1)
	
	root_n2	    = root_n * root_n;
	root_n_r0_s = root_n * (r0-sigma);
	root_n_L    = root_n * L;
	h_root_n    = h / root_n;
	
	if(v==0)	Xn = (h*sin(root_n_r0_s) + root_n*cos(root_n_r0_s)) / (L*(root_n2+h*h)+h)
			      * ( h_root_n + sin(root_n_L) - h_root_n*cos(root_n_L) ); 
	else		Xn = (h*sin(root_n_r0_s) + root_n*cos(root_n_r0_s)) / (L*(root_n2+h*h)+h)
			      * (exp_sigmav2D*h*k/D - exp_av2D*(root_n2+h*h)*cos(root_n_L)) / (h_root_n * (root_n2 + v2D*v2D)); 
		  
	exponent = -D*root_n2 + vexpo_t;

	// store the coefficients in the structure
	parameters.Xn[n] = Xn;
	// also store the values for the exponent
	parameters.exponent[n] = exponent;
    }
    
    // the prefactor of the sum is also different in case of drift<>0 :
    if(v==0)	prefactor = 2.0;
    else	prefactor = 2.0*exp(vexpo_pref);
    parameters.prefactor  = prefactor;
    
    // store the random number for the probability
    parameters.rnd = rnd;
    // store the number of terms used
    parameters.terms = MAX_TERMS;
    parameters.tscale = this->t_scale;

    // Define the function for the rootfinder
    gsl_function F;
    F.function = &GreensFunction1DRadAbs::drawT_f;
    F.params = &parameters;


    // Find a good interval to determine the first passage time in
    // get the distance to absorbing boundary (disregard rad BC)
    const Real dist(fabs(a-r0));
    //const Real dist( std::min(r0, a-r0));	// for test purposes
    // construct a guess: MSD = sqrt (2*d*D*t)
    Real t_guess( dist * dist / ( 2.0*D ) );
    // A different guess has to be made in case of nonzero drift to account for the displacement due to it
    // TODO: This does not work properly in this case yet, but we don't know why...
    // When drifting towards the closest boundary
    //if( (r0 >= a/2.0 && v > 0.0) || (r0 <= a/2.0 && v < 0.0) )	t_guess = sqrt(D*D/(v*v*v*v)+dist*dist/(v*v)) - D/(v*v);
    // When drifting away from the closest boundary
    //if( ( r0 < a/2.0 && v > 0.0) || ( r0 > a/2.0 && v < 0.0) )	t_guess = D/(v*v) - sqrt(D*D/(v*v*v*v)-dist*dist/(v*v));
    
    Real value( GSL_FN_EVAL( &F, t_guess ) );
    Real low( t_guess );
    Real high( t_guess );


    // scale the interval around the guess such that the function straddles
    if( value < 0.0 )
    {
	// if the guess was too low
	do
	{
	    // keep increasing the upper boundary until the
	    // function straddles
	    high *= 10;
	    value = GSL_FN_EVAL( &F, high );

	    if( fabs( high ) >= t_guess * 1e6 )
	    {
		std::cerr << "GF1DRad: Couldn't adjust high. F("
		          << high << ") = " << value << std::endl;
		throw std::exception();
	    }
	}
	while ( value <= 0.0 );
    }
    else
    {
	// if the guess was too high
	// initialize with 2 so the test below survives the first
	// iteration
	Real value_prev( 2 );
	do
	{
	    if( fabs( low ) <= t_guess * 1e-6 ||
	        fabs(value-value_prev) < EPSILON*1.0 )
	    {
		std::cerr << "GF1DRad: Couldn't adjust low. F(" << low << ") = "
		          << value << " t_guess: " << t_guess << " diff: "
		          << (value - value_prev) << " value: " << value
		          << " value_prev: " << value_prev << " rnd: "
		          << rnd << std::endl;
		return low;
	    }
	    value_prev = value;
	    // keep decreasing the lower boundary until the function straddles
	    low *= 0.1;
	    // get the accompanying value
	    value = GSL_FN_EVAL( &F, low );
	}
	while ( value >= 0.0 );
    }

    // find the intersection on the y-axis between the random number and
    // the function
    
    // define a new solver type brent
    const gsl_root_fsolver_type* solverType( gsl_root_fsolver_brent );
    // make a new solver instance
    // TODO: incl typecast?
    gsl_root_fsolver* solver( gsl_root_fsolver_alloc( solverType ) );
    const Real t( findRoot( F, solver, low, high, t_scale*EPSILON, EPSILON,
                            "GreensFunction1DRadAbs::drawTime" ) );

    // return the drawn time
    return t;
}