Source code for use_libwoden
"""Functions to load in the WODEN C/C++/GPU code via a dynamic library,
with the required `precision` (either load `libwoden_float.so` or `libwoden_double.so`)."""
import ctypes
import importlib_resources
import wodenpy
import numpy as np
import sys
import os
from ctypes import CFUNCTYPE
from multiprocessing import Queue, Process
from wodenpy.use_libwoden.create_woden_struct_classes import Woden_Struct_Classes
from wodenpy.use_libwoden.array_layout_struct import Array_Layout_Ctypes
VELC = 299792458.0
[docs]
def load_in_run_woden(woden_lib : ctypes.CDLL,
woden_struct_classes : Woden_Struct_Classes):
"""Load in and define the C wrapper function `run_woden`, which runs the C/C++/GPU code.
`woden_lib` is the ctypes object which has loaded in the WODEN library
via `ctypes.cdll.LoadLibrary(woden_lib_path)`.
Here `woden_lib_path` is the path to the WODEN library, which is either
`libwoden_float.so` or `libwoden_double.so`, depending on the precision.
Parameters
----------
woden_lib : ctypes.CDLL
The ctypes object which has loaded in the WODEN library
woden_struct_classes : Woden_Struct_Classes
This holds all the various ctype structure classes that are equivalent
to the C/CUDA structs. Should have been initialised with the correct
precision ("float" or "double").
Returns
-------
run_woden : _NamedFuncPointer
The C wrapper function `run_woden`, which runs the C/CUDA code.
This function takes the following args, where `sbf_pointer` is either
ctypes.POINTER(ctypes.c_float) or ctypes.POINTER(ctypes.c_double),
depending on the `woden_struct_classes.precision`:
- ctypes.POINTER(woden_struct_classes.Woden_Settings)
- ctypes.POINTER(woden_struct_classes.Visi_Set)
- ctypes.POINTER(woden_struct_classes.Source_Catalogue)
- ctypes.POINTER(Array_Layout)
- sbf_pointer
"""
#Select the run_woden function and define the return type
run_woden = woden_lib.run_woden
run_woden.restype = ctypes.c_int
##now define the argument types; we have defined the classes needed
##in woden_struct_classes. Final argument is the `sbf` array, which depends
##on the precision required
if woden_struct_classes.precision == 'float':
sbf_pointer = ctypes.POINTER(ctypes.c_float)
else:
sbf_pointer = ctypes.POINTER(ctypes.c_double)
run_woden.argtypes = [ctypes.POINTER(woden_struct_classes.Woden_Settings),
ctypes.POINTER(woden_struct_classes.Visi_Set),
ctypes.POINTER(woden_struct_classes.Source_Catalogue),
ctypes.POINTER(Array_Layout_Ctypes),
sbf_pointer]
return run_woden
[docs]
def worker_check_for_everybeam(woden_lib_path: str, q : Queue):
"""
Checks if libwoden*.so has been compiled against EveryBeam (via a flag
-DHAVE_EVERYBEAM which was set via CMake during compilation). Puts True
into the queue `q`, if it has, False otherwise.
This function is run in a separate process to avoid clashing with
`python-casacore`. `python-casacore` and `libwoden*.so`
can be linked to different versions of `casacore`. When
loaded, both create dependency paths and global variables in a persisting
`c++` state. This causes much explosions and segfaults. Wrapping in a
separate process isolates the state of the `c++` code. This is a hot-fix.
.. todo::
Replace all calls to `python-casacore` with calls to `casacore`
directly, via libuse_everybeam.so. It's also possible that using
pybind11 to call c++ instead of `ctypes` would be better?
Parameters
----------
woden_lib_path : str
The file path to the WODEN library (either `/some/path/libwoden_float.so`
or `/some/path/libwoden_double.so`).
q : Queue
A multiprocessing queue to store the result of the check.
"""
woden_lib = ctypes.cdll.LoadLibrary(woden_lib_path)
check_for_everybeam_compilation = woden_lib.check_for_everybeam_compilation
check_for_everybeam_compilation.restype = ctypes.c_bool
q.put(check_for_everybeam_compilation())
[docs]
def check_for_everybeam(woden_lib_path: str) -> bool:
"""
Checks if libwoden*.so has been compiled against EveryBeam (via a flag
-DHAVE_EVERYBEAM which was set via CMake during compilation).
Returns True if it has, False otherwise.
This function calls :func:~`worker_check_for_everybeam` in a separate
process to avoid clashing with `python-casacore`. See
:func:~`worker_check_for_everybeam` docs for more details.
Parameters
----------
woden_lib_path : str
The file path to the WODEN library (either `/some/path/libwoden_float.so`
or `/some/path/libwoden_double.so`).
Returns
-------
bool
True if the 'EveryBeam' feature is compiled in the WODEN library, False otherwise.
"""
q = Queue()
p = Process(target=worker_check_for_everybeam, args=(woden_lib_path, q))
p.start()
p.join()
return q.get()