A simulated planetary transit, with the associated light curve

An amateur astronomer colleague of mine, Mátyás SZŰCS, got me inspired to look into exoplanets — once again. I already had a close encounter with distant solar systems, while looking into the Kepler measurements as published on the planethunters org website, going through some 4k stars of interest, of the some 160k that Kepler observed during its first mission.

I’ve never done observations of this kind before, maybe I never will. But I wanted to see what it is I could expect. I put together a naive simulation and then looked up some professional material to check for those into such stuff.

So I went for a rather naive approach here, went for numeric simulations in… well, PHP… with a color (rgb) selective limb darkening and planets with no atmosphere. The stars are simple, spherical, no polar brightening and no flattening, as with say Vega.

The interesting thing is the sharp drop between the first and second contacts and then the steady drop till the maximum — see below.

 

I checked some 4k stars in the kepler database, and this looks like a lucky one

The set I generated: blue-white-red stars with color-selective limb darkening, several planetary diameters relative to the host star, and from transits through the center to those barely grazing. All the “planets” move across the “star” from left to right. An important aspect to observe is that the limb darkening is more severe for the blue end of the spectrum.

The diagram below the snapshot shows the shape of the light curve, at 100% being the unobstructed star, and the minimum representing the planet placed right onto the center of the stellar disk, regardless of the vertical offset being observed. The numbers on the left indicate the percentage of the star’s luminosity available at the extremes, and the green dot draws the light curve between the two extremes. The source code, meant to be run in a localhost apache installation, is below.

So what I understand is:

 

Some of the generated pictures I put below, smaller set and the source code to generate all can be downloaded here:

A really huge probably hot Jupiter in front of a blue main sequence star (no flattening etc)

A really huge probably hot Jupiter in front of a blue main sequence star (no flattening etc)

A rocky planet perhaps in front of a yellow dwarf

A rocky planet perhaps in front of a yellow dwarf

a rocky planet, probably a super earth in front of a probably F type star

a rocky planet, probably a super earth in front of a probably F type star

probably a hot neptune or something in front of a red dwarf

probably a hot neptune or something in front of a red dwarf

a puffed up hot jupiter in front of a perhaps K type star, otherwise this ratio is a bit unlikely

a puffed up hot jupiter in front of a perhaps K type star, otherwise this ratio is a bit unlikely

a jupiter with a perhaps F type star

a jupiter with a perhaps F type star

a small rocky one in front of a red dwarf perhaps

a small rocky one in front of a red dwarf perhaps

this could be a Jupiter against a young blue star

this could be a Jupiter against a young blue star

a grazing transit

a grazing transit

third contact

third contact

A simulated Venus, Earth and Jupiter in front of the simulated Sun

A simulated Venus, Earth and Jupiter in front of the simulated Sun

The simulated Sun, Jupiter, Venus and Earth. More or less to scale regarding both the speed and the relative sizes

 

Regarding the transit of Venus, my naive approach compared to real life transits

Below is a picture of a Venus transit to scale, when viewed (left) from an insterstellar distance, and (right) from Earth in 2012 (but without the sunspots some of us remember). And a picture of the transit, as I recorded it in 2012.

Note some differences: it was early in the morning, and in between rains and clouds, at least some of the hue of the Sun may be due to that; the different limb darkening ratio; the amateur equipment used, ie a point and shoot camera with a baader solar filter.

 

 

Source Code

Second version of the code, that generated the Jupiter-Earth-Venus transit

<?php

set_time_limit (60*60);


