/// <summary> Accretes dust and/or gas from all bands onto the specified protoplanet, /// iterating until the marginal mass increase approaches zero. Once the /// new mass has been calculated, the dust bands are updated to reflect the /// accretion of dust and/or gas onto the protoplanet. /// </summary> /// <param name="p">Protoplanet accreting in this cycle /// </param> public virtual void accrete_dust(Protoplanet p) { //double temp_mass; double start_mass = p.mass; double minimum_accretion = 0.0001 * start_mass; double r_inner, r_outer, gatherLast, gatherNow; DustBand db; gatherNow = 0.0; do { gatherLast = gatherNow; // calculate new mass of protoplanet, considering last calculated // quantity of accreted matter, then calculate region to be swept // based on the updated mass. p.mass = start_mass + gatherLast; p.reduce_mass(); gas = !p.accretes_gas(); r_inner = p.inner_reduced_limit(cloud_eccentricity); r_outer = p.outer_reduced_limit(cloud_eccentricity); if (r_inner < 0.0) r_inner = 0.0; // sweep through all dust bands, collecting matter within the // effective reach of the protoplanet's gravity. gatherNow = 0.0; for (db = dust_head; db != null; db = db.next_band) { gatherNow += db.collect_dust(r_inner, r_outer, p); } } while ((gatherNow - gatherLast) >= minimum_accretion); update_dust_lanes(p.inner_effect_limit(cloud_eccentricity), p.outer_effect_limit(cloud_eccentricity)); }
/// <summary> Accretes dust and/or gas from all bands onto the specified protoplanet, /// iterating until the marginal mass increase approaches zero. Once the /// new mass has been calculated, the dust bands are updated to reflect the /// accretion of dust and/or gas onto the protoplanet. /// </summary> /// <param name="p">Protoplanet accreting in this cycle /// </param> public virtual void accrete_dust(Protoplanet p) { //double temp_mass; double start_mass = p.mass; double minimum_accretion = 0.0001 * start_mass; double r_inner, r_outer, gatherLast, gatherNow; DustBand db; gatherNow = 0.0; do { gatherLast = gatherNow; // calculate new mass of protoplanet, considering last calculated // quantity of accreted matter, then calculate region to be swept // based on the updated mass. p.mass = start_mass + gatherLast; p.reduce_mass(); gas = !p.accretes_gas(); r_inner = p.inner_reduced_limit(cloud_eccentricity); r_outer = p.outer_reduced_limit(cloud_eccentricity); if (r_inner < 0.0) { r_inner = 0.0; } // sweep through all dust bands, collecting matter within the // effective reach of the protoplanet's gravity. gatherNow = 0.0; for (db = dust_head; db != null; db = db.next_band) { gatherNow += db.collect_dust(r_inner, r_outer, p); } }while ((gatherNow - gatherLast) >= minimum_accretion); update_dust_lanes(p.inner_effect_limit(cloud_eccentricity), p.outer_effect_limit(cloud_eccentricity)); }
/// <summary> Determines whether dust is present within the effect radius of /// a specific Protoplanet. /// </summary> /// <param name="p">Protoplanet within the disc /// </param> /// <returns>s true if there is a band containing dust which this body /// can accrete. /// </returns> public virtual bool dust_available(Protoplanet p) { double inside_range = p.inner_effect_limit(cloud_eccentricity); double outside_range = p.outer_effect_limit(cloud_eccentricity); DustBand current_dust_band; bool dust_here = false; current_dust_band = dust_head; while ((current_dust_band != null) && (current_dust_band.outer_edge < inside_range)) { current_dust_band = current_dust_band.next_band; } if (current_dust_band == null) { dust_here = false; } else { dust_here = current_dust_band.dust_present; } while ((current_dust_band != null) && (current_dust_band.inner_edge < outside_range)) { dust_here = dust_here || current_dust_band.dust_present; current_dust_band = current_dust_band.next_band; } return(dust_here); }
/// <summary> Copy constructor</summary> public Protoplanet(Protoplanet p) { a = p.a; e = p.e; mass = p.mass; //next_planet = p.next_planet; gas_giant = p.gas_giant; crit_mass = p.crit_mass; dust_density = p.dust_density; moons = new ArrayList(); if (p.moons != null) { foreach (Protoplanet moon in p.moons) { moons.Add(moon); } } }
/// <summary> Calculate the amount of dust which the specified protoplanet can /// accrete from this dust band, if any. /// </summary> /// <returns>s Quantity of dust, in units of solar masses. /// </returns> public virtual double collect_dust(double r_inner, double r_outer, Protoplanet p) { double gather = 0.0; /* as last_mass increases, temp approaches 1. * reduced_mass approaches 1 even quicker. * as reduced_mass approaches 1, r_inner approaches 0 and * r_outer approaches 2*a*(1.0 + e). Apparently the integration * is from 0 to 2a. * The masses are expressed in terms of solar masses; temp is therefore * the ratio of the planetary mass to the total system (sun + planet) */ if (intersect(r_inner, r_outer) != DBI_NO_INTERSECTION) { double bandwidth = (r_outer - r_inner); double temp1 = r_outer - outer_edge; double temp2 = inner_edge - r_inner; double width; double temp; double volume; if (bandwidth <= 0.0) { bandwidth = 0.0; } if (temp1 < 0.0) { temp1 = 0.0; } width = bandwidth - temp1; if (temp2 < 0.0) { temp2 = 0.0; } width -= temp2; if (width < 0.0) { width = 0.0; } temp = 4.0 * System.Math.PI * System.Math.Pow(p.a, 2.0) * p.reduced_mass * (1.0 - p.e * (temp1 - temp2) / bandwidth); volume = temp * width; gather = (volume * p.mass_density(dust_present, gas_present)); } return(gather); }
/// <summary> Accretes protoplanets from the dust disc in this system.</summary> /// <returns>s First protoplanet of accreted system, as the head /// element of a list of protoplanets. /// </returns> public virtual void dist_planetary_masses() { Protoplanet p0; while (disc.dust_left) { p0 = new Protoplanet(disc.body_inner_bound, disc.body_outer_bound); if (disc.dust_available(p0)) { p0.dust_density = PhysicalConstants.DUST_DENSITY_COEFF * System.Math.Sqrt(star.SM) * System.Math.Exp((-PhysicalConstants.ALPHA) * System.Math.Pow(p0.a, (1.0 / PhysicalConstants.N))); p0.crit_mass = star.critical_limit(p0.a, p0.e); disc.accrete_dust(p0); if (p0.massOK()) { coalesce_planetesimals(p0); } else { //System.out.println(".. failed due to large neighbor."); } } } }
/// <summary> Determines whether dust is present within the effect radius of /// a specific Protoplanet. /// </summary> /// <param name="p">Protoplanet within the disc /// </param> /// <returns>s true if there is a band containing dust which this body /// can accrete. /// </returns> public virtual bool dust_available(Protoplanet p) { double inside_range = p.inner_effect_limit(cloud_eccentricity); double outside_range = p.outer_effect_limit(cloud_eccentricity); DustBand current_dust_band; bool dust_here = false; current_dust_band = dust_head; while ((current_dust_band != null) && (current_dust_band.outer_edge < inside_range)) current_dust_band = current_dust_band.next_band; if (current_dust_band == null) dust_here = false; else dust_here = current_dust_band.dust_present; while ((current_dust_band != null) && (current_dust_band.inner_edge < outside_range)) { dust_here = dust_here || current_dust_band.dust_present; current_dust_band = current_dust_band.next_band; } return (dust_here); }
/// <summary> /// Constructor from an accreted protoplanet. /// </summary> /// <param name="p">Protoplanet that forms the basis of this planet /// </param> public Planet(Protoplanet p) { //next_planet = null; //first_moon = null; a = p.a; e = p.e; mass = p.mass * PhysicalConstants.SUN_MASS_IN_EARTH_MASSES; gas_giant = p.gas_giant; where_in_orbit = (nextDouble() * 360.0) * PhysicalConstants.DEG_TO_RAD; albedo = 0.0; // start with albedo of 0 plan_class = classify_by_accretion(); if (mass < 1.0e-6) { mass = 0.0; plan_class = '-'; } density = density_by_temperature(plan_class); radius = planet_radius(mass, density, plan_class); moons = new ArrayList(); if (p.moons != null) { foreach (Protoplanet moon in p.moons) { moons.Add(moon); } } }
/// <summary> Calculate the amount of dust which the specified protoplanet can /// accrete from this dust band, if any. /// </summary> /// <returns>s Quantity of dust, in units of solar masses. /// </returns> public virtual double collect_dust(double r_inner, double r_outer, Protoplanet p) { double gather = 0.0; /* as last_mass increases, temp approaches 1. * reduced_mass approaches 1 even quicker. * as reduced_mass approaches 1, r_inner approaches 0 and * r_outer approaches 2*a*(1.0 + e). Apparently the integration * is from 0 to 2a. * The masses are expressed in terms of solar masses; temp is therefore * the ratio of the planetary mass to the total system (sun + planet) */ if (intersect(r_inner, r_outer) != DBI_NO_INTERSECTION) { double bandwidth = (r_outer - r_inner); double temp1 = r_outer - outer_edge; double temp2 = inner_edge - r_inner; double width; double temp; double volume; if (bandwidth <= 0.0) bandwidth = 0.0; if (temp1 < 0.0) temp1 = 0.0; width = bandwidth - temp1; if (temp2 < 0.0) temp2 = 0.0; width -= temp2; if (width < 0.0) width = 0.0; temp = 4.0 * System.Math.PI * System.Math.Pow(p.a, 2.0) * p.reduced_mass * (1.0 - p.e * (temp1 - temp2) / bandwidth); volume = temp * width; gather = (volume * p.mass_density(dust_present, gas_present)); } return gather; }
/// <summary> Searches the planetesimals already present in this system /// for a possible collision. Does not run any long-term simulation /// of orbits, doesn't try to eject bodies... /// </summary> /// <param name="p"> /// Newly injected accreting protoplanet to test /// </param> public virtual void coalesce_planetesimals(Protoplanet p) { // note that p is not consumed by this routine... Protoplanet node2, node3; bool finished = false; double temp, dist1, dist2, a3; double reduced_mass = p.mass; // try to merge Protoplanets //node2 = node1 = planet_head; foreach (Protoplanet node1 in this.protoplanetsList) { node2 = node1; temp = node1.a - p.a; if ((temp > 0.0)) { dist1 = (p.a * (1.0 + p.e) * (1.0 + p.mass)) - p.a; /* x aphelion */ if (node1.mass <= 0.0) { reduced_mass = 0.0; } else { reduced_mass = System.Math.Pow((node1.mass / (1.0 + node1.mass)), (1.0 / 4.0)); } dist2 = node1.a - (node1.a * (1.0 - node1.e) * (1.0 - reduced_mass)); } else { dist1 = p.a - (p.a * (1.0 - p.e) * (1.0 - p.mass)); /* x perihelion */ if (node1.mass <= 0.0) { reduced_mass = 0.0; } else { reduced_mass = System.Math.Pow(node1.mass / (1.0 + node1.mass), (1.0 / 4.0)); } dist2 = (node1.a * (1.0 + node1.e) * (1.0 + reduced_mass)) - node1.a; } if (((System.Math.Abs(temp) <= System.Math.Abs(dist1)) || (System.Math.Abs(temp) <= System.Math.Abs(dist2)))) { //collision if (p.mass > 0.2 /*&& (node1.mass / p.mass) > 0.1*/) { } a3 = (node1.mass + p.mass) / ((node1.mass / node1.a) + (p.mass / p.a)); temp = node1.mass * System.Math.Sqrt(node1.a) * System.Math.Sqrt(1.0 - (node1.e * node1.e)); temp += (p.mass * System.Math.Sqrt(p.a) * System.Math.Sqrt(System.Math.Sqrt(1.0 - (p.e * p.e)))); temp /= ((node1.mass + p.mass) * System.Math.Sqrt(a3)); temp = 1.0 - (temp * temp); if (((temp < 0.0) || (temp >= 1.0))) { temp = 0.0; } p.e = System.Math.Sqrt(temp); temp = node1.mass + p.mass; node1.a = a3; node1.e = p.e; node1.mass = temp; disc.accrete_dust(node1); //node1 = null; finished = true; } } if (!finished) { // add copy of planetesimal to planets list node3 = new Protoplanet(p); node3.gas_giant = (p.mass >= p.crit_mass); protoplanetsList.Add(node3); protoplanetsList.Sort(new PlanetSort(SortDirection.Ascending)); #region Original code, made obsolete by sort method of ArrayList //if ((planet_head == null)) //{ // planet_head = node3; //} //else //{ // node1 = planet_head; // if ((p.a < node1.a)) // { // node3.next_planet = node1; // planet_head = node3; // } // else if ((planet_head.next_planet == null)) // { // planet_head.next_planet = node3; // } // else // { // while (((node1 != null) && (node1.a < p.a))) // { // node2 = node1; // node1 = node1.next_planet; // } // node3.next_planet = node1; // node2.next_planet = node3; // } //} #endregion } }
/// <summary> Searches the planetesimals already present in this system /// for a possible collision. Does not run any long-term simulation /// of orbits, doesn't try to eject bodies... /// </summary> /// <param name="p"> /// Newly injected accreting protoplanet to test /// </param> public virtual void coalesce_planetesimals(Protoplanet p) { // note that p is not consumed by this routine... Protoplanet node2, node3; bool finished = false; double temp, dist1, dist2, a3; double reduced_mass = p.mass; // try to merge Protoplanets //node2 = node1 = planet_head; foreach (Protoplanet node1 in this.protoplanetsList) { node2 = node1; temp = node1.a - p.a; if ((temp > 0.0)) { dist1 = (p.a * (1.0 + p.e) * (1.0 + p.mass)) - p.a; /* x aphelion */ if (node1.mass <= 0.0) reduced_mass = 0.0; else reduced_mass = System.Math.Pow((node1.mass / (1.0 + node1.mass)), (1.0 / 4.0)); dist2 = node1.a - (node1.a * (1.0 - node1.e) * (1.0 - reduced_mass)); } else { dist1 = p.a - (p.a * (1.0 - p.e) * (1.0 - p.mass)); /* x perihelion */ if (node1.mass <= 0.0) reduced_mass = 0.0; else reduced_mass = System.Math.Pow(node1.mass / (1.0 + node1.mass), (1.0 / 4.0)); dist2 = (node1.a * (1.0 + node1.e) * (1.0 + reduced_mass)) - node1.a; } if (((System.Math.Abs(temp) <= System.Math.Abs(dist1)) || (System.Math.Abs(temp) <= System.Math.Abs(dist2)))) { //collision if (p.mass > 0.2 /*&& (node1.mass / p.mass) > 0.1*/) { } a3 = (node1.mass + p.mass) / ((node1.mass / node1.a) + (p.mass / p.a)); temp = node1.mass * System.Math.Sqrt(node1.a) * System.Math.Sqrt(1.0 - (node1.e * node1.e)); temp += (p.mass * System.Math.Sqrt(p.a) * System.Math.Sqrt(System.Math.Sqrt(1.0 - (p.e * p.e)))); temp /= ((node1.mass + p.mass) * System.Math.Sqrt(a3)); temp = 1.0 - (temp * temp); if (((temp < 0.0) || (temp >= 1.0))) temp = 0.0; p.e = System.Math.Sqrt(temp); temp = node1.mass + p.mass; node1.a = a3; node1.e = p.e; node1.mass = temp; disc.accrete_dust(node1); //node1 = null; finished = true; } } if (!finished) { // add copy of planetesimal to planets list node3 = new Protoplanet(p); node3.gas_giant = (p.mass >= p.crit_mass); protoplanetsList.Add(node3); protoplanetsList.Sort(new PlanetSort(SortDirection.Ascending)); #region Original code, made obsolete by sort method of ArrayList //if ((planet_head == null)) //{ // planet_head = node3; //} //else //{ // node1 = planet_head; // if ((p.a < node1.a)) // { // node3.next_planet = node1; // planet_head = node3; // } // else if ((planet_head.next_planet == null)) // { // planet_head.next_planet = node3; // } // else // { // while (((node1 != null) && (node1.a < p.a))) // { // node2 = node1; // node1 = node1.next_planet; // } // node3.next_planet = node1; // node2.next_planet = node3; // } //} #endregion } }
/// <summary> Accretes protoplanets from the dust disc in this system.</summary> /// <returns>s First protoplanet of accreted system, as the head /// element of a list of protoplanets. /// </returns> public virtual void dist_planetary_masses() { Protoplanet p0; while (disc.dust_left) { p0 = new Protoplanet(disc.body_inner_bound, disc.body_outer_bound); if (disc.dust_available(p0)) { p0.dust_density = PhysicalConstants.DUST_DENSITY_COEFF * System.Math.Sqrt(star.SM) * System.Math.Exp((-PhysicalConstants.ALPHA) * System.Math.Pow(p0.a, (1.0 / PhysicalConstants.N))); p0.crit_mass = star.critical_limit(p0.a, p0.e); disc.accrete_dust(p0); if (p0.massOK()) coalesce_planetesimals(p0); else { //System.out.println(".. failed due to large neighbor."); } } } }
int IComparer.Compare(object x, object y) { if ((x is Protoplanet) && (y is Protoplanet)) { Protoplanet p1 = (Protoplanet)x; Protoplanet p2 = (Protoplanet)y; if (p1 == null && p2 == null) { return(0); } else if (p1 == null && p2 != null) { return((this.m_direction == SortDirection.Ascending) ? -1 : 1); } else if (p1 != null && p2 == null) { return((this.m_direction == SortDirection.Ascending) ? 1 : -1); } else { if (p1.a > 0 && p2.a > 0) { return((this.m_direction == SortDirection.Ascending) ? p1.a.CompareTo(p2.a) : p2.a.CompareTo(p1.a)); } else { return(0); } } } else if ((x is Planet) && (y is Planet)) { Planet p1 = (Planet)x; Planet p2 = (Planet)y; if (p1 == null && p2 == null) { return(0); } else if (p1 == null && p2 != null) { return((this.m_direction == SortDirection.Ascending) ? -1 : 1); } else if (p1 != null && p2 == null) { return((this.m_direction == SortDirection.Ascending) ? 1 : -1); } else { if (p1.a > 0 && p2.a > 0) { return((this.m_direction == SortDirection.Ascending) ? p1.a.CompareTo(p2.a) : p2.a.CompareTo(p1.a)); } else { return(0); } } } else { return(0); } }