Plugin Development¶
Atmospheric retrievals are not an isolated science. We regularly use different codes and models from various fields and contributors to better characterise exoplanetary systems. Often repetitive steps are needed to make use of an external code, and frequently, these are difficult to share or distribute to a broader audience. Plugins are a new feature in TauREx 3.1 that allows developers to simplify the distribution and usage of their profile/models/chemistry etc., to other users for their retrievals. The plugin system can be used to add the following new components:
Refer to the Developers guide on how to build each individual component. This guide will outline how to package your new components into a TauREx plugin.
Anatomy of a Plugin¶
Plugins are installable python packages that TauREx will integrate automatically into its pipeline.
Plugins can come from existing python libraries or dedicated packages. Dedicated packages only
contain TauREx components and generally have the name like taurex_something
. For example,
a package that provides wrappers to the GGchem chemistry code would be called taurex_ggchem
(which exists btw if you need it).
Importantly, open-source plugins should be registered to PyPI installable with a single command:
> pip install taurex_myplugin
If they rely on an external FORTRAN/C++ code then they should be packaged into a binary wheel distribution. We recommoned cibuildwheel for building these wheels. After install the plugin will be automatically detected by TauREx:
> taurex --plugins
Successfully loaded plugins
---------------------------
myplugin
A plugin, in its most basic form, points TauREx to the place where your components exist in your package.
This is accomplised through the entry_point
parameter in setup.py
of the plugin package:
entry_points = {'taurex.plugins': 'myplugin = taurex_myplugin'}
setup(name='taurex_myplugin',
..
entry_points=entry_points,
..)
What this does is allow TauREx to access taurex_myplugin
under taurex.plugins.myplugin
Plugins can also be defined in existing packages as well. If you have a coolscience
python
library and have built some TauREx components under coolscience.taurex
then you can add to
your entry_point
:
entry_points = {'taurex.plugins': 'coolscience = coolscience.taurex',
# ... other entrypoints
}
setup(name='coolscience',
...
entry_points=entry_points,
...)
The package will still be installable without TauREx. If later on someone installs TauREx then they automatically get the plugin for free! Neat!
TauREx Hello World!¶
Lets create a first plugin taurex_helloworld
where
we will define a new component: a randomized temperature profile.
First we setup our folder structure:
taurex_helloworld/
__init__.py
randomtemp.py
LICENSE
README.md
setup.py
setup.py¶
The most essential part is the setup.py
file to install the package and plugin.
The following is something you can work with:
#!/usr/bin/env python
import setuptools
from setuptools import find_packages
from setuptools import setup
packages = find_packages(exclude=('tests', 'doc'))
provides = ['taurex_helloworld', ]
requires = []
install_requires = ['taurex', ]
entry_points = {'taurex.plugins': 'helloworld = taurex_helloworld'}
setup(name='taurex_helloworld',
url='http://example.com/taurex_helloworld',
license='BSD',
author='Your Name',
author_email='your-email@example.com',
description='Very short description',
long_description=__doc__,
packages=packages,
entry_points=entry_points,
provides=provides,
requires=requires,
install_requires=install_requires)
randomtemp.py¶
This is our random temperature profile, we will steal the implementation from Custom Types and change it a little:
from taurex.temperature import TemperatureProfile
from taurex.core import fitparam
import numpy as np
class RandomTemperature(TemperatureProfile):
def __init__(self, base_temp=1500.0,
random_scale=10.0):
super().__init__(self.__class__.__name__)
self._base_temp = base_temp
self._random_scale = random_scale
# -----Fitting Parameters--------------
@fitparam(param_name='rand_scale',param_latex='rand')
def randomScale(self):
return self._random_scale
@randomScale.setter
def randomScale(self, value):
self._random_scale = value
@fitparam(param_name='base_T',param_latex='$T_{base}$')
def baseTemperature(self):
return self._base_temp
@baseTemperature.setter
def baseTemperature(self, value):
self._base_temp = value
# -------Actual calculation -----------
@property
def profile(self):
return self._base_temp + \
np.random.rand(self.nlayers) * self._random_scale
BIBTEX_ENTRIES = [
"""
@article{myart,
title={School of Life},
"""
]
# -----Plugin related------------------
@classmethod
def input_keywords(cls):
return ['helloworld', 'helloearth', 'hello-world',]
As before a terrible temperature profile we now include two extra parameters.
The class method input_keywords
informs TauREx on how this temperature profile
is selected in the input file. It must return a list and can include more than one keyword.
If this plugin is installed we can use the profile through one of those keywords:
[Temperature]
profile_type = helloworld # Valid keyword RandomTemperature
# profile_type = helloearth # Also valid
# profile_type = hello-world # Also valid
The BIBTEX_ENTRIES
parameter is used by TauREx to list relevant publications
involved with the atmospheric compoenent. See Basics for more information.
__init__.py¶
We can use __init__.py
to expose the temperature profile to TauREx
by importing it like so:
from .randomtemp import RandomTemperature
Tip
You could also just point the entry_point
to taurex_helloworld.randomtemp
.
However we recommend either putting it in an __init__.py
or defining
another python file that includes these imports. This allows you to include
components from different files and allows you to be selective on what to
expose to TauREx
Using our plugin¶
To use our plugin we can now do:
pip install .
Running taurex --plugins
we see:
Successfully loaded plugins
---------------------------
helloworld
Our plugin has now been loaded into TauREx! We can also see that our temperature
profile was detected as well by doing taurex --keywords temperature
:
╒═══════════════════════════════════════╤═══════════════════╤════════════╕
│ profile_type │ Class │ Source │
╞═══════════════════════════════════════╪═══════════════════╪════════════╡
│ file / fromfile │ TemperatureFile │ taurex │
├───────────────────────────────────────┼───────────────────┼────────────┤
│ isothermal │ Isothermal │ taurex │
├───────────────────────────────────────┼───────────────────┼────────────┤
│ guillot / guillot2010 │ Guillot2010 │ taurex │
├───────────────────────────────────────┼───────────────────┼────────────┤
│ npoint │ NPoint │ taurex │
├───────────────────────────────────────┼───────────────────┼────────────┤
│ helloworld / helloearth / hello-world │ RandomTemperature │ helloworld │
├───────────────────────────────────────┼───────────────────┼────────────┤
│ rodgers / rodgers2010 │ Rodgers2000 │ taurex │
╘═══════════════════════════════════════╧═══════════════════╧════════════╛
Now we can write in the input file:
[Temperature]
profile_type = helloworld
base_temp = 500.0
random_scale = 100.0
Which gives us
This is a minimal guide to developing plugins but we always recommend looking at plugin projects and seeing how they accomplish their tasks.