class LibSme: def __init__(self, file=None): if file: self._file = file else: self._file = self.libfile() self.lib = CDLL(str(self._file)) self._wfirst = None self._wlast = None self._vw_scale = None self._H2broad = None self._linelist = None @property def file(self): return self._file @property def wfirst(self): return self._wfirst @property def wlast(self): return self._wlast @property def vw_scale(self): return self._vw_scale @property def H2broad(self): return self._H2broad @property def linelist(self): return self._linelist def libfile(self): """Return absolute path to SME library file for the current platform. """ dir = Path(__file__).parent.joinpath('dll') file = '.'.join([ 'sme_synth.so', system().lower(), machine(), architecture()[0][0:2] ]) return dir.joinpath(file) def SMELibraryVersion(self): self.lib.SMELibraryVersion.restype = c_char_p return self.lib.SMELibraryVersion().decode('utf-8') def InputWaveRange(self, wfirst, wlast): libfunc = self.lib.InputWaveRange class Args(Structure): _fields_ = [ ('wfirst', POINTER(c_double)), ('wlast', POINTER(c_double))] def __init__(self, wfirst, wlast): self.wfirst = pointer(c_double(wfirst)) self.wlast = pointer(c_double(wlast)) argv = Args(wfirst, wlast) argc = len(argv._fields_) libfunc.argtypes = [c_int, *[POINTER(f[1]) for f in argv._fields_]] libfunc.restype = c_char_p error = libfunc( argc, byref(argv.wfirst), byref(argv.wlast) ).decode('utf-8') if error != '': raise ValueError(error) self._wfirst = wfirst self._wlast = wlast def SetVWscale(self, vw_scale): libfunc = self.lib.SetVWscale argv = pointer(c_double(vw_scale)) libfunc.argtypes = [c_int, POINTER(POINTER(c_double))] libfunc.restype = c_char_p error = libfunc(1, byref(argv)).decode('utf-8') if error != '': raise ValueError(error) self._vw_scale = vw_scale def SetH2broad(self): self.lib.SetH2broad.restype = c_char_p assert self.lib.SetH2broad().decode('utf-8') == '' self._H2broad = True def ClearH2broad(self): self.lib.ClearH2broad.restype = c_char_p assert self.lib.ClearH2broad().decode('utf-8') == '' self._H2broad = False def InputLineList(self, linelist): libfunc = self.lib.InputLineList nlines = len(linelist) m = 8 class Args(Structure): _fields_ = [ ('nlines', POINTER(c_int)), ('species', POINTER(IdlString * nlines)), ('atomic', POINTER(c_double * nlines * m)) ] def __init__(self, linelist): self._nlines = c_int(nlines) self._species = IdlStringArray(linelist.species) self._atomic = Array2D(c_double, nlines, m) self._atomic.data[2][:] = linelist.wlcent self._atomic.data[3][:] = linelist.excit self._atomic.data[4][:] = linelist.loggf self._atomic.data[5][:] = linelist.gamrad self._atomic.data[6][:] = linelist.gamqst self._atomic.data[7][:] = linelist.gamvw self.nlines = pointer(self._nlines) self.species = pointer(self._species.data) self.atomic = pointer(self._atomic.data) argv = Args(linelist) argc = len(argv._fields_) libfunc.argtypes = [c_int, *[POINTER(f[1]) for f in argv._fields_]] libfunc.restype = c_char_p error = libfunc( argc, byref(argv.nlines), byref(argv.species), byref(argv.atomic) ).decode('utf-8') if error != '': raise ValueError(error) self._linelist = linelist def OutputLineList(self): """Returns WLCENT, GF, EXCIT, log10(GAMRAD), log10(GAMQST), GAMVW. Note that InputLineList elements are 2:WLCENT, 3:log(GF), 4:EXCIT, whereas OutputLineList elements are 0:WLCENT, 1:EXCIT, 2:GF. """ libfunc = self.lib.OutputLineList assert self._linelist is not None nlines = len(self._linelist) m = 6 class Args(Structure): _fields_ = [ ('nlines', POINTER(c_int)), ('atomic', POINTER(c_double * m * nlines)) ] def __init__(self): self._nlines = c_int(nlines) self._atomic = Array2D(c_double, m, nlines) self.nlines = pointer(self._nlines) self.atomic = pointer(self._atomic.data) argv = Args() argc = len(argv._fields_) libfunc.argtypes = [c_int, *[POINTER(f[1]) for f in argv._fields_]] libfunc.restype = c_char_p error = libfunc( argc, byref(argv.nlines), byref(argv.atomic) ).decode('utf-8') if error != '': raise ValueError(error) return argv._atomic.data def UpdateLineList(self, linelist): libfunc = self.lib.UpdateLineList nlines = len(linelist) m = 8 class Args(Structure): _fields_ = [ ('nlines', POINTER(c_int)), ('species', POINTER(IdlString * nlines)), ('atomic', POINTER(c_double * nlines * m)), ('index', POINTER(c_int * nlines)) ] def __init__(self, linelist): self._nlines = c_int(nlines) self._species = IdlStringArray(linelist.species) self._atomic = Array2D(c_double, nlines, m) self._atomic.data[2][:] = linelist.wlcent self._atomic.data[3][:] = linelist.excit self._atomic.data[4][:] = linelist.loggf self._atomic.data[5][:] = linelist.gamrad self._atomic.data[6][:] = linelist.gamqst self._atomic.data[7][:] = linelist.gamvw self.nlines = pointer(self._nlines) self.species = pointer(self._species.data) self.atomic = pointer(self._atomic.data) argv = Args(linelist) argc = len(argv._fields_) libfunc.argtypes = [c_int, *[POINTER(f[1]) for f in argv._fields_]] libfunc.restype = c_char_p error = libfunc( argc, byref(argv.nlines), byref(argv.species), byref(argv.atomic) ).decode('utf-8') if error != '': raise ValueError(error) self._linelist = linelist
class LibSme: """Access SME external library code. """ def __init__(self, file=None): if file: self._file = file else: self._file = self.default_libfile() self.lib = CDLL(str(self._file)) self._wfirst = None self._wlast = None self._vwscale = None self._h2broad = None self._linelist = None @property def file(self): """Absolute path to SME library file for the current platform. """ return self._file @property def wfirst(self): return self._wfirst @property def wlast(self): return self._wlast @property def vwscale(self): return self._vwscale @property def h2broad(self): return self._h2broad @property def linelist(self): return self._linelist def default_libfile(self): """Return default absolute path to SME library file. """ dir = Path(__file__).parent.joinpath('dll') file = '.'.join([ 'sme_synth.so', system().lower(), machine(), architecture()[0][0:2] ]) return dir.joinpath(file) def SMELibraryVersion(self): """Return version number reported by SME library code. """ self.lib.SMELibraryVersion.restype = c_char_p return self.lib.SMELibraryVersion().decode('utf-8') def InputWaveRange(self, wfirst, wlast): """Pass wavelength range for spectrum synthesis to library code. """ libfunc = self.lib.InputWaveRange class Args(Structure): _fields_ = [('wfirst', POINTER(c_double)), ('wlast', POINTER(c_double))] def __init__(self, wfirst, wlast): self.wfirst = pointer(c_double(wfirst)) self.wlast = pointer(c_double(wlast)) argv = Args(wfirst, wlast) argc = len(argv._fields_) libfunc.argtypes = [c_int, *[POINTER(f[1]) for f in argv._fields_]] libfunc.restype = c_char_p error = libfunc(argc, byref(argv.wfirst), byref(argv.wlast)).decode('utf-8') if error != '': raise ValueError(error) self._wfirst = wfirst self._wlast = wlast def SetVWscale(self, vwscale): """Pass van der Waals broadening enhancement factor to library code. """ libfunc = self.lib.SetVWscale argv = pointer(c_double(vwscale)) libfunc.argtypes = [c_int, POINTER(POINTER(c_double))] libfunc.restype = c_char_p error = libfunc(1, byref(argv)).decode('utf-8') if error != '': raise ValueError(error) self._vwscale = vwscale def SetH2broad(self): """Enable collisional broadening by molecular hydrogen in library code. """ self.lib.SetH2broad.restype = c_char_p assert self.lib.SetH2broad().decode('utf-8') == '' self._h2broad = True def ClearH2broad(self): """Disable collisional broadening by molecular hydrogen in library code. """ self.lib.ClearH2broad.restype = c_char_p assert self.lib.ClearH2broad().decode('utf-8') == '' self._h2broad = False def InputLineList(self, linelist): """Pass atomic and molecular line data to library code. """ libfunc = self.lib.InputLineList nlines = len(linelist) m = 8 class Args(Structure): _fields_ = [('nlines', POINTER(c_int)), ('species', POINTER(_IdlString * nlines)), ('atomic', POINTER(c_double * nlines * m))] def __init__(self, linelist): self._nlines = c_int(nlines) self._species = _IdlStringArray(linelist.species) self._atomic = Array2D(c_double, nlines, m) self._atomic.data[2][:] = linelist.wlcent self._atomic.data[3][:] = linelist.excit self._atomic.data[4][:] = linelist.loggf self._atomic.data[5][:] = linelist.gamrad self._atomic.data[6][:] = linelist.gamqst self._atomic.data[7][:] = linelist.gamvw self.nlines = pointer(self._nlines) self.species = pointer(self._species.data) self.atomic = pointer(self._atomic.data) argv = Args(linelist) argc = len(argv._fields_) libfunc.argtypes = [c_int, *[POINTER(f[1]) for f in argv._fields_]] libfunc.restype = c_char_p error = libfunc(argc, byref(argv.nlines), byref(argv.species), byref(argv.atomic)).decode('utf-8') if error != '': raise ValueError(error) self._linelist = linelist def OutputLineList(self): """Returns WLCENT, GF, EXCIT, log10(GAMRAD), log10(GAMQST), GAMVW. Note that InputLineList elements are 2:WLCENT, 3:log(GF), 4:EXCIT, whereas OutputLineList elements are 0:WLCENT, 1:EXCIT, 2:GF. """ libfunc = self.lib.OutputLineList assert self._linelist is not None nlines = len(self._linelist) m = 6 class Args(Structure): _fields_ = [('nlines', POINTER(c_int)), ('atomic', POINTER(c_double * m * nlines))] def __init__(self): self._nlines = c_int(nlines) self._atomic = Array2D(c_double, m, nlines) self.nlines = pointer(self._nlines) self.atomic = pointer(self._atomic.data) argv = Args() argc = len(argv._fields_) libfunc.argtypes = [c_int, *[POINTER(f[1]) for f in argv._fields_]] libfunc.restype = c_char_p error = libfunc(argc, byref(argv.nlines), byref(argv.atomic)).decode('utf-8') if error != '': raise ValueError(error) return argv._atomic.data def UpdateLineList(self, newlinedata, index): """Pass new line data to library code for lines specified by index. """ libfunc = self.lib.UpdateLineList nlines = len(newlinedata) if len(index) != nlines: raise ValueError(f'mismatch: {nlines} lines, {len(index)} indexes') m = 8 class Args(Structure): _fields_ = [('nlines', POINTER(c_short)), ('species', POINTER(_IdlString * nlines)), ('atomic', POINTER(c_double * nlines * m)), ('index', POINTER(c_short * nlines))] def __init__(self, newlinedata, index): self._nlines = c_short(nlines) self._species = _IdlStringArray(newlinedata.species) self._atomic = Array2D(c_double, nlines, m) self._atomic.data[2][:] = newlinedata.wlcent self._atomic.data[3][:] = newlinedata.excit self._atomic.data[4][:] = newlinedata.loggf self._atomic.data[5][:] = newlinedata.gamrad self._atomic.data[6][:] = newlinedata.gamqst self._atomic.data[7][:] = newlinedata.gamvw self._index = Array1D(c_short, nlines) self._index.data[:] = index self.nlines = pointer(self._nlines) self.species = pointer(self._species.data) self.atomic = pointer(self._atomic.data) self.index = pointer(self._index.data) argv = Args(newlinedata, index) argc = len(argv._fields_) libfunc.argtypes = [c_int, *[POINTER(f[1]) for f in argv._fields_]] libfunc.restype = c_char_p error = libfunc(argc, byref(argv.nlines), byref(argv.species), byref(argv.atomic), byref(argv.index)).decode('utf-8') if error != '': raise RuntimeError(error) for i, line in enumerate(newlinedata): self._linelist[index[i]] = line