function drawStarWithPlanetsAndReturnIntensity(
    $star_info,
    $planets_info,
    &$include_graph,
    $filename
  ){
    if (!isset($GLOBALS["__star_cache"])){
      $GLOBALS["__star_cache"] = array();
    }

    if (is_array($filename)){
      $filename = getfilepath($star_info, $planets_info, true, $filename["index"]);
    }

    if ($filename === "auto"){
      $filename = getfilepath($star_info, $planets_info, true);
    }


  $margin = $star_info["radius_px"] / 4;

  $xs = $star_info["radius_px"]*2 + $margin+$margin;
  $ys = $xs;
  if ($include_graph !== null){
    $ys = $ys * 3/2;
  }
  $o = $star_info["radius_px"] + $margin;

  $i = imagecreatetruecolor($xs, $ys);

  $key = "star".md5(serialize($star_info));
  if (isset($GLOBALS["__star_cache"][$key])){
    imagecopy($i, $GLOBALS["__star_cache"][$key], 0, 0, 0, 0, imagesx($i), imagesy($i));
  }else{
    imagefilledrectangle($i, 0,0, imagesx($i), imagesy($i), 0);

    $GLOBALS["__star_cache"][$key] = imagecreatetruecolor($xs, $ys);
    imagefilledrectangle($GLOBALS["__star_cache"][$key], 0,0, imagesx($GLOBALS["__star_cache"][$key]), imagesy($GLOBALS["__star_cache"][$key]), 0);
    for ($r=0; $r < $star_info["radius_px"]-2; $r++){
      $i_0 = 255;
      $bgr = array(0.95, 0.8, 0.56);
      foreach ($bgr as &$c){
        $u = $c;
        $i_r = $i_0 * (1 - $u * (1 - sqrt(($star_info["radius_px"]*$star_info["radius_px"] - $r*$r) / ($star_info["radius_px"]*$star_info["radius_px"]))));
        $c = $i_r;
      }
      $si = 1+abs($star_info["color_index"]);
      $kount = 2;$mult = 1;
      $kmu = $si - 6;
      if ($kmu >= 0){
        $kount += $kmu;
        $mult += $kmu;
      }
      if ($star_info["color_index"] < 0){
        // blue
        $bgr[2] = $bgr[2]/$si;
        $bgr[1] = (($bgr[1]/$si)*$mult + $bgr[1])/$kount;
      }
      if ($star_info["color_index"] > 0){
        // red
        $bgr[0] = $bgr[0]/$si;
        $bgr[1] = (($bgr[1]/$si)*$mult + $bgr[1])/$kount;
      }
      foreach ($bgr as &$c2){
        $c2 = floor($c2);
      };
      $col = imagecolorallocate($i, $bgr[2], $bgr[1], $bgr[0]);
      foreach (array(-1, 1) as $x){
        foreach (array(-1, 1) as $y){
          imageellipse ($i, $o+$x, $o+$y, $r*2 , $r*2, $col);
        }
      }
    }
    imagecopy($GLOBALS["__star_cache"][$key], $i, 0, 0, 0, 0, imagesx($i), imagesy($i));
  }


  $planets_total_area = 0;
  $planet_color = imagecolorallocate($i, 0, 0, 0);
  $planet_circle = imagecolorallocate($i, 125, 55, 0);
  foreach ($planets_info as $planet){
    $r = $star_info["radius_px"] * $planet["radius__in_stellar_radii"];
    $planets_total_area += M_PI * $r * $r;
    if ($r > 0){
      imagefilledellipse ($i,
        $o + $star_info["radius_px"]*$planet["offset_from_center_x__in_stellar_radii"],
        $o + $star_info["radius_px"]*$planet["offset_from_center_y__in_stellar_radii"],
        $r * 2,
        $r * 2,
        $planet_color
      );
    }
  }
  $planets_approx_radius_px = sqrt($planets_total_area / M_PI);
  $planets_approx_radius___in_stellar_radii = $planets_approx_radius_px / $star_info["radius_px"];


  // now get the intensity
  $um = 0;
  $lum = 0;
  for ($x=0; $x<imagesx($i); $x++){
    //imagesx, to not include any graph
    for ($y=0; $y<imagesx($i); $y++){
      $rgb = imagecolorat($i, $x, $y);
      $r = ($rgb >> 16) & 0xFF;
      $g = ($rgb >> 8) & 0xFF;
      $b = $rgb & 0xFF;
      $lum += $r+$g*2 +$b;
    };
  }

  foreach ($planets_info as $planet){
    $r = $star_info["radius_px"] * $planet["radius__in_stellar_radii"];
    //if the planet is outside the star
    if ($r > 0){
      $d = pow(($star_info["radius_px"]*$planet["offset_from_center_x__in_stellar_radii"]), 2) + pow($star_info["radius_px"]*$planet["offset_from_center_y__in_stellar_radii"], 2);
      $d = sqrt($d);
      if ($d > $star_info["radius_px"] + $r){
        imageellipse($i,
          $o + $star_info["radius_px"]*$planet["offset_from_center_x__in_stellar_radii"],
          $o + $star_info["radius_px"]*$planet["offset_from_center_y__in_stellar_radii"],
          $r * 2,
          $r * 2,
          $planet_circle
        );
      }
    }
  }



  if ($include_graph !== null ){
    $null = NULL;
    $xtr = 0;
    if (!isset($include_graph["min_lum"])){
      $planet_in_the_middle = array(
        "radius__in_stellar_radii" => $planets_approx_radius___in_stellar_radii,
        "offset_from_center_x__in_stellar_radii" => 0,
        "offset_from_center_y__in_stellar_radii" => 0
      );
      $summa_planet = array($planet_in_the_middle);

      $include_graph["min_lum"] = drawStarWithPlanetsAndReturnIntensity(
        $star_info,
        $summa_planet,
        $null,
        "?",
      );
      $xtr++;
    }
    if (!isset($include_graph["max_lum"])){
      $no_planet = array();
      $include_graph["max_lum"] = drawStarWithPlanetsAndReturnIntensity(
        $star_info,
        $no_planet,
        $null,
        "?",
      );
      $xtr++;
    }
    if ($xtr == 2){
    //  die();
    }
    $window_height = $ys - $xs;
    $window_width = $xs;
    $window_margin = round($xs / 10);
    $window_height -= 2*$window_margin;
    $window_width -= 2*$window_margin;

    $col = imagecolorallocate($i, 0, 255, 0);
    $white = imagecolorallocate($i, 255, 255, 255);


    //var_dump($include_graph);

    imagestring ($i, 1, 0, $ys-$window_margin - $window_height, "100%", $white);
    imagestring ($i, 1, 0, $ys-$window_margin, (round(($include_graph["min_lum"] / $include_graph["max_lum"])*10000)/100) . "%", $white);
    imageline ($i, $window_margin, $ys - $window_margin, $window_margin+$window_width, $ys-$window_margin, $white);
    imageline ($i, $window_margin, $ys - $window_margin, $window_margin, $ys-$window_margin-$window_height, $white);
    $px = $window_margin + $window_width/2 + ($include_graph["xpos"] / $include_graph["xhalfsize"]) * $window_width/2;
    $py = $ys - $window_margin - ($lum - $include_graph["min_lum"])/($include_graph["max_lum"] - $include_graph["min_lum"])*$window_height;
    //echo $px.' '.$py;
    $include_graph["points"][] = array($px, $py);
    $prev = false;
    foreach ($include_graph["points"] as $pix){
      if ($prev === false){
        imagesetpixel($i,$pix[0], $pix[1], $col);
      }else{
        imageline($i, $prev[0], $prev[1], $pix[0], $pix[1], $col);
      }
      $prev = $pix;
    }


  }


  if ($filename != "?"){
    imagejpeg($i, $filename, 95);
  };
  imagedestroy($i);
  return $lum;
}


