Program Listing for File BrokenPowerlawPhaseLagZone.cpp

Return to documentation for file (/home/kpenev/projects/git/poet/poet_src/Evolve/BrokenPowerlawPhaseLagZone.cpp)

#define BUILDING_LIBRARY
#include "BrokenPowerlawPhaseLagZone.h"
#include <iostream>

namespace Evolve {

    double BrokenPowerlawPhaseLagZone::get_orbital_frequency(
        const BinarySystem &system
    ) const
    {
        return Core::orbital_angular_velocity(
            system.primary().mass(),
            system.secondary().mass(),
            system.semimajor()
        );
    }

    void BrokenPowerlawPhaseLagZone::reset()
    {
        __tidal_frequency_breaks.clear();
        __spin_frequency_breaks.clear();
        __tidal_frequency_powers.clear();
        __spin_frequency_powers.clear();
        __break_phase_lags.clear();
    }

    void BrokenPowerlawPhaseLagZone::set_spin_index()
    {
        if(__spin_frequency_breaks.size() != 0) {
            double abs_spin_frequency = std::abs(spin_frequency());
            __spin_index = (
                std::lower_bound(
                    __spin_frequency_breaks.begin(),
                    __spin_frequency_breaks.end(),
                    abs_spin_frequency
                )
                -
                __spin_frequency_breaks.begin()
            );
            if(
                __spin_index < __spin_frequency_breaks.size()
                &&
                __spin_frequency_breaks[__spin_index] == abs_spin_frequency
            )
                throw Core::Error::BadFunctionArguments(
                    "Starting evolution from exactly a critical spin "
                    "frequency is not currently supported."
                );
        } else
            __spin_index = 0;


    }

    std::vector<double>::size_type
        BrokenPowerlawPhaseLagZone::get_tidal_index(
            double abs_forcing_frequency
        ) const
        {
            assert(abs_forcing_frequency >= 0);
            if(__tidal_frequency_breaks.size() != 0)
                return (
                    std::lower_bound(
                        __tidal_frequency_breaks.begin(),
                        __tidal_frequency_breaks.end(),
                        abs_forcing_frequency
                    )
                    -
                    __tidal_frequency_breaks.begin()
                );
            else
                return 0;
        }

    void BrokenPowerlawPhaseLagZone::add_tidal_frequency_conditions(
        BinarySystem &system,
        bool primary,
        unsigned,
        CombinedStoppingCondition &result
    )
    {
        const DissipatingBody
            &this_body = (primary ? system.primary() : system.secondary()),
            &other_body = (primary ? system.secondary() : system.primary());

        for(
            int e_order = 0;
            e_order <= static_cast<int>(eccentricity_order());
            ++e_order
        )
        {

            int mp_step = (e_order == 0 ? 1 : 4 + 2 * e_order);

            for(int mp = 0; mp <= e_order + 2;  mp += mp_step)
                for(int m = -2; m <= 2; ++m)
                    result |= new LagForcingFrequencyBreakCondition(
                        *this,
                        this_body,
                        other_body,
                        mp,
                        m
                    );
        }

    }

    void BrokenPowerlawPhaseLagZone::print_configuration(std::ostream &out_stream)
    {
        return;
        out_stream << "Tidal breaks: ";
        for(
            std::vector<double>::const_iterator
                i = __tidal_frequency_breaks.begin();
            i != __tidal_frequency_breaks.end();
            ++i
        )
            out_stream << *i << " ";
        out_stream << std::endl;

        out_stream << "Tidal powers: ";
        for(
            std::vector<double>::const_iterator
                i = __tidal_frequency_powers.begin();
            i != __tidal_frequency_powers.end();
            ++i
        )
            out_stream << *i << " ";
        out_stream << std::endl;

        out_stream << "Spin breaks: ";
        for(
            std::vector<double>::const_iterator
                i = __spin_frequency_breaks.begin();
            i != __spin_frequency_breaks.end();
            ++i
        )
            out_stream << *i << " ";
        out_stream << std::endl;

        out_stream << "Spin powers: ";
        for(
            std::vector<double>::const_iterator
                i = __spin_frequency_powers.begin();
            i != __spin_frequency_powers.end();
            ++i
        )
            out_stream << *i << " ";
        out_stream << std::endl;

        out_stream << "Break lags: ";
        for(
            std::vector<double>::const_iterator
                i = __break_phase_lags.begin();
            i != __break_phase_lags.end();
            ++i
        )
            out_stream << *i << " ";
        out_stream << std::endl;
    }

