Advanced: Parameter Types

Setup

Let's first make sure we have the latest version of PHOEBE 2.3 installed (uncomment this line if running in an online notebook session such as colab).


In [1]:
#!pip install -I "phoebe>=2.3,<2.4"

Let's get started with some basic imports


In [2]:
import phoebe
from phoebe import u # units
import numpy as np

In [3]:
logger = phoebe.logger(clevel='INFO')

Parameters

Parameters hold a single value, but need to be aware about their own types, limits, and connection with other Parameters (more on this later when we discuss ParameterSets).

Note that generally you won't ever have to "create" or "define" your own Parameters, those will be created for you by helper functions, but we have to start somewhere... so let's create our first Parameter.

We'll start with creating a StringParameter since it is the most generic, and then discuss and specific differences for each type of Parameter.


In [4]:
param = phoebe.parameters.StringParameter(qualifier='myparameter', 
                                          description='mydescription',
                                          value='myvalue')

If you ever need to know the type of a Parameter, you can always use python's built-in type functionality:


In [5]:
print(type(param))


<class 'phoebe.parameters.parameters.StringParameter'>

If we print the parameter object we can see a summary of information


In [6]:
print(param)


Parameter: myparameter
                       Qualifier: myparameter
                     Description: mydescription
                           Value: myvalue
                  Constrained by: 
                      Constrains: None
                      Related to: None

You can see here that we've defined three a few things about parameter: the qualifier, description, and value (others do exist, they just don't show up in the summary).

These "things" can be split into two groups: tags and attributes (although in a pythonic sense, both can be accessed as attributes). Don't worry too much about this distinction - it isn't really important except for the fact that tags are shared across all Parameters whereas attributes are dependent on the type of the Parameter.

The tags of a Parameter define the Parameter and how it connects to other Parameters (again, more on this when we get to ParameterSets). For now, just know that you can access a list of all the tags as follows:


In [7]:
print(param.tags)


OrderedDict([('time', None), ('qualifier', 'myparameter'), ('feature', None), ('component', None), ('dataset', None), ('constraint', None), ('distribution', None), ('compute', None), ('model', None), ('solver', None), ('solution', None), ('figure', None), ('kind', None), ('context', None)])

and that each of these is available through both a dictionary key and an object attribute. For example:


In [8]:
print(param['qualifier'], param.qualifier)


myparameter myparameter

The 'qualifier' attribute is essentially an abbreviated name for the Parameter.

These tags will be shared across all Parameters, regardless of their type.

Attributes, on the other hand, can be dependent on the type of the Parameter and tell the Parameter its rules and how to interpret its value. You can access a list of available attributes as follows:


In [9]:
param.attributes


Out[9]:
['description', 'value', 'visible_if', 'copy_for', 'readonly', 'advanced']

and again, each of these are available through both a dictionary key and as an object attribute. For example, all parameters have a 'description' attribute which gives additional information about what the Parameter means:


In [10]:
print(param['description'], param.description)


mydescription mydescription

For the special case of the 'value' attribute, there is also a get_value method (will become handy later when we want to be able to request the value in a specific unit).


In [11]:
print(param.get_value(), param['value'], param.value)


myvalue myvalue myvalue

The value attribute is also the only attribute that you'll likely want to change, so it also has a set_value method:


In [12]:
param.set_value('newvalue')
print(param.get_value())


newvalue

The 'visible_if' attribute only comes into play when the Parameter is a member of a ParameterSet, so we'll discuss it at the end of this tutorial when we get to ParameterSets.

The 'copy_for' attribute is only used when the Parameter is in a particular type of ParameterSet called a Bundle (explained at the very end of this tutorial). We'll see the 'copy_for' capability in action later in the Datasets Tutorial, but for now, just know that you can view this property only and cannot change it... and most of the time it will just be an empty string.

StringParameters

We'll just mention StringParameters again for completeness, but we've already seen about all they can do - the value must cast to a valid string but no limits or checks are performed at all on the value.

ChoiceParameters

