Program Listing for File testOrbitSolver.cpp

Return to documentation for file (/home/kpenev/projects/git/poet/poet_src/unit_tests/testEvolve/testOrbitSolver.cpp)

#include "testOrbitSolver.h"

namespace Evolve {

    const double TSTART = 2.0 * MIN_AGE;
    const double zero = 0.0;
    const double one = 1.0;

    const double Mjup_to_Msun = (Core::AstroConst::jupiter_mass
                                 /
                                 Core::AstroConst::solar_mass);

    const double Rjup_to_Rsun = (Core::AstroConst::jupiter_radius
                                 /
                                 Core::AstroConst::solar_radius);

    std::ostream &operator<<(std::ostream &os,
                             RealEvolutionQuantity q)
    {
        switch(q) {
            case SEMIMAJOR :
                os << "SEMIMAJOR"; break;
            case ECCENTRICITY:
                os << "ECCENTRICITY"; break;
            case CONV_INCLINATION:
                os << "CONV_INCLINATION"; break;
            case RAD_INCLINATION:
                os << "RAD_INCLINATION"; break;
            case CONV_PERIAPSIS:
                os << "CONV_PERIAPSIS"; break;
            case RAD_PERIAPSIS:
                os << "RAD_PERIAPSIS"; break;
            case CONV_ANGMOM:
                os << "CONV_ANGMOM"; break;
            case RAD_ANGMOM:
                os << "RAD_ANGMOM"; break;
            case AGE:
                os << "AGE"; break;
            default :
                assert(false);
        }
        return os;
    }


    StellarEvolution::PolynomialEvolutionQuantity nan_func(
        std::valarray<double>(Core::NaN, 2),
        TSTART,
        MAX_AGE
    );

    StellarEvolution::PolynomialEvolutionQuantity zero_func(
        std::valarray<double>(),
        TSTART,
        MAX_AGE
    );

    StellarEvolution::PolynomialEvolutionQuantity one_func(
        std::valarray<double>(1.0, 1),
        TSTART,
        MAX_AGE
    );

    StellarEvolution::PolynomialEvolutionQuantity two_func(
        std::valarray<double>(2.0, 1),
        TSTART,
        MAX_AGE
    );

    StellarEvolution::PolynomialEvolutionQuantity two_hundred_func(
        std::valarray<double>(200.0, 1),
        TSTART,
        MAX_AGE
    );

    void test_OrbitSolver::set_single_component_dissipation(
        double min_frequency,
        double max_frequency,
        double decay_scale,
        double phase_lag
    )
    {
        //phase lag(min_frequency - decay_scale)
        //=
        //phase lag(max_frequency + decay_scale)
        //=
        //suppression_factor * phase_lag
        const double suppression_factor = 0.01;

        std::vector<double> breaks(2);
        breaks[0] = min_frequency;
        breaks[1] = max_frequency;

        std::vector<double> powerlaw_indices(3);
        powerlaw_indices[0] = (
            std::log(suppression_factor)
            /
            std::log(1.0 - decay_scale / min_frequency)
        );
        powerlaw_indices[1] = 0.0;
        powerlaw_indices[2] = (
            std::log(suppression_factor)
            /
            std::log(1.0 + decay_scale / max_frequency)
        );

        BrokenPowerlawPhaseLagZone *zone;

        if(__star) {
            assert(__primary_planet == NULL);
            zone = &(__star->envelope());
        } else {
            assert(__primary_planet);
            zone = &(__primary_planet->zone());
        }

        zone->setup(breaks,
                   std::vector<double>(),
                   powerlaw_indices,
                   std::vector<double>(1, 0.0),
                   phase_lag);
    }

    void test_OrbitSolver::make_single_component_star(
        const StellarEvolution::Interpolator &evolution,
        double wind_strength,
        double wind_sat_freq,
        double coupling_timescale,
        double min_frequency,
        double max_frequency,
        double decay_scale,
        double phase_lag
    )
    {
        __star = new Star::InterpolatedEvolutionStar(1.0,//mass
                                                     0.0,//feh
                                                     wind_strength,
                                                     wind_sat_freq,
                                                     coupling_timescale,
                                                     evolution);
        set_single_component_dissipation(min_frequency,
                                         max_frequency,
                                         decay_scale,
                                         phase_lag);

    }

    void test_OrbitSolver::evolve(double wdisk,
                                  double tdisk,
                                  double initial_a,
                                  const double *initial_Lstar,
                                  double initial_incl,
                                  double secondary_mass,
                                  double tsecondary,
                                  double max_age,
                                  double secondary_radius,
                                  double precision,
                                  double max_step_factor)
    {
        Evolve::DissipatingBody *primary;
       if(__star)
           primary = __star;
       else
           primary = __primary_planet;

        secondary_mass *= Mjup_to_Msun;
        secondary_radius *= Rjup_to_Rsun;

        if(std::isnan(tsecondary)) tsecondary = tdisk;

        Planet::Planet secondary(secondary_mass,
                                 (secondary_mass ? secondary_radius : 0.0));
        secondary.configure(true, //init
                            tsecondary, //age
                            primary->mass(), //mass
                            initial_a, //semimajor
                            0.0, //eccentricity
                            &zero, //spin angmom
                            NULL, //inclination
                            NULL, //periapsis
                            false, //locked surface
                            true, //zero outer inclination
                            true);//zero outer periapsis

        __system = new Evolve::DiskBinarySystem(
            *primary,
            secondary,
            initial_a, //semimajor
            0.0, //eccentricity
            initial_incl, //inclination
            wdisk, //Wdisk
            tdisk, //disk dissipation age
            tsecondary //secondary formation age
        );
        double zeros[] = {0.0, 0.0};
        if(__star) {
            if(tdisk <= TSTART) {
                if(tsecondary <= TSTART) {
                    __system->configure(true, //init
                                        TSTART,
                                        initial_a, //semimajor
                                        0.0, //eccentricity
                                        initial_Lstar, //spin angmom
                                        zeros, //inclination
                                        zeros, //periapsis
                                        Core::BINARY);
                } else {
                    __system->configure(true, //init
                                        TSTART,
                                        Core::NaN, //semimajor
                                        Core::NaN, //eccentricity
                                        initial_Lstar, //spin angmom
                                        zeros, //inclination
                                        zeros, //periapsis
                                        Core::SINGLE);
                }
            } else {
                __system->configure(true, //init
                                    TSTART,
                                    Core::NaN, //semimajor
                                    Core::NaN, //eccentricity
                                    initial_Lstar, //spin angmom
                                    NULL, //inclination
                                    NULL, //periapsis
                                    Core::LOCKED_SURFACE_SPIN);
            }
            __star->detect_saturation();
        } else {
            double initial_inclinations[] = {initial_incl, 0.0, 0.0};
            __system->configure(true, //init
                                tsecondary,
                                initial_a, //semimajor
                                0.0, //eccentricity
                                initial_Lstar, //spin angmom
                                initial_inclinations, //inclination
                                zeros, //periapsis
                                Core::BINARY);
        }
        __solver = new Evolve::OrbitSolver(max_age, precision);
        (*__solver)(*__system,
                    (max_age - __system->age()) * max_step_factor,//time step
                    std::list<double>()); //no required ages
    }

    std::vector< const std::list<double> *> test_OrbitSolver::get_evolution()
        const
    {
        std::vector< const std::list<double> *>
            tabulated_real_quantities(NUM_REAL_QUANTITIES);

            tabulated_real_quantities[AGE] = &(__solver->evolution_ages());

            tabulated_real_quantities[SEMIMAJOR] =
                &(__system->semimajor_evolution());

            tabulated_real_quantities[ECCENTRICITY] =
                &(__system->eccentricity_evolution());

            Evolve::DissipatingZone *primary_envelope;

            if(__star) {
                tabulated_real_quantities[RAD_INCLINATION] =
                    &(__star->core().get_evolution_real(Evolve::INCLINATION));

                tabulated_real_quantities[RAD_PERIAPSIS] =
                    &(__star->core().get_evolution_real(Evolve::PERIAPSIS));

                tabulated_real_quantities[RAD_ANGMOM] = &(
                    __star->core().get_evolution_real(Evolve::ANGULAR_MOMENTUM)
                );
                primary_envelope = &(__star->envelope());
            } else {
                tabulated_real_quantities[RAD_INCLINATION] = NULL;
                tabulated_real_quantities[RAD_PERIAPSIS] = NULL;
                tabulated_real_quantities[RAD_ANGMOM] = NULL;
                primary_envelope = &(__primary_planet->zone());
            }

            tabulated_real_quantities[CONV_INCLINATION] = &(
                primary_envelope->get_evolution_real(Evolve::INCLINATION)
            );

            tabulated_real_quantities[CONV_PERIAPSIS] = &(
                primary_envelope->get_evolution_real(Evolve::PERIAPSIS)
            );

            tabulated_real_quantities[CONV_ANGMOM] = &(
                primary_envelope->get_evolution_real(
                    Evolve::ANGULAR_MOMENTUM
                )
            );
        return tabulated_real_quantities;
    }

    void test_OrbitSolver::test_solution(
        const std::vector< const std::list<double> * > &
            tabulated_real_quantities,
        std::vector<const Core::OneArgumentDiffFunction *>
            expected_real_quantities,
        const ExpectedEvolutionMode<Core::EvolModeType> &expected_evol_mode,
        const ExpectedEvolutionMode<bool> &expected_wind_mode,
        double min_age,
        double max_age,
        bool debug_mode
    )
    {
        const std::list<Core::EvolModeType> &tabulated_modes =
            __solver->mode_evolution();

        const std::list<bool> *tabulated_wind_sat =
            (__star ? &(__star->wind_saturation_evolution()) : NULL);

        unsigned num_ages = tabulated_real_quantities[AGE]->size();

        std::ostringstream msg_start;
        std::ostringstream msg;
        msg.precision(16);
        msg.setf(std::ios_base::scientific);
        msg_start.precision(16);
        msg_start.setf(std::ios_base::scientific);
        msg << msg_start.str()
            << num_ages
            << " tabulated ages, ";
        bool all_same_size = true;

        for(unsigned q = 0; q < AGE; ++q) {
            if(tabulated_real_quantities[q]) {
                msg << tabulated_real_quantities[q]->size()
                    << " tabulated "
                    << static_cast<RealEvolutionQuantity>(q)
                    << ", ";
                all_same_size = (
                    all_same_size
                    &&
                    tabulated_real_quantities[q]->size() == num_ages
                );
            }
        }

        msg << tabulated_modes.size() << " tabulated modes";

        all_same_size = (all_same_size
                         &&
                         tabulated_modes.size() == num_ages);
        if(__star) {
            msg << ", "
                << tabulated_wind_sat->size()
                << " tabulated wind saturations";
            all_same_size = (all_same_size
                             &&
                             tabulated_wind_sat->size() == num_ages);
        }


        if(debug_mode) std::cout << msg.str() << std::endl;
        TEST_ASSERT_MSG(all_same_size, msg.str().c_str());

        msg.str("");
        msg << "Expected age range: " << min_age << " to " << max_age
            << ", actual age range: " << tabulated_real_quantities[AGE]->front()
            << " to " << tabulated_real_quantities[AGE]->back();
        if(debug_mode) std::cout << msg.str() << std::endl;
        TEST_ASSERT_MSG(
            (
                tabulated_real_quantities[AGE]->front() == min_age
                &&
                tabulated_real_quantities[AGE]->back() == max_age
            ),
            msg.str().c_str()
        );

        std::vector< std::list<double>::const_iterator >
            real_tabulated_iter(AGE);
        for(unsigned q = 0; q < AGE; ++q)
            if(tabulated_real_quantities[q])
                real_tabulated_iter[q] = tabulated_real_quantities[q]->begin();
        std::list<Core::EvolModeType>::const_iterator
            tabulated_mode_iter = tabulated_modes.begin();
        std::list<bool>::const_iterator tabulated_wind_sat_iter;
        if(__star)
            tabulated_wind_sat_iter = tabulated_wind_sat->begin();
        double last_checked_age = Core::NaN;

        for(
            std::list<double>::const_iterator
                age_i = tabulated_real_quantities[AGE]->begin();
            age_i != tabulated_real_quantities[AGE]->end();
            ++age_i
        ) {
            std::vector<double> expected_real_values(AGE);
            for(unsigned q = 0; q < AGE; ++q) {
                expected_real_values[q] =
                    (*(expected_real_quantities[q]))(*age_i);
            }
            Core::EvolModeType expected_mode = expected_evol_mode(*age_i);
            bool expected_wind_sat = expected_wind_mode(*age_i);

            std::ostringstream age_msg_start;
            age_msg_start.precision(16);
            age_msg_start.setf(std::ios_base::scientific);
            age_msg_start << msg_start.str()
                          << "age = " << *age_i
                          << ", mode = " << *tabulated_mode_iter;
            if(__star) {
                age_msg_start << ", wind is ";
                if(!(*tabulated_wind_sat_iter)) age_msg_start << " not ";
                age_msg_start << "saturated";
            }
            for(unsigned q = 0; q < AGE; ++q)
                if(tabulated_real_quantities[q])
                    age_msg_start << ", "
                                  << static_cast<RealEvolutionQuantity>(q)
                                  << " = "
                                  << *real_tabulated_iter[q];

            msg.str("");
            msg << age_msg_start.str() << " age is out of range.";
            TEST_ASSERT_MSG(*age_i >= min_age && *age_i <= max_age,
                            msg.str().c_str());

            std::list<double>::const_iterator next_age_i = age_i;
            ++next_age_i;
            bool
                can_skip = (
                    next_age_i != tabulated_real_quantities[AGE]->end()
                    &&
                    std::abs(*next_age_i - *age_i) < 1e-5
                    &&
                    expected_evol_mode.near_break(*age_i)
                    &&
                    expected_evol_mode.near_break(*next_age_i)
                ),
                skipped = (*age_i == last_checked_age);

            msg.str("");
            msg << age_msg_start.str() << ": mode is not "
                << expected_mode << ", but " << *tabulated_mode_iter;

            if(debug_mode) std::cout << msg.str() << std::endl;
            if(!skipped && expected_mode != *tabulated_mode_iter) {
                if(can_skip) skipped = true;
                else TEST_ASSERT_MSG(false, msg.str().c_str());
            }

            if(__star) {
                msg.str("");
                msg << age_msg_start.str() << ": wind is ";
                if(!(*tabulated_wind_sat_iter)) msg << " not ";
                msg << "saturated, but should";
                if(!expected_wind_sat) msg << " not ";
                msg << "be.";
                if(debug_mode) std::cout << msg.str() << std::endl;
                if(!skipped && expected_wind_sat != *tabulated_wind_sat_iter) {
                    if(can_skip) skipped = true;
                    else TEST_ASSERT_MSG(false, msg.str().c_str());
                }
            }
/*            TEST_ASSERT_MSG(
                (
                    skipped
                    ||
                    expected_wind_sat == *tabulated_wind_sat_iter
                    ||
                    expected_wind_mode.near_break(*age_i)
                ),
                msg.str().c_str()
            );*/

            for(unsigned q = 0; q < AGE; ++q) {
                if(!tabulated_real_quantities[q]) continue;
                msg.str("");
                msg << age_msg_start.str() << ": "
                    << static_cast<RealEvolutionQuantity>(q)
                    << " is not "
                    << expected_real_values[q]
                    << " but "
                    << *real_tabulated_iter[q]
                    << ", difference = "
                    << (*real_tabulated_iter[q]) - expected_real_values[q];
                if(debug_mode) std::cout << msg.str() << std::endl;
                if(
                    !skipped
                    &&
                    !check_diff((*real_tabulated_iter[q]),
                                expected_real_values[q],
                                1e-5,
                                0.0)
                ) {
                    if(can_skip) {
                        skipped = true;
                        break;
                    }
                    TEST_ASSERT_MSG(false, msg.str().c_str());
                }
            }
            if(!skipped)
                last_checked_age = *age_i;
            else if(debug_mode)
                std::cerr << "Skipped checks for t = " << *age_i
                          << std::endl;
            for(unsigned q = 0; q < AGE; ++q)
                if(tabulated_real_quantities[q])
                    ++(real_tabulated_iter[q]);
            if(__star)  ++tabulated_wind_sat_iter;
            ++tabulated_mode_iter;
        }
    }