//==============================================================================

function getfilepath($star_info, $planets_info, $create_folder = false, $index = false){
  $sepa = "__";
  $r = $star_info["radius_px"];
  while (strlen($r < 5)){
    $r = '0'.$r;
  }
  $folder = array();
  $folder[] = "starrad_".$r."px".$sepa;

  $col = abs($star_info["color_index"]);
  if ($star_info["color_index"] > 0){
    $col .= "r";
  }
  if ($star_info["color_index"] < 0){
    $col .= "b";
  }
  if ($star_info["color_index"] == 0){
    $col .= "w";
  }
  while (strlen($col) < 5){
    $col = '0'.$col;
  }
  $folder[] = "starcolorindex_".$col;

  $folder[] = "md5_".md5(serialize($folder));

  $filepath = array();
  if ($index!==false){
    while (strlen($index) < 5){
      $index = '0'.$index;
    }
    $filepath[] = $index;
  }

  $filepath = array_merge($filepath, $folder);

  if (count($planets_info) > 1){
    //filename too long
    $filepath[] = md5(serialize($planets_info));
  }else{
    $planetCounter = 0;
    foreach ($planets_info as $planet){
      $p = "planet".$planetCounter.$sepa."r_";
      $siz = $planet["radius__in_stellar_radii"] * $star_info["radius_px"];
      while (strlen($siz) < 5){
        $siz = "0".$siz;
      }
      $p .= $siz.'px';
      $filepath[] = $p;

      foreach (array("x", "y") as $xy){
        $p = "coff".$xy."_";
        $siz = $star_info["radius_px"]*$planet["offset_from_center_".$xy."__in_stellar_radii"];
        $asiz = round(abs($siz));
        while (strlen($asiz) < 5){
          $asiz = "0".$asiz;
        }
        $p .= ($siz < 0 ? "m" : "p").$asiz.'px';
        $filepath[] = $p;
      }


      $planetCounter++;
    }

  }


  $folder = implode($sepa, $folder);
  $filepath = implode($sepa, $filepath);
  if ($create_folder){
    @mkdir($folder);
  }
  return $folder.'/'.$filepath.'.jpg';
}

