## Overview

Kamodo provides a *functional* interface for space weather analysis, visualization, and knowledge discovery, allowing many problems in scientific data analysis to be posed in terms of function composition and evaluation. We'll walk through its general features here.

##  Kamodo objects

Users primarily interact with models and data through Kamodo objects. 


```python
from kamodo import Kamodo
```

### Function registration
Kamodo objects are essentially python dictionaries storing variable symbols as keys and their interpolating functions as values. New functions may be registered either at the initialization of the Kamodo object or later using dictionary bracket syntax.


```python
kamodo = Kamodo('$x = t^2$')
kamodo['g'] = 'y-1'
kamodo
```




\begin{equation}x{\left(t \right)} = t^{2}\end{equation}\begin{equation}g{\left(y \right)} = y - 1\end{equation}



### Function composition
Kamodo automatically composes functions through specifying on the right-hand-side.


```python
kamodo['f'] = 'g(x)'
kamodo
```




\begin{equation}x{\left(t \right)} = t^{2}\end{equation}\begin{equation}g{\left(y \right)} = y - 1\end{equation}\begin{equation}f{\left(t \right)} = g{\left(x{\left(t \right)} \right)}\end{equation}



Here we have defined two functions $x(t)$, $g(y)$, and the composition $g∘f$. Kamodo was able to determine that $f$ is implicitly a function of $t$ even though we did not say so in $f$'s declaration.

#### Function evaluation
Kamodo uses sympy's ```lambdify``` function to turn the above equations into highly optimized functions for numerical evaluation. We may evaluate $f(t)$ for $t=3$ using "dot" notation:


```python
kamodo.f(3)
```




    8



where the return type is a numpy array. We could also have passed in a numpy array and the result shares the same shape:


```python
import numpy as np
t = np.linspace(-5, 5, 100000)
result = kamodo.f(t)
```


```python
assert(t.shape == result.shape)
```

### Unit conversion
Kamodo automatically handles unit conversions. Simply declare units on the left-hand-side of expressions using bracket notation.


```python
kamodo = Kamodo('mass[kg] = x', 'vol[m^3] = y')
```


```python
kamodo
```




\begin{equation}\operatorname{mass}{\left(x \right)} [kg] = x\end{equation}\begin{equation}\operatorname{vol}{\left(y \right)} [m^3] = y\end{equation}



Unless specified, Kamodo will assign the units for newly defined variables:


```python
kamodo['rho'] = 'mass/vol'
kamodo
```




\begin{equation}\operatorname{mass}{\left(x \right)} [kg] = x\end{equation}\begin{equation}\operatorname{vol}{\left(y \right)} [m^3] = y\end{equation}\begin{equation}\rho{\left(x,y \right)} [kilogram/meter**3] = \frac{\operatorname{mass}{\left(x \right)}}{\operatorname{vol}{\left(y \right)}}\end{equation}



We may override the default behavior by simply naming the our chosen units in the left hand side.


```python
kamodo['rho[g/cm^3]'] = 'mass/vol'
kamodo
```




\begin{equation}\operatorname{mass}{\left(x \right)} [kg] = x\end{equation}\begin{equation}\operatorname{vol}{\left(y \right)} [m^3] = y\end{equation}\begin{equation}\rho{\left(x,y \right)} [g/cm^3] = \frac{\operatorname{mass}{\left(x \right)}}{1000 \operatorname{vol}{\left(y \right)}}\end{equation}



!!! note
    Kamodo will raise an error if the left and right-hand-side units are incompatible.

Even though generated functions are unitless, the units are clearly displayed on the lhs. We think this is a good trade-off between performance and legibility.

We can verify that kamodo produces the correct output upon evaluation.


```python
assert(kamodo.rho(3,8) == (3*1000.)/(8*100**3))
```

### Variable naming conventions
Kamodo allows for a wide array of variable names to suite your problem space, including greek, subscripts, superscripts.


```python
kamodo = Kamodo(
    'rho = ALPHA+BETA+GAMMA',
    'rvec = t',
    'fprime = x',
    'xvec_i = xvec_iminus1 + 1',
    'F__gravity = G*M*m/R**2',
)
kamodo
```




