Skip to content

Commit 129b351

Browse files
authored
Adds code to build ratMain extension (#21)
* Add code for rat_core, events, custom wrapper, setup.py and pyproject.toml
1 parent 8732a27 commit 129b351

File tree

12 files changed

+1977
-9
lines changed

12 files changed

+1977
-9
lines changed

.github/workflows/runTests.yml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ jobs:
1717
matrix:
1818
os: [ubuntu-latest, windows-latest, macos-latest]
1919
version: ["3.9", "3.x"]
20+
defaults:
21+
run:
22+
shell: bash -l {0}
2023

2124
runs-on: ${{ matrix.os }}
2225

@@ -28,11 +31,21 @@ jobs:
2831
uses: actions/setup-python@v4
2932
with:
3033
python-version: ${{ matrix.version }}
31-
- name: Install dependencies
34+
- name: Install OMP (MacOS)
35+
if: runner.os == 'macOS'
3236
run: |
33-
python -m pip install --upgrade pip
34-
pip install -r requirements.txt
35-
- name: Test with pytest
37+
brew install llvm libomp
38+
echo "export CC=/usr/local/opt/llvm/bin/clang" >> ~/.bashrc
39+
echo "export CFLAGS=\"$CFLAGS -I/usr/local/opt/libomp/include\"" >> ~/.bashrc
40+
echo "export CXXFLAGS=\"$CXXFLAGS -I/usr/local/opt/libomp/include\"" >> ~/.bashrc
41+
echo "export LDFLAGS=\"$LDFLAGS -Wl,-rpath,/usr/local/opt/libomp/lib -L/usr/local/opt/libomp/lib -lomp\"" >> ~/.bashrc
42+
source ~/.bashrc
43+
- name: Install OMP (Linux)
44+
if: runner.os == 'Linux'
3645
run: |
37-
pip install pytest pytest-cov
38-
pytest tests/ --cov=${{ github.event.repository.name }} --cov-report=html:htmlcov
46+
sudo apt-get update
47+
sudo apt install libomp-dev
48+
- name: Install and Test with pytest
49+
run: |
50+
python -m pip install -e .[Dev]
51+
pytest tests/ --cov=${{ github.event.repository.name }} --cov-report=html:htmlcov --cov-report=term

.gitignore

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,16 @@ htmlcov/
1515
# Build
1616
_build
1717
docs/.buildinfo
18-
docs/*.inv
18+
docs/*.inv
19+
*.rat.cpp
20+
*.so
21+
*.dll
22+
*.dylib
23+
*.obj
24+
*.exp
25+
*.lib
26+
*.a
27+
*.egg-info/
28+
build/*
29+
dist/*
30+
*.whl

RAT/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
import os
12
from RAT.classlist import ClassList
23
from RAT.project import Project
34
import RAT.controls
45
import RAT.models
6+
7+
8+
dir_path = os.path.dirname(os.path.realpath(__file__))
9+
os.environ["RAT_PATH"] = os.path.join(dir_path, '')

RAT/events.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from typing import Callable, Union, List
2+
import RAT.rat_core
3+
from RAT.rat_core import EventTypes, PlotEventData
4+
5+
6+
def notify(event_type: EventTypes, data: Union[str, PlotEventData]) -> None:
7+
"""Calls registered callbacks with the data when event type has
8+
been triggered.
9+
10+
Parameters
11+
----------
12+
event_type : EventTypes
13+
The event type that was triggered.
14+
data : str or PlotEventData
15+
The data sent by the event. The message event data is a string.
16+
"""
17+
callbacks = __event_callbacks[event_type]
18+
for callback in callbacks:
19+
callback(data)
20+
21+
def get_event_callback(event_type: EventTypes) -> List[Callable[[Union[str, PlotEventData]], None]]:
22+
"""Returns all callbacks registered for the given event type.
23+
24+
Parameters
25+
----------
26+
event_type : EventTypes
27+
The event type.
28+
29+
Retuns
30+
------
31+
callback : Callable[[Union[str, PlotEventData]], None]
32+
The callback for the event type.
33+
"""
34+
return list(__event_callbacks[event_type])
35+
36+
37+
def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventData]], None]) -> None:
38+
"""Registers a new callback for the event type.
39+
40+
Parameters
41+
----------
42+
event_type : EventTypes
43+
The event type to register.
44+
callback : Callable[[Union[str, PlotEventData]], None]
45+
The callback for when the event is triggered.
46+
"""
47+
if not isinstance(event_type, EventTypes):
48+
raise ValueError("event_type must be a events.EventTypes enum")
49+
50+
if len(__event_callbacks[event_type]) == 0:
51+
__event_impl.register(event_type)
52+
__event_callbacks[event_type].add(callback)
53+
54+
55+
def clear() -> None:
56+
"""Clears all event callbacks."""
57+
__event_impl.clear()
58+
for key in __event_callbacks.keys():
59+
__event_callbacks[key] = set()
60+
61+
62+
__event_impl = RAT.rat_core.EventBridge(notify)
63+
__event_callbacks = {EventTypes.Message: set(), EventTypes.Plot: set()}

RAT/misc.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import pathlib
2+
from typing import Callable, Tuple
3+
import numpy as np
4+
from numpy.typing import ArrayLike
5+
import RAT.rat_core
6+
7+
8+
class MatlabWrapper:
9+
"""Creates a python callback for a MATLAB function.
10+
11+
Parameters
12+
----------
13+
filename : string
14+
The path of the file containing MATLAB function
15+
"""
16+
def __init__(self, filename: str) -> None :
17+
self.engine = None
18+
try:
19+
import matlab.engine
20+
except ImportError:
21+
raise ImportError('matlabengine is required to use MatlabWrapper')
22+
self.engine = matlab.engine.start_matlab()
23+
path = pathlib.Path(filename)
24+
self.engine.cd(str(path.parent), nargout=0)
25+
self.function_name = path.stem
26+
27+
def __del__(self):
28+
if self.engine is not None:
29+
self.engine.quit()
30+
31+
def getHandle(self)\
32+
-> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]:
33+
"""Returns a wrapper for the custom MATLAB function
34+
35+
Returns
36+
-------
37+
wrapper : Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]
38+
The wrapper function for the MATLAB callback
39+
"""
40+
def handle(params, bulk_in, bulk_out, contrast, domain=-1):
41+
if domain == -1:
42+
output, sub_rough = getattr(self.engine, self.function_name)(np.array(params, 'float'),
43+
np.array(bulk_in, 'float'),
44+
np.array(bulk_out, 'float'),
45+
float(contrast + 1), nargout=2)
46+
else:
47+
output, sub_rough = getattr(self.engine, self.function_name)(np.array(params, 'float'),
48+
np.array(bulk_in, 'float'),
49+
np.array(bulk_out, 'float'),
50+
float(contrast + 1), float(domain + 1), nargout=2)
51+
return output, sub_rough
52+
return handle
53+
54+
55+
class DylibWrapper:
56+
"""Creates a python callback for a function in dynamic library.
57+
58+
Parameters
59+
----------
60+
filename : str
61+
The path of the dyanamic library
62+
function_name : str
63+
The name of the function to call
64+
"""
65+
def __init__(self, filename, function_name) -> None:
66+
self.engine = RAT.rat_core.DylibEngine(filename, function_name)
67+
68+
def getHandle(self)\
69+
-> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]:
70+
71+
"""Returns a wrapper for the custom dynamic library function
72+
73+
Returns
74+
-------
75+
wrapper : Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]
76+
The wrapper function for the dynamic library callback
77+
"""
78+
def handle(params, bulk_in, bulk_out, contrast, domain=-1):
79+
if domain == -1:
80+
output, sub_rough = self.engine.invoke(params, bulk_in, bulk_out, contrast)
81+
else:
82+
output, sub_rough = self.engine.invoke(params, bulk_in, bulk_out, contrast, domain)
83+
return output, sub_rough
84+
return handle

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
11
python-RAT
22
==========
3-
Python-RAT is the Python interface for the [Reflectivity Algorithm Toolbox](https://github.com/RascalSoftware/RAT) (RAT).
3+
Python-RAT is the Python interface for the [Reflectivity Algorithm Toolbox](https://github.com/RascalSoftware/RAT) (RAT).
4+
5+
Install
6+
=======
7+
To install in local directory:
8+
9+
pip install -e .
10+
11+
matlabengine is an optional dependency only required for Matlab custom functions. The version of matlabengine should match the version of Matlab installed on the machine. This can be installed as shown below:
12+
pip install -e .[Matlab-2023a]
13+
14+
Development dependencies can be installed as shown below
15+
pip install -e .[Dev]
16+
17+
To build wheel:
18+
pip install build
19+
python -m build --wheel

0 commit comments

Comments
 (0)