//==============================================================================

function createEmptyGraph(){
  return array(
        "points" => array(),
        "xpos" => 0,
        "xhalfsize" => 1
  );
}

//==============================================================================
function planets_xoffsetextreme_for_star($planet, $star_info){
  $spm = 1;
  if (isset($planet["speed_multiplier"])){
    $spm = $planet["speed_multiplier"];
    //die("kocka".$spm);
  }
  $px = ($star_info["radius_px"] * $planet["radius__in_stellar_radii"] * 1.3 * $spm) + $star_info["radius_px"];
  $sr = $px / $star_info["radius_px"];
  return array(
    "xoff__in_px" => $px,
    "xoff__in_stellar_radii" => $sr
  );
}


//==============================================================================

$star_info = array(
  "radius_px" => 305,
  "color_index" => -1
);

$planets_info = array();

$planets_info[] = array(
  "name" => "Venus",
  "radius__in_stellar_radii" => 0.01,
  "initial_offset_from_center_x__in_stellar_radii" => -7.2,
  "offset_from_center_x__in_stellar_radii" => 0.8,
  "offset_from_center_y__in_stellar_radii" => 0.1,
  "speed_multiplier" => 14
);

$planets_info[] = array(
  "name" => "Earth",
  "radius__in_stellar_radii" => 0.01,
  "initial_offset_from_center_x__in_stellar_radii" => -5.5,
  "offset_from_center_x__in_stellar_radii" => 0.8,
  "offset_from_center_y__in_stellar_radii" => 0.25,
  "speed_multiplier" => 11
);


$planets_info[] = array(
  "name" => "Jupiter",
  "radius__in_stellar_radii" => 0.1,
  "offset_from_center_x__in_stellar_radii" => -0.3,
  "offset_from_center_y__in_stellar_radii" => 0.3,
  "speed_multiplier" => 1
);


$include_graph = createEmptyGraph();



$planet_hastener_factor = 2;
$planet_unit_speed_factor = 5;
$planets_unit_speed = ($planet_unit_speed_factor / $star_info["radius_px"]) / 5;

$needed_half_steps = 0;
foreach ($planets_info as &$p){
  $k = planets_xoffsetextreme_for_star($p, $star_info);
  $k = $k["xoff__in_stellar_radii"];
  $p["offset_from_center_x__in_stellar_radii"] = -1 * $k;
  $nhs = (abs($p["offset_from_center_x__in_stellar_radii"]) / $planets_unit_speed) / $p["speed_multiplier"];
  $needed_half_steps = max($needed_half_steps, $nhs);
  if (isset($p["initial_offset_from_center_x__in_stellar_radii"])){
    $p["offset_from_center_x__in_stellar_radii"] += $p["initial_offset_from_center_x__in_stellar_radii"];
  }
};