ChoiceParameters are essentially StringParameters with one very important exception: the value must match one of the prescribed choices.

Therefore, they have a 'choice' attribute and an error will be raised if trying to set the value to any string not in that list.


In [13]:
param = phoebe.parameters.ChoiceParameter(qualifier='mychoiceparameter',
                                          description='mydescription',
                                          choices=['choice1', 'choice2'],
                                          value='choice1')

In [14]:
print(param)


Parameter: mychoiceparameter
                       Qualifier: mychoiceparameter
                     Description: mydescription
                           Value: choice1
                         Choices: choice1, choice2
                  Constrained by: 
                      Constrains: None
                      Related to: None


In [15]:
print(param.attributes)


['description', 'choices', 'value', 'visible_if', 'copy_for', 'readonly', 'advanced']

In [16]:
print(param['choices'], param.choices)


['choice1', 'choice2'] ['choice1', 'choice2']

In [17]:
print(param.get_value())


choice1

In [18]:
#param.set_value('not_a_choice') # would raise a ValueError
param.set_value('choice2')
print(param.get_value())


choice2

SelectParameters

SelectParameters are very similar to ChoiceParameters except that the value is a list, where each item must match one of the prescribed choices.


In [19]:
param = phoebe.parameters.SelectParameter(qualifier='myselectparameter',
                                          description='mydescription',
                                          choices=['choice1', 'choice2'],
                                          value=['choice1'])

In [20]:
print(param)


Parameter: myselectparameter
                       Qualifier: myselectparameter
                     Description: mydescription
                           Value: ['choice1']
                         Choices: choice1, choice2
                  Constrained by: 
                      Constrains: None
                      Related to: None


In [21]:
print(param.attributes)


['description', 'choices', 'value', 'visible_if', 'readonly', 'copy_for']

In [22]:
print(param['choices'], param.choices)


['choice1', 'choice2'] ['choice1', 'choice2']

In [23]:
print(param.get_value())


['choice1']

However, SelectParameters also allow you to use * as a wildcard and will expand to any of the choices that match that wildcard. For example,


In [24]:
param.set_value(["choice*"])

In [25]:
print(param.get_value())


['choice*']

In [26]:
print(param.expand_value())


['choice1', 'choice2']

FloatParameters

FloatParameters are probably the most common Parameter used in PHOEBE and hold both a float and a unit, with the ability to retrieve the value in any other convertible unit.


In [27]:
param = phoebe.parameters.FloatParameter(qualifier='myfloatparameter',
                                         description='mydescription',
                                         default_unit=u.m,
                                         limits=[None,20],
                                         value=5)

In [28]:
print(param)


Parameter: myfloatparameter
                       Qualifier: myfloatparameter
                     Description: mydescription
                           Value: 5.0 m
                  Constrained by: 
                      Constrains: None
                      Related to: None

You'll notice here a few new mentions in the summary... "Constrained by", "Constrains", and "Related to" are all referring to constraints.


In [29]:
print(param.attributes)


['description', 'value', 'quantity', 'default_unit', 'limits', 'visible_if', 'copy_for', 'readonly', 'advanced']

FloatParameters have an attribute which hold the "limits" - whenever a value is set it will be checked to make sure it falls within the limits. If either the lower or upper limit is None, then there is no limit check for that extreme.


In [30]:
print(param['limits'], param.limits)


[None, <Quantity 20. m>] [None, <Quantity 20. m>]

In [31]:
#param.set_value(30) # would raise a ValueError
param.set_value(2)
print(param.get_value())


2.0

FloatParameters have an attribute which holds the "default_unit" - this is the unit in which the value is stored and the unit that will be provided if not otherwise overriden.


In [32]:
print(param['default_unit'], param.default_unit)


m m

Calling get_value will then return a float in these units


In [33]:
print(param.get_value())


2.0

But we can also request the value in a different unit, by passing an astropy Unit object or its string representation.


In [34]:
print(param.get_value(unit=u.km), param.get_value(unit='km'))


0.002 0.002