    void BrokenPowerlawPhaseLagZone::setup(
        const std::vector<double> &tidal_frequency_breaks,
        const std::vector<double> &spin_frequency_breaks,
        const std::vector<double> &tidal_frequency_powers,
        const std::vector<double> &spin_frequency_powers,
        double reference_phase_lag
    )
    {
        __dissipative = true;
        reset();
        assert(__spin_frequency_breaks.size() == 0);
        assert(__tidal_frequency_breaks.size() == 0);
        assert(__spin_frequency_breaks.size() == 0);
        assert(__spin_frequency_powers.size() == 0);
        assert(__break_phase_lags.size() == 0);
        assert(tidal_frequency_powers.size()
               ==
               tidal_frequency_breaks.size() + 1);
        assert(spin_frequency_powers.size()
               ==
               spin_frequency_breaks.size() + 1);
        assert(tidal_frequency_breaks.size() > 0
               ||
               tidal_frequency_powers.front() == 0);
        assert(spin_frequency_breaks.size() > 0
               ||
               spin_frequency_powers.front() == 0);

        __tidal_frequency_breaks = tidal_frequency_breaks;
        __spin_frequency_breaks = spin_frequency_breaks;
        __tidal_frequency_powers = tidal_frequency_powers;
        __spin_frequency_powers = spin_frequency_powers;
        __break_phase_lags.resize(
            std::max(int(spin_frequency_breaks.size()), 1)
            *
            std::max(int(tidal_frequency_breaks.size()), 1)
        );

        unsigned break_lag_i = 0;
        for(
            int spin_break_i = 0;
            spin_break_i < std::max(int(spin_frequency_breaks.size()), 1);
            ++spin_break_i
        ) {
            if(break_lag_i == 0)
                __break_phase_lags[break_lag_i] = reference_phase_lag;
            else
                __break_phase_lags[break_lag_i] = (
                    __break_phase_lags[
                        break_lag_i - tidal_frequency_breaks.size()
                    ]
                    *
                    (
                        spin_frequency_powers[spin_break_i] == 0
                        ? 1.0
                        : std::pow(
                            (
                                spin_frequency_breaks[spin_break_i]
                                /
                                spin_frequency_breaks[spin_break_i - 1]
                            ),
                            spin_frequency_powers[spin_break_i]
                        )
                    )
                );
            ++break_lag_i;
            for(
                int tidal_break_i = 1;
                tidal_break_i < std::max(int(tidal_frequency_breaks.size()),
                                         1);
                ++tidal_break_i
            ) {
                __break_phase_lags[break_lag_i] = (
                    __break_phase_lags[break_lag_i - 1]
                    *
                    (
                        tidal_frequency_powers[tidal_break_i] == 0
                        ? 1.0
                        : std::pow(
                            (
                                tidal_frequency_breaks[tidal_break_i]
                                /
                                tidal_frequency_breaks[tidal_break_i - 1]
                            ),
                            tidal_frequency_powers[tidal_break_i]
                        )
                    )
                );
                ++break_lag_i;
            }
        }

#ifndef NDEBUG
        print_configuration();
#endif
    }//End BrokenPowerlawPhaseLagZone::BrokenPowerlawPhaseLagZone definition.

    void BrokenPowerlawPhaseLagZone::configure(
        bool initialize,
        double age,
        double orbital_frequency,
        double eccentricity,
        double orbital_angmom,
        double spin,
        double inclination,
        double periapsis,
        bool spin_is_frequency
    )
    {

        if(initialize && !std::isnan(orbital_frequency)) {
            initializing(true);

#ifndef NDEBUG
            std::cerr << "Initializing broken powerlaw lag zone"
                      << (initialize ? " for the first time." : ".")
                      << std::endl;
#endif

            configure_spin(spin, spin_is_frequency);

            set_spin_index();

            __tidal_indices.resize(5 * (eccentricity_order() + 3));
#ifndef NDEBUG
            std::cerr << "__tidal_indices size = "
                      << __tidal_indices.size()
                      << std::endl;
#endif

            std::vector< std::vector<double>::size_type >::iterator
                destination = __tidal_indices.begin();

            for(
                int mp = 0;
                mp <= static_cast<int>(eccentricity_order()) + 2;
                ++mp
            ) {
                for(int m = -2; m <= 2; ++m) {
                    double abs_forcing_frequency = std::abs(
                        forcing_frequency(mp, m, orbital_frequency)
                    );
                    *destination = get_tidal_index(abs_forcing_frequency);
                    if(
                        *destination < __tidal_frequency_breaks.size()
                        &&
                        (
                            __tidal_frequency_breaks[*destination]
                            ==
                            abs_forcing_frequency
                        )
                    )
                        throw Core::Error::BadFunctionArguments(
                            "Starting evolution from exactly a critical tidal "
                            "forcing frequency is not currently supported."
                        );
                    ++destination;
                }
            }

            initializing(false);
        }

        DissipatingZone::configure(initialize,
                                   age,
                                   orbital_frequency,
                                   eccentricity,
                                   orbital_angmom,
                                   spin,
                                   inclination,
                                   periapsis,
                                   spin_is_frequency);
        set_spin_index();

    }