$include_graph["xhalfsize"] = $needed_half_steps;
$steps = $include_graph["xhalfsize"]*2;
$null = NULL;

for ($step = 0; $step<min(400, $steps); $step++){
  $include_graph["xpos"] = $step - $include_graph["xhalfsize"];
  drawStarWithPlanetsAndReturnIntensity($star_info, $planets_info, $null, array(
    "index" => $step,
    "filename" => "auto"
  ));
  foreach ($planets_info as &$planet){
    $planet["offset_from_center_x__in_stellar_radii"] += $planet["speed_multiplier"]*$planets_unit_speed*$planet_hastener_factor;
  }
}


?>

First version of the code

<?php

set_time_limit (60*60);

function drawStarWithPlanetAndReturnIntensity(
    $star_radius,
    $planet_per_star_radius,
    $planet_offset_x__stellar_radii,
    $planet_offset_y__stellar_radii,
    &$include_graph,
    $filename,
    $star_color_index = 0
  ){
  $margin = $star_radius / 4;

  $xs = $star_radius*2+$margin+$margin;
  $ys = $xs;
  if ($include_graph !== null){
    $ys = $ys * 3/2;
  }

  $i = imagecreatetruecolor($xs, $ys);
  imagefilledrectangle($i, 0,0, imagesx($i), imagesy($i), 0);
  $o = $star_radius + $margin;
  for ($r=0; $r < $star_radius-2; $r++){
    $i_0 = 255;
    $bgr = array(0.95, 0.8, 0.56);
    foreach ($bgr as &$c){
      $u = $c;
      $i_r = $i_0 * (1 - $u * (1 - sqrt(($star_radius*$star_radius - $r*$r) / ($star_radius*$star_radius))));
      $c = $i_r;
    }
    $si = 1+abs($star_color_index);
    if ($star_color_index < 0){
      // blue
      $bgr[2] = $bgr[2]/$si;
      $bgr[1] = (($bgr[1]/$si) + $bgr[1])/2;
    }
    if ($star_color_index > 0){
      // red
      $bgr[0] = $bgr[0]/$si;
      $bgr[1] = (($bgr[1]/$si) + $bgr[1])/2;
    }
    foreach ($bgr as &$c2){
      $c2 = floor($c2);
    };
    $col = imagecolorallocate($i, $bgr[2], $bgr[1], $bgr[0]);
    foreach (array(-1, 1) as $x){
      foreach (array(-1, 1) as $y){
        imageellipse ($i, $o+$x, $o+$y, $r*2 , $r*2, $col);
      }
    }
  }

  imagefilledellipse ($i,
    $o + $star_radius*$planet_offset_x__stellar_radii,
    $o + $star_radius*$planet_offset_y__stellar_radii,
    $star_radius * $planet_per_star_radius * 2,
    $star_radius * $planet_per_star_radius * 2,
    0
  );

  // now get the intensity
  $um = 0;
  $lum = 0;
  for ($x=0; $x<imagesx($i); $x++){
    //imagesx, to not include any graph
    for ($y=0; $y<imagesx($i); $y++){
      $rgb = imagecolorat($i, $x, $y);
      $r = ($rgb >> 16) & 0xFF;
      $g = ($rgb >> 8) & 0xFF;
      $b = $rgb & 0xFF;
      $lum += $r+$g*2 +$b;
    };
  }


  if ($include_graph !== null ){
    $null = NULL;
    $xtr = 0;
    if (!isset($include_graph["min_lum"])){
      $include_graph["min_lum"] = drawStarWithPlanetAndReturnIntensity(
          $star_radius,
          $planet_per_star_radius,
          0,
          0,
          $null,
          "?",
          $star_color_index
        );
      $xtr++;
    }
    if (!isset($include_graph["max_lum"])){
      $include_graph["max_lum"] = drawStarWithPlanetAndReturnIntensity(
          $star_radius,
          $planet_per_star_radius,
          10,
          10,
          $null,
          "?",
          $star_color_index
        );
      $xtr++;
    }
    if ($xtr == 2){
    //  die();
    }
    $window_height = $ys - $xs;
    $window_width = $xs;
    $window_margin = round($xs / 10);
    $window_height -= 2*$window_margin;
    $window_width -= 2*$window_margin;

    $col = imagecolorallocate($i, 0, 255, 0);
    $white = imagecolorallocate($i, 255, 255, 255);


    //var_dump($include_graph);

    imagestring ($i, 1, 0, $ys-$window_margin - $window_height, "100%", $white);
    imagestring ($i, 1, 0, $ys-$window_margin, (round(($include_graph["min_lum"] / $include_graph["max_lum"])*10000)/100) . "%", $white);
    imageline ($i, $window_margin, $ys - $window_margin, $window_margin+$window_width, $ys-$window_margin, $white);
    imageline ($i, $window_margin, $ys - $window_margin, $window_margin, $ys-$window_margin-$window_height, $white);
    $px = $window_margin + $window_width/2 + ($include_graph["xpos"] / $include_graph["xhalfsize"]) * $window_width/2;
    $py = $ys - $window_margin - ($lum - $include_graph["min_lum"])/($include_graph["max_lum"] - $include_graph["min_lum"])*$window_height;
    //echo $px.' '.$py;
    $include_graph["points"][] = array($px, $py);
    $prev = false;
    foreach ($include_graph["points"] as $pix){
      if ($prev === false){
        imagesetpixel($i,$pix[0], $pix[1], $col);
      }else{
        imageline($i, $prev[0], $prev[1], $pix[0], $pix[1], $col);
      }
      $prev = $pix;
    }


  }


  if ($filename != "?"){
    imagejpeg($i, $filename, 95);
  };
  imagedestroy($i);
  return $lum;
}


