Let's first make sure we have the latest version of PHOEBE 2.0 installed. (You can comment out this line if you don't use pip for your installation or don't want to update to the latest release).
In [ ]:
!pip install -I "phoebe>=2.0,<2.1"
From now on, we'll just quickly do common setup at the beginning of each tutorial. For full gory details on the general concepts here, make sure to read General Concepts.
We'll always start by doing our basic imports, setting up a logger, and initializing an empty Bundle.
In [1]:
import phoebe
from phoebe import u # units
import numpy as np
import matplotlib.pyplot as plt
logger = phoebe.logger()
b = phoebe.Bundle()
In [2]:
b = phoebe.Bundle.default_binary()
or for short:
In [3]:
b = phoebe.default_binary()
In [4]:
print b.hierarchy
To build the same binary but as a contact system, you would call:
In [5]:
b = phoebe.default_binary(contact_binary=True)
In [6]:
print b.hierarchy
For more details on dealing with contact binary systems, see the Contact Binary Example Script
By default, an empty Bundle does not contain any information about our system.
So, let's first start by adding a few stars. Here we'll call the generic add_component method. This method works for any type of component in the system - stars, orbits, planets, disks, rings, spots, etc. The first argument needs to be a callable or the name of a callable in phoebe.parameters.component which include the following options:
add_component also takes a keyword argument for the 'component' tag. Here we'll give them component tags 'primary' and 'secondary' - but note that these are merely convenience labels and do not hold any special roles. Some tags, however, are forbidden if they clash with other tags or reserved values - so if you get error stating the component tag is forbidden, try using a different string.
In [7]:
b = phoebe.Bundle()
In [8]:
b.add_component(phoebe.component.star, component='primary')
b.add_component('star', component='secondary')
Out[8]:
But there are also shortcut methods for add_star and add_orbit. In these cases you don't need to provide the function, but only the component tag of your star/orbit.
Any of these functions also accept values for any of the qualifiers of the created parameters.
In [9]:
b.add_star('extrastarforfun', teff=6000)
Out[9]:
Here we call the add_component method of the bundle with several arguments:
and then we'll do the same to add an orbit:
In [10]:
b.add_orbit('binary')
Out[10]:
At this point all we've done is add a bunch of Parameters to our Bundle, but we still need to specify the hierarchical setup of our system.
Here we want to place our two stars (with component tags 'primary' and 'secondary') in our orbit (with component tag 'binary'). This can be done with several different syntaxes:
In [11]:
b.set_hierarchy(phoebe.hierarchy.binaryorbit, b['binary'], b['primary'], b['secondary'])
or
In [12]:
b.set_hierarchy(phoebe.hierarchy.binaryorbit(b['binary'], b['primary'], b['secondary']))
If you access the value that this set, you'll see that it really just resulted in a simple string representation:
In [13]:
b.get_hierarchy()
Out[13]:
We could just as easily have used this string to set the hierarchy:
In [14]:
b.set_hierarchy('orbit:binary(star:primary, star:secondary)')
If at any point we want to flip the primary and secondary components or make this binary a triple, its seriously as easy as changing this hierarchy and everything else will adjust as needed (including cross-ParameterSet constraints, and datasets)
In [15]:
b['hierarchy@system']
Out[15]:
or through any of these shortcuts:
In [16]:
b.get_hierarchy()
Out[16]:
In [17]:
b.hierarchy
Out[17]:
This hierarchy parameter then has several methods unique to itself. You can, for instance, list the component tags of all the stars or orbits in the hierarchy:
In [18]:
print b.hierarchy.get_stars()
In [19]:
print b.hierarchy.get_orbits()
Or you can ask for the component tag of the top-level item in the hierarchy
In [20]:
print b.hierarchy.get_top()
And request the parent, children, child, or sibling of any item in the hierarchy
In [21]:
print b.hierarchy.get_parent_of('primary')
In [22]:
print b.hierarchy.get_children_of('binary')
In [23]:
print b.hierarchy.get_child_of('binary', 0) # here 0 means primary component, 1 means secondary
In [24]:
print b.hierarchy.get_sibling_of('primary')
We can also check whether a given component (by component tag) is the primary or secondary component in its parent orbit. Note that here its just a coincidence (although on purpose) that the component tag is also 'secondary'.
In [25]:
print b.hierarchy.get_primary_or_secondary('secondary')
Next up: let's learn about saving and loading
In [ ]: