diff --git a/.gitignore b/.gitignore index 1bb95c0..157f002 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,10 @@ /build .project - .pydevproject + +*.py[cod] + +cython_numpy_auto/erfa.c + +cython_numpy_auto/erfa.pyx diff --git a/cython_numpy/erfa.pyx b/cython_numpy/erfa.pyx index 6504f38..f3943e8 100644 --- a/cython_numpy/erfa.pyx +++ b/cython_numpy/erfa.pyx @@ -3,7 +3,8 @@ cimport numpy as np np.import_array() -__all__ = ['atco13', 'd2dtf'] +__all__ = ['atco13', 'd2dtf', 'aper'] + cdef extern from "erfa.h": int eraAtco13(double rc, double dc, @@ -15,28 +16,86 @@ cdef extern from "erfa.h": double *dob, double *rob, double *eo) int eraD2dtf(const char *scale, int ndp, double d1, double d2, int *iy, int *im, int *id, int ihmsf[4]) + void eraAper(double theta, eraASTROM *astrom) + +cdef struct eraASTROM: + double pmt + double eb[3] + double eh[3] + double em + double v[3] + double bm1 + double bpn[3][3] + double along + double phi + double xpl + double ypl + double sphi + double cphi + double diurab + double eral + double refa + double refb + +dt_eraASTROM = np.dtype([('pmt','d'), + ('eb','d',(3,)), + ('eh','d',(3,)), + ('em','d'), + ('v','d',(3,)), + ('bm1 ','d'), + ('bpn','d',(3,3)), + ('along','d'), + ('phi','d'), + ('xpl','d'), + ('ypl','d'), + ('sphi','d'), + ('cphi','d'), + ('diurab','d'), + ('eral','d'), + ('refa','d'), + ('refb','d')], align=True) + #Note: the pattern used here follows https://github.com/cython/cython/wiki/tutorials-numpy#dimensionally-simple-functions + def atco13(rc, dc, pr, pd, px, rv, utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tk, rh, wl): shape = np.broadcast(rc, dc, pr, pd, px, rv, utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tk, rh, wl).shape - aob = np.empty(shape, dtype=np.double) - zob = np.empty(shape, dtype=np.double) - hob = np.empty(shape, dtype=np.double) - dob = np.empty(shape, dtype=np.double) - rob = np.empty(shape, dtype=np.double) - eo = np.empty(shape, dtype=np.double) + aob_out = np.empty(shape, dtype=np.double) + zob_out = np.empty(shape, dtype=np.double) + hob_out = np.empty(shape, dtype=np.double) + dob_out = np.empty(shape, dtype=np.double) + rob_out = np.empty(shape, dtype=np.double) + eo_out = np.empty(shape, dtype=np.double) - cdef np.broadcast it = np.broadcast(rc, dc, pr, pd, px, rv, utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tk, rh, wl, aob, zob, hob, dob, rob, eo) + cdef np.broadcast it = np.broadcast(rc, dc, pr, pd, px, rv, utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tk, rh, wl, aob_out, zob_out, hob_out, dob_out, rob_out, eo_out) - cdef double _aob - cdef double _zob - cdef double _hob - cdef double _dob - cdef double _rob - cdef double _eo + cdef double _rc + cdef double _dc + cdef double _pr + cdef double _pd + cdef double _px + cdef double _rv + cdef double _utc1 + cdef double _utc2 + cdef double _dut1 + cdef double _elong + cdef double _phi + cdef double _hm + cdef double _xp + cdef double _yp + cdef double _phpa + cdef double _tk + cdef double _rh + cdef double _wl + cdef double *_aob + cdef double *_zob + cdef double *_hob + cdef double *_dob + cdef double *_rob + cdef double *_eo while np.PyArray_MultiIter_NOTDONE(it): @@ -58,47 +117,76 @@ def atco13(rc, dc, pr, pd, px, rv, utc1, utc2, dut1, elong, phi, hm, xp, yp, php _tk = (np.PyArray_MultiIter_DATA(it, 15))[0] _rh = (np.PyArray_MultiIter_DATA(it, 16))[0] _wl = (np.PyArray_MultiIter_DATA(it, 17))[0] + _aob = (np.PyArray_MultiIter_DATA(it, 18)) + _zob = (np.PyArray_MultiIter_DATA(it, 19)) + _hob = (np.PyArray_MultiIter_DATA(it, 20)) + _dob = (np.PyArray_MultiIter_DATA(it, 21)) + _rob = (np.PyArray_MultiIter_DATA(it, 22)) + _eo = (np.PyArray_MultiIter_DATA(it, 23)) - ret = eraAtco13(_rc, _dc, _pr, _pd, _px, _rv, _utc1, _utc2, _dut1, _elong, _phi, _hm, _xp, _yp, _phpa, _tk, _rh, _wl, &_aob, &_zob, &_hob, &_dob, &_rob, &_eo) - - (np.PyArray_MultiIter_DATA(it, 18))[0] = _aob - (np.PyArray_MultiIter_DATA(it, 19))[0] = _zob - (np.PyArray_MultiIter_DATA(it, 20))[0] = _hob - (np.PyArray_MultiIter_DATA(it, 21))[0] = _dob - (np.PyArray_MultiIter_DATA(it, 22))[0] = _rob - (np.PyArray_MultiIter_DATA(it, 23))[0] = _eo + ret = eraAtco13(_rc, _dc, _pr, _pd, _px, _rv, _utc1, _utc2, _dut1, _elong, _phi, _hm, _xp, _yp, _phpa, _tk, _rh, _wl, _aob, _zob, _hob, _dob, _rob, _eo) np.PyArray_MultiIter_NEXT(it) - return aob, zob, hob, dob, rob, eo + return aob_out, zob_out, hob_out, dob_out, rob_out, eo_out + + def d2dtf(scale, ndp, d1, d2): - shape = np.broadcast(d1, d2).shape - iy = np.empty(shape, dtype=np.int) - im = np.empty(shape, dtype=np.int) - id = np.empty(shape, dtype=np.int) - ihmsf = np.empty(shape, dtype=[('h','i'),('m','i'),('s','i'),('f','i')]) + shape = np.broadcast(scale, ndp, d1, d2).shape + iy_out = np.empty(shape, dtype=np.int) + im_out = np.empty(shape, dtype=np.int) + id_out = np.empty(shape, dtype=np.int) + ihmsf_out = np.empty(shape, dtype=[('h','i'),('m','i'),('s','i'),('f','i')]) - cdef np.broadcast it = np.broadcast(d1, d2, iy, im, id, ihmsf) + cdef np.broadcast it = np.broadcast(scale, ndp, d1, d2, iy_out, im_out, id_out, ihmsf_out) - cdef int _iy - cdef int _im - cdef int _id - cdef int _ihmsf[4] + cdef char *_scale + cdef int _ndp + cdef double _d1 + cdef double _d2 + cdef int *_iy + cdef int *_im + cdef int *_id + cdef int *_ihmsf while np.PyArray_MultiIter_NOTDONE(it): - _d1 = (np.PyArray_MultiIter_DATA(it, 0))[0] - _d2 = (np.PyArray_MultiIter_DATA(it, 1))[0] + _scale = ( np.PyArray_MultiIter_DATA(it, 0)) + _ndp = ( np.PyArray_MultiIter_DATA(it, 1))[0] + _d1 = (np.PyArray_MultiIter_DATA(it, 2))[0] + _d2 = (np.PyArray_MultiIter_DATA(it, 3))[0] + _iy = ( np.PyArray_MultiIter_DATA(it, 4)) + _im = ( np.PyArray_MultiIter_DATA(it, 5)) + _id = ( np.PyArray_MultiIter_DATA(it, 6)) + _ihmsf = ( np.PyArray_MultiIter_DATA(it, 7)) + + ret = eraD2dtf(_scale, _ndp, _d1, _d2, _iy, _im, _id, _ihmsf) + + np.PyArray_MultiIter_NEXT(it) + + return iy_out, im_out, id_out, ihmsf_out + + + +def aper(theta, astrom): + + shape = np.broadcast(theta, astrom).shape + astrom_out = np.array(np.broadcast_arrays(theta, astrom)[1], dtype=dt_eraASTROM) + + cdef np.broadcast it = np.broadcast(theta, astrom_out) + + cdef double _theta + cdef eraASTROM *_astrom + + while np.PyArray_MultiIter_NOTDONE(it): - ret = eraD2dtf(scale, ndp, _d1, _d2, &_iy, &_im, &_id, _ihmsf) + _theta = ( np.PyArray_MultiIter_DATA(it, 0))[0] + _astrom = (np.PyArray_MultiIter_DATA(it, 1)) - (np.PyArray_MultiIter_DATA(it, 2))[0] = _iy - (np.PyArray_MultiIter_DATA(it, 3))[0] = _im - (np.PyArray_MultiIter_DATA(it, 4))[0] = _id - (np.PyArray_MultiIter_DATA(it, 5))[0:4] = _ihmsf + eraAper(_theta, _astrom) np.PyArray_MultiIter_NEXT(it) - return iy, im, id, ihmsf + return astrom_out \ No newline at end of file diff --git a/cython_numpy_auto/__init__.py b/cython_numpy_auto/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cython_numpy_auto/code_analyzer.py b/cython_numpy_auto/code_analyzer.py new file mode 100644 index 0000000..bde0348 --- /dev/null +++ b/cython_numpy_auto/code_analyzer.py @@ -0,0 +1,177 @@ +import os.path +import re + + +__all__ = ['Function'] + + +ctype_to_dtype = {'double' : "numpy.double", + 'double *' : "numpy.double", + 'int' : "numpy.int", + 'int *' : "numpy.int", + 'int[4]' : "numpy.dtype([('', 'i', (4,))])", + 'double[2]' : "numpy.dtype([('', 'd', (2,))])", + 'double[3]' : "numpy.dtype([('p', 'd', (3,))])", + 'double[2][3]' : "numpy.dtype([('pv', 'd', (2,3))])", + 'double[3][3]' : "numpy.dtype([('r', 'd', (3,3))])", + 'eraASTROM *' : "dt_eraASTROM", + 'char *' : "numpy.dtype('S1')", + } + + +class FunctionDoc(object): + + def __init__(self, doc): + self.doc = doc.replace("**"," ").replace("/*"," ").replace("*/"," ") + self.__input = None + self.__output = None + + @property + def input(self): + if self.__input is None: + self.__input = [] + result = re.search("Given([^\n]*):\n(.+?) \n", self.doc, re.DOTALL) + if result is not None: + __input = result.group(2) + for i in __input.split("\n"): + arg_doc = ArgumentDoc(i) + if arg_doc.name is not None: + self.__input.append(arg_doc) + result = re.search("Given and returned([^\n]*):\n(.+?) \n", self.doc, re.DOTALL) + if result is not None: + __input = result.group(2) + for i in __input.split("\n"): + arg_doc = ArgumentDoc(i) + if arg_doc.name is not None: + self.__input.append(arg_doc) + return self.__input + + @property + def output(self): + if self.__output is None: + self.__output = [] + result = re.search("Returned([^\n]*):\n(.+?) \n", self.doc, re.DOTALL) + if result is not None: + __output = result.group(2) + for i in __output.split("\n"): + arg_doc = ArgumentDoc(i) + if arg_doc.name is not None: + self.__output.append(arg_doc) + result = re.search("Given and returned([^\n]*):\n(.+?) \n", self.doc, re.DOTALL) + if result is not None: + __output = result.group(2) + for i in __output.split("\n"): + arg_doc = ArgumentDoc(i) + if arg_doc.name is not None: + self.__output.append(arg_doc) + return self.__output + + def __repr__(self): + return self.doc + +class ArgumentDoc(object): + + def __init__(self, doc): + match = re.search("^ +([^ ]+)[ ]+([^ ]+)[ ]+(.+)", doc) + if match is not None: + self.name = match.group(1) + self.type = match.group(2) + self.doc = match.group(3) + else: + self.name = None + self.type = None + self.doc = None + + def __repr__(self): + return " {0:15} {1:15} {2}".format(self.name, self.type, self.doc) + +class Argument(object): + + def __init__(self, definition, doc): + self.__doc = doc + self.__inout_state = None + self.definition = definition.strip() + if "*" in self.definition: + self.ctype, self.name = self.definition.split("*", 1) + self.ctype += "*" + else: + self.ctype, self.name = self.definition.rsplit(" ", 1) + if "[" in self.name: + self.name, arr = self.name.split("[", 1) + self.ctype += ("["+arr) + + @property + def inout_state(self): + if self.__inout_state is None: + self.__inout_state = '' + for i in self.__doc.input: + if self.name in i.name.split(','): + self.__inout_state = 'in' + for o in self.__doc.output: + if self.name in o.name.split(','): + if self.__inout_state == 'in': + self.__inout_state = 'inout' + else: + self.__inout_state = 'out' + return self.__inout_state + + @property + def ctype_ptr(self): + if self.ctype[-1] == ']': + return self.ctype.split('[')[0]+" *" + elif self.ctype[:6] == 'const ': + return self.ctype[6:] + else: + return self.ctype + + @property + def dtype(self): + return ctype_to_dtype[self.ctype] + + def __repr__(self): + return "Argument('{0}', name='{1}', ctype='{2}', inout_state='{3}')".format(self.definition, self.name, self.ctype, self.inout_state) + +class Return(object): + + def __init__(self, ctype, doc): + self.name = 'ret' + self.ctype = ctype + self.inout_state = 'ret' + self.ctype_ptr = ctype + + @property + def dtype(self): + return ctype_to_dtype[self.ctype] + +class Function(object): + + def __init__(self, name, source_path): + self.name = name + self.pyname = name.split('era')[-1].lower() + self.filename = name.split("era")[-1].lower()+".c" + self.filepath = os.path.join(os.path.normpath(source_path), self.filename) + pattern = "\n([^\n]+{0} ?\([^)]+\)).+?(/\*.+?\*/)".format(name) + p = re.compile(pattern, flags=re.DOTALL|re.MULTILINE) + with open(self.filepath) as f: + search = p.search(f.read()) + self.cfunc = search.group(1) + self.__doc = FunctionDoc(search.group(2)) + self.args = [] + for arg in re.search("\(([^)]+)\)", self.cfunc, flags=re.MULTILINE|re.DOTALL).group(1).split(','): + self.args.append(Argument(arg, self.__doc)) + self.ret = re.search("^(.*){0}".format(name), self.cfunc).group(1).strip() + if self.ret == 'double': + self.args.append(Return(self.ret, self.__doc)) + + def args_by_inout(self, inout_filter, prop=None, join=None): + result = [] + for arg in self.args: + if arg.inout_state in inout_filter.split('|'): + if prop is None: + result.append(arg) + else: + result.append(getattr(arg, prop)) + if join is not None: + return join.join(result) + else: + return result diff --git a/cython_numpy_auto/cython_generator.py b/cython_numpy_auto/cython_generator.py new file mode 100644 index 0000000..3b227fe --- /dev/null +++ b/cython_numpy_auto/cython_generator.py @@ -0,0 +1,41 @@ +import re +from jinja2 import Environment, PackageLoader +from cython_numpy_auto.code_analyzer import Function + +ERFA_SOURCES = "../../erfa/src" + +#Prepare the jinja2 templating environment +env = Environment(loader=PackageLoader('cython_numpy_auto', '.')) + +def prefix(a_list, pre): + return [pre+'{0}'.format(an_element) for an_element in a_list] +def postfix(a_list, post): + return ['{0}'.format(an_element)+post for an_element in a_list] +def surround(a_list, pre, post): + return [pre+'{0}'.format(an_element)+post for an_element in a_list] +env.filters['prefix'] = prefix +env.filters['postfix'] = postfix +env.filters['surround'] = surround + +erfa_pyx_in = env.get_template('erfa.pyx.in') + + +#Extract all the ERFA function names from erfa.h +with open(ERFA_SOURCES+"/erfa.h", "r") as f: + + erfa_h = f.read() + + funcs = [] + section_subsection_functions = re.findall('/\* (\w*)/(\w*) \*/\n(.*?)\n\n', erfa_h, flags=re.DOTALL|re.MULTILINE) + for section, subsection, functions in section_subsection_functions: + print("{0}.{1}".format(section, subsection)) + if section == "Astronomy": + func_names = re.findall(' (\w+)\(.*?\);', functions, flags=re.DOTALL) + for name in func_names: + print("{0}.{1}.{2}...".format(section, subsection, name)) + funcs.append(Function(name, ERFA_SOURCES)) + print("Done!") + #Render the template and save + erfa_pyx = erfa_pyx_in.render(funcs=funcs) + with open("erfa.pyx", "w") as f: + f.write(erfa_pyx) diff --git a/cython_numpy_auto/erfa.pyx.in b/cython_numpy_auto/erfa.pyx.in new file mode 100644 index 0000000..3b65992 --- /dev/null +++ b/cython_numpy_auto/erfa.pyx.in @@ -0,0 +1,99 @@ +import numpy +cimport numpy + +numpy.import_array() + +__all__ = [{{ funcs|map(attribute='name')|surround("'","'")|join(", ") }}] + + +cdef extern from "erfa.h": + struct eraASTROM: + pass + struct eraLDBODY: + pass +{%- for func in funcs %} + {{ func.ret }} {{ func.name }}({{ func.args_by_inout('in|inout|out')|map(attribute='ctype_ptr')|join(', ') }}) +{%- endfor %} + +dt_eraASTROM = numpy.dtype([('pmt','d'), + ('eb','d',(3,)), + ('eh','d',(3,)), + ('em','d'), + ('v','d',(3,)), + ('bm1 ','d'), + ('bpn','d',(3,3)), + ('along','d'), + ('phi','d'), + ('xpl','d'), + ('ypl','d'), + ('sphi','d'), + ('cphi','d'), + ('diurab','d'), + ('eral','d'), + ('refa','d'), + ('refb','d')], align=True) + + +{% for func in funcs %} +def {{ func.pyname }}({{ func.args_by_inout('in|inout')|map(attribute='name')|join(', ') }}): + + {%- if func.args_by_inout('in|inout') %} + shape = numpy.broadcast({{ func.args_by_inout('in|inout')|map(attribute='name')|join(', ') }}).shape + {%- for arg in func.args_by_inout('out|ret') %} + {{ arg.name }}_out = numpy.empty(shape, dtype={{ arg.dtype }}) + {%- endfor %} + {%- for arg in func.args_by_inout('inout') %} + {{ arg.name }}_out = numpy.array(numpy.broadcast_arrays({{ func.args_by_inout('in|inout')|map(attribute='name')|join(', ') }})[{{ func.args.index(arg) }}], dtype={{ arg.dtype }}) + {%- endfor %} + + cdef numpy.broadcast it = numpy.broadcast({{ (func.args_by_inout('in')|map(attribute='name')|list + func.args_by_inout('inout|out|ret')|map(attribute='name')|postfix('_out')|list) |join(', ') }}) + {%- for arg in func.args_by_inout('in|inout|out|ret') %} + cdef {{ arg.ctype_ptr }} _{{ arg.name }} + {%- endfor %} + + while numpy.PyArray_MultiIter_NOTDONE(it): + + {%- for arg in func.args_by_inout('in|inout|out') %} + {%- if arg.ctype_ptr[-1] == '*' %} + _{{ arg.name }} = (<{{ arg.ctype_ptr }}>numpy.PyArray_MultiIter_DATA(it, {{ func.args.index(arg) }})) + {%- else %} + _{{ arg.name }} = (<{{ arg.ctype_ptr }}*>numpy.PyArray_MultiIter_DATA(it, {{ func.args.index(arg) }}))[0] + {%- endif %} + {%- endfor %} + + {{ func.args_by_inout('ret')|map(attribute='name')|surround('_',' = ')|join }}{{ func.name }}({{ func.args_by_inout('in|out|inout')|map(attribute='name')|prefix('_')|join(', ') }}) + + {%- for arg in func.args_by_inout('ret') %} + (<{{ arg.ctype_ptr }}*>numpy.PyArray_MultiIter_DATA(it, {{ func.args.index(arg) }}))[0] = _{{ arg.name }} + {%- endfor %} + + numpy.PyArray_MultiIter_NEXT(it) + {%- else %} + shape = [] + {%- for arg in func.args_by_inout('out') %} + {{ arg.name }}_out = numpy.empty(shape, dtype={{ arg.dtype }}) + {%- endfor %} + + cdef numpy.broadcast it = numpy.broadcast({{ (func.args_by_inout('in')|map(attribute='name')|list + func.args_by_inout('inout|out|ret')|map(attribute='name')|postfix('_out')|list) |join(', ') }}) + {%- for arg in func.args_by_inout('out') %} + cdef {{ arg.ctype_ptr }} _{{ arg.name }} + {%- endfor %} + + while numpy.PyArray_MultiIter_NOTDONE(it): + + {%- for arg in func.args_by_inout('in|inout|out') %} + {%- if arg.ctype_ptr[-1] == '*' %} + _{{ arg.name }} = (<{{ arg.ctype_ptr }}>numpy.PyArray_MultiIter_DATA(it, {{ func.args.index(arg) }})) + {%- else %} + _{{ arg.name }} = (<{{ arg.ctype_ptr }}*>numpy.PyArray_MultiIter_DATA(it, {{ func.args.index(arg) }}))[0] + {%- endif %} + {%- endfor %} + + {{ func.name }}({{ func.args_by_inout('in|out|inout')|map(attribute='name')|prefix('_')|join(', ') }}) + + numpy.PyArray_MultiIter_NEXT(it) + {%- endif %} + + return {{ func.args_by_inout('inout|out|ret')|map(attribute='name')|postfix('_out')|join(', ') }} + +{% endfor %} diff --git a/setup.py b/setup.py index acfd3b0..4b7a75a 100644 --- a/setup.py +++ b/setup.py @@ -10,8 +10,14 @@ include_dirs = [np.get_include(), '/opt/local/include'], library_dirs = ['/opt/local/lib']) +cython_numpy_auto_ext = Extension("erfa.cython_numpy_auto", + ["cython_numpy_auto/erfa.pyx"], + libraries=['erfa'], + include_dirs = [np.get_include(), '/opt/local/include'], + library_dirs = ['/opt/local/lib']) + setup(name = "erfa", cmdclass = { "build_ext": build_ext }, packages = ["erfa"], package_dir = {"erfa":"."}, - ext_modules = [cython_numpy_ext]) + ext_modules = [cython_numpy_ext, cython_numpy_auto_ext]) diff --git a/tests/test_erfa.py b/tests/test_erfa.py index 80653bc..7126c05 100644 --- a/tests/test_erfa.py +++ b/tests/test_erfa.py @@ -1,24 +1,37 @@ +import importlib import numpy as np -import erfa.cython_numpy as erfa - -jd = np.linspace(2456855.5, 2456855.5+1.0/24.0/60.0, 60*2+1) -ra = np.linspace(0.0,np.pi*2.0,5) -dec = np.linspace(-np.pi/2.0,+np.pi/2.0,4) - -aob, zob, hob, dob, rob, eo = erfa.atco13(0.0,0.0,0.0,0.0,0.0,0.0,jd,0.0,0.0,0.0,np.pi/4.0,0.0,0.0,0.0,1014.0,0.0,0.0,0.5) -print(aob.shape) - -aob, zob, hob, dob, rob, eo = erfa.atco13(0.0,0.0,0.0,0.0,0.0,0.0,jd[0],0.0,0.0,0.0,np.pi/4.0,0.0,0.0,0.0,1014.0,0.0,0.0,0.5) -print(aob.shape) - -aob, zob, hob, dob, rob, eo = erfa.atco13(ra[:,None,None],dec[None,:,None],0.0,0.0,0.0,0.0,jd[None,None,:],0.0,0.0,0.0,np.pi/4.0,0.0,0.0,0.0,1014.0,0.0,0.0,0.5) -print(aob.shape) - -iy, im, id, ihmsf = erfa.d2dtf("UTC", 3, jd, 0.0) -print(iy.shape, ihmsf.shape, ihmsf.dtype) -print(ihmsf) - -iy, im, id, ihmsf = erfa.d2dtf("UTC", 3, jd[0], 0.0) -print(iy.shape, ihmsf.shape, ihmsf.dtype) -print(ihmsf) +for erfa_wrapper_name in ['cython_numpy', 'cython_numpy_auto']: + + erfa_module_name = '.'.join(['erfa', erfa_wrapper_name]) + print("Testing with {0}...".format(erfa_module_name)) + + erfa = importlib.import_module(erfa_module_name) + + jd = np.linspace(2456855.5, 2456855.5+1.0/24.0/60.0, 60*2+1) + ra = np.linspace(0.0,np.pi*2.0,5) + dec = np.linspace(-np.pi/2.0,+np.pi/2.0,4) + + aob, zob, hob, dob, rob, eo = erfa.atco13(0.0,0.0,0.0,0.0,0.0,0.0,jd,0.0,0.0,0.0,np.pi/4.0,0.0,0.0,0.0,1014.0,0.0,0.0,0.5) + print(aob.shape) + + aob, zob, hob, dob, rob, eo = erfa.atco13(0.0,0.0,0.0,0.0,0.0,0.0,jd[0],0.0,0.0,0.0,np.pi/4.0,0.0,0.0,0.0,1014.0,0.0,0.0,0.5) + print(aob.shape) + + aob, zob, hob, dob, rob, eo = erfa.atco13(ra[:,None,None],dec[None,:,None],0.0,0.0,0.0,0.0,jd[None,None,:],0.0,0.0,0.0,np.pi/4.0,0.0,0.0,0.0,1014.0,0.0,0.0,0.5) + print(aob.shape) + + iy, im, id, ihmsf = erfa.d2dtf("UTC", 3, jd, 0.0) + print(iy.shape, ihmsf.shape, ihmsf.dtype) + print(ihmsf) + + iy, im, id, ihmsf = erfa.d2dtf("UTC", 3, jd[0], 0.0) + print(iy.shape, ihmsf.shape, ihmsf.dtype) + print(ihmsf) + + astrom = np.zeros([2],dtype=erfa.dt_eraASTROM) + theta = np.arange(0,10.0) + print(theta.shape) + print(astrom.shape) + astrom = erfa.aper(theta[:,None], astrom[None,:]) + print(astrom)