FloatParameters also have their own method to access an astropy Quantity object that includes both the value and the unit


In [35]:
print(param.get_quantity(), param.get_quantity(unit=u.km))


2.0 m 0.002 km

The set_value method also accepts a unit - this doesn't change the default_unit internally, but instead converts the provided value before storing.


In [36]:
param.set_value(10)
print(param.get_quantity())


10.0 m

In [37]:
param.set_value(0.001*u.km)
print(param.get_quantity())


1.0 m

In [38]:
param.set_value(10, unit='cm')
print(param.get_quantity())


0.1 m

If for some reason you want to change the default_unit, you can do so as well:


In [39]:
param.set_default_unit(u.km)
print(param.get_quantity())


0.0001 km

But note that the limits are still stored as a quantity object in the originally defined default_units


In [40]:
print(param.limits)


[None, <Quantity 20. m>]

IntParameters

IntParameters are essentially the same as FloatParameters except they always cast to an Integer and they have no units.


In [41]:
param = phoebe.parameters.IntParameter(qualifier='myintparameter',
                                       description='mydescription',
                                       limits=[0,None],
                                       value=1)

In [42]:
print(param)


Parameter: myintparameter
                       Qualifier: myintparameter
                     Description: mydescription
                           Value: 1
                  Constrained by: 
                      Constrains: None
                      Related to: None


In [43]:
print(param.attributes)


['description', 'value', 'limits', 'visible_if', 'copy_for', 'readonly', 'advanced']

Like FloatParameters above, IntParameters still have limits


In [44]:
print(param['limits'], param.limits)


[0, None] [0, None]

Note that if you try to set the value to a float it will not raise an error, but will cast that value to an integer (following python rules of truncation, not rounding)


In [45]:
param.set_value(1.9)
print(param.get_value())


1

Bool Parameters

BoolParameters are even simpler - they accept True or False.


In [46]:
param = phoebe.parameters.BoolParameter(qualifier='myboolparameter',
                                        description='mydescription',
                                        value=True)

In [47]:
print(param)


Parameter: myboolparameter
                       Qualifier: myboolparameter
                     Description: mydescription
                           Value: True
                  Constrained by: 
                      Constrains: None
                      Related to: None


In [48]:
print(param.attributes)


['description', 'value', 'visible_if', 'copy_for', 'readonly', 'advanced']

Note that, like IntParameters, BoolParameters will attempt to cast anything you give it into True or False.


In [49]:
param.set_value(0)
print(param.get_value())


False

In [50]:
param.set_value(None)
print(param.get_value())


False

As with Python, an empty string will cast to False and a non-empty string will cast to True


In [51]:
param.set_value('')
print(param.get_value())


False

In [52]:
param.set_value('some_string')
print(param.get_value())


True

The only exception to this is that (unlike Python), 'true' or 'True' will cast to True and 'false' or 'False' will cast to False.


In [53]:
param.set_value('False')
print(param.get_value())


False

In [54]:
param.set_value('false')
print(param.get_value())


False

FloatArrayParameters

FloatArrayParameters are essentially the same as FloatParameters (in that they have the same unit treatment, although obviously no limits) but hold numpy arrays rather than a single value.

By convention in Phoebe, these will (almost) always have a pluralized qualifier.


In [55]:
param = phoebe.parameters.FloatArrayParameter(qualifier='myfloatarrayparameters',
                                              description='mydescription',
                                              default_unit=u.m,
                                              value=np.array([0,1,2,3]))

In [56]:
print(param)


Parameter: myfloatarrayparameters
                       Qualifier: myfloatarrayparameters
                     Description: mydescription
                           Value: [0. 1. 2. 3.] m
                  Constrained by: 
                      Constrains: None
                      Related to: None


In [57]:
print(param.attributes)


['description', 'value', 'default_unit', 'visible_if', 'required_shape', 'copy_for', 'readonly', 'advanced']

In [58]:
print(param.get_value(unit=u.km))


[0.    0.001 0.002 0.003]

