/* compute first and (optionally) second derivative at particular abscissa, using numerical approximations to derivatives if necessary. Allows for bounds. For use in one-dimensional optimizers. Set deriv2 == NULL to skip second derivative. Note: function value fx is only used in the numerical case (avoids a redundant function evaluation) */ void opt_derivs_1d(double *deriv, double *deriv2, double x, double fx, double lb, double ub, double (*f)(double, void*), void *data, double (*compute_deriv)(double x, void *data, double lb, double ub), double (*compute_deriv2)(double x, void *data, double lb, double ub), double deriv_epsilon) { double fxeps=-1.0, fx2eps=-1.0; int at_ub = (ub - x < BOUNDARY_EPS2); /* at upper bound */ if (compute_deriv == NULL) { if (at_ub) { /* use backward method if at upper bound */ fxeps = f(x - deriv_epsilon, data); *deriv = (fx - fxeps) / deriv_epsilon; } else { fxeps = f(x + deriv_epsilon, data); *deriv = (fxeps - fx) / deriv_epsilon; } } else *deriv = compute_deriv(x, data, lb, ub); if (deriv2 == NULL) return; if (compute_deriv2 == NULL) { /* numerical 2nd deriv */ if (at_ub) { /* at upper bound */ if (compute_deriv != NULL) /* exact 1d available */ *deriv2 = (*deriv - compute_deriv(x - deriv_epsilon, data, lb, ub)) / deriv_epsilon; else { /* numerical 1st and second derivs */ fx2eps = f(x - 2*deriv_epsilon, data); *deriv2 = (fx2eps + 2*fxeps - fx) / (deriv_epsilon * deriv_epsilon); } } else { /* not at upper bound */ if (compute_deriv != NULL) /* exact 1d available */ *deriv2 = (compute_deriv(x + deriv_epsilon, data, lb, ub) - *deriv) / deriv_epsilon; else { /* numerical 1st and second derivs */ fx2eps = f(x + 2*deriv_epsilon, data); *deriv2 = (fx2eps - 2*fxeps + fx) / (deriv_epsilon * deriv_epsilon); } } } else /* exact 2nd deriv */ *deriv2 = compute_deriv2(x, data, lb, ub); }
int TTVFast(double *params,double dt, double Time, double total,int n_plan,CalcTransit *transit,CalcRV *RV_struct, int nRV, int n_events, int input_flag) { n_planets=n_plan; int planet; int i, j; j=0; void jacobi_heliocentric(PhaseState *jacobi, PhaseState *helio, double GMsun, double *GM); double dot0,dot1,dot2,rskyA,rskyB,vprojA,vprojB,rsky,vproj,velocity,new_dt; double compute_RV(PhaseState *ps); double compute_deriv(PhaseState ps,int planet); int RV_count = 0; int k=0; double deriv; double dt2 = dt/2.0; if(RV_struct !=NULL){ RV_count = nRV; } machine_epsilon = determine_machine_epsilon(); if(input_flag ==0){ read_jacobi_planet_elements(params); } if(input_flag ==1){ read_helio_planet_elements(params); } if(input_flag ==2){ read_helio_cartesian_params(params); } if(input_flag !=0 && input_flag !=1 && input_flag !=2){ printf("Input flag must be 0,1, or 2. \n"); //exit(-1); return FAILURE; } copy_system(p, rp); compute_corrector_coefficientsTO(dt); real_to_mapTO(rp, p); for(i = 0;i<n_planets;i++){ prev_dot[i] = p[i].x*p[i].xd+p[i].y*p[i].yd; count[i]=0; } if (A(p, dt2) != SUCCESS) return FAILURE; while(Time < total){ copy_system(p, p_tmp); B(p,dt); if( A(p,dt) != SUCCESS) return FAILURE; Time+=dt; /* Calculate RV if necessary */ if(j <RV_count){ RVTime = Time+dt2; if(RVTime>(RV_struct+j)->time && RVTime-dt<(RV_struct+j)->time){ if(RVTime-(RV_struct+j)->time > (RV_struct+j)->time-(RVTime-dt)){ copy_system(p_tmp,p_RV); new_dt= (RV_struct+j)->time-(RVTime-dt); if( A(p,dt) != SUCCESS) return FAILURE; velocity = compute_RV(p_RV); (RV_struct+j)->RV =velocity; }else{ copy_system(p,p_RV); new_dt= (RV_struct+j)->time-RVTime; if( A(p,dt) != SUCCESS) return FAILURE; velocity = compute_RV(p_RV); (RV_struct+j)->RV =velocity; } j++; } } /* now look for transits */ for(i = 0;i<n_planets;i++){ /* for each planet */ curr_dot[i] = p[i].x*p[i].xd+p[i].y*p[i].yd; curr_z[i] = p[i].z; tplanet=i; /* Check Transit Condition*/ if(prev_dot[tplanet]<0 && curr_dot[tplanet]>0 && curr_z[tplanet]>0){ bad_transit_flag = 0; copy_system(p,p_ahead); copy_system(p_tmp,p_behind); if (A(p_ahead,-dt2) != SUCCESS) return FAILURE ; if (A(p_behind,-dt2) !=SUCCESS) return FAILURE ; jacobi_heliocentric(p_behind,helioBehind,GMsun,GM); jacobi_heliocentric(p_ahead,helioAhead,GMsun,GM); /* Calculate Rsky.Vsky */ dot2 = helioAhead[tplanet].x*helioAhead[tplanet].xd+helioAhead[tplanet].y*helioAhead[tplanet].yd; dot1 = helioBehind[tplanet].x*helioBehind[tplanet].xd+helioBehind[tplanet].y*helioBehind[tplanet].yd; if(dot1 < 0 && dot2 >0){ /* If Rsky.Vsky passed through zero*/ TimeA=Time; TimeB = Time-dt; dotA= TimeA+kepler_transit_locator(kc_helio[tplanet],-dt,&helioAhead[tplanet],&temporary); deriv = compute_deriv(temporary,tplanet); if(deriv < 0.0 || temporary.z <0.0 || dotA < TimeB-PI/mm[tplanet] || dotA > TimeA+PI/mm[tplanet]){ /* was the right root found?*/ dotA= TimeA+bisection(kc_helio[tplanet],&helioAhead[tplanet],&helioBehind[tplanet],&temporary); } rskyA = sqrt(temporary.x*temporary.x + temporary.y*temporary.y); vprojA = sqrt(temporary.xd*temporary.xd + temporary.yd*temporary.yd); dotB= TimeB+kepler_transit_locator(kc_helio[tplanet],dt,&helioBehind[tplanet],&temporary); deriv = compute_deriv(temporary,tplanet); if(deriv < 0.0 || temporary.z <0.0 || dotB < TimeB-PI/mm[tplanet] || dotB > TimeA+PI/mm[tplanet]){ /* was the right root found?*/ dotB= TimeB+bisection(kc_helio[tplanet],&helioBehind[tplanet],&helioAhead[tplanet],&temporary); } rskyB = sqrt(temporary.x*temporary.x + temporary.y*temporary.y); vprojB = sqrt(temporary.xd*temporary.xd + temporary.yd*temporary.yd); tdot_result = ((dotB-TimeB)*dotA+(TimeA-dotA)*dotB)/(TimeA-TimeB-dotA+dotB); rsky = ((dotB-TimeB)*rskyA+(TimeA-dotA)*rskyB)/(TimeA-TimeB-dotA+dotB); vproj = ((dotB-TimeB)*vprojA+(TimeA-dotA)*vprojB)/(TimeA-TimeB-dotA+dotB); }else{ copy_system(helioAhead,helioBehind); copy_system(p,p_ahead); B(p_ahead,dt); if (A(p_ahead,dt2) != SUCCESS) return FAILURE; TimeA=Time+dt; TimeB = Time; jacobi_heliocentric(p_ahead,helioAhead,GMsun,GM); dotB= TimeB+kepler_transit_locator(kc_helio[tplanet],dt,&helioBehind[tplanet],&temporary); deriv = compute_deriv(temporary,tplanet); if(deriv < 0.0 || temporary.z <0.0 || dotB < TimeB-PI/mm[tplanet] || dotB > TimeA+PI/mm[tplanet]){ /* was the right root found?*/ dotB= TimeB+bisection(kc_helio[tplanet],&helioBehind[tplanet],&helioAhead[tplanet],&temporary); } rskyB = sqrt(temporary.x*temporary.x + temporary.y*temporary.y); vprojB = sqrt(temporary.xd*temporary.xd + temporary.yd*temporary.yd); dotA= TimeA+kepler_transit_locator(kc_helio[tplanet],-dt,&helioAhead[tplanet],&temporary); deriv = compute_deriv(temporary,tplanet); if(deriv < 0.0 || temporary.z <0.0 || dotA < TimeB-PI/mm[tplanet] || dotA > TimeA+PI/mm[tplanet]){ /* was the right root found?*/ dotA= TimeA+bisection(kc_helio[tplanet],&helioAhead[tplanet],&helioBehind[tplanet],&temporary); } rskyA = sqrt(temporary.x*temporary.x + temporary.y*temporary.y); vprojA = sqrt(temporary.xd*temporary.xd + temporary.yd*temporary.yd); tdot_result = ((dotB-TimeB)*dotA+(TimeA-dotA)*dotB)/(TimeA-TimeB-dotA+dotB); rsky = ((dotB-TimeB)*rskyA+(TimeA-dotA)*rskyB)/(TimeA-TimeB-dotA+dotB); vproj = ((dotB-TimeB)*vprojA+(TimeA-dotA)*vprojB)/(TimeA-TimeB-dotA+dotB); } if(k< n_events){ if(bad_transit_flag ==0){ (transit+k)->planet = tplanet; (transit+k)->epoch = count[tplanet]; (transit+k)->time = tdot_result; (transit+k)->rsky = rsky; (transit+k)->vsky = vproj; }else{ (transit+k)->planet = tplanet; (transit+k)->epoch = count[tplanet]; (transit+k)->time = BAD_TRANSIT; (transit+k)->rsky = BAD_TRANSIT; (transit+k)->vsky = BAD_TRANSIT; } count[tplanet]++; k++; }else{ printf("Not enough memory allocated for Transit structure: more events triggering as transits than expected. Possibily indicative of larger problem.\n"); //exit(-1); return FAILURE; } } prev_dot[i]=curr_dot[i]; } } return SUCCESS; }