    void test_OrbitSolver::test_no_planet_scenario(
        const StellarEvolution::Interpolator &stellar_evol,
        double *initial_Lstar,
        double windK,
        double wind_sat_freq,
        double core_env_coupling_time,
        std::vector<const Core::OneArgumentDiffFunction *>
            &expected_real_quantities,
        const ExpectedEvolutionMode<bool> &expected_wind_mode,
        double max_age,
        bool debug_mode
    ) {
            ExpectedEvolutionMode<Core::EvolModeType> single_mode,
                                                      binary_mode;
            single_mode.add_break(TSTART, Core::SINGLE);
            binary_mode.add_break(TSTART, Core::BINARY);

            __star = make_const_lag_star(stellar_evol,
                                         windK,
                                         wind_sat_freq,
                                         core_env_coupling_time,
                                         1.0);//phase lag
            evolve(0.0,//Wdisk
                   0.0,//tdisk
                   1.0,//initial semimajor
                   initial_Lstar,
                   0.0,//initial inclination
                   1.0,//planet mass
                   max_age,//planet formation age.
                   max_age);//end evolution age
            expected_real_quantities[SEMIMAJOR] = &nan_func;
            expected_real_quantities[ECCENTRICITY] = &nan_func;
            expected_real_quantities[CONV_INCLINATION] = &zero_func;
            expected_real_quantities[RAD_INCLINATION] = &zero_func;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;

            test_solution(get_evolution(),
                          expected_real_quantities,
                          single_mode,
                          expected_wind_mode,
                          TSTART,
                          max_age,
                          debug_mode);

            if(initial_Lstar[0] == 0) return;

            for(double phase_lag = 0.0; phase_lag < 1.5; phase_lag += 1.0)
                for(
                    double mplanet = 0.0;
                    mplanet < 1.5 - phase_lag;
                    mplanet += 1.0
                ) {
                    delete __star;
                    delete __system;
                    delete __solver;

                    __star = make_const_lag_star(stellar_evol,
                                                 windK,
                                                 wind_sat_freq,
                                                 core_env_coupling_time,
                                                 phase_lag);
                    evolve(0.0,//Wdisk
                           0.0,//tdisk
                           1.0,//initial semimajor
                           initial_Lstar,
                           0.0,//initial inclination
                           mplanet,//planet mass
                           TSTART,//planet formation age.
                           max_age);//end evolution age

                    expected_real_quantities[SEMIMAJOR] = &one_func;
                    expected_real_quantities[ECCENTRICITY] = &zero_func;
                    test_solution(get_evolution(),
                                  expected_real_quantities,
                                  binary_mode,
                                  expected_wind_mode,
                                  TSTART,
                                  max_age,
                                  debug_mode);
                    delete __system;
                    delete __solver;

                    evolve(0.0,//Wdisk
                           0.0,//tdisk
                           200.0,//initial semimajor
                           initial_Lstar,
                           0.0,//initial inclination
                           mplanet,//planet mass
                           TSTART,//planet formation age.
                           max_age);//end evolution age

                    expected_real_quantities[SEMIMAJOR] = &two_hundred_func;
                    test_solution(get_evolution(),
                                  expected_real_quantities,
                                  binary_mode,
                                  expected_wind_mode,
                                  TSTART,
                                  max_age,
                                  debug_mode);

                }
            delete __star;
            __star = NULL;
            delete __system;
            __system = NULL;
            delete __solver;
            __solver = NULL;

    }

    std::vector<const Core::OneArgumentDiffFunction *>
        test_OrbitSolver::calculate_expected_unlocked_evolution(
            double phase_lag,
            double secondary_mass,
            bool decaying
        )
        {
            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);

            double msecondary_si = (secondary_mass
                                    *
                                    Core::AstroConst::jupiter_mass),
                   mprimary_si = Core::AstroConst::solar_mass,
                   alpha = (
                       2.4 * M_PI
                       *
                       std::sqrt(
                           Core::AstroConst::G * (msecondary_si + mprimary_si)
                           /
                           Core::AstroConst::solar_radius
                       )
                       *
                       msecondary_si / mprimary_si
                       *
                       phase_lag * Core::AstroConst::Gyr
                       /
                       Core::AstroConst::solar_radius
                   ),
                   a6p5_offset,
                   a0,
                   Lscale = (
                       -msecondary_si
                       /
                       std::pow(Core::AstroConst::solar_radius, 1.5)
                       *
                       std::sqrt(
                           Core::AstroConst::G
                           /
                           (msecondary_si + Core::AstroConst::solar_mass)
                       )
                       *
                       Core::AstroConst::day
                   );

            if(decaying) {
                a6p5_offset = std::pow(2.0, 6.5) + 6.5 * alpha;
                a0 = std::pow(a6p5_offset, 1.0 / 6.5);
            } else {
                a0 = 2.6;
                a6p5_offset = std::pow(a0, 6.5);
            }

            std::valarray<double> a6p5_poly_coef(2);
            a6p5_poly_coef[0] = a6p5_offset;
            a6p5_poly_coef[1] = (decaying ? -1.0 : 1.0) * 6.5 * alpha;
            StellarEvolution::PolynomialEvolutionQuantity *a6p5_evol = (
                new StellarEvolution::PolynomialEvolutionQuantity(
                    a6p5_poly_coef,
                    TSTART,
                    1.0
                )
            );
            __temp_functions.push_back(a6p5_evol);

            FunctionToPower *sqrta_evol = new FunctionToPower(a6p5_evol, 1.0/13.0);
            __temp_functions.push_back(sqrta_evol);


            ExponentialPlusFunc *Lconv_unscaled = new ExponentialPlusFunc(
                sqrta_evol,
                (decaying ? 0.0 : -1e5) - std::sqrt(a0),
                0
            );
            __temp_functions.push_back(Lconv_unscaled);

            expected_real_quantities[SEMIMAJOR] = new FunctionToPower(
                a6p5_evol,
                1.0 / 6.5
            );
            __temp_functions.push_back(expected_real_quantities[SEMIMAJOR]);

