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.

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:

```
case class HzLimit(val flux : Double, val distance : Double)
case class HabitableZone(val recentVenus : HzLimit,
val runawayGreenhouse : HzLimit,
val maxGreenhouse : HzLimit,
val earlyMars : HzLimit)
```

The HZ calculator will be a stateless object:

```
object HabitableZoneCalculator {
// the code below is placed here
}
```

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

```
private val teffSun = 5780
private val coeffsRecentVenus = List(1.776, 2.136e-04, 2.533e-08, -1.332e-11, -3.097e-15)
private val coeffsRunawayGreenhouse = List(1.107, 1.332e-04, 1.58e-08, -8.308e-12, -1.931e-15)
private val coeffsMaxGreenhouse = List(3.56e-01, 6.171e-05, 1.698e-09, -3.198e-12, -5.575e-16)
private 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:

```
private def roundToDecimals(value : Double, nbDecimals : Int) = {
val multiplier = Math.pow(10, nbDecimals);
Math.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:

```
private def calculateLimit(effectiveTemperature: Int,
luminosity: Double,
coeffs: List[Double]) : HzLimit = {
val flux = calculateFlux(effectiveTemperature, coeffs)
val distance = roundToDecimals(Math.sqrt(luminosity / flux), 3)
HzLimit(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:

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

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

```
def calculateHabitableZone(effectiveTemperature : Int,
luminosity : Double) : HabitableZone = {
val recentVenus = calculateLimit(effectiveTemperature, luminosity, coeffsRecentVenus)
val runawayGreenHouse = calculateLimit(effectiveTemperature, luminosity, coeffsRunawayGreenhouse)
val maxGreenhouse = calculateLimit(effectiveTemperature, luminosity, coeffsMaxGreenhouse)
val earlyMars = calculateLimit(effectiveTemperature, luminosity, coeffsEarlyMars)
HabitableZone(recentVenus, runawayGreenHouse, maxGreenhouse, earlyMars)
}
```

programming
scala
maths
scientific
exoplanets
habitable zone

intermediate

intermediate