private IEnumerable <Seed> ProcessSeeds(InnerSeed nextSeed)
        {
            var seedList = new List <Seed>();
            var next     = nextSeed;

            while (next != null)
            {
                seedList.Add(next);
                if (next.FirstSatellite != null)
                {
                    next.Satellites = ProcessSeeds(next.FirstSatellite);
                }
                next = next.NextBody;
            }

            return(seedList);
        }
        private void SetInitialConditions(Length inner_limit_of_dust, Length outer_limit_of_dust)
        {
            _histHead = new Generation();

            _planetHead           = null;
            _dustHead             = new DustRecord();
            _dustHead.NextBand    = null;
            _dustHead.OuterEdge   = outer_limit_of_dust.AstronomicalUnits;
            _dustHead.InnerEdge   = inner_limit_of_dust.AstronomicalUnits;
            _dustHead.DustPresent = true;
            _dustHead.GasPresent  = true;
            _dustLeft             = true;
            _cloudEccentricity    = CloudEccentricity;

            _histHead.Dusts  = _dustHead;
            _histHead.Bodies = _planetHead;
            _histHead.Next   = _histHead;
        }
        private void CoalescePlanetesimals(Length a,
                                           Ratio e,
                                           Mass mass,
                                           Mass critMass,
                                           Mass dustMass,
                                           Mass gasMass,
                                           Luminosity stellLuminosityRatio,
                                           Length bodyInnerBound,
                                           Length bodyOuterBound,
                                           bool doMoons)
        {
            // First we try to find an existing planet with an over-lapping orbit.
            InnerSeed thePlanet  = null;
            InnerSeed nextPlanet = null;
            InnerSeed prevPlanet = null;
            var       finished   = false;

            for (thePlanet = _planetHead; thePlanet != null; thePlanet = thePlanet.NextBody)
            {
                Length diff = thePlanet.SemiMajorAxis - a;
                Length dist1;
                Length dist2;

                if (diff.AstronomicalUnits > 0.0)
                {
                    dist1 = a * (1.0 + e.Value) * (1.0 + _reducedMass) - a;
                    /* x aphelion	 */
                    _reducedMass = Math.Pow(thePlanet.Mass.SolarMasses / (1.0 + thePlanet.Mass.SolarMasses), 1.0 / 4.0);
                    dist2        = thePlanet.SemiMajorAxis - thePlanet.SemiMajorAxis * (1.0 - thePlanet.Eccentricity.Value) * (1.0 - _reducedMass);
                }
                else
                {
                    dist1 = a - a * (1.0 - e.Value) * (1.0 - _reducedMass);
                    /* x perihelion */
                    _reducedMass = Math.Pow(thePlanet.Mass.SolarMasses / (1.0 + thePlanet.Mass.SolarMasses), 1.0 / 4.0);
                    dist2        = thePlanet.SemiMajorAxis * (1.0 + thePlanet.Eccentricity.Value) * (1.0 + _reducedMass)
                                   - thePlanet.SemiMajorAxis;
                }

                // Did the planetesimal collide with this planet?
                if (Math.Abs(diff.Value) <= Math.Abs(dist1.Value) || Math.Abs(diff.Value) <= Math.Abs(dist2.Value))
                {
                    Mass   new_dust = Mass.FromSolarMasses(0.0);
                    Mass   new_gas  = Mass.FromSolarMasses(0.0);
                    Length new_a    = Length.FromAstronomicalUnits((thePlanet.Mass.SolarMasses + mass.SolarMasses)
                                                                   / (thePlanet.Mass.SolarMasses / thePlanet.SemiMajorAxis.AstronomicalUnits + mass.SolarMasses / a.AstronomicalUnits));

                    e = GetNewEccentricity(thePlanet, e, a, mass, new_a);

                    if (doMoons)
                    {
                        finished = DoMoons(thePlanet, mass, critMass, dustMass, gasMass);
                    }

                    if (!finished)
                    {
                        //Trace.TraceInformation("Collision between two planetesimals!\n {0:0.00} AU ({1:0.00}EM) + {2:0.00} AU ({3:0.00}EM = {4:0.00}EMd + {5:0.00}EMg [{6:0.00}EM]). {7:0.00} AU ({8:0.00})",
                        //    the_planet.a, the_planet.mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES,
                        //    a, mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES,
                        //    dust_mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES,
                        //    gas_mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES,
                        //    crit_mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES,
                        //    new_a, e);

                        var newMass = thePlanet.Mass + mass;
                        // TODO: Why is a solar luminosity ratio passed as a Mass for critical mass?
                        AccreteDust(ref newMass, ref new_dust, ref new_gas,
                                    new_a, e, Mass.FromSolarMasses(stellLuminosityRatio.SolarLuminosities),
                                    bodyInnerBound, bodyOuterBound);

                        thePlanet.SemiMajorAxis = new_a;
                        thePlanet.Eccentricity  = e;
                        thePlanet.Mass          = newMass;
                        thePlanet.DustMass     += dustMass + new_dust;
                        thePlanet.GasMass      += gasMass + new_gas;
                        if (thePlanet.Mass >= critMass)
                        {
                            thePlanet.IsGasGiant = true;
                        }

                        while (thePlanet.NextBody != null && thePlanet.NextBody.SemiMajorAxis < new_a)
                        {
                            nextPlanet = thePlanet.NextBody;

                            if (thePlanet == _planetHead)
                            {
                                _planetHead = nextPlanet;
                            }
                            else
                            {
                                prevPlanet.NextBody = nextPlanet;
                            }

                            thePlanet.NextBody  = nextPlanet.NextBody;
                            nextPlanet.NextBody = thePlanet;
                            prevPlanet          = nextPlanet;
                        }
                    }

                    finished = true;
                    break;
                }
                else
                {
                    prevPlanet = thePlanet;
                }
            }

            // Planetesimals didn't collide. Make it a planet.
            if (!finished)
            {
                thePlanet = new InnerSeed(a, e, mass, dustMass, gasMass);

                if (mass >= critMass)
                {
                    thePlanet.IsGasGiant = true;
                }
                else
                {
                    thePlanet.IsGasGiant = false;
                }

                if (_planetHead == null)
                {
                    _planetHead        = thePlanet;
                    thePlanet.NextBody = null;
                }
                else if (a < _planetHead.SemiMajorAxis)
                {
                    thePlanet.NextBody = _planetHead;
                    _planetHead        = thePlanet;
                }
                else if (_planetHead.NextBody == null)
                {
                    _planetHead.NextBody = thePlanet;
                    thePlanet.NextBody   = null;
                }
                else
                {
                    nextPlanet = _planetHead;
                    while (nextPlanet != null && nextPlanet.SemiMajorAxis < a)
                    {
                        prevPlanet = nextPlanet;
                        nextPlanet = nextPlanet.NextBody;
                    }
                    thePlanet.NextBody  = nextPlanet;
                    prevPlanet.NextBody = thePlanet;
                }
            }
        }
        private bool DoMoons(InnerSeed planet, Mass mass, Mass critMass, Mass dustMass, Mass gasMass)
        {
            bool finished     = false;
            Mass existingMass = Mass.FromSolarMasses(0.0);

            if (planet.FirstSatellite != null)
            {
                for (InnerSeed m = planet.FirstSatellite; m != null; m = m.NextBody)
                {
                    existingMass += m.Mass;
                }
            }

            if (mass < critMass)
            {
                if (mass.EarthMasses < 2.5 && mass.EarthMasses > .0001 && existingMass < planet.Mass * .05)
                {
                    InnerSeed moon = new InnerSeed(Length.FromMeters(0.0), Ratio.FromDecimalFractions(0.0), mass, dustMass, gasMass);

                    if (moon.DustMass + moon.GasMass > planet.DustMass + planet.GasMass)
                    {
                        Mass tempDust = planet.DustMass;
                        Mass tempGas  = planet.GasMass;
                        Mass tempMass = planet.Mass;

                        planet.DustMass = moon.DustMass;
                        planet.GasMass  = moon.GasMass;
                        planet.Mass     = moon.Mass;

                        moon.DustMass = tempDust;
                        moon.GasMass  = tempGas;
                        moon.Mass     = tempMass;
                    }

                    if (planet.FirstSatellite == null)
                    {
                        planet.FirstSatellite = moon;
                    }
                    else
                    {
                        moon.NextBody         = planet.FirstSatellite;
                        planet.FirstSatellite = moon;
                    }

                    finished = true;

                    //Trace.TraceInformation("Moon captured... {0:0.00} AU ({1:0.00}EM) <- {2:0.00} EM",
                    //    the_planet.a,
                    //    the_planet.mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES,
                    //    mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES);
                }
                //else
                //{
                //    Trace.TraceInformation("Moon escapes... {0:0.00} AU ({1:0.00} EM){2} {3:0.00}L {4}",
                //        the_planet.a,
                //        the_planet.mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES,
                //        existing_mass < (the_planet.mass * .05) ? "" : " (big moons)",
                //        mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES,
                //        (mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES) >= 2.5 ? ", too big" : (mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES) <= .0001 ? ", too small" : "");
                //}
            }

            return(finished);
        }