\begin{equation}\rho{\left(\alpha,\beta,\gamma \right)} = \alpha + \beta + \gamma\end{equation}\begin{equation}\vec{r}{\left(t \right)} = t\end{equation}\begin{equation}\operatorname{{f}'}{\left(x \right)} = x\end{equation}\begin{equation}\vec{x}_{i}{\left(\vec{x}_{i-1} \right)} = \vec{x}_{i-1} + 1\end{equation}\begin{equation}\operatorname{F^{gravity}}{\left(G,M,R,m \right)} = \frac{G M m}{R^{2}}\end{equation}



For more details on variable names, see the [Syntax](../Syntax/) section.

## Kamodofication

Many functions can not be written as simple mathematical expressions - they could represent simulation output or observational data. For this reason, we provide a ```@kamodofy``` decorator, which turns any callable function into a kamodo-compatible variable and adds metadata that enables unit conversion.


```python
from kamodo import kamodofy, Kamodo
import numpy as np

@kamodofy(units = 'kg/m^3', citation = 'Pembroke et. al, 2018')
def rho(x = np.array([3,4,5]), y = np.array([1,2,3])):
    """A function that computes density"""
    return x+y

kamodo = Kamodo(rho = rho)
kamodo['den[g/cm^3]'] = 'rho'
kamodo
```




\begin{equation}\rho{\left(x,y \right)} [kg/m^3] = \lambda{\left(x,y \right)}\end{equation}\begin{equation}\operatorname{den}{\left(x,y \right)} [g/cm^3] = \frac{\rho{\left(x,y \right)}}{1000}\end{equation}




```python
kamodo.rho
```




$\rho{\left(x,y \right)} = \lambda{\left(x,y \right)}$




```python
kamodo.den(3,4)
```




    0.007




```python
kamodo.rho.meta # PyHC standard
```




    {'units': 'kg/m^3',
     'citation': 'Pembroke et. al, 2018',
     'equation': None,
     'hidden_args': []}




```python
kamodo.rho.data # PyHC standard
```




    array([4, 6, 8])



Original function doc strings and signatures passed through


```python
help(kamodo.rho)
```

    Help on function rho in module __main__:
    
    rho(x=array([3, 4, 5]), y=array([1, 2, 3]))
        A function that computes density
        
        citation: Pembroke et. al, 2018
    



```python
kamodo.detail()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>lhs</th>
      <th>rhs</th>
      <th>symbol</th>
      <th>units</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>rho(x, y)</th>
      <td>rho</td>
      <td>None</td>
      <td>rho(x, y)</td>
      <td>kg/m^3</td>
    </tr>
    <tr>
      <th>den(x, y)</th>
      <td>den</td>
      <td>rho(x, y)/1000</td>
      <td>den(x, y)</td>
      <td>g/cm^3</td>
    </tr>
  </tbody>
</table>
</div>



# Visualization

Kamodo graphs are generated directly from function signatures by examining the structure of both output and input arguments. 


```python
from plotting import plot_types
plot_types
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th></th>
      <th>plot_type</th>
      <th>function</th>
    </tr>
    <tr>
      <th>out_shape</th>
      <th>arg_shapes</th>
      <th></th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>(1,)</th>
      <th>((N, M), (N, M), (N, M))</th>
      <td>3d-parametric</td>
      <td>&lt;function surface at 0x12f27f620&gt;</td>
    </tr>
    <tr>
      <th rowspan="2" valign="top">(N,)</th>
      <th>((N,),)</th>
      <td>1d-line</td>
      <td>&lt;function line_plot at 0x11e265950&gt;</td>
    </tr>
    <tr>
      <th>((N,), (N,), (N,))</th>
      <td>3d-line-scalar</td>
      <td>&lt;function line_plot at 0x11e265950&gt;</td>
    </tr>
    <tr>
      <th rowspan="2" valign="top">(N, 2)</th>
      <th>((N,),)</th>
      <td>2d-line</td>
      <td>&lt;function line_plot at 0x11e265950&gt;</td>
    </tr>
    <tr>
      <th>((N, 2),)</th>
      <td>2d-vector</td>
      <td>&lt;function vector_plot at 0x12f27f400&gt;</td>
    </tr>
    <tr>
      <th rowspan="2" valign="top">(N, 3)</th>
      <th>((N,),)</th>
      <td>3d-line</td>
      <td>&lt;function line_plot at 0x11e265950&gt;</td>
    </tr>
    <tr>
      <th>((N, 3),)</th>
      <td>3d-vector</td>
      <td>&lt;function vector_plot at 0x12f27f400&gt;</td>
    </tr>
    <tr>
      <th rowspan="6" valign="top">(N, M)</th>
      <th>((N,), (M,))</th>
      <td>2d-contour</td>
      <td>&lt;function contour_plot at 0x12f27f488&gt;</td>
    </tr>
    <tr>
      <th>((N, M), (N, M))</th>
      <td>2d-contour-skew</td>
      <td>&lt;function contour_plot at 0x12f27f488&gt;</td>
    </tr>
    <tr>
      <th>((N, M), (N, M), (N, M))</th>
      <td>3d-parametric-scalar</td>
      <td>&lt;function surface at 0x12f27f620&gt;</td>
    </tr>
    <tr>
      <th>((1,), (N, M), (N, M))</th>
      <td>3d-plane</td>
      <td>&lt;function plane at 0x12f27f598&gt;</td>
    </tr>
    <tr>
      <th>((N, M), (1,), (N, M))</th>
      <td>3d-plane</td>
      <td>&lt;function plane at 0x12f27f598&gt;</td>
    </tr>
    <tr>
      <th>((N, M), (N, M), (1,))</th>
      <td>3d-plane</td>
      <td>&lt;function plane at 0x12f27f598&gt;</td>
    </tr>
    <tr>
      <th rowspan="3" valign="top">(N, M, 1)</th>
      <th>((1,), (N,), (M,))</th>
      <td>3d-plane</td>
      <td>&lt;function plane at 0x12f27f598&gt;</td>
    </tr>
    <tr>
      <th>((N,), (1,), (M,))</th>
      <td>3d-plane</td>
      <td>&lt;function plane at 0x12f27f598&gt;</td>
    </tr>
    <tr>
      <th>((N,), (M,), (1,))</th>
      <td>3d-plane</td>
      <td>&lt;function plane at 0x12f27f598&gt;</td>
    </tr>
  </tbody>
</table>
</div>



Kamodo uses [plotly](https://plot.ly/python/) for visualization, enabling a rich array of interactive graphs and easy web deployment.


```python
import plotly.io as pio
from plotly.offline import iplot,plot, init_notebook_mode
init_notebook_mode(connected=True)
```







```python
@kamodofy(units = 'kg/m^3')
def rho(x = np.linspace(0,1, 20), y = np.linspace(-1, 1, 40)):
    """A function that computes density"""
    x_, y_ = np.meshgrid(x,y)
    return x_*y_

kamodo = Kamodo(rho = rho)
kamodo
```




\begin{equation}\rho{\left(x,y \right)} [kg/m^3] = \lambda{\left(x,y \right)}\end{equation}



We will generate an image of this function using plotly


```python
fig = kamodo.plot('rho')
pio.write_image(fig, 'images/Kamodo_fig1.svg')
```



See the [Visualization](../Visualization/) section for detailed examples.

## Latex I/O

Even though math is the language of physics, most scientific analysis software requires you to learn new programing languages. Kamodo allows users to write their mathematical expressions in LaTeX, a typesetting language most scientists already know:


```python
kamodo = Kamodo('$rho[kg/m^3] = x^3$', '$v[cm/s] = y^2$')
kamodo['p[Pa]'] = '$\\rho v^2$'
kamodo
```




\begin{equation}\rho{\left(x \right)} [kg/m^3] = x^{3}\end{equation}\begin{equation}v{\left(y \right)} [cm/s] = y^{2}\end{equation}\begin{equation}p{\left(x,y \right)} [Pa] = \frac{\rho{\left(x \right)} v^{2}{\left(y \right)}}{10000}\end{equation}



The resulting equation set may also be exported as a LaTeX string for use in publications:


```python
print(kamodo.to_latex() + '\n.')
```

    \begin{equation}\rho{\left(x \right)} [kg/m^3] = x^{3}\end{equation}\begin{equation}v{\left(y \right)} [cm/s] = y^{2}\end{equation}\begin{equation}p{\left(x,y \right)} [Pa] = \frac{\rho{\left(x \right)} v^{2}{\left(y \right)}}{10000}\end{equation}
    .


# Simulation api

Kamodo offers a simple api for functions composed of each other.

Define variables as usual (order matters).


```python
kamodo = Kamodo()
kamodo['y_iplus1'] = 'x_i + 1'
kamodo['x_iplus1'] = 'y_i - 2'
kamodo
```




\begin{equation}\operatorname{y_{i+1}}{\left(x_{i} \right)} = x_{i} + 1\end{equation}\begin{equation}\operatorname{x_{i+1}}{\left(y_{i} \right)} = y_{i} - 2\end{equation}



Now add the ```update``` attribute to map functions onto arguments.


```python
kamodo.x_iplus1.update = 'x_i'
kamodo.y_iplus1.update = 'y_i'
```

Create a simulation with initial conditions


```python
simulation = kamodo.simulate(x_i = 0, steps = 5)
simulation #an iterator of arg, val dictionaries
```




    <generator object simulate at 0x12fdd5a98>



Run the simulation by iterating through the generator.


```python
import pandas as pd
pd.DataFrame(simulation) # pandas conveniently iterates the results for display
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>y_i</th>
      <th>x_i</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>NaN</td>
      <td>0</td>
    </tr>
    <tr>
      <th>1</th>
      <td>1.0</td>
      <td>-1</td>
    </tr>
    <tr>
      <th>2</th>
      <td>0.0</td>
      <td>-2</td>
    </tr>
    <tr>
      <th>3</th>
      <td>-1.0</td>
      <td>-3</td>
    </tr>
    <tr>
      <th>4</th>
      <td>-2.0</td>
      <td>-4</td>
    </tr>
    <tr>
      <th>5</th>
      <td>-3.0</td>
      <td>-5</td>
    </tr>
  </tbody>
</table>
</div>



a40a97252f269cf52a0e0f8294e1e4510310c063
ipynb
Jupyter Notebook
docs/notebooks/Kamodo.ipynb
iamjavaexpert/Kamodo
26e7de66e67b9196ab19f13e73136db75832813c
NASA-1.3
docs/notebooks/Kamodo.ipynb
iamjavaexpert/Kamodo
26e7de66e67b9196ab19f13e73136db75832813c
NASA-1.3
docs/notebooks/Kamodo.ipynb
iamjavaexpert/Kamodo
26e7de66e67b9196ab19f13e73136db75832813c
NASA-1.3
Qwen/Qwen-72B
1. YES
2. YES