//==============================================================================

if (!isset($_GET["thread"])){
  $planetary_radii = array(1, 0.5, 0.25, 0.1, 0.05, 0.01);
  foreach ($planetary_radii as $p){
    echo '<iframe src="?thread='.$p.'"></iframe>';
  }
  die();
}else{
  $planetary_radii = array(floatval($_GET["thread"]));
}

$star_radius_pixel = 200;

$star_color_indices = array(-5, -1, 0, 1, 5);
$planetary_offsets = array(0, 0.3, 0.5, 0.8, 1);
$dist = 100;
$dist_step = 1;

foreach ($planetary_radii as $planet_rad){
  foreach ($star_color_indices as $star_color_index){
    foreach ($planetary_offsets as $y_off){
      $extreme = $dist + $planet_rad*$dist*3;
      $setname = "starrad_".$star_radius_pixel.'__starcol_'.$star_color_index.'__planetrad_'.($star_radius_pixel * $planet_rad).'__yoff_'.($y_off * $star_radius_pixel).'';
      $graph = array(
        "xpos" => 0,
        "xhalfsize" => $extreme,
        "points" => array()
      );
      mkdir($setname);

      for ($x = -$extreme; $x<=$extreme; $x += $dist_step){
        $x1 = $x+$extreme;
        //$y = 0;
        while (strlen($x1) < 4){
          $x1 = '0'.$x1;
        }

        $filename = $setname . "/out_".$x1.".jpg";
        $graph["xpos"] = $x;
        $lum = drawStarWithPlanetAndReturnIntensity(
            $star_radius_pixel,
            $planet_rad,
            $x/$dist,
            $y_off,
            $graph,
            $filename,
            $star_color_index
          );
        rename($filename, str_replace('.jpg', '_'.$lum.'.jpg', $filename));
        //die();
      }

    }
  }
}








//echo '<img src="out.jpg?'.mt_rand().'">';

?>

 

 

Professional stuff:

https://www.cfa.harvard.edu/~avanderb/tutorial/tutorial.html

https://exoctk.stsci.edu/limb_darkening

http://adsabs.harvard.edu/full/1990A%26A…230..412C

https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TblView/nph-tblView?app=ExoTbls&config=PS

https://github.com/hpparvi/ldtk

https://hatnet.org

facebooktwittergoogle_plusredditpinterestlinkedinmail