    double BrokenPowerlawPhaseLagZone::modified_phase_lag(
        int orbital_frequency_multiplier,
        int spin_frequency_multiplier,
        double forcing_frequency,
        Dissipation::QuantityEntry entry,
        double &above_lock_value
    ) const
    {
        if(
            !__dissipative
            ||
            entry == Dissipation::AGE
            ||
            entry == Dissipation::EXPANSION_ERROR
        )
            return 0;

        double abs_forcing_frequency = std::abs(forcing_frequency),
               abs_spin_frequency = std::abs(spin_frequency());

        /*
        std::vector<double>::size_type tidal_index
            = __tidal_indices[tidal_term_index(orbital_frequency_multiplier,
                                               spin_frequency_multiplier)];
        */
        std::vector<double>::size_type
            tidal_index = get_tidal_index(abs_forcing_frequency);

        double tidal_power = __tidal_frequency_powers[tidal_index],
               spin_power = __spin_frequency_powers[__spin_index];

        std::vector<double>::size_type tidal_break_index = tidal_index,
                                       spin_break_index = __spin_index;
        if(
            spin_break_index > 0
            &&
            spin_break_index >= __spin_frequency_breaks.size()
        )
            --spin_break_index;

        if(
            tidal_break_index > 0
            &&
            tidal_break_index >= __tidal_frequency_breaks.size()
        )
            --tidal_break_index;

        std::vector<double>::size_type
            lag_index = (spin_break_index * __tidal_frequency_breaks.size()
                         +
                         tidal_break_index);
        double tidal_factor = (
            tidal_power == 0
            ? 1.0
            : std::pow(abs_forcing_frequency
                       /
                       __tidal_frequency_breaks[tidal_break_index]
                       ,
                       tidal_power)
        );
        double spin_factor = (
            spin_power == 0
            ? 1.0
            : std::pow(
                (
                    abs_spin_frequency
                    /
                    __spin_frequency_breaks[spin_break_index]
                ),
                spin_power
            )
        );
        double result = (__break_phase_lags[lag_index]
                         *
                         tidal_factor
                         *
                         spin_factor);
        switch(entry) {
            case Dissipation::SPIN_FREQUENCY :
                result *= (
                    (spin_power ? spin_power / spin_frequency() : 0.0)
                    -
                    (
                        tidal_power
                        ? (spin_frequency_multiplier * tidal_power
                           /
                           forcing_frequency)
                        : 0.0
                    )
                );
                break;
            case Dissipation::ORBITAL_FREQUENCY :
                result *= (
                    tidal_power
                    ? (orbital_frequency_multiplier * tidal_power
                       /
                       forcing_frequency)
                    : 0.0
                );
                break;
            default :
                assert(entry == Dissipation::NO_DERIV);
        }

        if(forcing_frequency == 0) {
            if(tidal_power) {
                if(entry != Dissipation::NO_DERIV) {
                    assert(
                        entry == Dissipation::SPIN_FREQUENCY
                        ||
                        entry == Dissipation::ORBITAL_FREQUENCY
                    );
                    if(tidal_power == 1) {
                        result = (
                            (
                                entry == Dissipation::SPIN_FREQUENCY
                                ? spin_frequency_multiplier
                                : -orbital_frequency_multiplier
                            )
                            *
                            __break_phase_lags[lag_index]
                            *
                            spin_factor
                            /
                            __tidal_frequency_breaks[tidal_break_index]
                        );
                    } else {
                        assert(tidal_power > 1);
                        result = 0;
                    }
                }
            }
            if(spin_frequency_multiplier >= 0) {
                above_lock_value = -result;
                return result;
            } else {
                above_lock_value = result;
                return -result;
            }
        } else {
            return (forcing_frequency > 0 ? result : -result);
        }

    }//End BrokenPowerlawPhaseLagZone::modified_phase_lag definition.

    CombinedStoppingCondition *
        BrokenPowerlawPhaseLagZone::stopping_conditions(
            BinarySystem &system,
            bool primary,
            unsigned zone_index
        )
    {
        CombinedStoppingCondition *result =
            DissipatingZone::stopping_conditions(system,
                                                 primary,
                                                 zone_index);
        return result;

        if(system.evolution_mode() != Core::BINARY) return result;

        if(__spin_frequency_breaks.size() != 0) {
            *result |= new LagSpinBreakCondition(
                *this,
                (primary ? system.primary() : system.secondary()),
                (primary ? system.secondary() : system.primary()),
                primary,
                zone_index
            );
        }

        if(__tidal_frequency_breaks.size() != 0)
            add_tidal_frequency_conditions(system,
                                           primary,
                                           zone_index,
                                           *result);

        return result;
    }//End BrokenPowerlawPhaseLagZone::stopping_conditions definition.

    void BrokenPowerlawPhaseLagZone::change_e_order(
        unsigned new_e_order,
        BinarySystem &system,
        bool primary,
        unsigned zone_index
    )
    {
        __tidal_indices.resize(5 * (new_e_order + 3));

        double orbital_frequency = get_orbital_frequency(system);

        std::vector< std::vector<double>::size_type >::iterator
            destination = (__tidal_indices.begin()
                           +
                           5 * (eccentricity_order() + 3));
        for(
            int mp = static_cast<int>(eccentricity_order()) + 3;
            mp <= static_cast<int>(new_e_order) + 2;
            ++mp
        ) {
            for(int m = -2; m <= 2; ++m) {
                *destination = get_tidal_index(
                    std::abs(forcing_frequency(mp, m, orbital_frequency))
                );
                ++destination;
            }
        }

        DissipatingZone::change_e_order(new_e_order,
                                        system,
                                        primary,
                                        zone_index);
    }

} //End BinarySystem namespace.