            expected_real_quantities[ECCENTRICITY] = &zero_func;
            expected_real_quantities[CONV_INCLINATION] = &zero_func;
            expected_real_quantities[RAD_INCLINATION] = &zero_func;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] = new ScaledFunction(
                Lconv_unscaled,
                Lscale
            );
            __temp_functions.push_back(expected_real_quantities[CONV_ANGMOM]);
            expected_real_quantities[RAD_ANGMOM] = &zero_func;

            return expected_real_quantities;

        }

    std::vector<const Core::OneArgumentDiffFunction *>
        test_OrbitSolver::calculate_expected_disklocked_to_fast_to_locked(
            double lgQ,
            double tdisk,
            double async,
            double tsync,
            double tend,
            bool include_disk_lock
        )
        {
            const double Q = std::pow(10.0, lgQ),
                         alpha = (
                             -4.5
                             *
                             std::sqrt(
                                 Core::AstroConst::G
                                 /
                                 (
                                     Core::AstroConst::solar_radius
                                     *
                                     Core::AstroConst::solar_mass
                                 )
                             )
                             *
                             Core::AstroConst::jupiter_mass / Q
                             *
                             Core::AstroConst::Gyr
                             /
                             Core::AstroConst::solar_radius
                         ),
                         Lscale = (
                             Core::AstroConst::jupiter_mass
                             /
                             std::pow(Core::AstroConst::solar_radius, 1.5)
                             *
                             std::sqrt(Core::AstroConst::G
                                       /
                                       (
                                           Core::AstroConst::jupiter_mass
                                           +
                                           Core::AstroConst::solar_mass
                                       )
                             )
                             *
                             Core::AstroConst::day
                         ),
                         beta = (
                             std::sqrt(
                                 Core::AstroConst::G
                                 *
                                 (
                                     Core::AstroConst::solar_mass
                                     +
                                     Core::AstroConst::jupiter_mass
                                 )
                             )
                             *
                             Core::AstroConst::day
                             /
                             std::pow(Core::AstroConst::solar_radius, 1.5)
                         ),
                         a6p5_offset = (std::pow(async, 6.5)
                                        -
                                        6.5 * alpha * tsync),
                         a_formation=std::pow(
                             a6p5_offset + 6.5 * alpha * tdisk,
                             1.0 / 6.5
                         ),
                         Ic = (
                             Lscale
                             *
                             (std::sqrt(a_formation) - std::sqrt(async))
                             /
                             (beta * (std::pow(async, -1.5)
                                      -
                                      0.5 * std::pow(a_formation, -1.5)))
                         ),
                         wdisk = 0.5 * beta / std::pow(a_formation, 1.5),
                         wlocked = beta / std::pow(async, 1.5);

            std::valarray<double> a6p5_poly_coef(2);
            a6p5_poly_coef[0] = a6p5_offset;
            a6p5_poly_coef[1] = 6.5 * alpha;
            StellarEvolution::PolynomialEvolutionQuantity
                *a6p5_evol = new StellarEvolution::PolynomialEvolutionQuantity(
                    a6p5_poly_coef,
                    tdisk,
                    tsync
                ),
                *Lconv_disk = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(Ic * wdisk, 1),
                    TSTART,
                    tdisk
                ),
                *Lconv_locked = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(Ic * wlocked, 1),
                    tsync,
                    tend
                ),
                *nan_disk = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(Core::NaN, 2),
                    TSTART,
                    tdisk
                ),
                *a_locked = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(async, 1),
                    tsync,
                    tend
                ),
                *Lrad_evol = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(),
                    TSTART,
                    tend
                ),
                *zero_e = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(),
                    tdisk,
                    tend
                );
            __temp_functions.push_back(a6p5_evol);
            __temp_functions.push_back(Lconv_disk);
            __temp_functions.push_back(Lconv_locked);
            __temp_functions.push_back(nan_disk);
            __temp_functions.push_back(a_locked);
            __temp_functions.push_back(Lrad_evol);
            __temp_functions.push_back(zero_e);

            FunctionToPower *a_fast = new FunctionToPower(a6p5_evol,
                                                          1.0 / 6.5),
                            *sqrta_evol = new FunctionToPower(a6p5_evol,
                                                              1.0 / 13.0);
            __temp_functions.push_back(a_fast);
            __temp_functions.push_back(sqrta_evol);

            ExponentialPlusFunc *Lconv_unscaled = new ExponentialPlusFunc(
                sqrta_evol,
                -Ic * wdisk / Lscale - std::sqrt(a_formation), 0
            );
            __temp_functions.push_back(Lconv_unscaled);

            ScaledFunction *Lconv_fast = new ScaledFunction(Lconv_unscaled,
                                                            -Lscale);
            __temp_functions.push_back(Lconv_fast);

            PiecewiseFunction *a_evol = new PiecewiseFunction,
                              *e_evol = new PiecewiseFunction,
                              *Lconv_evol = new PiecewiseFunction;
            __temp_functions.push_back(a_evol);
            __temp_functions.push_back(e_evol);
            __temp_functions.push_back(Lconv_evol);

            StellarEvolution::PolynomialEvolutionQuantity *zero_quantity;

            if(include_disk_lock) {
                a_evol->add_piece(nan_disk);
                e_evol->add_piece(nan_disk);
                Lconv_evol->add_piece(Lconv_disk);
                zero_quantity = &zero_func;
            } else {
                zero_quantity = zero_e;
            }

            a_evol->add_piece(a_fast);
            a_evol->add_piece(a_locked);

            e_evol->add_piece(zero_e);

            Lconv_evol->add_piece(Lconv_fast);
            Lconv_evol->add_piece(Lconv_locked);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);

            expected_real_quantities[SEMIMAJOR] = a_evol;
            expected_real_quantities[ECCENTRICITY] = e_evol;
            expected_real_quantities[CONV_INCLINATION] = zero_quantity;
            expected_real_quantities[RAD_INCLINATION] = zero_quantity;
            expected_real_quantities[CONV_PERIAPSIS] = zero_quantity;
            expected_real_quantities[RAD_PERIAPSIS] = zero_quantity;
            expected_real_quantities[CONV_ANGMOM] = Lconv_evol;
            expected_real_quantities[RAD_ANGMOM] = zero_quantity;

            return expected_real_quantities;
        }

    std::vector<const Core::OneArgumentDiffFunction *>
        test_OrbitSolver::calculate_expected_polar_1_0(double tdisk,
                                                       double wstar,
                                                       double worb)

        {
            double aorb = std::pow(
                         (
                             Core::AstroConst::G
                             *
                             (
                                 Core::AstroConst::solar_mass
                                 +
                                 Core::AstroConst::jupiter_mass
                             )
                         )
                         /
                         std::pow(
                             worb / Core::AstroConst::day,
                             2
                         ),
                         1.0 / 3.0
                     ) / Core::AstroConst::solar_radius;

            StellarEvolution::PolynomialEvolutionQuantity
                *disk_nan_evol = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(Core::NaN, 1),
                    TSTART,
                    tdisk
                ),
                *fixed_a_evol = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(aorb, 1),
                    tdisk,
                    MAX_AGE
                ),
                *fixed_e_evol = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(),
                    tdisk,
                    MAX_AGE
                ),
                *disk_zero_evol = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(),
                    TSTART,
                    tdisk
                ),
                *halfpi_evol = new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(M_PI / 2.0, 1),
                    tdisk,
                    MAX_AGE
                );
            __temp_functions.push_back(disk_nan_evol);
            __temp_functions.push_back(fixed_a_evol);
            __temp_functions.push_back(fixed_e_evol);
            __temp_functions.push_back(disk_zero_evol);
            __temp_functions.push_back(halfpi_evol);

            PiecewiseFunction *a_evol = new PiecewiseFunction,
                              *e_evol = new PiecewiseFunction,
                              *conv_incl_evol = new PiecewiseFunction,
                              *rad_incl_evol = new PiecewiseFunction;
            __temp_functions.push_back(a_evol);
            __temp_functions.push_back(e_evol);
            __temp_functions.push_back(conv_incl_evol);
            __temp_functions.push_back(rad_incl_evol);

            a_evol->add_piece(disk_nan_evol);
            a_evol->add_piece(fixed_a_evol);

            e_evol->add_piece(disk_nan_evol);
            e_evol->add_piece(fixed_e_evol);

            conv_incl_evol->add_piece(disk_zero_evol);
            conv_incl_evol->add_piece(halfpi_evol);

            rad_incl_evol->add_piece(disk_zero_evol);
            rad_incl_evol->add_piece(halfpi_evol);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);

            expected_real_quantities[SEMIMAJOR] = a_evol;
            expected_real_quantities[ECCENTRICITY] = e_evol;
            expected_real_quantities[CONV_INCLINATION] = conv_incl_evol;
            expected_real_quantities[RAD_INCLINATION] = rad_incl_evol;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] =
                new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(wstar, 1),
                    TSTART,
                    MAX_AGE
                );
            __temp_functions.push_back(
                expected_real_quantities[CONV_ANGMOM]
            );
            expected_real_quantities[RAD_ANGMOM] = &one_func;

            return expected_real_quantities;
        }

    std::vector<const Core::OneArgumentDiffFunction *>
        test_OrbitSolver::calculate_expected_polar_2_0(double tdisk,
                                                       double wstar,
                                                       double worb,
                                                       double phase_lag,
                                                       double &lconv_decay_rate,
                                                       double &semimajor)
        {
            semimajor = std::pow(
                    (
                        Core::AstroConst::G
                        *
                        (
                            Core::AstroConst::solar_mass
                            +
                            Core::AstroConst::jupiter_mass
                        )
                    )
                    /
                    std::pow(
                        worb / Core::AstroConst::day,
                        2
                    ),
                    1.0 / 3.0
                ) / Core::AstroConst::solar_radius;
            lconv_decay_rate = (
                0.3 * M_PI
                *
                (
                    Core::AstroConst::G
                    *
                    std::pow(
                        (
                            Core::AstroConst::jupiter_mass
                            /
                            std::pow(
                                semimajor * Core::AstroConst::solar_radius,
                                3
                            )
                        ),
                        2
                    )
                    *
                    std::pow(Core::AstroConst::solar_radius, 5)
                )
                /
                (
                    Core::AstroConst::solar_mass
                    *
                    std::pow(Core::AstroConst::solar_radius, 2)
                )
                *
                Core::AstroConst::day
                *
                Core::AstroConst::Gyr
                *
                phase_lag
            );
            double lorb = (
                (
                    Core::AstroConst::jupiter_mass
                    /
                    Core::AstroConst::solar_mass
                )
                /
                (
                    1.0
                    +
                    Core::AstroConst::jupiter_mass
                    /
                    Core::AstroConst::solar_mass
                )
                *
                semimajor * semimajor
                *
                worb
            );
            double lconv_offset = lconv_decay_rate * tdisk;

            std::valarray<double> spindown_coef(2);
            spindown_coef[0] = wstar + lconv_decay_rate * tdisk;
            spindown_coef[1] = - lconv_decay_rate;

            std::valarray<double> conv_cosinc_numer_coef(3),
                conv_cosinc_denom_coef(2),
                rad_cosinc_numer_coef(3),
                rad_cosinc_denom_coef(3);
            conv_cosinc_numer_coef[0] = - (
                (2.0 * wstar + lconv_offset) * lconv_offset
            );
            conv_cosinc_numer_coef[1] = 2.0 * wstar * lconv_decay_rate;
            conv_cosinc_numer_coef[2] = -std::pow(lconv_decay_rate, 2);

            conv_cosinc_denom_coef[0] = 2.0 * lorb * (wstar + lconv_offset);
            conv_cosinc_denom_coef[1] = -2.0 * lconv_decay_rate * lorb;

            conv_cosinc_numer_coef[0] += conv_cosinc_denom_coef[0];
            conv_cosinc_numer_coef[1] += conv_cosinc_denom_coef[1];

            rad_cosinc_numer_coef[0] = - 2.0 * lorb * lconv_decay_rate * tdisk;
            rad_cosinc_numer_coef[1] = 2.0 * lorb * lconv_decay_rate;

            rad_cosinc_denom_coef[0] = (2.0 * lorb * lorb
                                        -
                                        2.0 * wstar * lconv_decay_rate * tdisk
                                        -
                                        std::pow(lconv_decay_rate * tdisk, 2));
            rad_cosinc_denom_coef[1] =
                2.0 * lconv_decay_rate * (worb + lconv_decay_rate * tdisk);
            rad_cosinc_denom_coef[2] = - std::pow(lconv_decay_rate, 2);

            rad_cosinc_numer_coef += rad_cosinc_denom_coef;

            StellarEvolution::PolynomialEvolutionQuantity
                *disk_nan_evol =
                new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(Core::NaN, 1),
                    TSTART,
                    tdisk
                ),
                    *fixed_a_evol =
                        new StellarEvolution::PolynomialEvolutionQuantity(
                            std::valarray<double>(semimajor, 1),
                            tdisk,
                            MAX_AGE
                        ),
                    *fixed_e_evol
                        = new StellarEvolution::PolynomialEvolutionQuantity(
                            std::valarray<double>(),
                            tdisk,
                            MAX_AGE
                        ),
                    *disk_cosinc_evol =
                        new StellarEvolution::PolynomialEvolutionQuantity(
                            std::valarray<double>(2.0, 1),
                            TSTART,
                            tdisk
                        ),
                    *conv_cosinc_binary_numer =
                        new StellarEvolution::PolynomialEvolutionQuantity(
                            conv_cosinc_numer_coef,
                            tdisk, MAX_AGE
                        ),
                    *conv_cosinc_binary_denom =
                        new StellarEvolution::PolynomialEvolutionQuantity(
                            conv_cosinc_denom_coef,
                            tdisk,
                            MAX_AGE
                        ),
                    *rad_cosinc_binary_numer =
                        new StellarEvolution::PolynomialEvolutionQuantity(
                            rad_cosinc_numer_coef,
                            tdisk,
                            MAX_AGE
                        ),
                    *rad_cosinc_binary_denom =
                        new StellarEvolution::PolynomialEvolutionQuantity(
                            rad_cosinc_denom_coef,
                            tdisk,
                            MAX_AGE
                        ),
                    *lconv_disk =
                        new StellarEvolution::PolynomialEvolutionQuantity(
                            std::valarray<double>(wstar, 1),
                            TSTART,
                            tdisk
                        ),
                    *lconv_spindown =
                        new StellarEvolution::PolynomialEvolutionQuantity(
                            spindown_coef,
                            tdisk,
                            MAX_AGE
                        );
            __temp_functions.push_back(disk_nan_evol);
            __temp_functions.push_back(fixed_a_evol);
            __temp_functions.push_back(fixed_e_evol);
            __temp_functions.push_back(disk_cosinc_evol);
            __temp_functions.push_back(conv_cosinc_binary_numer);
            __temp_functions.push_back(conv_cosinc_binary_denom);
            __temp_functions.push_back(rad_cosinc_binary_numer);
            __temp_functions.push_back(rad_cosinc_binary_denom);
            __temp_functions.push_back(lconv_disk);
            __temp_functions.push_back(lconv_spindown);

            FunctionRatio *conv_cosinc_binary = new FunctionRatio(
                conv_cosinc_binary_numer,
                conv_cosinc_binary_denom
            );
            __temp_functions.push_back(conv_cosinc_binary);
            FunctionRatio *rad_cosinc_binary = new FunctionRatio(
                rad_cosinc_binary_numer,
                rad_cosinc_binary_denom
            );
            __temp_functions.push_back(rad_cosinc_binary);

            PiecewiseFunction *a_evol = new PiecewiseFunction,
                              *e_evol = new PiecewiseFunction,
                              *conv_cosinc_evol = new PiecewiseFunction,
                              *rad_cosinc_evol = new PiecewiseFunction,
                              *lconv_evol = new PiecewiseFunction;
            __temp_functions.push_back(a_evol);
            __temp_functions.push_back(e_evol);
            __temp_functions.push_back(conv_cosinc_evol);
            __temp_functions.push_back(rad_cosinc_evol);
            __temp_functions.push_back(lconv_evol);

            a_evol->add_piece(disk_nan_evol);
            a_evol->add_piece(fixed_a_evol);

            e_evol->add_piece(disk_nan_evol);
            e_evol->add_piece(fixed_e_evol);

            conv_cosinc_evol->add_piece(disk_cosinc_evol);
            conv_cosinc_evol->add_piece(conv_cosinc_binary);

            rad_cosinc_evol->add_piece(disk_cosinc_evol);
            rad_cosinc_evol->add_piece(rad_cosinc_binary);

            lconv_evol->add_piece(lconv_disk);
            lconv_evol->add_piece(lconv_spindown);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);

            expected_real_quantities[SEMIMAJOR] = a_evol;
            expected_real_quantities[ECCENTRICITY] = e_evol;
            expected_real_quantities[CONV_INCLINATION] = conv_cosinc_evol;
            expected_real_quantities[RAD_INCLINATION] = rad_cosinc_evol;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] = lconv_evol;
            expected_real_quantities[RAD_ANGMOM] = &one_func;

            return expected_real_quantities;
        }

    std::vector<const Core::OneArgumentDiffFunction *>
        test_OrbitSolver::calculate_expected_oblique_m_0(
            unsigned m,
            double tdisk,
            double worb,
            double initial_inc,
            double initial_wstar,
            double phase_lag,
            double &min_wstar
        )
        {
            assert(m == 1 || m == 2);
            double aorb = std::pow(
                    (
                        Core::AstroConst::G
                        *
                        (
                            Core::AstroConst::solar_mass
                            +
                            Core::AstroConst::jupiter_mass
                        )
                    )
                    /
                    std::pow(
                        worb / Core::AstroConst::day,
                        2
                    ),
                    1.0 / 3.0
                ) / Core::AstroConst::solar_radius;
            double lorb = (Mjup_to_Msun
                           /
                           (1.0 + Mjup_to_Msun)
                           *
                           aorb * aorb
                           *
                           worb);

            double ltot = std::sqrt(
                std::pow(initial_wstar, 2)
                +
                2.0 * initial_wstar * lorb * std::cos(initial_inc)
                +
                std::pow(lorb, 2)
            );

            min_wstar = ltot - lorb;

            double linear_quantity_rate = (
                0.6 * M_PI
                *
                (
                    Core::AstroConst::G
                    *
                    std::pow(
                        (
                            Core::AstroConst::jupiter_mass
                            /
                            std::pow(
                                aorb * Core::AstroConst::solar_radius,
                                3
                            )
                        ),
                        2
                    )
                    *
                    std::pow(Core::AstroConst::solar_radius, 5)
                )
                /
                (
                    Core::AstroConst::solar_mass
                    *
                    std::pow(Core::AstroConst::solar_radius, 2)
                )
                *
                Core::AstroConst::day
                *
                Core::AstroConst::Gyr
                *
                phase_lag
            );

            StellarEvolution::PolynomialEvolutionQuantity *disk_nan_evol =
                new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(Core::NaN, 1),
                    TSTART,
                    tdisk
                );
            __temp_functions.push_back(disk_nan_evol);

            StellarEvolution::PolynomialEvolutionQuantity *fixed_a_evol =
                new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(aorb, 1),
                    tdisk,
                    MAX_AGE
                );
            __temp_functions.push_back(fixed_a_evol);

            StellarEvolution::PolynomialEvolutionQuantity *fixed_e_evol =
                new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(),
                    tdisk,
                    MAX_AGE
                );
            __temp_functions.push_back(fixed_e_evol);

            PiecewiseFunction *a_evol = new PiecewiseFunction,
                              *e_evol = new PiecewiseFunction;
            __temp_functions.push_back(a_evol);
            __temp_functions.push_back(e_evol);

            a_evol->add_piece(disk_nan_evol);
            a_evol->add_piece(fixed_a_evol);

            e_evol->add_piece(disk_nan_evol);
            e_evol->add_piece(fixed_e_evol);

            Core::OneArgumentDiffFunction *lconv_evol;
            if(m == 1)
               lconv_evol =
                   new InverseLinearLconvEvolution<Oblique10LinearQuantity>(
                       tdisk,
                       ltot,
                       lorb,
                       initial_wstar,
                       linear_quantity_rate
                   );
            else
                lconv_evol =
                    new InverseLinearLconvEvolution<Oblique20LinearQuantity>(
                        tdisk,
                        ltot,
                        lorb,
                        initial_wstar,
                        linear_quantity_rate / 2.0
                    );
            __temp_functions.push_back(lconv_evol);

            ConservedLEConvObliquityEvolution *conv_obliq_evol =
                new ConservedLEConvObliquityEvolution(*lconv_evol,
                                                      lorb,
                                                      ltot,
                                                      tdisk);
            __temp_functions.push_back(conv_obliq_evol);

            ConservedLERadObliquityEvolution *rad_obliq_evol =
                new ConservedLERadObliquityEvolution(*lconv_evol,
                                                     *conv_obliq_evol,
                                                     lorb,
                                                     tdisk);
            __temp_functions.push_back(rad_obliq_evol);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);
            expected_real_quantities[SEMIMAJOR] = a_evol;
            expected_real_quantities[ECCENTRICITY] = e_evol;
            expected_real_quantities[CONV_INCLINATION] = conv_obliq_evol;
            expected_real_quantities[RAD_INCLINATION] = rad_obliq_evol;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] = lconv_evol;
            expected_real_quantities[RAD_ANGMOM] = &one_func;

            return expected_real_quantities;
        }

    void test_OrbitSolver::test_disk_locked_no_stellar_evolution()
    {
        try {
            StellarEvolution::MockStellarEvolution *no_evol =
                StellarEvolution::make_no_evolution();
            __star = make_const_lag_star(*no_evol,
                                         1.0,
                                         1.0,
                                         1.0);

            ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
            expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);

            ExpectedEvolutionMode<bool> expected_wind_mode;
            expected_wind_mode.add_break(TSTART, false);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);
            expected_real_quantities[SEMIMAJOR] = &nan_func;
            expected_real_quantities[ECCENTRICITY] = &nan_func;
            expected_real_quantities[CONV_INCLINATION] = &zero_func;
            expected_real_quantities[RAD_INCLINATION] = &zero_func;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] = &one_func;
            expected_real_quantities[RAD_ANGMOM] = &one_func;

            evolve(1.0, MAX_AGE, 1.0, &one);
            test_solution(get_evolution(),
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          TSTART,
                          MAX_AGE);

            delete __solver;
            delete __system;

            evolve(1.0, MAX_AGE, 1.0, &zero);
            expected_real_quantities[RAD_ANGMOM] = new ExponentialPlusFunc(
                &one_func,
                -std::exp(TSTART/2.0),
                -0.5
            );
            test_solution(get_evolution(),
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          TSTART,
                          MAX_AGE);

            delete expected_real_quantities[RAD_ANGMOM];
            delete no_evol;
        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")+
                        ex.what()+": "+ex.get_message()).c_str());
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")+
                        ex.what()).c_str());
        }
    }

    void test_OrbitSolver::test_disk_locked_with_stellar_evolution()
    {
        try {
            StellarEvolution::MockStellarEvolution *evol1 =
                StellarEvolution::make_linear_I_evolution();

            __star = make_const_lag_star(*evol1, 1.0, 1.0, 1.0);

            ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
            expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);

            ExpectedEvolutionMode<bool> expected_wind_mode;
            expected_wind_mode.add_break(TSTART, false);

            std::valarray<double> temp_array=std::valarray<double>(1.0, 2);
            temp_array[0] = -1;
            StellarEvolution::PolynomialEvolutionQuantity *temp_poly =
                new StellarEvolution::PolynomialEvolutionQuantity(temp_array,
                                                                  TSTART,
                                                                  MAX_AGE);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);
            expected_real_quantities[SEMIMAJOR] = &nan_func;
            expected_real_quantities[ECCENTRICITY] = &nan_func;
            expected_real_quantities[CONV_INCLINATION] = &zero_func;
            expected_real_quantities[RAD_INCLINATION] = &zero_func;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] =
                new StellarEvolution::PolynomialEvolutionQuantity(
                    std::valarray<double>(1.0, 2),
                    TSTART,
                    MAX_AGE
                );
            expected_real_quantities[RAD_ANGMOM] =
                new ExponentialPlusFunc(temp_poly, 1, -0.5);

            double initial_Lrad = TSTART - 1 + std::exp(-TSTART / 2.0);
            evolve(1.0,
                   MAX_AGE,
                   1.0,
                   &initial_Lrad);
            test_solution(get_evolution(),
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          TSTART,
                          MAX_AGE);

            delete expected_real_quantities[CONV_ANGMOM];
            delete expected_real_quantities[RAD_ANGMOM];
            delete temp_poly;
            delete __solver;
            delete __system;
            delete __star;
            delete evol1;

            std::valarray< std::valarray<double> > Ic_arr(
                std::valarray<double>(1.0, 1),
                2
            );
            Ic_arr[1][0]=-1.0/6.0;
            StellarEvolution::MockStellarEvolution evol2(
                -1,
                std::valarray< std::valarray<double> >(//R
                    std::valarray<double>(1.0, 1),
                    1
                ),
                Ic_arr,                                //Iconv
                std::valarray< std::valarray<double> >(//Irad
                    std::valarray<double>(1.0/6.0, 1),
                    2
                ),
                std::valarray< std::valarray<double> >(//Rcore
                    std::valarray<double>(0.5, 1),
                    1
                ),
                std::valarray< std::valarray<double> >(//Mcore
                    std::valarray<double>(1.0, 1),
                    2
                )
            );

            __star = make_const_lag_star(evol2, 1.0, 1.0, 1.0);

            std::valarray<double> Lc_coef(1.0, 2);
            Lc_coef[1]=-1.0/6.0;
            expected_real_quantities[SEMIMAJOR] = &nan_func;
            expected_real_quantities[ECCENTRICITY] = &nan_func;
            expected_real_quantities[CONV_INCLINATION] = &zero_func;
            expected_real_quantities[RAD_INCLINATION] = &zero_func;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] =
                new StellarEvolution::PolynomialEvolutionQuantity(Lc_coef,
                                                                  TSTART,
                                                                  MAX_AGE);
            expected_real_quantities[RAD_ANGMOM] =
                new StellarEvolution::PolynomialEvolutionQuantity(
                        std::valarray<double>(1.0/6.0, 2),
                        TSTART,
                        MAX_AGE
                );
            initial_Lrad = (TSTART / 2.0 + 1.0) / 6.0;
            evolve(1.0,
                   MAX_AGE,
                   1.0,
                   &initial_Lrad);
            test_solution(get_evolution(),
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          TSTART,
                          MAX_AGE);

            delete expected_real_quantities[CONV_ANGMOM];
            delete expected_real_quantities[RAD_ANGMOM];
        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")
                                    +
                                    ex.what()+": "+ex.get_message()).c_str());
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")
                                    +
                                    ex.what()).c_str());
        }
    }

    void test_OrbitSolver::test_no_planet_evolution()
    {
        try {
            const double rt2 = std::sqrt(2.0);

            StellarEvolution::MockStellarEvolution
                *stellar_evol = StellarEvolution::make_no_evolution();
            double initial_Lstar[] = {0.0, 0.0};

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);
            expected_real_quantities[CONV_ANGMOM] = &zero_func;
            expected_real_quantities[RAD_ANGMOM] = &zero_func;
            ExpectedEvolutionMode<bool> unsat_wind_mode, sat_wind_mode;
            unsat_wind_mode.add_break(TSTART, false);
            sat_wind_mode.add_break(TSTART, true);

            test_no_planet_scenario(*stellar_evol,
                                    initial_Lstar,
                                    1.0,//Wind K
                                    2.0,//wind sat freq.
                                    Core::Inf,//core-env coupling timescale
                                    expected_real_quantities,
                                    unsat_wind_mode);

            delete stellar_evol;
            stellar_evol = StellarEvolution::make_linear_I_evolution();

            initial_Lstar[0] = 1.0;
            expected_real_quantities[CONV_ANGMOM] = &one_func;
            test_no_planet_scenario(*stellar_evol,
                                    initial_Lstar,
                                    0.0,//Wind K
                                    2.0,//wind sat freq.
                                    Core::Inf,//core-env coupling timescale
                                    expected_real_quantities,
                                    unsat_wind_mode);


            initial_Lstar[0] = 0.5 * (1.0 + std::exp(-TSTART));
            initial_Lstar[1] = 0.5 * (1.0 - std::exp(-TSTART));

            StellarEvolution::PolynomialEvolutionQuantity half_func(
                std::valarray<double>(0.5, 1),
                TSTART,
                MAX_AGE
            );
            expected_real_quantities[CONV_ANGMOM] = new ExponentialPlusFunc(
                &half_func,
                0.5,
                -1.0
            );
            expected_real_quantities[RAD_ANGMOM] = new ExponentialPlusFunc(
                &half_func,
                -0.5,
                -1.0
            );
            test_no_planet_scenario(*stellar_evol,
                                    initial_Lstar,
                                    0.0,//Wind K
                                    1.0,//wind sat freq.
                                    1.0,//core-env coupling timescale
                                    expected_real_quantities,
                                    unsat_wind_mode);

            delete expected_real_quantities[CONV_ANGMOM];
            delete expected_real_quantities[RAD_ANGMOM];

            initial_Lstar[0] = 1.0/(1.0+TSTART);
            initial_Lstar[1] = 1.0;

            double wind_sat_age = std::pow(2.0, 0.25) - 1;
            std::valarray<double> late_denom_coef(3);
            late_denom_coef[0] = 2.0 * rt2 - 2.0;
            late_denom_coef[1] = 4.0 * rt2;
            late_denom_coef[2] = 2.0 * rt2;
            StellarEvolution::PolynomialEvolutionQuantity
                one_func_early(std::valarray<double>(1.0, 1),
                               TSTART, wind_sat_age),
                one_plus_t(std::valarray<double>(1.0, 2), TSTART, MAX_AGE),
                late_denom2(late_denom_coef, wind_sat_age, MAX_AGE);
            FunctionToPower late_denom(&late_denom2, 0.5);
            FunctionRatio early_solution(&one_func_early, &one_plus_t),
                          late_solution(&one_plus_t, &late_denom);
            PiecewiseFunction full_solution;
            full_solution.add_piece(&early_solution);
            full_solution.add_piece(&late_solution);

            expected_real_quantities[CONV_ANGMOM] = &full_solution;
            expected_real_quantities[RAD_ANGMOM] = &one_func;
            ExpectedEvolutionMode<bool> changing_wind_mode;
            changing_wind_mode.add_break(TSTART, true);
            changing_wind_mode.add_break(wind_sat_age, false);

            test_no_planet_scenario(*stellar_evol,
                                    initial_Lstar,
                                    2.0,//Wind K
                                    1.0 / rt2, //wind sat freq.
                                    Core::Inf,//core-env coupling timescale
                                    expected_real_quantities,
                                    changing_wind_mode);

            double b1 = (std::sqrt(2) - 1) / (2.0 * rt2),
                   b2 = (std::sqrt(2) + 1) / (2.0 * rt2);
            initial_Lstar[0] = (b1 * std::exp(-TSTART / (2.0 + rt2))
                                +
                                b2 * std::exp(-TSTART / (2.0 - rt2)));
            initial_Lstar[1] = (
                0.5 / rt2 * std::exp(-1.0 / (2.0 + rt2) * (TSTART))
                -
                0.5 / rt2 * std::exp(-1.0 / (2.0 - rt2) * (TSTART))
            );

            ExponentialPlusFunc
                Lc1(&zero_func, b1, -1.0 / (2.0 + rt2)),
                Lc2(&zero_func, b2, -1.0 / (2.0 - rt2)),
                Lr1(&zero_func, 0.5 / rt2, -1.0 / (2.0 + rt2)),
                Lr2(&zero_func, -0.5 / rt2, -1.0 / (2.0 - rt2));

            expected_real_quantities[CONV_ANGMOM] = new FuncPlusFunc(&Lc1,
                                                                     &Lc2);
            expected_real_quantities[RAD_ANGMOM] = new FuncPlusFunc(&Lr1,
                                                                    &Lr2);
            delete stellar_evol;
            stellar_evol = StellarEvolution::make_no_evolution();
            test_no_planet_scenario(*stellar_evol,
                                    initial_Lstar,
                                    100.0,//Wind K
                                    0.1,//wind sat freq.
                                    1.0,//core-env coupling timescale
                                    expected_real_quantities,
                                    sat_wind_mode,
                                    2.0);
            delete expected_real_quantities[CONV_ANGMOM];
            delete expected_real_quantities[RAD_ANGMOM];

            delete stellar_evol;
        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")+
                                    ex.what()+": "+ex.get_message()).c_str());
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")+
                                    ex.what()).c_str());
        }
    }

    void test_OrbitSolver::test_unlocked_evolution()
    {
        try {
            ExpectedEvolutionMode<Core::EvolModeType> binary_mode;
            binary_mode.add_break(TSTART, Core::BINARY);
            ExpectedEvolutionMode<bool> unsat_wind_mode, sat_wind_mode;
            unsat_wind_mode.add_break(TSTART, false);
            sat_wind_mode.add_break(TSTART, true);

            StellarEvolution::MockStellarEvolution
                *no_evol = StellarEvolution::make_no_evolution(1.0);

            const double mplanet = 100;
            double lag = 1e-8 / mplanet;

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities = calculate_expected_unlocked_evolution(
                    lag,
                    mplanet
                );

            __star = make_const_lag_star(*no_evol,
                                         0.0,//wind K
                                         100.0,//wsat
                                         Core::Inf,//tcoup
                                         lag);

            while(true) {
                double initial_a = (
                    *expected_real_quantities[SEMIMAJOR]
                )(TSTART);

                std::valarray<double> initial_L(3);
                initial_L[0] = (*expected_real_quantities[CONV_ANGMOM])(
                    TSTART
                );
                initial_L[1] = 0.0;
                initial_L[2] = 0.0;

                evolve(0.0,//wdisk
                       TSTART,//tdisk
                       initial_a,
                       &(initial_L[0]),
                       0.0,//initial inclination
                       mplanet,//planet mass
                       Core::NaN,//tplanet
                       1.0,//stop evolution age
                       0.0001);//Rplanet
                test_solution(get_evolution(),
                              expected_real_quantities,
                              binary_mode,
                              unsat_wind_mode,
                              TSTART,
                              1.0);

                delete __system;
                delete __solver;

                expected_real_quantities =
                    calculate_expected_unlocked_evolution(
                        lag,
                        mplanet,
                        false
                    );

                initial_a = (*expected_real_quantities[SEMIMAJOR])(TSTART);
                initial_L[0] = (*expected_real_quantities[CONV_ANGMOM])(TSTART);

                evolve(0.0,//wdisk
                       TSTART,//tdisk
                       initial_a,
                       &(initial_L[0]),
                       0.0,//initial inclination
                       mplanet,//planet mass
                       Core::NaN,//tplanet
                       1.0,//stop evolution age
                       0.0001);//Rplanet
                test_solution(get_evolution(),
                              expected_real_quantities,
                              binary_mode,
                              sat_wind_mode,
                              TSTART,
                              1.0);

                if(__star) {
                    delete __star;
                    __star = NULL;

                    __primary_planet = new Planet::Planet(1.0, 1.0, 1.0);
                    __primary_planet->zone().setup(
                        std::vector<double>(),//Wtide breaks
                        std::vector<double>(),//W* breaks
                        std::vector<double>(1, 0.0),//Wtide pow.
                        std::vector<double>(1, 0.0),//W* pow.
                        lag
                    );
                } else
                    break;
            }

            delete no_evol;
        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")
                                    +
                                    ex.what()+": "+ex.get_message()).c_str());
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")
                                    +
                                    ex.what()).c_str());
        }
    }

    double locked_unsat_eq(double a, void *params)
    {
        double *dbl_par = static_cast<double *>(params);
        double alpha = dbl_par[0],
               beta = dbl_par[1],
               kappa = dbl_par[2],
               c = dbl_par[3],
               t = dbl_par[4];
        return (
            0.1 * alpha * std::pow(a, 5)
            -
            0.5 * beta * std::pow(a, 3)
            +
            kappa*t
            -
            c
        );
    }

    double locked_sat_eq(double a, void *params)
    {
        double *dbl_par = static_cast<double *>(params);
        double alpha = dbl_par[0],
               beta = dbl_par[1],
               kappa = dbl_par[2],
               c = dbl_par[3],
               t = dbl_par[4];
        return (
            alpha * a * a / 4.0
            -
            1.5 * beta * std::log(a)
            +
            kappa * t
            -
            c
        );
    }

    double locked_unsat_deriv(double a, void *params)
    {
        double *dbl_par = static_cast<double *>(params);
        double alpha = dbl_par[0],
               beta = dbl_par[1];
        return 0.5 * alpha * std::pow(a, 4) - 1.5 * beta * std::pow(a, 2);
    }

    double locked_sat_deriv(double a, void *params)
    {
        double *dbl_par = static_cast<double *>(params);
        double alpha = dbl_par[0],
               beta = dbl_par[1];
        return alpha * a / 2.0 - 1.5 * beta / a;
    }

    void locked_unsat_eq_deriv(double a, void *params, double *f, double *df)
    {
        double *dbl_par = static_cast<double *>(params);
        double alpha = dbl_par[0],
               beta = dbl_par[1],
               kappa = dbl_par[2],
               c = dbl_par[3],
               t = dbl_par[4];
        *f = (
            0.1 * alpha * std::pow(a, 5)
            -
            0.5 * beta * std::pow(a, 3)
            +
            kappa * t
            -
            c
        );
        *df = (0.5 * alpha * std::pow(a, 4)
               -
               1.5 * beta * std::pow(a, 2));
    }

    void locked_sat_eq_deriv(double a, void *params, double *f, double *df)
    {
        double *dbl_par = static_cast<double *>(params);
        double alpha = dbl_par[0],
               beta = dbl_par[1],
               kappa = dbl_par[2],
               c = dbl_par[3],
               t = dbl_par[4];
        *f = (
            alpha * a * a / 4.0
            -
            1.5 * beta * std::log(a)
            +
            kappa * t
            -
            c
        );
        *df = alpha * a / 2.0 - 1.5 * beta / a;
    }

    void test_OrbitSolver::test_locked_evolution()
    {
        try {
            ExpectedEvolutionMode<Core::EvolModeType> expected_mode;
            expected_mode.add_break(TSTART, Core::BINARY);
            ExpectedEvolutionMode<bool> expected_wind_mode;
            expected_wind_mode.add_break(TSTART, false);
            const double Ic = 0.001, Kwind = 1e-3, Kwind_s = 1;
            StellarEvolution::MockStellarEvolution *
                no_evol = StellarEvolution::make_no_evolution(1.0, Ic);

            double a1 = 3,
                   Lscale = (Core::AstroConst::jupiter_mass
                             /
                             std::pow(Core::AstroConst::solar_radius, 1.5)
                             *
                             std::sqrt(
                                 Core::AstroConst::G
                                 /
                                 (Core::AstroConst::jupiter_mass
                                  +
                                  Core::AstroConst::solar_mass)
                             )
                             *
                             Core::AstroConst::day),
                   beta = (
                       Ic * std::sqrt(
                           Core::AstroConst::G
                           *
                           (
                               Core::AstroConst::solar_mass
                               +
                               Core::AstroConst::jupiter_mass
                           )
                       )
                       *
                       Core::AstroConst::day
                       /
                       std::pow(Core::AstroConst::solar_radius, 1.5)
                   ),
                   wsat_s = 0.1, //Must be adjusted if a1 is adjusted
//                   wsat = Core::Inf,
                   kappa=(
                       Kwind
                       *
                       std::pow(
                           (
                               Core::AstroConst::G
                               *
                               (
                                   Core::AstroConst::solar_mass
                                   +
                                   Core::AstroConst::jupiter_mass
                               )
                               /
                               std::pow(Core::AstroConst::solar_radius, 3)
                           ),
                           1.5
                       )
                       *
                       std::pow(Core::AstroConst::day, 3)
                   ),
                   kappa_s = (
                       Kwind_s * wsat_s * wsat_s *
                       std::sqrt(
                           Core::AstroConst::G
                           *
                           (
                               Core::AstroConst::solar_mass
                               +
                               Core::AstroConst::jupiter_mass
                           )
                           /
                           std::pow(Core::AstroConst::solar_radius, 3)
                       )
                       *
                       Core::AstroConst::day
                   ),
                   int_const = (Lscale / 10.0 * std::pow(a1, 5)
                                -
                                beta / 2.0 * std::pow(a1, 3)
                                +
                                kappa),
                   int_const_s = (Lscale / 4.0 * std::pow(a1, 2)
                                  -
                                  3.0 * beta / 2.0 * std::log(a1)
                                  +
                                  kappa_s);
/*            double solver_params[] = {Lscale, beta, kappa, int_const, 0.0};
            double a0 = solve(a1,
                              0.0,
                              1e-9,
                              &locked_unsat_eq,
                              &locked_unsat_deriv,
                              &locked_unsat_eq_deriv,
                              static_cast<void*>(solver_params));
            solver_params[4] = TSTART;
            double astart = solve(a0,
                                  0.0,
                                  1e-9,
                                  &locked_unsat_eq,
                                  &locked_unsat_deriv,
                                  &locked_unsat_eq_deriv,
                                  static_cast<void*>(solver_params));
            solver_params[2] = kappa_s;
            solver_params[3] = int_const_s;
            solver_params[4] = 0;
            double a0_s = solve(a1,
                                0.0,
                                1e-9,
                                &locked_sat_eq,
                                &locked_sat_deriv,
                                &locked_sat_eq_deriv,
                                static_cast<void*>(solver_params));
            solver_params[4] = TSTART;
            double astart_s = solve(a1,
                                    0.0,
                                    1e-9,
                                    &locked_sat_eq,
                                    &locked_sat_deriv,
                                    &locked_sat_eq_deriv,
                                    static_cast<void*>(solver_params));
            solver_params[4] = 1.0;

            double w0=std::sqrt(
                           AstroConst::G*
                           (AstroConst::solar_mass+AstroConst::jupiter_mass)/
                           std::pow(a0*AstroConst::solar_radius, 3))*
                       AstroConst::day,
                   w0_s=std::sqrt(
                           AstroConst::G*
                           (AstroConst::solar_mass+AstroConst::jupiter_mass)/
                           std::pow(a0_s*AstroConst::solar_radius, 3))*
                       AstroConst::day,
                   w1=std::sqrt(
                           AstroConst::G*
                           (AstroConst::solar_mass+AstroConst::jupiter_mass)/
                           std::pow(a1_check*AstroConst::solar_radius, 3))*
                       AstroConst::day,
                   w1_s=std::sqrt(
                           AstroConst::G*
                           (AstroConst::solar_mass+AstroConst::jupiter_mass)/
                           std::pow(a1_check_s*AstroConst::solar_radius, 3))*
                       AstroConst::day;*/
            std::valarray<double> a_transform_coef(0.0, 6),
                                  t_coef(2),
                                  t_coef_s(2);
            a_transform_coef[5] = Lscale / 10.0;
            a_transform_coef[3] = -beta / 2.0;
            t_coef[0] = int_const;
            t_coef[1] = -kappa;
            t_coef_s[0] = int_const_s;
            t_coef_s[1] = -kappa_s;
            std::valarray<double> Lconv_term1_coef(0.0, 2),
                                  Lconv_term2_coef(0.0, 3),
                                  identity_coef(0.0, 2),
                                  a_term1_coef_s(0.0, 3),
                                  Lconv_term1_coef_s(0.0, 2),
                                  Lc_beta_coef_s(0.0, 2);
            Lconv_term1_coef[1] = 1.0 / beta * std::pow(10.0 / Lscale,
                                                        3.0 / 10.0);
            Lconv_term2_coef[2] = -2.0 / std::pow(beta, 3);
            identity_coef[1] = 1;
            a_term1_coef_s[2] = Lscale / 4.0;
            Lconv_term1_coef_s[1] = 1.0 / beta * std::pow(4.0 / Lscale,
                                                          3.0 / 4.0);
            Lc_beta_coef_s[1] = 1.0 / beta;

            StellarEvolution::PolynomialEvolutionQuantity
                a_transform(a_transform_coef, 0.0, Core::Inf),
                a_transform1_s(a_term1_coef_s, 0.0, Core::Inf),
                transformed_a_evol(t_coef, TSTART, 1.0),
                transformed_a_evol_s(t_coef_s, TSTART, 1.0),
                Lconv_term1_poly(Lconv_term1_coef, 0.0, Core::Inf),
                Lconv_term2_poly(Lconv_term2_coef, 0.0, Core::Inf),
                Lconv_term1_poly_s(Lconv_term1_coef_s, 0.0, Core::Inf),
                Lc_beta_s(Lc_beta_coef_s, 0.0, Core::Inf),
                identity(identity_coef, 0.0, Core::Inf);
            FunctionToPower L_transform1(&Lconv_term1_poly, -10.0 / 3.0),
                            L_transform2(&Lconv_term2_poly, -1.0),
                            L_transform1_s(&Lconv_term1_poly_s, -4.0 / 3.0);
            LogFunction log_a(&identity),
                        log_Lc_beta_s(&Lc_beta_s);
            ScaledFunction a_transform2_s(&log_a, -1.5 * beta),
                           L_transform2_s(&log_Lc_beta_s, beta);
            FuncPlusFunc L_transform(&L_transform1, &L_transform2),
                         a_transform_s(&a_transform1_s, &a_transform2_s),
                         L_transform_s(&L_transform1_s, &L_transform2_s);
#if 0
            std::valarray<double> initial_orbit(2);

            initial_orbit[0]=astart;
            initial_orbit[1]=0.0;
            std::cout.precision(16);
            std::cout.setf(std::ios_base::scientific);
            Star star_not_saturated_wind_no_coupling(1.0, 0.0, Kwind, wsat, Inf,
                    0.0, 0.0, 0.0, no_evol);
            Planet planet1(&star_not_saturated_wind_no_coupling, 1.0, 1.0, 1.0);
            StellarSystem system1(&star_not_saturated_wind_no_coupling, &planet1);
            OrbitSolver solver(tstart, 1.0, 1e-9);
            solver(system1, Inf, 0.0, a0, tstart, LOCKED_TO_PLANET, initial_orbit, true);
            TransformedSolution to_check(a_transform, L_transform, identity, -Inf);
            to_check(solver);
            test_solution(to_check, transformed_a_evol, transformed_a_evol,
                    zero_func, tstart, 1.0, expected_mode);

            initial_orbit[0]=astart_s;
            initial_orbit[1]=0.0;
            Star star_saturated_wind_no_coupling(1.0, 0.0, Kwind_s, wsat_s, Inf,
                    0.0, 0.0, 0.0, no_evol);
            Planet planet2(&star_saturated_wind_no_coupling, 1.0, 1.0, 1.0);
            StellarSystem system2(&star_saturated_wind_no_coupling, &planet2);
            solver(system2, Inf, 0.0, a0_s, tstart, LOCKED_TO_PLANET,
                    initial_orbit, true);
            TransformedSolution to_check_s(a_transform_s, L_transform_s,
                    identity, -Inf);
            to_check_s(solver);
            test_solution(to_check_s, transformed_a_evol_s, transformed_a_evol_s,
                    zero_func, tstart, 1.0, expected_mode);
#endif
            delete no_evol;
        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")
                                    +
                                    ex.what()+": "+ex.get_message()).c_str());
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")
                                    +
                                    ex.what()).c_str());
        }
    }

    void test_OrbitSolver::test_disklocked_to_locked_to_noplanet()
    {
        try {
            const double Ic = 0.001,
                         Kwind = 2e-4,
                         tdisk = 1,
                         tfinal = 2;
            StellarEvolution::MockStellarEvolution *
                no_evol = StellarEvolution::make_no_evolution(1.0, Ic);

            double afinal = 1.75,
                   Lscale = (Core::AstroConst::jupiter_mass
                             /
                             std::pow(Core::AstroConst::solar_radius, 1.5)
                             *
                             std::sqrt(
                                 Core::AstroConst::G
                                 /
                                 (
                                     Core::AstroConst::jupiter_mass
                                     +
                                     Core::AstroConst::solar_mass
                                 )
                             )
                             *
                             Core::AstroConst::day),
                   beta = (
                       Ic
                       *
                       std::sqrt(
                           Core::AstroConst::G
                           *
                           (
                               Core::AstroConst::solar_mass
                               +
                               Core::AstroConst::jupiter_mass
                           )
                       )
                       *
                       Core::AstroConst::day
                       /
                       std::pow(Core::AstroConst::solar_radius, 1.5)
                   ),
                   wsat = 1e100,
                   kappa = (
                       Kwind
                       *
                       std::pow(
                           Core::AstroConst::G
                           *
                           (
                               Core::AstroConst::solar_mass
                               +
                               Core::AstroConst::jupiter_mass
                           )
                           /
                           std::pow(Core::AstroConst::solar_radius, 3),
                           1.5
                       )
                       *
                       std::pow(Core::AstroConst::day, 3)
                   ),
                   int_const = (Lscale / 10.0 * std::pow(afinal, 5)
                                -
                                beta / 2.0 * std::pow(afinal, 3)
                                +
                                kappa * tfinal);
            double solver_params[]={Lscale, beta, kappa, int_const, tdisk};
            double ainitial = solve(2.0 * afinal,
                                    0.0,
                                    1e-9,
                                    &locked_unsat_eq,
                                    &locked_unsat_deriv,
                                    &locked_unsat_eq_deriv,
                                    static_cast<void*>(solver_params)),
                   wdisk = (
                       std::sqrt(
                           Core::AstroConst::G
                           *
                           (
                               Core::AstroConst::solar_mass
                               +
                               Core::AstroConst::jupiter_mass
                           )
                           /
                           std::pow(ainitial * Core::AstroConst::solar_radius, 3)
                       )
                       *
                       Core::AstroConst::day
                   );

            __star = make_const_lag_star(
                *no_evol,
                Kwind,
                wsat,
                Core::Inf,//core-env coupling timescale
                lag_from_lgQ(0.1, (Core::AstroConst::jupiter_mass
                                   /
                                   Core::AstroConst::solar_mass))
            );
            Planet::Planet planet(Mjup_to_Msun, Rjup_to_Rsun);
            planet.configure(true, //init
                             tdisk, //age
                             __star->mass(), //mass
                             ainitial * (1.0 - 1e-14),//planet formation semimajor
                             0.0, //eccentricity
                             &zero, //spin angmom
                             NULL, //inclination
                             NULL, //periapsis
                             false, //locked surface
                             true, //zero outer inclination
                             true);//zero outer periapsis

            __system = new Evolve::DiskBinarySystem(
                *__star,
                planet,
                ainitial * (1.0 - 1e-14), //semimajor
                0.0, //eccentricity
                0, //inclination
                wdisk, //Wdisk
                tdisk, //disk dissipation age
                tdisk //planet formation age
            );

            __system->configure(true, //init
                                TSTART,
                                Core::NaN, //semimajor
                                Core::NaN, //eccentricity
                                &zero, //spin angmom
                                NULL, //inclination
                                NULL, //periapsis
                                Core::LOCKED_SURFACE_SPIN);


            double adestr = __system->minimum_separation(),
                   tdestr = ((beta / 2.0 * std::pow(adestr, 3)
                              +
                              int_const
                              -
                              Lscale / 10.0 * std::pow(adestr, 5)) / kappa),
                   Lc_at_destr = (beta / std::pow(adestr, 1.5)
                                  +
                                  Lscale * std::sqrt(adestr));


            std::valarray<double> a_transform_coef(0.0, 6), t_coef(2);
            a_transform_coef[5] = Lscale / 10.0;
            a_transform_coef[3] = -beta / 2.0;
            t_coef[0] = int_const;
            t_coef[1] = -kappa;
            std::valarray<double> Lconv_term1_coef(0.0, 2),
                                  Lconv_term2_coef(0.0, 3),
                                  identity_coef(0.0, 2),
                                  noplanet_Lconv_m2_coef(2);
            Lconv_term1_coef[1] = 1.0 / beta * std::pow(10.0 / Lscale, 0.3);
            Lconv_term2_coef[2] = -2.0 / std::pow(beta, 3);
            noplanet_Lconv_m2_coef[0] = (
                std::pow(Lc_at_destr, -2)
                -
                2.0 * Kwind * tdestr / std::pow(Ic, 3)
            );
            noplanet_Lconv_m2_coef[1] = 2.0 * Kwind / std::pow(Ic, 3);
            identity_coef[1] = 1;
            StellarEvolution::PolynomialEvolutionQuantity
                identity(identity_coef, -Core::Inf, Core::Inf),
                disk_nan_evol(std::valarray<double>(Core::NaN, 2),
                              TSTART,
                              tdisk),
                locked_a_transform(a_transform_coef, -Core::Inf, Core::Inf),
                locked_aLconv_evol(t_coef, tdisk, tdestr),
                locked_e_evol(std::valarray<double>(), tdisk, tdestr),
                noplanet_nan_evol(std::valarray<double>(Core::NaN, 2),
                                  tdestr,
                                  tfinal),
                disk_Lconv_evol(std::valarray<double>(wdisk * Ic, 1),
                                TSTART,
                                tdisk),
                noplanet_Lconv_m2_evol(noplanet_Lconv_m2_coef, tdestr, tfinal),
                Lconv_term1_poly(Lconv_term1_coef, -Core::Inf, Core::Inf),
                Lconv_term2_poly(Lconv_term2_coef, -Core::Inf, Core::Inf),
                Lrad_evol(std::valarray<double>(), TSTART, tfinal);
            FunctionToPower L_transform1(&Lconv_term1_poly, -10.0 / 3.0),
                            L_transform2(&Lconv_term2_poly, -1.0),
                            noplanet_Lconv_evol(&noplanet_Lconv_m2_evol, -0.5);
            LogFunction log_a(&identity);
            FuncPlusFunc locked_Lconv_transform(&L_transform1, &L_transform2);
            PiecewiseFunction a_evol, e_evol, Lconv_evol;
            a_evol.add_piece(&disk_nan_evol);
            a_evol.add_piece(&locked_aLconv_evol);
            a_evol.add_piece(&noplanet_nan_evol);
            e_evol.add_piece(&disk_nan_evol);
            e_evol.add_piece(&locked_e_evol);
            e_evol.add_piece(&noplanet_nan_evol);
            Lconv_evol.add_piece(&disk_Lconv_evol);
            Lconv_evol.add_piece(&locked_aLconv_evol);
            Lconv_evol.add_piece(&noplanet_Lconv_evol);

            std::vector< const Core::OneArgumentDiffFunction * >
                transformations(NUM_REAL_QUANTITIES - 1, &identity);
            TransformedSolution to_check(transformations, TSTART);
            transformations[SEMIMAJOR] = &locked_a_transform;
            transformations[CONV_ANGMOM] = &locked_Lconv_transform;
            to_check.add_transformation(transformations, tdisk);
            transformations[SEMIMAJOR] = &identity;
            transformations[CONV_ANGMOM] = &identity;
            to_check.add_transformation(transformations, tdestr);

            ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
            expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);
            expected_evol_mode.add_break(tdisk, Core::BINARY);
            expected_evol_mode.add_break(tdestr, Core::SINGLE);

            ExpectedEvolutionMode<bool> expected_wind_mode;
            expected_wind_mode.add_break(TSTART, false);

            __star->detect_saturation();
            __solver = new Evolve::OrbitSolver(tfinal, 1e-8);
            (*__solver)(*__system,
                        (tfinal - __system->age()) / 10000.0, //time step
                        std::list<double>()); //no required ages*/

            std::vector< const std::list<double> * >
                tabulated_evolution = get_evolution();
            const std::vector< const std::list<double> * > &
                transformed_evolution = to_check(tabulated_evolution);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);
            expected_real_quantities[SEMIMAJOR] = &a_evol;
            expected_real_quantities[ECCENTRICITY] = &e_evol;
            expected_real_quantities[CONV_INCLINATION] = &zero_func;
            expected_real_quantities[RAD_INCLINATION] = &zero_func;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] = &Lconv_evol;
            expected_real_quantities[RAD_ANGMOM] = &Lrad_evol;

            test_solution(transformed_evolution,
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          TSTART,
                          tfinal);
            delete no_evol;

