Skip to content

Secular Frequencies (C)

Try it out this example!

REBOUND has been compiled with emscripten to WebAssembly. This lets you run this example interactively from within your browser at almost native speed. No installation is required. Click here to try it out.

This example integrates the outer Solar System and then performs a frequency analysis using the Frequency Modified Fourier Transform to determine the secular frequencies (g-modes).

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "rebound.h"

double ss_pos[6][3] =
    {
     {-4.06428567034226e-3, -6.08813756435987e-3, -1.66162304225834e-6}, // Sun
     {+3.40546614227466e+0, +3.62978190075864e+0, +3.42386261766577e-2}, // Jupiter
     {+6.60801554403466e+0, +6.38084674585064e+0, -1.36145963724542e-1}, // Saturn
     {+1.11636331405597e+1, +1.60373479057256e+1, +3.61783279369958e-1}, // Uranus
     {-3.01777243405203e+1, +1.91155314998064e+0, -1.53887595621042e-1}, // Neptune
     {-2.13858977531573e+1, +3.20719104739886e+1, +2.49245689556096e+0}  // Pluto
};
double ss_vel[6][3] =
    {
     {+6.69048890636161e-6, -6.33922479583593e-6, -3.13202145590767e-9}, // Sun
     {-5.59797969310664e-3, +5.51815399480116e-3, -2.66711392865591e-6}, // Jupiter
     {-4.17354020307064e-3, +3.99723751748116e-3, +1.67206320571441e-5}, // Saturn
     {-3.25884806151064e-3, +2.06438412905916e-3, -2.17699042180559e-5}, // Uranus
     {-2.17471785045538e-4, -3.11361111025884e-3, +3.58344705491441e-5}, // Neptune
     {-1.76936577252484e-3, -2.06720938381724e-3, +6.58091931493844e-4}  // Pluto
};

double ss_mass[6] =
    {
     1.00000597682, // Sun + inner planets
     1. / 1047.355, // Jupiter
     1. / 3501.6,   // Saturn
     1. / 22869.,   // Uranus
     1. / 19314.,   // Neptune
     0.0  // Pluto
};

int main(int argc, char* argv[]) {
    struct reb_simulation* r = reb_simulation_create();
    const double k = 0.01720209895; // Gaussian constant
    r->dt = 120;                    // Timestep is 120 days.
    r->G = k * k;                   // These are the same units as used by the mercury6 code.
    r->integrator = REB_INTEGRATOR_WHFAST;

    // Initial conditions
    for (int i = 0; i < 6; i++) {
        struct reb_particle p = {0};
        p.x = ss_pos[i][0];
        p.y = ss_pos[i][1];
        p.z = ss_pos[i][2];
        p.vx = ss_vel[i][0];
        p.vy = ss_vel[i][1];
        p.vz = ss_vel[i][2];
        p.m = ss_mass[i];
        reb_simulation_add(r, p);
    }

    reb_simulation_move_to_com(r);

    int Nsamples = 2048; // Number of samples. Must be a power of two.
                         // Choose a larger number for better accuracy, e.g. 32768.
    double* inp = malloc(sizeof(double)*2*Nsamples);
    // Start integration
    for (int i=0; i<Nsamples; i++){
        // Integrate for 1000 steps (120000 days)
        reb_simulation_steps(r, 1000);
        // Calculate orbital elements of Jupiter
        struct reb_orbit o = reb_orbit_from_particle(r->G, r->particles[1], r->particles[0]);
        // Store complex eccentricity in array
        inp[i*2+0] = o.e*cos(o.pomega);
        inp[i*2+1] = o.e*sin(o.pomega);
    }

    // Perform frequency analysis
    int nfreq = 5;
    double datasep = 120000.0/365.25*2.0*M_PI;  // sampling interval in units of year/2pi
    double minfreq = 60.0/1296000.0*datasep;    // min/max frequenxy 60"/year
    double* out = malloc(sizeof(double)*3*nfreq);
    // The next command performs the actual Frequency Modified Fourier Transform (FMFT).
    // Other options are MFT (faster) and FMFT2 (more accurate).
    // See Sidlichovsky and Nesvorny (1996) for more details:
    //     https://ui.adsabs.harvard.edu/abs/1996CeMDA..65..137S/abstract
    int error = reb_frequency_analysis(out, nfreq, -minfreq, minfreq, REB_FREQUENCY_ANALYSIS_FMFT, inp, Nsamples);
    if (error){
        printf("An error occured during the frequency analysis.\n");
    }

    // Output the nfreq most dominate modes
    for (int i=0; i<nfreq; i++){
        double nu = out[0*nfreq+i]*1296000.0/datasep; // frequency in "/year
        double A = out[1*nfreq+i];                    // amplitude error
        double phi = out[2*nfreq+i]/M_PI*180.0;       // phase in deg
        printf("nu = %5.2f\"/yr  A = %0.6f  phi = %5.1f°\n", nu, A, phi);
    }

    // Cleanup
    free(out);
    free(inp);
    reb_simulation_free(r);
}

This example is located in the directory examples/secular_frequencies