FloatArrayParameters also allow for built-in interpolation... but this requires them to be a member of a Bundle, so we'll discuss this in just a bit.

ParametersSets

ParameterSets are a collection of Parameters that can be filtered by their tags to return another ParameterSet.

For illustration, let's create 3 random FloatParameters and combine them to make a ParameterSet.


In [59]:
param1 = phoebe.parameters.FloatParameter(qualifier='param1',
                                          description='param1 description',
                                          default_unit=u.m,
                                          limits=[None,20],
                                          value=5,
                                          context='context1',
                                          kind='kind1')

param2 = phoebe.parameters.FloatParameter(qualifier='param2',
                                          description='param2 description',
                                          default_unit=u.deg,
                                          limits=[0,2*np.pi],
                                          value=0,
                                          context='context2',
                                          kind='kind2')

param3 = phoebe.parameters.FloatParameter(qualifier='param3',
                                          description='param3 description',
                                          default_unit=u.kg,
                                          limits=[0,2*np.pi],
                                          value=0,
                                          context='context1',
                                          kind='kind2')

In [60]:
ps = phoebe.parameters.ParameterSet([param1, param2, param3])

In [61]:
print(ps.to_list())


[<Parameter: param1=5.0 m | keys: description, value, quantity, default_unit, limits, visible_if, copy_for, readonly, advanced>, <Parameter: param2=0.0 deg | keys: description, value, quantity, default_unit, limits, visible_if, copy_for, readonly, advanced>, <Parameter: param3=0.0 kg | keys: description, value, quantity, default_unit, limits, visible_if, copy_for, readonly, advanced>]

If we print a ParameterSet, we'll see a listing of all the Parameters and their values.


In [62]:
print(ps)


ParameterSet: 3 parameters
            param1@kind1@context1: 5.0 m
            param2@kind2@context2: 0.0 deg
            param3@kind2@context1: 0.0 kg

Similarly to Parameters, we can access the tags of a ParameterSet


In [63]:
print(ps.tags)


{'times': [], 'qualifiers': ['param1', 'param2', 'param3'], 'features': [], 'components': [], 'datasets': [], 'constraints': [], 'distributions': [], 'computes': [], 'models': [], 'solvers': [], 'solutions': [], 'figures': [], 'kinds': ['kind1', 'kind2'], 'contexts': ['context1', 'context2']}

Twigs

The string notation used for the Parameters is called a 'twig' - its simply a combination of all the tags joined with the '@' symbol and gives a very convenient way to access any Parameter.

The order of the tags doesn't matter, and you only need to provide enough tags to produce a unique match. Since there is only one parameter with kind='kind1', we do not need to provide the extraneous context='context1' in the twig to get a match.


In [64]:
print(ps.get('param1@kind1'))


Parameter: param1@kind1@context1
                       Qualifier: param1
                     Description: param1 description
                           Value: 5.0 m
                  Constrained by: 
                      Constrains: None
                      Related to: None

Note that this returned the ParameterObject itself, so you can now use any of the Parameter methods or attributes we saw earlier. For example:


In [65]:
print(ps.get('param1@kind1').description)


param1 description

But we can also use set and get_value methods from the ParameterSet itself:


In [66]:
ps.set_value('param1@kind1', 10)
print(ps.get_value('param1@kind1'))


10.0

Tags

Each Parameter has a number of tags, and the ParameterSet has the same tags - where the value of any given tag is None if not shared by all Parameters in that ParameterSet.

So let's just print the names of the tags again and then describe what each one means.


In [67]:
print(ps.meta.keys())


odict_keys(['time', 'qualifier', 'history', 'feature', 'component', 'dataset', 'constraint', 'distribution', 'compute', 'model', 'solver', 'solution', 'figure', 'kind', 'context'])

Most of these "metatags" act as labels - for example, you can give a component tag to each of the components for easier referencing.