#if 0
            Star star_not_saturated_wind_no_coupling(
                1.0,//M*
                1.0e-10,//Q*
                Kwind,
                wsat,
                Inf,//core-env coupling timescale
                0.0,//Q transition width
                wdisk,
                tdisk,
                no_evol);
            Planet planet1(&star_not_saturated_wind_no_coupling, 1.0, 1.0, 1.0);
            StellarSystem system1(&star_not_saturated_wind_no_coupling, &planet1);
    /*      std::cout << std::endl << "alpha=" << Lscale
                << std::endl << "beta=" << beta
                << std::endl << "kappa=" << kappa
                << std::endl << "wdisk=" << wdisk << std::endl;
            std::cout << std::endl << "ainitial=" << ainitial << std::endl;
            std::cout << std::endl << "Destruction a=" << adestr
                << ", t=" << tdestr << ", " << ", Lc=" << Lc_at_destr
                << ", no planet time="
                << (Lscale*(std::pow(adestr, 5)-std::pow(afinal, 5))/10.0 -
                        beta*(std::pow(adestr, 3)-std::pow(afinal, 3))/2.0)/kappa
                << std::endl;*/

            OrbitSolver solver(tstart, tfinal, 1e-8);
            solver(system1,
                   Inf,//Max step
                   0.0,//Planet formation age
                   ainitial/AU_Rsun,//planet formation semimajor
                   tstart);//Start age

            test_solution(to_check,
                          a_evol,
                          Lconv_evol,
                          Lrad_evol,
                          tstart,
                          tfinal,
                          expected_mode);
