Habitable Zone Calculation

Choice of Estimation Method

After checking different approaches to estimate the boundaries of habitable zones (HZ), I decided to take one of them as base method for calculating the zone to be rendered in the planetary systems comparison diagrams.

Many of the estimation methods cited in the table give either inner or outer boundary of HZ and only four of them provide both (Dole, Hart, Vladilo and Kopparapu).

After a brief analyze I decided to use the one that looks as the most optimistic and has the hugest spread of the four. The estimation suggested by Kopparapu et al places the Earth close to the inner edge of the HZ and Mars close to the outer edge, which may be quite interesting for visualization, instead of having only the Earth's orbit drawn within the HZ, as in the other three estimations.

HZ Boundaries Calculation

The original Javascript code used in the page really needs cleaning, so while examining it, I translated it into Scala and eliminated a number of redundancies.

To wrap the parameters describing a habitable zone, we need two simple data structures:

 class HzLimit(val flux : Double, val distance : Double)

 class HabitableZone(val recentVenus : HzLimit,
                     val runawayGreenhouse : HzLimit,
                     val maxGreenhouse : HzLimit,
                     val earlyMars : HzLimit)

The HZ calculator will be a stateless object:

ct HabitableZoneCalculator {
 the code below is placed here

Inside this object, the coefficients and the solar effective temperature become constants:

ate val teffSun = 5780
ate val coeffsRecentVenus = List(1.776, 2.136e-04, 2.533e-08, -1.332e-11, -3.097e-15)
ate val coeffsRunawayGreenhouse = List(1.107, 1.332e-04, 1.58e-08, -8.308e-12, -1.931e-15)
ate val coeffsMaxGreenhouse = List(3.56e-01, 6.171e-05, 1.698e-09, -3.198e-12, -5.575e-16)
ate val coeffsEarlyMars = List(3.2e-01, 5.547e-05, 1.526e-09, -2.874e-12, -5.011e-16)

The results of operations with these numbers will need to be rounded, so we create a short rounding function like:

ate def roundToDecimals(value : Double, nbDecimals : Int) = {
l multiplier = Math.pow(10, nbDecimals);
th.round(value * multiplier) / multiplier;

because, unfortunately, the standard API provides the possibility to round a number to the closest integer only.

To characterize a limit of a habitable zone, we need to calculate its two parameters, the flux and the distance from the star:

ate def calculateLimit(effectiveTemperature: Int,
                       luminosity: Double,
                       coeffs: List[Double]) : HzLimit = {
l flux = calculateFlux(effectiveTemperature, coeffs)
l distance = roundToDecimals(Math.sqrt(luminosity / flux), 3)
Limit(flux, distance)

The distance value is calculated straightforward using the square root of luminosity divided by flux, but the value of the latter needs a deeper approach:

ate def calculateFlux(effectiveTemperature : Int,
                      coeffs : List[Double]) = {
l coeffsToPower = coeffs.tail.zipWithIndex
l flux = coeffsToPower.foldLeft(coeffs.head){
case (curFlux, (coeff, power)) => {
  curFlux + coeff * Math.pow(effectiveTemperature - teffSun, power + 1)

undToDecimals(flux, 3)

Finally, the only public function makes calls to calculate each of the HZ limits and produces the resulting object:

calculateHabitableZone(effectiveTemperature : Int,
                       luminosity : Double) : HabitableZone = {
l recentVenus = calculateLimit(effectiveTemperature, luminosity, coeffsRecentVenus)
l runawayGreenHouse = calculateLimit(effectiveTemperature, luminosity, coeffsRunawayGreenhouse)
l maxGreenhouse = calculateLimit(effectiveTemperature, luminosity, coeffsMaxGreenhouse)
l earlyMars = calculateLimit(effectiveTemperature, luminosity, coeffsEarlyMars)
bitableZone(recentVenus, runawayGreenHouse, maxGreenhouse, earlyMars)

The complete source code and tests are available.

Tags:  programming scala maths scientific exoplanets habitable zone
Level:  intermediate