But a few of these tags are fixed and not editable:

  • qualifier: literally the name of the parameter.
  • kind: tells what kind a parameter is (ie whether a component is a star or an orbit).
  • context: tells what context this parameter belongs to
  • twig: a shortcut to the parameter in a single string.
  • uniquetwig: the minimal twig needed to reach this parameter.
  • uniqueid: an internal representation used to reach this parameter

These contexts are (you'll notice that most are represented in the tags):

  • setting
  • history
  • system
  • figure
  • component
  • feature
  • dataset
  • distribution
  • compute
  • model
  • solver
  • solution
  • time
  • qualifier

One way to distinguish between context and kind is with the following question and answer:

"What kind of [context] is this? It's a [kind] tagged [context]=[tag-with-same-name-as-context]."

In different cases, this will then become:

  • "What kind of component is this? It's a star tagged component=starA." (context='component', kind='star', component='starA')
  • "What kind of feature is this? It's a spot tagged feature=spot01." (context='feature', kind='spot', feature='spot01')
  • "What kind of dataset is this? It's a LC (light curve) tagged dataset=lc01." (context='dataset', kind='LC', dataset='lc01')
  • "What kind of compute (options) are these? They're phoebe (compute options) tagged compute=preview." (context='compute', kind='phoebe', compute='preview')

As we saw before, these tags can be accessed at the Parameter level as either a dictionary key or as an object attribute. For ParameterSets, the tags are only accessible through object attributes.


In [68]:
print(ps.context)


None

This returns None since not all objects in this ParameterSet share a single context. But you can see all the options for a given tag by providing the plural version of that tag name:


In [69]:
print(ps.contexts)


['context1', 'context2']

Filtering

Any of the tags can also be used to filter the ParameterSet:


In [70]:
print(ps.filter(context='context1'))


ParameterSet: 2 parameters
            param1@kind1@context1: 10.0 m
            param3@kind2@context1: 0.0 kg

Here we were returned a ParameterSet of all Parameters that matched the filter criteria. Since we're returned another ParameterSet, we can chain additional filter calls together.


In [71]:
print(ps.filter(context='context1', kind='kind1'))


ParameterSet: 1 parameters
            param1@kind1@context1: 10.0 m

Now we see that we have drilled down to a single Parameter. Note that a ParameterSet is still returned - filter will always return a ParameterSet.

We could have accomplished the exact same thing with a single call to filter:


In [72]:
print(ps.filter(context='context1', kind='kind1'))


ParameterSet: 1 parameters
            param1@kind1@context1: 10.0 m

If you want to access the actual Parameter, you must use get instead of (or in addition to) filter. All of the following lines do the exact same thing:


In [73]:
print(ps.filter(context='context1', kind='kind1').get())


Parameter: param1@kind1@context1
                       Qualifier: param1
                     Description: param1 description
                           Value: 10.0 m
                  Constrained by: 
                      Constrains: None
                      Related to: None


In [74]:
print(ps.get(context='context1', kind='kind1'))


Parameter: param1@kind1@context1
                       Qualifier: param1
                     Description: param1 description
                           Value: 10.0 m
                  Constrained by: 
                      Constrains: None
                      Related to: None

Or we can use those twigs. Remember that twigs are just a combination of these tags separated by the @ symbol. You can use these for dictionary access in a ParameterSet - without needing to provide the name of the tag, and without having to worry about order. And whenever this returns a ParameterSet, these are also chainable, so the following two lines will do the same thing:


In [75]:
print(ps['context1@kind1'])


Parameter: param1@kind1@context1
                       Qualifier: param1
                     Description: param1 description
                           Value: 10.0 m
                  Constrained by: 
                      Constrains: None
                      Related to: None


In [76]:
print(ps['context1']['kind1'])


Parameter: param1@kind1@context1
                       Qualifier: param1
                     Description: param1 description
                           Value: 10.0 m
                  Constrained by: 
                      Constrains: None
                      Related to: None

You may notice that the final result was a Parameter, not a ParameterSet. Twig dictionary access tries to be smart - if exactly 1 Parameter is found, it will return that Parameter instead of a ParameterSet. Notice the difference between the two following lines:


In [77]:
print(ps['context1'])


ParameterSet: 2 parameters
            param1@kind1@context1: 10.0 m
            param3@kind2@context1: 0.0 kg

In [78]:
print(ps['context1@kind1'])


Parameter: param1@kind1@context1
                       Qualifier: param1
                     Description: param1 description
                           Value: 10.0 m
                  Constrained by: 
                      Constrains: None
                      Related to: None

Of course, once you get the Parameter you can then use dictionary keys to access any attributes of that Parameter.


In [79]:
print(ps['context1@kind1']['description'])


param1 description

So we decided we might as well allow access to those attributes directly from the twig as well


In [80]:
print(ps['description@context1@kind1'])


param1 description

The Bundle

The Bundle is nothing more than a glorified ParameterSet with some extra methods to compute models, add new components and datasets, etc.

You can initialize an empty Bundle as follows:


In [81]:
b = phoebe.Bundle()
print(b)


Mon, 25 May 2020 12:57 BUNDLE       ERROR   Constraint 'ebv@extinction@constraint' raised the following error while setting the value of 'ebv@system'.  Original error: 0 results found for twig: 'None', {'qualifier': 'run_checks_compute', 'context': 'setting', 'check_visible': False, 'check_default': False, 'check_advanced': False, 'check_single': False}
PHOEBE Bundle: 21 parameters
                        t0@system: 0.0 d
                        ra@system: 0.0 deg
                       dec@system: 0.0 deg
                  distance@system: 1.0 m
                    vgamma@system: 0.0 km / s
C                      ebv@system: 0.0
                        Av@system: 0.0
                        Rv@system: 3.1
                   ebv@constraint: {Av@system} / {Rv@system}
R          phoebe_version@setting: devel
              log_history@setting: False
              dict_filter@setting: {}
             dict_set_all@setting: False
       run_checks_compute@setting: ['*']
        run_checks_solver@setting: ['*']
      run_checks_solution@setting: []
        run_checks_figure@setting: []
          auto_add_figure@setting: False
       auto_remove_figure@setting: False
                 hierarchy@system: 
       default_time_source@figure: None

and filter just as you would for a ParameterSet


In [82]:
print(b.filter(context='system'))


ParameterSet: 9 parameters
                        t0@system: 0.0 d
                        ra@system: 0.0 deg
                       dec@system: 0.0 deg
                  distance@system: 1.0 m
                    vgamma@system: 0.0 km / s
C                      ebv@system: 0.0
                        Av@system: 0.0
                        Rv@system: 3.1
                 hierarchy@system: 

Visible If

As promised earlier, the 'visible_if' attribute of a Parameter controls whether its visible to a ParameterSet... but it only does anything if the Parameter belongs to a Bundle.

Let's make a new ParameterSet in which the visibility of one parameter is dependent on the value of another.


In [83]:
param1 = phoebe.parameters.ChoiceParameter(qualifier='what_is_this',
                                           choices=['matter', 'aether'],
                                           value='matter',
                                           context='context1')
param2 = phoebe.parameters.FloatParameter(qualifier='mass',
                                          default_unit=u.kg,
                                          value=5,
                                          visible_if='what_is_this:matter',
                                          context='context1')

b = phoebe.Bundle([param1, param2])

In [84]:
print(b)


PHOEBE Bundle: 3 parameters
            what_is_this@context1: matter
                    mass@context1: 5.0 kg
                 hierarchy@system: 

It doesn't make much sense to need to define a mass if this thing isn't baryonic. So if we change the value of 'what_is_this' to 'aether' then the 'mass' Parameter will temporarily hide itself.


In [85]:
b.set_value('what_is_this', 'aether')
print(b)


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-85-aa7f5c658b2b> in <module>
----> 1 b.set_value('what_is_this', 'aether')
      2 print(b)

~/.local/lib/python3.7/site-packages/phoebe/parameters/parameters.py in set_value(self, twig, value, **kwargs)
   3056         return self.get_parameter(twig=twig,
   3057                                   **kwargs).set_value(value=value,
-> 3058                                                       **kwargs)
   3059 
   3060     def set_values_all(self, *args, **kwargs):

~/.local/lib/python3.7/site-packages/phoebe/parameters/parameters.py in _send_if_client(self, *args, **kwargs)
    361                 self._bundle.client_update()
    362         else:
--> 363             return fctn(self, *args, **kwargs)
    364     return _send_if_client
    365 

~/.local/lib/python3.7/site-packages/phoebe/parameters/parameters.py in set_value(self, value, run_checks, run_constraints, **kwargs)
   7259             run_checks = conf.interactive_checks
   7260         if run_checks and self._bundle:
-> 7261             report = self._bundle.run_checks(allow_skip_constraints=True, raise_logger_warning=True)
   7262 
   7263         self._add_history(redo_func='set_value', redo_kwargs={'value': value, 'uniqueid': self.uniqueid}, undo_func='set_value', undo_kwargs={'value': _orig_value, 'uniqueid': self.uniqueid})

~/.local/lib/python3.7/site-packages/phoebe/frontend/bundle.py in run_checks(self, raise_logger_warning, raise_error, **kwargs)
   2999         """
   3000         report = self.run_checks_system(raise_logger_warning=False, raise_error=False, **kwargs)
-> 3001         report = self.run_checks_compute(run_checks_system=False, raise_logger_warning=False, raise_error=False, report=report, **kwargs)
   3002         # TODO: passing run_checks_compute=False is to try to avoid duplicates with the call above,
   3003         # but could get us into trouble if compute@solver references a compute that is

~/.local/lib/python3.7/site-packages/phoebe/frontend/bundle.py in run_checks_compute(self, compute, raise_logger_warning, raise_error, run_checks_system, **kwargs)
   3408         if compute is None:
   3409             computes = run_checks_compute
-> 3410             addl_parameters += [self.get_parameter(qualifier='run_checks_compute', context='setting', **_skip_filter_checks)]
   3411         else:
   3412             computes = compute

~/.local/lib/python3.7/site-packages/phoebe/parameters/parameters.py in get_parameter(self, twig, **kwargs)
   2693             matching the search.
   2694         """
-> 2695         return self.get(twig=twig, **kwargs)
   2696 
   2697     def get_or_create(self, qualifier, new_parameter, attach_to_bundle=False, **kwargs):

~/.local/lib/python3.7/site-packages/phoebe/parameters/parameters.py in get(self, twig, check_visible, check_default, check_advanced, check_single, **kwargs)
   2342         if not len(ps):
   2343             # TODO: custom exception?
-> 2344             raise ValueError("0 results found for twig: '{}', {}".format(twig, kwargs))
   2345         elif len(ps) != 1:
   2346             # TODO: custom exception?

ValueError: 0 results found for twig: 'None', {'qualifier': 'run_checks_compute', 'context': 'setting', 'check_visible': False, 'check_default': False, 'check_advanced': False, 'check_single': False}

FloatArrayParameters: interpolation

As mentioned earlier, when a part of a Bundle, FloatArrayParameters can handle simple linear interpolation with respect to another FloatArrayParameter in the same Bundle.


In [ ]:
xparam = phoebe.parameters.FloatArrayParameter(qualifier='xs',
                                               default_unit=u.d,
                                               value=np.linspace(0,1,10),
                                               context='context1')

yparam = phoebe.parameters.FloatArrayParameter(qualifier='ys',
                                               default_unit=u.m,
                                               value=np.linspace(0,1,10)**2,
                                               context='context1')

b = phoebe.Bundle([xparam, yparam])

In [ ]:
print(b.filter('ys').get().twig)

In [ ]:
print(b['ys'].get_value())

Now we can interpolate the 'ys' param for any given value of 'xs'


In [ ]:
print(b['ys'].interp_value(xs=0))

In [ ]:
print(b['ys'].interp_value(xs=0.2))

NOTE: interp_value does not (yet) support passing a unit.. it will always return a value (not a quantity) and will always be in the default_unit.