#endif
        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")
                                    +
                                    ex.what()+": "+ex.get_message()).c_str());
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")
                                    +
                                    ex.what()).c_str());
        }

    }

    void test_OrbitSolver::test_disklocked_to_fast_to_noplanet()
    {
        try {
            const double TDISK = 1,
                         TDESTR = 2,
                         WDISK = 0.0,
                         I_CONV = 1,
                         L_SCALE = (
                             -Core::AstroConst::jupiter_mass
                             /
                             std::pow(Core::AstroConst::solar_radius, 1.5)
                             *
                             std::sqrt(
                                 Core::AstroConst::G
                                 /
                                 (
                                     Core::AstroConst::jupiter_mass
                                     +
                                     Core::AstroConst::solar_mass
                                 )
                             )
                             *
                             Core::AstroConst::day
                         );

            StellarEvolution::MockStellarEvolution *
                no_evol = StellarEvolution::make_no_evolution(1.0, I_CONV);

            double lgQ = 8,
                   alpha = (
                       -4.5
                       *
                       std::sqrt(
                           Core::AstroConst::G
                           /
                           (
                               Core::AstroConst::solar_radius
                               *
                               Core::AstroConst::solar_mass
                           )
                       )
                       *
                       Core::AstroConst::jupiter_mass / std::pow(10.0, lgQ)
                       *
                       Core::AstroConst::Gyr / Core::AstroConst::solar_radius
                   );

            __star = make_const_lag_star(
                *no_evol,
                0.0,
                1.0,
                Core::Inf,
                lag_from_lgQ(lgQ,
                             (Core::AstroConst::jupiter_mass
                              /
                              Core::AstroConst::solar_mass))
            );

            double adestr = (
                2.44
                *
                std::pow(
                    (
                        __star->mass() * Core::AstroConst::solar_mass
                        /
                        Core::AstroConst::jupiter_mass
                    ),
                    1.0 / 3.0
                )
                *
                Core::AstroConst::jupiter_radius
                /
                Core::AstroConst::solar_radius
            );
            double a6p5_offset = (std::pow(adestr, 6.5)
                                  -
                                  6.5 * alpha * TDESTR),
                   a_formation = std::pow(a6p5_offset + 6.5 * alpha * TDISK,
                                          1.0 / 6.5);

            evolve(WDISK,
                   TDISK,
                   a_formation,
                   &zero);//Initial L*

            ExpectedEvolutionMode<Core::EvolModeType> expected_mode;
            expected_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);
            expected_mode.add_break(TDISK, Core::BINARY);
            expected_mode.add_break(TDESTR, Core::SINGLE);

            ExpectedEvolutionMode<bool> unsat_wind_mode;
            unsat_wind_mode.add_break(TSTART, false);

            std::valarray<double> a6p5_poly_coef(2);
            a6p5_poly_coef[0] = a6p5_offset;
            a6p5_poly_coef[1] = 6.5 * alpha;
            StellarEvolution::PolynomialEvolutionQuantity
                a6p5_evol(a6p5_poly_coef, TDISK, TDESTR),
                Lconv_disk(std::valarray<double>(I_CONV*WDISK, 1),
                           TSTART,
                           TDISK),
                Lconv_noplanet(
                    std::valarray<double>(
                        -L_SCALE * std::sqrt(a_formation) + I_CONV * WDISK,
                        1
                    ),
                    TDESTR,
                    MAX_AGE
                ),
                nan_disk(std::valarray<double>(Core::NaN, 2), TSTART, TDISK),
                nan_noplanet(std::valarray<double>(Core::NaN, 2),
                             TDESTR,
                             MAX_AGE),
                e_fast(std::valarray<double>(0.0, 1),
                       TDISK,
                       TDESTR),
                Lrad_evol(std::valarray<double>(), TSTART, MAX_AGE);
            FunctionToPower a_fast(&a6p5_evol, 1.0 / 6.5),
                            sqrta_evol(&a6p5_evol, 1.0 / 13.0);
            ExponentialPlusFunc Lconv_unscaled(
                &sqrta_evol,
                I_CONV * WDISK / L_SCALE - std::sqrt(a_formation),
                0
            );
            ScaledFunction Lconv_fast(&Lconv_unscaled, L_SCALE);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);

            PiecewiseFunction a_evol, e_evol, conv_angmom_evol;

            a_evol.add_piece(&nan_disk);
            a_evol.add_piece(&a_fast);
            a_evol.add_piece(&nan_noplanet);

            e_evol.add_piece(&nan_disk);
            e_evol.add_piece(&e_fast);
            e_evol.add_piece(&nan_noplanet);

            conv_angmom_evol.add_piece(&Lconv_disk);
            conv_angmom_evol.add_piece(&Lconv_fast);
            conv_angmom_evol.add_piece(
                &Lconv_noplanet
            );

            expected_real_quantities[SEMIMAJOR] = &a_evol;
            expected_real_quantities[ECCENTRICITY] = &e_evol;
            expected_real_quantities[CONV_INCLINATION] = &zero_func;
            expected_real_quantities[RAD_INCLINATION] = &zero_func;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_ANGMOM] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] = &conv_angmom_evol;
            expected_real_quantities[RAD_ANGMOM] = &zero_func;

            test_solution(get_evolution(),
                          expected_real_quantities,
                          expected_mode,
                          unsat_wind_mode,
                          TSTART,
                          MAX_AGE);

            delete no_evol;
        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")+
                    ex.what()+": "+ex.get_message()).c_str());
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(false, (std::string("Unexpected exception thrown: ")+
                    ex.what()).c_str());
        }
    }

    void test_OrbitSolver::test_disklocked_to_fast_to_locked()
    {
        try {
            const double lgQ = 8,
                         tdisk = 1,
                         async = 2.5,
                         tsync = 2.0,
                         tend = 3;

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities
                =
                calculate_expected_disklocked_to_fast_to_locked(
                    lgQ,
                    tdisk,
                    async,
                    tsync,
                    tend
                );

            double wsync = Core::orbital_angular_velocity(1.0,
                                                          Mjup_to_Msun,
                                                          async),
                   Lconv_sync = (*expected_real_quantities[CONV_ANGMOM])(
                       (tsync + tend) / 2.0
                   ),
                   Iconv = Lconv_sync / wsync,
                   Ldisk = (*expected_real_quantities[CONV_ANGMOM])(
                       (TSTART + tdisk) / 2.0
                   ),
                   wdisk = Ldisk / Iconv,
                   a_formation = (*expected_real_quantities[SEMIMAJOR])(tdisk),
                   phase_lag = lag_from_lgQ(lgQ,
                                            (Core::AstroConst::jupiter_mass
                                             /
                                             Core::AstroConst::solar_mass));

            StellarEvolution::MockStellarEvolution *
                no_evol = StellarEvolution::make_no_evolution(1.0, Iconv);

            __star = make_const_lag_star(
                *no_evol,//evolution
                0.0,//Kwind
                100.0,//wsat
                Core::Inf,//tcoup
                phase_lag
            );

            ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
            expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);
            expected_evol_mode.add_break(tdisk, Core::BINARY);

            ExpectedEvolutionMode<bool> expected_wind_mode;
            expected_wind_mode.add_break(TSTART, false);

            while(true) {
                evolve(wdisk,//wdisk,
                       tdisk,//tdisk
                       a_formation,//initial semimajor
                       (__star ? &zero : &Ldisk),//initial L*
                       0.0,//initial inclination
                       1.0,//planet_mass
                       Core::NaN,//time of secondary formation
                       tend,//max evolution age
                       0.01,//planet radius
                       1e-7);//precision

                test_solution(get_evolution(),
                              expected_real_quantities,
                              expected_evol_mode,
                              expected_wind_mode,
                              (__star ? TSTART : tdisk),
                              tend);
                if(__star) {
                    delete __star;
                    __star = NULL;

                    __primary_planet = new Planet::Planet(1.0, 1.0, Iconv);
                    __primary_planet->zone().setup(
                        std::vector<double>(),//Wtide breaks
                        std::vector<double>(),//W* breaks
                        std::vector<double>(1, 0.0),//Wtide pow.
                        std::vector<double>(1, 0.0),//W* pow.
                        phase_lag
                    );
                } else
                    break;
            }
            delete no_evol;

        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(
                false,
                (
                    std::string("Unexpected exception thrown: ")
                    +
                    ex.what() + ": " + ex.get_message()).c_str()
            );
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(
                false,
                (
                    std::string("Unexpected exception thrown: ")
                    +
                    ex.what()
                ).c_str()
            );
        }
    }

    void test_OrbitSolver::test_disklocked_to_locked_to_fast()
    {
        try {
            const double
                a0=3.2,
                abreak=3.0,
                adeath=2.0,
                tdisk=1,
                tbreak=2,
                tdeath=3,
                tend=4,
                Rp = (
                    adeath
                    *
                    Core::AstroConst::solar_radius
                    /
                    Core::AstroConst::jupiter_radius
                    /
                    (
                        2.44 * std::pow(Core::AstroConst::solar_mass
                                        /
                                        Core::AstroConst::jupiter_mass,
                                        1.0 / 3.0)
                    )
                ),
                beta = (
                    std::sqrt(
                        Core::AstroConst::G
                        *
                        (
                            Core::AstroConst::solar_mass
                            +
                            Core::AstroConst::jupiter_mass
                        )
                    )
                    *
                    Core::AstroConst::day
                    /
                    std::pow(Core::AstroConst::solar_radius, 1.5)
                ),
                wdisk = beta / std::pow(a0, 1.5),
                gamma = (
                    (std::pow(abreak, 6.5) - std::pow(adeath, 6.5))
                    /
                    (tdeath - tbreak)
                ),
                Q = (
                    9.0 * 13.0 / 4.0
                    *
                    std::sqrt(Core::AstroConst::G
                              /
                              Core::AstroConst::solar_mass)
                    *
                    Core::AstroConst::jupiter_mass
                    *
                    Core::AstroConst::Gyr
                    /
                    (gamma * std::pow(Core::AstroConst::solar_radius, 1.5))
                ),
                alphaL = (
                    Core::AstroConst::jupiter_mass
                    /
                    std::pow(Core::AstroConst::solar_radius, 1.5)
                    *
                    std::sqrt(Core::AstroConst::G
                              /
                              (
                                  Core::AstroConst::jupiter_mass
                                  +
                                  Core::AstroConst::solar_mass
                              )
                    )
                    *
                    Core::AstroConst::day
                ),
                Ic = (
                    (
                        (
                            (std::pow(a0, 5) - std::pow(abreak, 5))
                            *
                            std::pow(abreak, 3.5)
                            *
                            6.5
                        )
                        -
                        5.0 * gamma * abreak * abreak
                    )
                    /
                    (
                        (
                            (std::pow(a0, 3) - std::pow(abreak, 3))
                            *
                            std::pow(abreak, 3.5) * 6.5
                        )
                        -
                        3.0 * gamma
                    )
                    *
                    alphaL
                    /
                    (5.0 * beta)
                ),
                kappa = (
                    (std::pow(a0, 5) - std::pow(abreak, 5)) * alphaL / 10.0
                    -
                    (std::pow(a0, 3) - std::pow(abreak, 3)) * beta * Ic / 2.0
                ),
                Kwind = (
                    kappa
                    /
                    std::pow(
                        Core::AstroConst::G
                        *
                        (
                            Core::AstroConst::solar_mass
                            +
                            Core::AstroConst::jupiter_mass
                        )
                        /
                        std::pow(Core::AstroConst::solar_radius, 3),
                        1.5
                    )
                    /
                    std::pow(Core::AstroConst::day, 3)
                ),
                locked_a_int_const = (alphaL * std::pow(a0, 5) / 10.0
                                      -
                                      beta * Ic * std::pow(a0, 3) / 2.0
                                      +
                                      kappa * tdisk);

            StellarEvolution::MockStellarEvolution *
                no_evol = StellarEvolution::make_no_evolution(1.0, Ic);

            __star = make_const_lag_star(
                *no_evol,//evolution
                Kwind,//Kwind
                100.0,//wsat
                Core::Inf,//tcoup
                lag_from_lgQ(
                    std::log10(Q),
                    (Core::AstroConst::jupiter_mass
                     /
                     Core::AstroConst::solar_mass)
                )
            );
            evolve(wdisk,//wdisk,
                   tdisk,//tdisk
                   a0 * (1.0 + 1e-14),//initial semimajor
                   &zero,//initial L*
                   0.0,//initial inclination
                   1.0,//planet_mass
                   Core::NaN,//form the planet when disk dissipates
                   tend,//max evolution age
                   Rp);//planet radius

            ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
            expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);
            expected_evol_mode.add_break(tdisk, Core::BINARY);
            expected_evol_mode.add_break(tdeath, Core::SINGLE);

            ExpectedEvolutionMode<bool> expected_wind_mode;
            expected_wind_mode.add_break(TSTART, false);

            std::valarray<double> a_locked_transform_coef(0.0, 6),
                                  a_locked_evol_coef(2),
                                  identity_coef(0.0, 2),
                                  a6p5_fast_evol_coef(2),
                                  Lconv_locked_term1_coef(0.0, 2),
                                  Lconv_locked_term2_coef(0.0, 3);
            a_locked_transform_coef[5] = alphaL / 10.0;
            a_locked_transform_coef[3] = -beta * Ic / 2.0;
            a_locked_evol_coef[0] = locked_a_int_const;
            a_locked_evol_coef[1] = -kappa;
            identity_coef[1] = 1.0;
            a6p5_fast_evol_coef[0] = gamma * tbreak + std::pow(abreak, 6.5);
            a6p5_fast_evol_coef[1] = -gamma;
            Lconv_locked_term1_coef[1] = (1.0
                                          /
                                          (beta * Ic)
                                          *
                                          std::pow(10.0 / alphaL, 3.0 / 10.0));
            Lconv_locked_term2_coef[2] = -2.0 / std::pow(beta * Ic, 3);

            StellarEvolution::PolynomialEvolutionQuantity
                identity(identity_coef, -Core::Inf, Core::Inf),
                a_disk_transform = identity,
                nan_disk_evol(std::valarray<double>(Core::NaN, 2),
                            TSTART,
                            tdisk),
                a_locked_transform(a_locked_transform_coef,
                                   -Core::Inf,
                                   Core::Inf),
                a_locked_evol(a_locked_evol_coef, tdisk, tbreak),
                a_fast_transform = identity,
                a6p5_fast_evol(a6p5_fast_evol_coef, tbreak, tdeath),
                a_noplanet_transform = identity,
                nan_noplanet_evol(std::valarray<double>(Core::NaN, 2),
                                tdeath,
                                tend),

                Lconv_disk_transform = identity,
                Lconv_disk_evol(std::valarray<double>(wdisk * Ic, 1),
                                TSTART,
                                tdisk),
                Lconv_locked_term1_poly(Lconv_locked_term1_coef,
                                        -Core::Inf,
                                        Core::Inf),
                Lconv_locked_term2_poly(Lconv_locked_term2_coef,
                                        -Core::Inf,
                                        Core::Inf),
                Lconv_locked_evol = a_locked_evol,
                Lconv_fast_transform(std::valarray<double>(Core::NaN, 2),
                                     -Core::Inf,
                                     Core::Inf),
                Lconv_fast_evol(std::valarray<double>(Core::NaN, 2),
                                tbreak,
                                tdeath),
                Lconv_noplanet_transform(std::valarray<double>(Core::NaN, 2),
                                         -Core::Inf,
                                         Core::Inf),
                Lconv_noplanet_evol(std::valarray<double>(Core::NaN, 2),
                                    tdeath,
                                    tend),
                Lrad_transform = identity,
                Lrad_evol(std::valarray<double>(), TSTART, tend),
                zero_e(std::valarray<double>(), tdisk, tdeath);

            FunctionToPower
                a_fast_evol(&a6p5_fast_evol, 1.0 / 6.5),
                Lconv_locked_transform1(&Lconv_locked_term1_poly,
                                        -10.0 / 3.0),
                Lconv_locked_transform2(&Lconv_locked_term2_poly, -1.0);

            FuncPlusFunc Lconv_locked_transform(&Lconv_locked_transform1,
                                                &Lconv_locked_transform2);

            PiecewiseFunction a_evol, e_evol, Lconv_evol;

            a_evol.add_piece(&nan_disk_evol);
            a_evol.add_piece(&a_locked_evol);
            a_evol.add_piece(&a_fast_evol);
            a_evol.add_piece(&nan_noplanet_evol);

            e_evol.add_piece(&nan_disk_evol);
            e_evol.add_piece(&zero_e);
            e_evol.add_piece(&nan_noplanet_evol);

            Lconv_evol.add_piece(&Lconv_disk_evol);
            Lconv_evol.add_piece(&Lconv_locked_evol);
            Lconv_evol.add_piece(&Lconv_fast_evol);
            Lconv_evol.add_piece(&Lconv_noplanet_evol);

            std::vector< const Core::OneArgumentDiffFunction * >
                transformations(NUM_REAL_QUANTITIES - 1, &identity);
            TransformedSolution to_check(transformations, TSTART);

            transformations[SEMIMAJOR] = &a_disk_transform;
            transformations[CONV_ANGMOM] = &Lconv_disk_transform;
            to_check.add_transformation(transformations, TSTART);

            transformations[SEMIMAJOR] = &a_locked_transform;
            transformations[CONV_ANGMOM] = &Lconv_locked_transform;
            to_check.add_transformation(transformations, tdisk);

            transformations[SEMIMAJOR] = &a_fast_transform;
            transformations[CONV_ANGMOM] = &Lconv_fast_transform;
            to_check.add_transformation(transformations, tbreak);

            transformations[SEMIMAJOR] = &a_fast_transform;
            transformations[CONV_ANGMOM] = &Lconv_fast_transform;
            to_check.add_transformation(transformations, tbreak);

            transformations[SEMIMAJOR] = &a_noplanet_transform;
            transformations[CONV_ANGMOM] = &Lconv_noplanet_transform;
            to_check.add_transformation(transformations, tdeath);

            std::vector<const Core::OneArgumentDiffFunction *>
                expected_real_quantities(NUM_REAL_QUANTITIES - 1);

            std::vector< const std::list<double> * >
                tabulated_evolution = get_evolution();

            const std::vector< const std::list<double> * > &
                transformed_evolution = to_check(tabulated_evolution);

            expected_real_quantities[SEMIMAJOR] = &a_evol;
            expected_real_quantities[ECCENTRICITY] = &e_evol;
            expected_real_quantities[CONV_INCLINATION] = &zero_func;
            expected_real_quantities[RAD_INCLINATION] = &zero_func;
            expected_real_quantities[CONV_PERIAPSIS] = &zero_func;
            expected_real_quantities[RAD_PERIAPSIS] = &zero_func;
            expected_real_quantities[CONV_ANGMOM] = &Lconv_evol;
            expected_real_quantities[RAD_ANGMOM] = &zero_func;

            test_solution(transformed_evolution,
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          TSTART,
                          tend);
            delete no_evol;
        } catch (Core::Error::General &ex) {
            TEST_ASSERT_MSG(
                false,
                (
                    std::string("Unexpected exception thrown: ")
                    +
                    ex.what()+": "+ex.get_message()
                ).c_str()
            );
        } catch (std::exception &ex) {
            TEST_ASSERT_MSG(
                false,
                (
                    std::string("Unexpected exception thrown: ")
                    +
                    ex.what()
                ).c_str()
            );
        }

    }

    void test_OrbitSolver::test_polar_1_0_evolution()
    {
        StellarEvolution::MockStellarEvolution *
            no_evol = StellarEvolution::make_no_evolution();

        const double TDISK = 0.1,
                     WSTAR = 0.01,
                     WORB = 0.1;
        double initial_L = 1.0;
        std::vector<const Core::OneArgumentDiffFunction *>
            expected_real_quantities = calculate_expected_polar_1_0(
                TDISK,
                WSTAR,
                WORB
            );
        ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
        expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);
        expected_evol_mode.add_break(TDISK, Core::BINARY);

        ExpectedEvolutionMode<bool> expected_wind_mode;
        expected_wind_mode.add_break(TSTART, false);

        double semimajor = (*expected_real_quantities[SEMIMAJOR])(
            (TDISK + MAX_AGE) / 2.0
        );

        make_single_component_star(*no_evol,
                                   0.0,//Kw
                                   1.0,//Wsat
                                   Core::Inf,
                                   0.9 * WSTAR,
                                   1.1 * WSTAR,
                                   0.1 * WSTAR,
                                   1.0);//tcoup

        while(true) {
            evolve(WSTAR,//wdisk
                   TDISK,//tdisk
                   semimajor,//initial semimajor
                   &initial_L,//initial L*
                   M_PI / 2.0);//initial inclination

            test_solution(get_evolution(),
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          (__star ? TSTART : TDISK),
                          MAX_AGE);

            if(__star) {
                delete __star;
                delete __system;
                delete __solver;
                __star = NULL;
                __system = NULL;
                __solver = NULL;

                __primary_planet = new Planet::Planet(1.0, 1.0, 1.0);
                set_single_component_dissipation(
                    0.9 * WSTAR,
                    1.1 * WSTAR,
                    0.1 * WSTAR,
                    1.0
                );
                initial_L = WSTAR;
            } else
                break;
        }

        delete no_evol;
    }

    void test_OrbitSolver::test_polar_2_0_evolution()
    {
        StellarEvolution::MockStellarEvolution *
            no_evol = StellarEvolution::make_no_evolution();

        const double TDISK = 0.1,
                     WSTAR = 0.01,
                     WORB = 0.1,
                     PHASE_LAG = 1e-2;

        double lconv_decay_rate, semimajor, initial_L = 1.0;

        std::vector<const Core::OneArgumentDiffFunction *>
            expected_real_quantities = calculate_expected_polar_2_0(TDISK,
                                                                    WSTAR,
                                                                    WORB,
                                                                    PHASE_LAG,
                                                                    lconv_decay_rate,
                                                                    semimajor);


        std::valarray<double> identity_coef(0.0, 2);
        identity_coef[1] = 1.0;
        StellarEvolution::PolynomialEvolutionQuantity
            identity(identity_coef, -Core::Inf, Core::Inf),
            one_func(std::valarray<double>(1.0, 1), -Core::Inf, Core::Inf);

        CosFunction cos_transform(&identity);
        FuncPlusFunc one_plus_cos_transform(&one_func,
                                            &cos_transform);


        make_single_component_star(
            *no_evol,
            0.0,//Kw
            1.0,//Wsat
            Core::Inf,//tcoup
            2.0 * (WSTAR - lconv_decay_rate * MAX_AGE),
            2.0 * (WSTAR + lconv_decay_rate * MAX_AGE),
            0.1 * WSTAR,
            PHASE_LAG
        );

        while(true) {
            evolve(WSTAR,//wdisk
                   TDISK,//tdisk
                   semimajor,//initial semimajor
                   &initial_L,//initial L*
                   M_PI / 2.0);//initial inclination

            std::vector< const Core::OneArgumentDiffFunction * >
                transformations(NUM_REAL_QUANTITIES - 1, &identity);
            transformations[CONV_INCLINATION] = &one_plus_cos_transform;
            transformations[RAD_INCLINATION] = &one_plus_cos_transform;
            TransformedSolution to_check(transformations, TSTART);

            std::vector< const std::list<double> * >
                tabulated_evolution = get_evolution();
            const std::vector< const std::list<double> * > &
                transformed_evolution = to_check(tabulated_evolution);

            ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
            expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);
            expected_evol_mode.add_break(TDISK, Core::BINARY);

            ExpectedEvolutionMode<bool> expected_wind_mode;
            expected_wind_mode.add_break(TSTART, false);

            test_solution(transformed_evolution,
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          (__star ? TSTART : TDISK),
                          MAX_AGE);

            if(__star) {
                delete __star;
                delete __system;
                delete __solver;
                __star = NULL;
                __system = NULL;
                __solver = NULL;

                __primary_planet = new Planet::Planet(1.0, 1.0, 1.0);
                set_single_component_dissipation(
                    2.0 * (WSTAR - lconv_decay_rate * MAX_AGE),
                    2.0 * (WSTAR + lconv_decay_rate * MAX_AGE),
                    0.1 * WSTAR,
                    PHASE_LAG
                );
                initial_L = WSTAR;
            } else
                break;
        }

        delete no_evol;
    }
    void test_OrbitSolver::test_oblique_1_0_evolution()
    {
        StellarEvolution::MockStellarEvolution *
            no_evol = StellarEvolution::make_no_evolution();

        const double PHASE_LAG = 0.1,
                     TDISK = 0.1,
                     WORB = 0.1,
                     INITIAL_INC = 0.25 * M_PI,
                     INITIAL_WSTAR = 0.01;

        double initial_angmom = 1.0,
               min_wstar;

        std::vector<const Core::OneArgumentDiffFunction *>
            expected_real_quantities = calculate_expected_oblique_m_0(
                1,
                TDISK,
                WORB,
                INITIAL_INC,
                INITIAL_WSTAR,
                PHASE_LAG,
                min_wstar
            );

        double wstar_tolerance = 0.01 * (INITIAL_WSTAR - min_wstar),
               semimajor = (*expected_real_quantities[SEMIMAJOR])(
                   (TDISK + MAX_AGE) / 2.0
               );

        ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
        expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);
        expected_evol_mode.add_break(TDISK, Core::BINARY);

        ExpectedEvolutionMode<bool> expected_wind_mode;
        expected_wind_mode.add_break(TSTART, false);

        make_single_component_star(
            *no_evol,
            0.0,//Kw
            1.0,//Wsat
            Core::Inf,//tcoup
            min_wstar - wstar_tolerance,
            INITIAL_WSTAR + wstar_tolerance,
            0.1 * INITIAL_WSTAR,
            PHASE_LAG
        );

        while(true) {
            evolve(INITIAL_WSTAR,//wdisk
                   TDISK,//tdisk
                   semimajor,//initial semimajor
                   &initial_angmom,//initial L*
                   INITIAL_INC);//initial inclination

            test_solution(get_evolution(),
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          (__star ? TSTART : TDISK),
                          MAX_AGE);

            if(__star) {
                delete __star;
                delete __system;
                delete __solver;
                __star = NULL;
                __system = NULL;
                __solver = NULL;

                __primary_planet = new Planet::Planet(1.0, 1.0, 1.0);
                set_single_component_dissipation(
                    min_wstar - wstar_tolerance,
                    INITIAL_WSTAR + wstar_tolerance,
                    0.1 * INITIAL_WSTAR,
                    PHASE_LAG
                );

                initial_angmom = INITIAL_WSTAR;
            } else
                break;
        }
    }

    void test_OrbitSolver::test_oblique_2_0_evolution()
    {
        StellarEvolution::MockStellarEvolution *
            no_evol = StellarEvolution::make_no_evolution();

        const double PHASE_LAG = 0.1,
                     TDISK = 0.1,
                     WORB = 0.1,
                     INITIAL_INC = 0.25 * M_PI,
                     INITIAL_WSTAR = 0.01;

        double initial_angmom = 1.0,
               min_wstar;

        std::vector<const Core::OneArgumentDiffFunction *>
            expected_real_quantities = calculate_expected_oblique_m_0(
                2,
                TDISK,
                WORB,
                INITIAL_INC,
                INITIAL_WSTAR,
                PHASE_LAG,
                min_wstar
            );

        double wstar_tolerance = 0.01 * (INITIAL_WSTAR - min_wstar),
               semimajor = (*expected_real_quantities[SEMIMAJOR])(
                   (TDISK + MAX_AGE) / 2.0
               );

        ExpectedEvolutionMode<Core::EvolModeType> expected_evol_mode;
        expected_evol_mode.add_break(TSTART, Core::LOCKED_SURFACE_SPIN);
        expected_evol_mode.add_break(TDISK, Core::BINARY);

        ExpectedEvolutionMode<bool> expected_wind_mode;
        expected_wind_mode.add_break(TSTART, false);

        make_single_component_star(
            *no_evol,
            0.0,//Kw
            1.0,//Wsat
            Core::Inf,//tcoup
            2.0 * min_wstar - wstar_tolerance,
            2.0 * INITIAL_WSTAR + wstar_tolerance,
            0.1 * INITIAL_WSTAR,
            PHASE_LAG
        );

        while(true) {
            evolve(INITIAL_WSTAR,//wdisk
                   TDISK,//tdisk
                   semimajor,//initial semimajor
                   &initial_angmom,//initial L*
                   INITIAL_INC);//initial inclination

            test_solution(get_evolution(),
                          expected_real_quantities,
                          expected_evol_mode,
                          expected_wind_mode,
                          (__star ? TSTART : TDISK),
                          MAX_AGE);
            if(__star) {
                delete __star;
                delete __system;
                delete __solver;
                __star = NULL;
                __system = NULL;
                __solver = NULL;

                __primary_planet = new Planet::Planet(1.0, 1.0, 1.0);
                set_single_component_dissipation(
                    2.0 * min_wstar - wstar_tolerance,
                    2.0 * INITIAL_WSTAR + wstar_tolerance,
                    0.1 * INITIAL_WSTAR,
                    PHASE_LAG
                );

                initial_angmom = INITIAL_WSTAR;
            } else
                break;
        }

        delete no_evol;

    }

    void test_OrbitSolver::setup()
    {
        assert(__star == NULL);
        assert(__primary_planet == NULL);
        assert(__system == NULL);
        assert(__solver == NULL);
        assert(__temp_functions.empty());
    }

    void test_OrbitSolver::tear_down()
    {
        if(__star) {
            std::cout << "Deleting star" << std::endl;
            delete __star;
            __star = NULL;
        }
        if(__primary_planet) {
            std::cout << "Deleting primary planet" << std::endl;
            delete __primary_planet;
            __primary_planet = NULL;
        }
        if(__system) {
            std::cout << "Deleting system" << std::endl;
            delete __system;
            __system = NULL;
        }
        if(__solver) {
            std::cout << "Deleting solver" << std::endl;
            delete __solver;
            __solver = NULL;
        }
        for(
            std::vector< const Core::OneArgumentDiffFunction* >::iterator
                temp_func_i = __temp_functions.begin();
            temp_func_i != __temp_functions.end();
            ++temp_func_i
        ) {
            std::cout << "Deleting function" << std::endl;
            delete *temp_func_i;
        }
        __temp_functions.clear();
    }

    test_OrbitSolver::test_OrbitSolver() :
        __solver(NULL),
        __system(NULL),
        __star(NULL),
        __primary_planet(NULL)
    {
        TEST_ADD(test_OrbitSolver::test_disk_locked_no_stellar_evolution);
        TEST_ADD(test_OrbitSolver::test_disk_locked_with_stellar_evolution);
        TEST_ADD(test_OrbitSolver::test_no_planet_evolution);
        TEST_ADD(test_OrbitSolver::test_unlocked_evolution);
//        TEST_ADD(test_OrbitSolver::test_locked_evolution);//NOT REVIVED!!!
        TEST_ADD(test_OrbitSolver::test_disklocked_to_locked_to_noplanet);
        TEST_ADD(test_OrbitSolver::test_disklocked_to_fast_to_noplanet);
        TEST_ADD(test_OrbitSolver::test_disklocked_to_fast_to_locked);
        TEST_ADD(test_OrbitSolver::test_disklocked_to_locked_to_fast);
        TEST_ADD(test_OrbitSolver::test_polar_1_0_evolution);
        TEST_ADD(test_OrbitSolver::test_polar_2_0_evolution);
        TEST_ADD(test_OrbitSolver::test_oblique_1_0_evolution);
        TEST_ADD(test_OrbitSolver::test_oblique_2_0_evolution);
    }

}//End Evolve namespace.