ExoOPS-scripting-API 1.0
ExoOPS™ Mission Design scripting API
Keywords: exoops scripting propulsion

# ExoOPS™ - Mission Design Scripting API Documentation

## Table of contents
### 1. [Installation](#installation)
### 2. [Connection](#connection)
### 3. [Swagger](#swagger)
  *  [Example using the Swagger](#example-using-the-swagger)
### 4. [Built-in Functions](#built-in-functions)
  *  [Example using built-in functions](#example-using-built-in-functions)
### 5. [Missions and objects names differences](#missions-and-objects-names-differences)

---

## Installation

1. You will need to have both Python and pip installed on your computer.
2. Install the **ExoOPS™** library with the following command:

  ```bash
  pip install exoops
  ```

  This will install the `exoops` package and the `requests` library, used to perform HTTP calls.

3. In your Python script, import the library by adding this line at the very top of your file:

  ```python
  import exoops
  ```

4. The library has now been imported, you can start using it.

--------------------------------------------------------------------------------

## Connection

In order to use the library, you need to be connected. You can do so by calling the `connect()` function:

```python
exoops.connect(url, mail, password)
```

You need to replace the parameter `url` with the URL you have been given in order to use the scripting API, `mail` with the email address you use to connect to ExoOPS™ - Mission Design and `password` with your password.

From this point on, you will be connected to the API.

- If you wish to make your own API calls, with the help of our **Swagger** (see [Swagger](#swagger) section below), you can retrieve your user id as well as your token or directly your headers with the following functions:

  ```python
  exoops.get_user_id()
  exoops.get_jwt()
  exoops.get_headers()
  ```

- If you would rather use our library's **built-in functions**, to create objects and to create and compute missions, see the [Built-In Functions](#built-in-functions) section below.

--------------------------------------------------------------------------------

## Swagger

Our **Swagger** is available at the endpoint `/swagger-ui.html` from your `url`. There, you will find two sets of endpoints (_Select a spec_ at the top right-hand corner of the page):

> The Swagger is protected by JWT and most of the routes need a user id. To try the routes, you will need to provide your user id and token, check the [Connection](#connection) section above to see how.

- **Scripting API - Missions:** Here, you will see all the endpoints you can call in order to create any type of objects and missions, modify or delete existing ones. In order to create your objects and missions, please refer to the _Fields Description_ JSON file, available at `/exoops/users/fieldsdescription`. **(Do not refer to the "Models" section at the bottom of the Swagger page or to the "newValue" from the POST and PUT routes as they are misleading for a user-friendly experience)**.

- **Scripting API - User:** Here, you will find all the endpoints related to the user. What you may find the most interesting are the endpoints:

  - `/exoops/users/{id}/runningProcess` to check which processes are being run.
  - `/exoops/users/{id}/pendingProcess` to check which processes are waiting for computation.
  - `/exoops/users/fieldsdescription` to know how to create your objects/missions. **(Do not refer to the "Models" section at the bottom of the Swagger page or to the "newValue" from the POST and PUT routes as they are misleading for a user-friendly experience)**.

  ### Example using the Swagger

  In this quick example, we are going to create an **analytical thruster**.<br>
  First, we are going to import `exoops`, `json` (the objects we are going to create are JSON objects) and `requests` (to handle our HTTP calls, that you can install with `pip install requests`). Finally, we can connect to ExoOPS™ - Mission Design through the `connect()` function.

  ```python
  import exoops, json, requests

  exoops.connect('https://exoops.exotrail.space', 'my_great_email@exotrail.com', 'my_great_password')
  ```

  Then, we can go to the endpoint `/exoops/users/fieldsdescription`, and see what the JSON object looks like to create an analytical thruster. For this example, we are only going to fill in the required fields.

  ```python
  thruster_object = {
    'name': 'Python Thruster',
    'thrust': 20,
    'isp': 1000,
    'power': 500,
    'standbyPower': 0,
    'totalMass': 30,
    'propellantCapacityChoice': 'UNLIMITED'
  }
  ```

  Now, we can see that the endpoint to create our analytical thruster is `/exoops/users/{id}/analyticalthrusters`. In order to create the URL and the headers, we are going to use two of the library's functions. To perform the POST request, we use the `requests` library.

  ```python
  url = 'https://exoops.exotrail.space' + '/exoops/users/' + exoops.get_user_id() + '/analyticalthrusters'
  headers = exoops.get_headers()

  requests.post(url, headers = headers, data = json.dumps(thruster_object))
  ```

  Your request has now been received, and your object has been created.

  _The full script, with some improvements:_

  ```python
  import exoops, requests, json

  base_url = 'https://exoops.exotrail.space'
  mail = 'my_great_email@exotrail.com'
  password = 'my_great_password'
  api_url = '/exoops/users/'
  analytical_thruster_url = '/analyticalthrusters'

  exoops.connect(base_url, mail, password)

  thruster_object = {
    'name': 'Python Thruster',
    'thrust': 20,
    'isp': 1000,
    'power': 500,
    'standbyPower': 0,
    'totalMass': 30,
    'propellantCapacityChoice': 'UNLIMITED'
  }

  api_endpoint_builder = api_url + exoops.get_user_id() + analytical_thruster_url

  url = base_url + api_endpoint_builder
  headers = exoops.get_headers()

  requests.post(url, headers = headers, data = json.dumps(thruster_object))
  ```

--------------------------------------------------------------------------------

## Built-in functions

The library comes with functions to create objects and missions, retrieve specific objects and missions (e.g. retrieve a specific `analytical thruster`) or all objects and missions (e.g. retrieve all `numerical missions`), as well as computing missions.

To create these missions and objects, you need to build JSON objects. Check the endpoint `/exoops/users/fieldsdescription` to know how. **(Do not refer to the "Models" section at the bottom of the Swagger page or to the "newValue" from the POST and PUT routes as they are misleading for a user-friendly experience)**.

All the objects and missions are separated in their own type.

- You can create and get all `analytical` type of objects and missions with `exoops.analytical`,
- You can create and get all `constellation` type of objects and missions with `exoops.constellation`,
- You can create and get all `deployment` type of objects and missions with `exoops.deployment`,
- You can create and get all `numerical` type of objects and missions with `exoops.numerical`.

Then, you can simply call the functions as follow:

- To `create`, use `create_` followed by the object or mission you want to create. For example, to create an `analytical orbit`, a `numerical mission` or a `deployment launch`, we can type:

  ```python
  exoops.analytical.create_orbit(orbit_json_object)
  exoops.numerical.create_mission(mission_json_object)
  exoops.deployment.create_launch(launch_json_object)
  ```

  **All the `create_` functions need the JSON object you created as their only parameter.**

- To `retrieve` specific objects and missions (e.g. to build more complex objects, see the [Example](#example-using-built-in-functions) section below), you can use `get_` followed by the kind of object or mission and pass in as its parameter the **name** of the object or mission. For example, if we want to retrieve the `analytical mission` called **'RAAN phasing demo'**, the `numerical orbit` called **'SSO 600km'** or the `constellation earth mesh` called **'World meshing'**, we can type:

  ```python
  exoops.analytical.get_mission('RAAN phasing demo')
  exoops.numerical.get_orbit('SSO 600km')
  exoops.constellation.get_earth_mesh('World meshing')
  ```

  **All the `get_` functions need the name of the object/mission as their only parameter.**

- To `retrieve` all objects or missions, you can use `get_all_` followed by the kind of object or mission. For example, if we want to retrieve all `numerical spacecrafts`, all `deployment missions` or all `constellation ground stations`, we can type:

  ```python
  exoops.numerical.get_all_spacecrafts()
  exoops.deployment.get_all_missions()
  exoops.constellation.get_all_ground_stations()
  ```

  **These functions can be useful if you wish to print out the list of objects/missions you already created. Simply use the native Python function `print()`.**

- To `compute` missions, you can use `compute_ ... _mission` (replace `...` with the type of mission (ONLY FOR CONSTELLATION, see [Missions and objects names differences](#missions-and-objects-names-differences) section below)) followed by the kind of mission and pass in as its parameter the name of the mission. For example, if we want to compute an `analytical mission` called **'Orbital transfer demo'**, a `constellation simulation mission` called **'Simulation demo'** or a `numerical mission` called **'Orbit extrapolation test'**, we can type:

  ```python
  exoops.analytical.compute_mission('Orbital transfer demo')
  exoops.constellation.compute_simulation_mission('Simulation demo')
  exoops.numerical.compute_mission('Orbit extrapolation test')
  ```

- To get a mission `results`, you can use `get_ ... _mission_results` (replace `...` with the type of mission (ONLY FOR CONSTELLATION, see [Missions and objects names differences](#missions-and-objects-names-differences) section below)). For example, if we want to get the results of the `analytical mission` called **'LEO Station keeping demo'**, the `deployment mission` called **'Deployment test'** or the `constellation performance analysis` called **'Constellation test'**, we can type:

  ```python
  exoops.analytical.get_mission_results('LEO Station keeping demo')
  exoops.deployement.get_mission_results('Deployment test')
  exoops.constellation.get_numerical_constellation_mission_results('Constellation test')
  ```

- To get a specific mission's `id` (e.g. to try a route in the Swagger), you can use the `get_ ... _mission_id` (replace `...` with the type of mission (ONLY FOR CONSTELLATION, see [Missions and objects names differences](#missions-and-objects-names-differences) section below)). For example, if we want to get the id for the `constellation optimisation mission` called **'Optimisation test'**, the `deployment mission` called **'Deployment demo'** or the `numerical mission` called **'Orbital transfer test'**, we can type:

  ```python
  exoops.constellation.get_revisit_optimisation_mission_id('Optimisation test')
  exoops.deployment.get_mission_id('Deployment demo')
  exoops.numerical.get_mission_id('Orbital transfer test')
  ```

  ### Example using built-in functions

  In this quick example, we are going to create an `analytical orbital transfer`.

  1. First, we are going to create all the objects from scratch, using the `create_` functions.
  2. Also, we will retrieve objects to create other ones (e.g. we are going to specify a thruster in order to create a spacecraft), using the `get_` functions.
  3. Then, we will be computing the mission using the `compute_` function.
  4. At last, we are going to `print` its results using the `get_mission_results()` function.

  ```python
  import exoops

  base_url = 'https://exoops.exotrail.space'
  mail = 'my_great_email@exotrail.com'
  password = 'm_great_password'

  exoops.connect(base_url, mail, password)

  thruster_object = {
   'name': 'Python Thruster',
   'thrust': 20,
   'isp': 1000,
   'power': 500,
   'standbyPower': 0
  }

  exoops.analytical.create_thruster(thruster_object)

  orbit_object = {
   'name': 'Python Orbit',
   'altitude': 800000,
   'type': 'Circular',
   'sunSynchronousOrbit': False
  }

  exoops.analytical.create_orbit(orbit_object)
  thruster_to_use = 'Python Thruster'

  spacecraft_object = {
   'name': 'Python Spacecraft',
   'platformMass': 60,
   'dragArea': 0.20,
   'dragCoefficient': 3.0,
    'orbitalAveragePower': 70,
   'thruster': exoops.analytical.get_thruster(thruster_to_use)
  }

  exoops.analytical.create_spacecraft(spacecraft_object)

  mission_type = 'RAAN Phasing'
  initial_orbit = 'SSO 600km'
  final_orbit = 'Python Orbit'
  spacecraft = 'Python Spacecraft'
  mission_duration = 250
  delta_raan = 20

  mission_object = {
   'name': 'Python RAAN Phasing',
   'type': mission_type,
   'initialOrbit': exoops.analytical.get_orbit(initial_orbit),
   'finalOrbit': exoops.analytical.get_orbit(final_orbit),
   'spacecraft': exoops.analytical.get_spacecraft(spacecraft),
   'targetMissionDuration': mission_duration,
   'targetDeltaRaan': delta_raan
  }

  exoops.analytical.create_mission(mission_object)

  mission_to_compute = 'Python RAAN Phasing'

  exoops.analytical.compute_mission(mission_to_compute)

  mission_to_get_results = mission_to_compute

  print(exoops.analytical.get_mission_results(mission_to_get_results))
  ```

  **All the native functions `return` their result (except when you encounter an `error`, it will be printed to the console). If you wish to print the results of a function, you need to pass it in as the parameter of the `print()` function, even for the `get_mission_results()` functions.**

--------------------------------------------------------------------------------

## Missions and objects names differences

If you refer to the Swagger and the user interface of ExoOPS™ - Mission Design, you may be wondering which mission names from the user interface correspond to which mission names from the Swagger/library. This is especially true for the `constellation` module.<br>
Here is a table to let you know the differences:

|Module Name User Interface | Module Name API | Mission Name User Interface |        Mission Name API|
|:------------------------: | :-------------: | :-------------------------: | :-----------------------------:|
|      Constellations       |  Constellation  |    Performance analysis     | Numerical constellation mission|
|      Constellations       |  Constellation  |        Optimisation         |  Revisit optimisation mission|
|      Constellations       |  Constellation  |         Generation          |       Generation mission|
|      Constellations       |  Constellation  |         Simulation          |       Simulation mission|
|  Deployment Strategies    |   Deployment    |     Deployment Scenario     |             Mission|
|  Deployment Strategies    |   Deployment    |   Deployment Optimisation   |             Mission|
|    Parametric Studies     |   Analytical    |      Orbital transfer       |             Mission|
|    Parametric Studies     |   Analytical    |        Orbit Phasing        |             Mission|
|    Parametric Studies     |   Analytical    |        RAAN Phasing         |             Mission|
|    Parametric Studies     |   Analytical    |     LEO Station Keeping     |             Mission|
|    Parametric Studies     |   Analytical    |        Deorbitation         |             Mission|
|    Parametric Studies     |   Analytical    |    Sequence of missions     |             Mission|
|    Parametric Studies     |   Analytical    |         ADCS Design         |             Mission|
|       Simulations         |    Numerical    |      Orbital Transfer       |             Mission|
|       Simulations         |    Numerical    |        Orbit Phasing        |             Mission|
|       Simulations         |    Numerical    |        RAAN Phasing         |             Mission|
|       Simulations         |    Numerical    |     LEO Station Keeping     |             Mission|
|       Simulations         |    Numerical    | Spacecraft Design Analysis  |             Mission|
|       Simulations         |    Numerical    |     Orbit Extrapolation     |             Mission|

You can then refer to this table to understand how to create, retrieve, compute missions as well as getting missions results. You just need to type:

- `exoops.[Module Name API].create_[Mission Name API](mission_object)`,
- `exoops.[Module Name API].get_[Mission Name API](mission_name)`,
- `exoops.[Module Name API].compute_[Mission Name API](mission_name)`,
- `exoops.[Module Name API].get_[Mission Name API]_results(mission_name)`.

> [Mission Name API] is always written in snake_case.

If we want to create a Performance analysis mission from the Constellations module, we will type:

```python
exoops.constellation.create_numerical_constellation_mission('Name of the mission')
```

It is a bit easier for objects. You just need to ignore the first part of the name from the Swagger (`analytical-`, `analytical-constellation-`, `deployment-`, `numerical-`) as well as the last part (`-controller`).<br>
To create a constellation earth point of interest, we can see that the related controller from the Swagger is called  `analytical-constellation-earth-point-of-interest-controller`. We can type:

```python
exoops.constellation.create_earth_point_of_interest(json_object)
```