├── .gitignore
├── mpfit
├── tests
│ ├── __init__.py
│ └── test_mpfit.py
└── mpfitexpr.py
├── my_utils
├── astropy2pg.py
├── get_dss.py
├── resolve.py
├── from_hex.py
├── wav2RGB.py
├── table_joiner.py
├── sphere_rotate.py
├── rotate_pm.py
├── staralt.py
├── match_lists.py
├── clicker.py
├── pg2hdf5.py
├── crossmatcher.py
├── quick_hist.py
├── adabinner.py
├── sky_plotter.py
└── correct_pm.py
├── astrolib
├── sphdist.py
├── cv_coord.py
├── precess_xyz.py
├── readcol.py
├── daycnv.py
├── premat.py
├── zang.py
├── convolve.py
├── cosmo_param.py
├── helio_jd.py
├── helcorr.py
├── galage.py
├── euler.py
├── lumdist.py
├── precess.py
├── gal_uvw.py
├── xyz.py
├── bprecess.py
└── baryvel.py
├── README.md
├── utils
├── workerpool.py
└── idlsave.py
├── plotting
├── idlplotInd.py
└── lasso_plot.py
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | __pycache__
--------------------------------------------------------------------------------
/mpfit/tests/__init__.py:
--------------------------------------------------------------------------------
1 | def test(level=1, verbosity=1):
2 | from numpy.testing import Tester
3 | return Tester().test(level, verbosity)
4 |
--------------------------------------------------------------------------------
/my_utils/astropy2pg.py:
--------------------------------------------------------------------------------
1 | import astropy.table as atpy2
2 | import pandas
3 | import sqlalchemy
4 | import sqlutil
5 |
6 | def printSchema(fname, host, db, user='koposov', tabname='newtab'):
7 | # print the sql schema for a given table
8 | tab = atpy2.Table().read(fname)
9 | df = tab.filled().to_pandas()
10 | conn = sqlutil.getConnection(driver='psycopg2', host=host, db=db, user=user)
11 | AL = sqlalchemy.create_engine('postgresql://', creator=(lambda : conn))
12 | print (pandas.io.sql.get_schema(df,tabname, con=AL))
13 |
14 |
--------------------------------------------------------------------------------
/astrolib/sphdist.py:
--------------------------------------------------------------------------------
1 | from numpy import deg2rad,rad2deg,sin,cos,sqrt,arcsin
2 |
3 | def sphdist (ra1, dec1, ra2, dec2):
4 | """measures the spherical distance in degrees
5 | The input has to be in degrees too
6 | """
7 | dec1_r = deg2rad(dec1)
8 | dec2_r = deg2rad(dec2)
9 | return 2 *\
10 | rad2deg \
11 | (
12 | arcsin
13 | (
14 | sqrt
15 | (
16 | (
17 | sin((dec1_r - dec2_r) / 2)
18 | )**2
19 | +
20 | cos(dec1_r) * cos(dec2_r) *
21 | (
22 | sin((deg2rad(ra1 - ra2)) / 2)
23 | )**2
24 | )
25 | )
26 | )
27 |
28 | def sphdist_fast(ra1,dec1,ra2,dec2):
29 | import numexpr
30 | return numexpr.evaluate('2*57.295779513082323*(arcsin(sqrt((sin(0.017453292519943295*(dec1-dec2)/2))**2+cos(0.017453292519943295*dec1)*cos(0.017453292519943295*dec2)*(sin(0.017453292519943295*((ra1-ra2))/2))**2)))')
31 |
--------------------------------------------------------------------------------
/astrolib/cv_coord.py:
--------------------------------------------------------------------------------
1 | from numpy import sin,cos,deg2rad,rad2deg,arctan2,sqrt
2 |
3 | def cv_coord(a,b,c,fr=None,to=None,degr=False):
4 | if degr:
5 | degrad = deg2rad
6 | raddeg = rad2deg
7 | else:
8 | degrad = lambda x: x
9 | raddeg = lambda x: x
10 | if fr=='sph':
11 | x=c*cos(degrad(a))*cos(degrad(b))
12 | y=c*sin(degrad(a))*cos(degrad(b))
13 | z=c*sin(degrad(b))
14 | elif fr=='rect':
15 | x=a
16 | y=b
17 | z=c
18 | elif fr is None:
19 | raise Exception('You must specify the input coordinate system')
20 | else:
21 | raise Exception('Unknown input coordinate system')
22 | if to=='rect':
23 | return (x,y,z)
24 | elif to=='sph':
25 | ra = raddeg(arctan2(y,x))
26 | dec = raddeg(arctan2(z,sqrt(x**2+y**2)))
27 | rad = sqrt(x**2+y**2+z**2)
28 | return (ra,dec,rad)
29 | elif to is None:
30 | raise Exception('You must specify the output coordinate system')
31 | else:
32 | raise Exception('Unknown output coordinate system')
33 |
34 |
--------------------------------------------------------------------------------
/my_utils/get_dss.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import aplpy
3 | try:
4 | from urllib2 import urlopen
5 | except:
6 | from urllib.request import urlopen
7 | try:
8 | from StringIO import StringIO
9 | except:
10 | from io import BytesIO as StringIO
11 |
12 | import astropy.io.fits as pyfits
13 | import matplotlib.pyplot as plt
14 | def get_dss(ra, dec, survey='all', radius = 15, debug=False, noerase=False,
15 | subplot=(1,1,1)):
16 | """
17 | radius is in arcmins
18 | survey: 'all', 'poss2ukstu', 'dss1'..
19 | """
20 | #survey='poss2ukstu'
21 | url='http://archive.stsci.edu/cgi-bin/dss_search?v=%s&r=%fd&d=%fd&e=J2000&h=%f&w=%f&f=fits&c=none&fov=NONE&v3='%(survey,ra,dec,radius,radius)
22 |
23 | response = urlopen(url)
24 | if debug:
25 | print( url)
26 | html = response.read()
27 | f=StringIO(html)
28 |
29 | dat=pyfits.open(f)
30 | if not noerase:
31 | plt.clf()
32 | gc=aplpy.FITSFigure(dat,figure=plt.gcf(),subplot=subplot)
33 | gc.set_tick_labels_format('ddd.dddd','ddd.dddd')
34 | gc.show_grayscale()
35 | return gc
36 |
37 |
--------------------------------------------------------------------------------
/my_utils/resolve.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from urllib.parse import quote_plus
3 | from lxml import etree
4 | from urllib.request import urlopen
5 |
6 |
7 | def resolve(objectName):
8 | """ R
9 | esolve the object by name using CDS
10 | Example:
11 | >> resolve.resolve('M31')
12 | (10.684708329999999, 41.268749999999997)
13 |
14 | Requires the following modules:
15 | suds, lxml
16 | """
17 | url = 'http://vizier.u-strasbg.fr/cgi-bin/Sesame/-ox/?%s' % quote_plus(
18 | objectName)
19 | f = urlopen(url)
20 | result = f.read()
21 | tree = etree.fromstring(result)
22 | # take the first resolver
23 | success = True
24 | for i in range(4):
25 | pathRa = tree.xpath('/Sesame/Target/Resolver[%d]/jradeg' % i)
26 | pathDec = tree.xpath('/Sesame/Target/Resolver[%d]/jdedeg' % i)
27 | if len(pathRa) != 0:
28 | success = True
29 | break
30 | if not success:
31 | return []
32 | ra = float(pathRa[0].text)
33 | dec = float(pathDec[0].text)
34 | return ra, dec
35 |
36 |
37 | if __name__ == '__main__':
38 | res = resolve(sys.argv[1])
39 | if len(res) > 0:
40 | print(res[0], res[1])
41 | else:
42 | print('Not found')
43 |
--------------------------------------------------------------------------------
/my_utils/from_hex.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2009-2010 Sergey Koposov
2 | # This file is part of astrolibpy
3 | #
4 | # astrolibpy is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # astrolibpy is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with astrolibpy. If not, see .
16 |
17 |
18 | import numpy, re
19 | def from_hex(arr, delim=':'):
20 | r=re.compile('\s*(\-?)(.+)%s(.+)%s(.+)'%(delim,delim))
21 | ret=[]
22 | for a in arr:
23 | m = r.search(a)
24 |
25 | sign = m.group(1)=='-'
26 | if sign:
27 | sign=-1
28 | else:
29 | sign=1
30 | i1 = int(m.group(2))
31 | i2 = int(m.group(3))
32 | i3 = float(m.group(4))
33 | val = sign*(int(i1)+int(i2)/60.+(float(i3))/3600.)
34 | ret.append(val)
35 | return numpy.array(ret)
36 |
37 |
--------------------------------------------------------------------------------
/my_utils/wav2RGB.py:
--------------------------------------------------------------------------------
1 | """
2 | code taken from here:
3 | http://codingmess.blogspot.com/2009/05/conversion-of-wavelength-in-nanometers.html
4 | """
5 |
6 | def wav2RGB(wavelength):
7 | """
8 | convert wavelength in angstrems to matplotlib color string
9 | """
10 | w = int(wavelength/10.) # convert to integer nanometers
11 |
12 | # colour
13 | if w >= 380 and w < 440:
14 | R = -(w - 440.) / (440. - 350.)
15 | G = 0.0
16 | B = 1.0
17 | elif w >= 440 and w < 490:
18 | R = 0.0
19 | G = (w - 440.) / (490. - 440.)
20 | B = 1.0
21 | elif w >= 490 and w < 510:
22 | R = 0.0
23 | G = 1.0
24 | B = -(w - 510.) / (510. - 490.)
25 | elif w >= 510 and w < 580:
26 | R = (w - 510.) / (580. - 510.)
27 | G = 1.0
28 | B = 0.0
29 | elif w >= 580 and w < 645:
30 | R = 1.0
31 | G = -(w - 645.) / (645. - 580.)
32 | B = 0.0
33 | elif w >= 645 and w <= 780:
34 | R = 1.0
35 | G = 0.0
36 | B = 0.0
37 | else:
38 | R = 0.0
39 | G = 0.0
40 | B = 0.0
41 |
42 | # intensity correction
43 | if w >= 380 and w < 420:
44 | SSS = 0.3 + 0.7*(w - 350) / (420 - 350)
45 | elif w >= 420 and w <= 700:
46 | SSS = 1.0
47 | elif w > 700 and w <= 780:
48 | SSS = 0.3 + 0.7*(780 - w) / (780 - 700)
49 | else:
50 | SSS = 0.0
51 | SSS *= 255
52 |
53 | val = (int(SSS*R), int(SSS*G), int(SSS*B))
54 | strval = "#%02x%02x%02x"%(val)
55 | return strval
56 |
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # astrolibpy
2 | ### This library contains a few astronomy routines that I wrote or I converted from IDL.
3 |
4 | Author (2008-2024) Sergey Koposov
5 |
6 | Email: skoposov __AT__ ed __DOT__ ac __DOT__ uk
7 |
8 | The tools that may be still interesting to other users are
9 | * idlsave.py -- module for saving/restoring sets of variables in a file
10 | * lasso_plot -- module for selecting points on the plot by drawing a contour
11 | * clicker -- module for extracting one or many clicks coordinates from matplotlib plot
12 | * crossmatcher -- module for x-matching a table by position with a table inside a Postgresql database
13 | * match_lists -- x-match lists by position on the sky using kd-tree
14 | * mpfit -- Levenberg-Marquardt fitter (converted from IDL)
15 | * idlplot/idlplotInd -- set of wrappers for plotting in IDL style where your command has all
16 | the options you want. Also allows efficient histogramming, subsetting etc
17 |
18 |
19 |
20 | The astrolib part of this repo is probably obsolete given the existance of astropy
21 |
22 | ### Installation
23 | This package does not need to be installed in the sense of 'pip install', so if you
24 | want to you use it, you can either copy a script that you want and add it to the current
25 | directory or clone the repo and add the path to PYTHONPATH
26 |
27 | ### License
28 | The licensing for the programs I wrote myself is GPL3. For all other
29 | programs (mainly converted from IDL) I guess the license is either BSD or
30 | they are in public domain.
31 |
--------------------------------------------------------------------------------
/astrolib/precess_xyz.py:
--------------------------------------------------------------------------------
1 | from numpy import sin, cos, arctan2, sqrt, arcsin
2 | from precess import precess
3 |
4 | def precess_xyz(x, y, z, equinox1, equinox2):
5 | #+
6 | # NAME:
7 | # PRECESS_XYZ
8 | #
9 | # PURPOSE:
10 | # Precess equatorial geocentric rectangular coordinates.
11 | #
12 | # CALLING SEQUENCE:
13 | # precess_xyz, x, y, z, equinox1, equinox2
14 | #
15 | # INPUT/OUTPUT:
16 | # x,y,z: scalars or vectors giving heliocentric rectangular coordinates
17 | # THESE ARE CHANGED UPON RETURNING.
18 | # INPUT:
19 | # EQUINOX1: equinox of input coordinates, numeric scalar
20 | # EQUINOX2: equinox of output coordinates, numeric scalar
21 | #
22 | # OUTPUT:
23 | # x,y,z are changed upon return
24 | #
25 | # NOTES:
26 | # The equatorial geocentric rectangular coords are converted
27 | # to RA and Dec, precessed in the normal way, then changed
28 | # back to x, y and z using unit vectors.
29 | #
30 | #EXAMPLE:
31 | # Precess 1950 equinox coords x, y and z to 2000.
32 | # IDL> precess_xyz,x,y,z, 1950, 2000
33 | #
34 | #HISTORY:
35 | # Written by P. Plait/ACC March 24 1999
36 | # (unit vectors provided by D. Lindler)
37 | # Use /Radian call to PRECESS W. Landsman November 2000
38 | # Use two parameter call to ATAN W. Landsman June 2001
39 | #-
40 | #check inputs
41 |
42 | #take input coords and convert to ra and dec (in radians)
43 |
44 | ra = arctan2(y, x)
45 | _del = sqrt(x * x + y * y + z * z) #magnitude of distance to Sun
46 | dec = arcsin(z / _del)
47 |
48 | # precess the ra and dec
49 | ra,dec = precess(ra, dec, equinox1, equinox2, radian=True)
50 |
51 | #convert back to x, y, z
52 | xunit = cos(ra) * cos(dec)
53 | yunit = sin(ra) * cos(dec)
54 | zunit = sin(dec)
55 |
56 | x = xunit * _del
57 | y = yunit * _del
58 | z = zunit * _del
59 |
60 | return x,y,z
61 |
62 |
63 |
--------------------------------------------------------------------------------
/utils/workerpool.py:
--------------------------------------------------------------------------------
1 | import multiprocessing as mp, numpy as np
2 | import signal
3 |
4 | def doit(func, queuein, queout, args, kw):
5 | signal.signal(signal.SIGINT, signal.SIG_IGN)
6 | while True:
7 | inp = queuein.get()
8 | if inp is None:
9 | break
10 | i, p = inp
11 | res = func(p, *args, **kw)
12 | queout.put((i, res))
13 |
14 | class pool:
15 | def __init__(self, func, args=None, kw={}, nthreads=1, mpmap=False):
16 | # create a processing pool that has the function that needs to
17 | # be called stored
18 | # that reduces the overhead of constantly pickling the function
19 | # mpmap=True flag enables the multiprocessing.Pool.map syntax of map
20 | # e.g. map(func, list)
21 | # the first argument is then ignored
22 | self.nthreads = nthreads
23 | self.queuein = mp.Queue()
24 | self.queueout = mp.Queue()
25 | self.mpmap = mpmap
26 | self.procs = [mp.Process(target=doit, name='xpool_%d'%i,
27 | args=(func, self.queuein, self.queueout, args, kw))
28 | for i in range(nthreads) ]
29 | [_.start() for _ in self.procs]
30 | self.stage = {}
31 |
32 | def apply_async(self, i, p):
33 | self.queuein.put((i, p))
34 |
35 | def get(self, i):
36 | if i in self.stage:
37 | ret = self.stage[i]
38 | del self.stage[i]
39 | return ret
40 | else:
41 | while True:
42 | iret, ret = self.queueout.get()
43 | if iret != i:
44 | self.stage[iret] = ret
45 | else:
46 | return ret
47 |
48 | def get_any(self):
49 | if len(self.stage) != 0:
50 | i, ret = self.stage.popitem()
51 | return i, ret
52 | else:
53 | iret, ret = self.queueout.get()
54 | return iret, ret
55 |
56 | def map(self, *args):
57 | if self.mpmap:
58 | params=args[1]
59 | else:
60 | params=args[0]
61 | for i, p in enumerate(params):
62 | self.queuein.put((i, p))
63 | ret = [None] * len(params)
64 | for i in range(len(params)):
65 | resi, res = self.queueout.get()
66 | ret[resi] = res
67 | return ret
68 |
69 | def __del__(self):
70 | self.join()
71 |
72 | def join(self):
73 | for p in self.procs:
74 | self.queuein.put(None)
75 | for p in self.procs:
76 | p.join()
77 | del self.queuein
78 | del self.queueout
79 |
--------------------------------------------------------------------------------
/my_utils/table_joiner.py:
--------------------------------------------------------------------------------
1 | import duckdb
2 | import numpy as np
3 | import pandas as pd
4 | import astropy.table as atpy
5 |
6 |
7 | def order_convert(x):
8 | if x.dtype.byteorder not in ('=', '|'):
9 | x = x.byteswap()
10 | return x.view(x.data.dtype.newbyteorder())
11 | return x
12 |
13 |
14 | def check_type(arr):
15 | # Check if the array is of string type
16 | if np.issubdtype(arr.dtype, np.str_):
17 | return 'string'
18 | if np.issubdtype(arr.dtype, np.bytes_):
19 | return 'string'
20 | elif np.issubdtype(arr.dtype, np.integer):
21 | return 'int'
22 | if np.issubdtype(arr.dtype, np.floating):
23 | return 'float'
24 | raise RuntimeError('unsupported type')
25 |
26 |
27 | def join_to_left(T1,
28 | T2,
29 | key=None,
30 | fill_value=None,
31 | key_left=None,
32 | key_right=None,
33 | fill_values={
34 | 'string': '',
35 | 'int': -9999,
36 | 'float': np.nan
37 | }):
38 | """
39 | Return Table 2 matched to T1 using key.
40 |
41 | In the case of multiple matches a random one is returned
42 |
43 | """
44 | rowid1 = np.arange(len(T1))
45 | assert ((key is not None)
46 | or (key_left is not None and key_right is not None))
47 | if key is not None:
48 | key_left, key_right = key, key
49 |
50 | df1 = pd.DataFrame({'rowid': rowid1, 'key': order_convert(T1[key_left])})
51 | rowid2 = np.arange(len(T2))
52 | df2 = pd.DataFrame({'rowid': rowid2, 'key': order_convert(T2[key_right])})
53 | duckdb.register("tab1", df1)
54 | duckdb.register("tab2", df2)
55 | R = duckdb.sql('''
56 | select distinct on (tab1.rowid) tab1.rowid as r1, tab2.rowid as r2
57 | from tab1, tab2 where
58 | tab1.key = tab2.key order by tab1.rowid''').fetchnumpy()
59 | xrowid1, xrowid2 = R['r1'], R['r2']
60 | ret = {}
61 | n1 = len(T1)
62 | for k in T2.columns:
63 | cura = T2[k][xrowid2]
64 | cur_fill = fill_values[check_type(cura)]
65 | cur_ret = np.zeros(n1, dtype=cura.dtype)
66 | cur_ret[:] = cur_fill
67 | cur_ret[xrowid1] = cura
68 | ret[k] = cur_ret
69 | return atpy.Table(ret)
70 |
--------------------------------------------------------------------------------
/astrolib/readcol.py:
--------------------------------------------------------------------------------
1 | import scipy.io
2 | import numpy
3 |
4 | def readcol(filename, delimiter=' ', format=None, skiprows=0, **kw):
5 | """ This routine reads the data from the ascii file
6 | a,b,c=readcol('dat.txt',delimiter='|')
7 | you can skip a certain number of rows in the top of the file by
8 | specifying skiprows=X option.
9 | The format option is needed if you have datatypes different from float in your table
10 | In that case format string should be comma delimted set of I (int) F(float) D (double)
11 | S (string) characters. E.g.
12 | a,b,c=readcol('dat.txt',format='I,S,D')
13 | """
14 | if format==None:
15 | res=numpy.loadtxt(filename, delimiter=delimiter, skiprows=skiprows, **kw)
16 | nrows = res.shape[0]
17 | if res.ndim==2:
18 | ncols = res.shape[1]
19 | elif res.ndim==1:
20 | ncols=1
21 | res.shape=(nrows,1)
22 | else:
23 | raise "Exception: wrong array dimensions"
24 |
25 | stor=[]
26 | for i in range(ncols):
27 | stor.append(res[:,i])
28 | return tuple(stor)
29 | else:
30 | types=[]
31 | i=0
32 | formats=format.split(',')
33 | convs={}
34 |
35 | retnull = lambda s: numpy.float(s or 0)
36 | for i, a in enumerate(formats):
37 | if a=='I':
38 | curtype=numpy.int32
39 | convs[i]=retnull
40 | elif a=='L':
41 | curtype=numpy.int64
42 | convs[i]=retnull
43 | elif a=='F':
44 | curtype=numpy.float32
45 | convs[i]=retnull
46 | elif a=='D':
47 | curtype=numpy.float64
48 | convs[i]=retnull
49 | elif a=='S':
50 | curtype="S100"#numpy.str
51 | else:
52 | raise Exception("Sorry, Unknown type in the format string\n The allowed types are S,I,F,D (string, int, float, double)")
53 | types.append(("a%d"%i,curtype))
54 |
55 | rec=numpy.loadtxt(filename,dtype=types, delimiter=delimiter,
56 | skiprows=skiprows,converters=convs)
57 | ncols=len(rec[0])
58 | nrows=len(rec)
59 |
60 | buf="("
61 | stor=[]
62 | for a in formats:
63 | if a=='I':
64 | tmp=numpy.zeros(nrows,dtype=numpy.int32)
65 | if a=='L':
66 | tmp=numpy.zeros(nrows,dtype=numpy.int64)
67 | elif a=='F':
68 | tmp=numpy.zeros(nrows,dtype=numpy.float32)
69 | elif a=='D':
70 | tmp=numpy.zeros(nrows,dtype=numpy.float64)
71 | elif a=='S':
72 | tmp=numpy.zeros(nrows,dtype="S100")
73 | stor.append(tmp)
74 |
75 | for i in range(ncols):
76 | for j in range(nrows):
77 | stor[i][j]=rec[j][i]
78 | return tuple(stor)
79 |
--------------------------------------------------------------------------------
/astrolib/daycnv.py:
--------------------------------------------------------------------------------
1 | from numpy import array
2 |
3 | def daycnv(xjd):
4 | """
5 | NAME:
6 | DAYCNV
7 | PURPOSE:
8 | Converts Julian dates to Gregorian calendar dates
9 |
10 | CALLING SEQUENCE:
11 | DAYCNV, XJD, YR, MN, DAY, HR
12 |
13 | INPUTS:
14 | XJD = Julian date, positive double precision scalar or vector
15 |
16 | OUTPUTS:
17 | YR = Year (Integer)
18 | MN = Month (Integer)
19 | DAY = Day (Integer)
20 | HR = Hours and fractional hours (Real). If XJD is a vector,
21 | then YR,MN,DAY and HR will be vectors of the same length.
22 |
23 | EXAMPLE:
24 | IDL> DAYCNV, 2440000.D, yr, mn, day, hr
25 |
26 | yields yr = 1968, mn =5, day = 23, hr =12.
27 |
28 | WARNING:
29 | Be sure that the Julian date is specified as double precision to
30 | maintain accuracy at the fractional hour level.
31 |
32 | METHOD:
33 | Uses the algorithm of Fliegel and Van Flandern (1968) as reported in
34 | the "Explanatory Supplement to the Astronomical Almanac" (1992), p. 604
35 | Works for all Gregorian calendar dates with XJD > 0, i.e., dates after
36 | -4713 November 23.
37 | REVISION HISTORY:
38 | Converted to IDL from Yeoman's Comet Ephemeris Generator,
39 | B. Pfarr, STX, 6/16/88
40 | Converted to IDL V5.0 W. Landsman September 1997
41 | """
42 |
43 | # Adjustment needed because Julian day starts at noon, calendar day at midnight
44 |
45 | jd = array(xjd).astype(int) #Truncate to integral day
46 | frac = array(xjd).astype(float) - jd + 0.5 #Fractional part of calendar day
47 | after_noon = (frac >= 1.0)
48 |
49 | if after_noon.any(): #Is it really the next calendar day?
50 | if frac.ndim>0: # proper array
51 | frac[after_noon] = frac[after_noon] - 1.0
52 | jd[after_noon] = jd[after_noon] + 1
53 | else: # scalar
54 | frac = frac - 1.0
55 | jd = jd + 1
56 | hr = frac * 24.0
57 | l = jd + 68569
58 | n = 4 * l / 146097
59 | l = l - (146097 * n + 3) / 4
60 | yr = 4000 * (l + 1) / 1461001
61 | l = l - 1461 * yr / 4 + 31 #1461 = 365.25 * 4
62 | mn = 80 * l / 2447
63 | day = l - 2447 * mn / 80
64 | l = mn / 11
65 | mn = mn + 2 - 12 * l
66 | yr = 100 * (n - 49) + yr + l
67 | return (yr, mn, day, hr)
--------------------------------------------------------------------------------
/my_utils/sphere_rotate.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import numexpr
3 |
4 |
5 | def torect(ra, dec):
6 | x = numexpr.evaluate(
7 | 'cos(ra/57.295779513082323)*cos(dec/57.295779513082323)')
8 | y = numexpr.evaluate(
9 | 'sin(ra/57.295779513082323)*cos(dec/57.295779513082323)')
10 | z = numexpr.evaluate('sin(dec/57.295779513082323)')
11 | return x, y, z
12 |
13 |
14 | def fromrect(x, y, z):
15 | ra = numexpr.evaluate('arctan2(y,x)*57.295779513082323')
16 | dec = numexpr.evaluate('57.295779513082323*arctan2(z,sqrt(x**2+y**2))')
17 | return ra, dec
18 |
19 |
20 | def rotation_matrix(rapol, decpol, ra0):
21 | """
22 | Return the rotation matrix corresponding to the pole of rapol, decpol
23 | and with zero of new latitude corresponding to ra=ra0
24 | This matrix need to be np.dot'ed with the input vector to get
25 | forward transform
26 | """
27 | tmppol = np.array(torect(rapol, decpol)) # pole axis
28 | tmpvec1 = np.array(torect(ra0, 0)) # x axis
29 | tmpvec1 = np.array(tmpvec1)
30 |
31 | tmpvec1[2] = (-tmppol[0] * tmpvec1[0] - tmppol[1] * tmpvec1[1]) / tmppol[2]
32 | tmpvec1 /= np.sqrt((tmpvec1**2).sum())
33 | tmpvec2 = np.cross(tmppol, tmpvec1) # y axis
34 | M = np.array([tmpvec1, tmpvec2, tmppol])
35 | return M
36 |
37 |
38 | def sphere_rotate(ra,
39 | dec,
40 | rapol=None,
41 | decpol=None,
42 | ra0=None,
43 | revert=False,
44 | mat=None):
45 | """ rotate ra,dec to a new spherical coordinate system where the pole is
46 | at rapol,decpol and the zeropoint is at ra=ra0
47 | revert flag allows to reverse the transformation
48 | """
49 |
50 | x, y, z = torect(ra, dec)
51 | if rapol is not None and decpol is not None and ra0 is not None:
52 | M = rotation_matrix(rapol, decpol, ra0)
53 | else:
54 | if mat is None:
55 | raise Exception('matrix or rapol,decpol, ra0'
56 | ' need to be provided')
57 | else:
58 | M = mat
59 |
60 | if not revert:
61 | Axx, Axy, Axz = M[0]
62 | Ayx, Ayy, Ayz = M[1]
63 | Azx, Azy, Azz = M[2]
64 | else:
65 | Axx, Ayx, Azx = M[0]
66 | Axy, Ayy, Azy = M[1]
67 | Axz, Ayz, Azz = M[2]
68 | xnew = numexpr.evaluate('x*Axx+y*Axy+z*Axz')
69 | ynew = numexpr.evaluate('x*Ayx+y*Ayy+z*Ayz')
70 | znew = numexpr.evaluate('x*Azx+y*Azy+z*Azz')
71 | del x, y, z
72 | tmp = fromrect(xnew, ynew, znew)
73 | return (tmp[0], tmp[1])
74 |
--------------------------------------------------------------------------------
/my_utils/rotate_pm.py:
--------------------------------------------------------------------------------
1 | import sphere_rotate
2 | import numpy as np
3 |
4 |
5 | def cosd(x):
6 | return np.cos(np.deg2rad(x))
7 |
8 |
9 | def sind(x):
10 | return np.sin(np.deg2rad(x))
11 |
12 |
13 | def rotate_pm(
14 | ra,
15 | dec,
16 | pmra,
17 | pmdec,
18 | rapol=None,
19 | decpol=None,
20 | ra0=None,
21 | revert=False,
22 | mat=None,
23 | ):
24 | """
25 | Rotate the proper motion to the sphere_rotate coord system
26 | that is specified by the pole direction and right ascencion of the (0,0) pt
27 | I assume all angles are in degrees and proper motions are in mas/yr
28 | Arguments:
29 | ra:
30 | dec:
31 | pmra:
32 | pmdec:
33 | rapol: float
34 | RA of the pole
35 | decpol float
36 | Dec of the pole
37 | ra0: float
38 | RA of the (0,0) point of the new coordinate system
39 | revert: bool
40 | if true do the inverse transformation. I.e. convert
41 | phi1,phi2,pmphii1,pmphi2
42 | to pmra,pmdec
43 | Returns:
44 | pmphi1, pmphi2 in the new coordinate system
45 | """
46 |
47 | ra, dec, pmra, pmdec = [
48 | np.asarray(np.atleast_1d(_)) for _ in [ra, dec, pmra, pmdec]
49 | ]
50 | if rapol is not None and decpol is not None and ra0 is not None:
51 | M = sphere_rotate.rotation_matrix(rapol, decpol, ra0)
52 | else:
53 | if mat is None:
54 | raise Exception(
55 | 'either rapol,decpol,ra0 or mat needs to be provided')
56 | M = mat
57 | if revert:
58 | M = M.T
59 | # unit vectors
60 | e_mura = np.array([-sind(ra), cosd(ra), ra * 0])
61 | e_mudec = np.array(
62 | [-sind(dec) * cosd(ra), -sind(dec) * sind(ra),
63 | cosd(dec)])
64 | # velocity vector in arbitrary units
65 | V = pmra * e_mura + pmdec * e_mudec
66 | del e_mura, e_mudec
67 | # apply rotation to velocity
68 | V1 = M @ V
69 | del V
70 | X = np.array([cosd(ra) * cosd(dec), sind(ra) * cosd(dec), sind(dec)])
71 | # apply rotation to position
72 | X1 = M @ X
73 | del X
74 | # rotated coordinates in radians
75 | lon = np.arctan2(X1[1, :], X1[0, :])
76 | lat = np.arctan2(X1[2, :], np.sqrt(X1[0, :]**2 + X1[1, :]**2))
77 | del X1
78 | # unit vectors in rotated coordinates
79 | e_mura = np.array([-np.sin(lon), np.cos(lon), lon * 0])
80 | e_mudec = np.array(
81 | [-np.sin(lat) * np.cos(lon), -np.sin(lat) * np.sin(lon),
82 | np.cos(lat)])
83 | del lon, lat
84 | return np.sum(e_mura * V1, axis=0), np.sum(e_mudec * V1, axis=0)
85 |
--------------------------------------------------------------------------------
/my_utils/staralt.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Copyright (C) 2014 Sergey Koposov koposov@ast.cam.ac.uk
3 | #
4 | # This file is part of astrolibpy
5 | #
6 | # astrolibpy is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | # astrolibpy is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with astrolibpy. If not, see .
17 |
18 | import ephem
19 | import numpy as np
20 | import sphdist
21 |
22 |
23 | def getalt(ra,
24 | dec,
25 | yr,
26 | mon,
27 | day,
28 | hr,
29 | minu,
30 | sec=0,
31 | lon='-111:35:59',
32 | lat='31:57:12',
33 | elev=2000,
34 | retSun=False,
35 | retDistMoon=False):
36 | """
37 | computes the altitude in degrees of a given object at the given utc time
38 | ra dec in degrees
39 | yr mon day hr minu in utc
40 | lon lat are in degrees and lon is positive to the East
41 | retSun means that you'll get height of the sun above the horizon
42 | retDistMoon means that you'll also get the distance to the moon
43 | """
44 |
45 | obs = ephem.Observer()
46 | obs.lon = lon # longitude
47 | obs.lat = lat # latitude
48 | obs.elevation = elev
49 | fb = ephem.FixedBody()
50 | fb._ra = np.deg2rad(ra)
51 | fb._dec = np.deg2rad(dec)
52 | obs.date = ephem.Date('%d/%02d/%d %d:%d:0' % (yr, mon, day, hr, minu))
53 | fb.compute(obs)
54 | alt = np.rad2deg(1 * fb.alt)
55 | az = np.rad2deg(1 * fb.az)
56 | if retSun:
57 | fbSun = ephem.Sun()
58 | fbSun.compute(obs)
59 | altSun = np.rad2deg(1 * (fbSun.alt))
60 | if retDistMoon:
61 | fbMoon = ephem.Moon()
62 | fbMoon.compute(obs)
63 | altMoon = np.rad2deg(1 * fbMoon.alt)
64 | azMoon = np.rad2deg(1 * fbMoon.az)
65 | distMoon = sphdist.sphdist(az, alt, azMoon, altMoon)
66 | if retSun or retDistMoon:
67 | ret = [alt]
68 | else:
69 | ret = alt
70 | if retSun:
71 | ret.append(altSun)
72 | if retDistMoon:
73 | ret.append(distMoon)
74 | return ret
75 |
--------------------------------------------------------------------------------
/mpfit/tests/test_mpfit.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from numpy.testing import *
3 | import numpy as N
4 | import copy
5 |
6 | from mpfit import mpfit
7 |
8 |
9 | def Flin(x,p):
10 | y = p[0] -p[1]*x
11 | return y
12 |
13 |
14 | def myfunctlin(p, fjac=None, x=None, y=None, err=None):
15 | # Parameter values are passed in "p"
16 | # If fjac==None then partial derivatives should not be
17 | # computed. It will always be None if MPFIT is called with default
18 | # flag.
19 | model = Flin(x, p)
20 | # Non-negative status value means MPFIT should continue, negative means
21 | # stop the calculation.
22 | status = 0
23 | return [status, (y-model)/err]
24 |
25 |
26 |
27 | def test_linfit():
28 | x=N.array([-1.7237128E+00,1.8712276E+00,-9.6608055E-01,
29 | -2.8394297E-01,1.3416969E+00,1.3757038E+00,
30 | -1.3703436E+00,4.2581975E-02,-1.4970151E-01,
31 | 8.2065094E-01])
32 | y=N.array([1.9000429E-01,6.5807428E+00,1.4582725E+00,
33 | 2.7270851E+00,5.5969253E+00,5.6249280E+00,
34 | 0.787615,3.2599759E+00,2.9771762E+00,
35 | 4.5936475E+00])
36 | ey=0.07*N.ones(y.shape,dtype='float64')
37 | p0=N.array([1.0,1.0],dtype='float64') #initial conditions
38 | pactual=N.array([3.2,1.78]) #actual values used to make data
39 | parbase={'value':0., 'fixed':0, 'limited':[0,0], 'limits':[0.,0.]}
40 | parinfo=[]
41 | for i in range(len(pactual)):
42 | parinfo.append(copy.deepcopy(parbase))
43 | for i in range(len(pactual)):
44 | parinfo[i]['value']=p0[i]
45 | fa = {'x':x, 'y':y, 'err':ey}
46 | m = mpfit(myfunctlin, p0, parinfo=parinfo,functkw=fa)
47 | if (m.status <= 0):
48 | print( 'error message = ', m.errmsg)
49 | assert N.allclose(m.params,N.array([ 3.20996572, -1.7709542 ],dtype='float64'))
50 | assert N.allclose(m.perror,N.array([ 0.02221018, 0.01893756],dtype='float64'))
51 | chisq=(myfunctlin(m.params, x=x, y=y, err=ey)[1]**2).sum()
52 |
53 | assert N.allclose(N.array([chisq],dtype='float64'),N.array([2.756284983],dtype='float64'))
54 | assert m.dof==8
55 | return
56 |
57 | def myfunctrosenbrock(p, fjac=None):
58 | # rosenbrock function
59 | res = N.array([1-p[0],-(1-p[0]),10*(p[1]-p[0]**2),-10*(p[1]-p[0]**2)])
60 | status = 0
61 | return [status, res]
62 |
63 |
64 |
65 | def test_rosenbrock():
66 | p0=N.array([-1,1.],dtype='float64') #initial conditions
67 | pactual=N.array([1.,1.]) #actual minimum of the rosenbrock function
68 | m = mpfit(myfunctrosenbrock, p0)
69 | if (m.status <= 0):
70 | print( 'error message = ', m.errmsg)
71 | assert m.status > 0
72 | assert N.allclose(m.params,pactual)
73 | assert N.allclose(m.fnorm,0)
74 | return
75 |
76 | if __name__ == "__main__":
77 | run_module_suite()
78 |
--------------------------------------------------------------------------------
/mpfit/mpfitexpr.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (C) 2009 Sergey Koposov
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | """
17 |
18 | import mpfit
19 | import re
20 | import numpy
21 | import scipy
22 |
23 | def mpfitexpr(func, x, y, err , start_params, check=True, full_output=False,
24 | imports=None, **kw):
25 | """Fit the used defined expression to the data
26 | Input:
27 | - func: string with the function definition
28 | - x: x vector
29 | - y: y vector
30 | - err: vector with the errors of y
31 | - start_params: the starting parameters for the fit
32 | Output:
33 | - The tuple (params, yfit) with best-fit params and the values of func evaluated at x
34 | Keywords:
35 | - check: boolean parameter. If true(default) the function will be checked for sanity
36 | - full_output: boolean parameter. If True(default is False) then instead of best-fit parameters the mpfit object is returned
37 | - imports: list of strings, of optional modules to be imported, required to evaluate the function
38 | Example:
39 | params,yfit=mpfitexpr('p[0]+p[2]*(x-p[1])',x,y,err,[0,10,1])
40 |
41 | If you need to use numpy and scipy functions in your function, then
42 | you must to use the full names of these functions, e.g.:
43 | numpy.sin, numpy.cos etc.
44 |
45 | This function is motivated by mpfitexpr() from wonderful MPFIT IDL package
46 | written by Craig Markwardt
47 |
48 | """
49 |
50 | hash={}
51 | hash['numpy']=numpy
52 | hash['scipy']=scipy
53 |
54 | if imports is not None:
55 | for i in imports:
56 | #exec '%s=__import__("%s")'%(a,b) in globals(),locals()
57 | hash[i]= __import__(i)
58 | def myfunc(p,fjac=None,x=None, y=None, err=None):
59 | return [0, eval('(y-(%s))/err'%func,hash,locals())]
60 |
61 | myre = "(?:[^a-zA-Z_]|^)p\[(\d+)\]"
62 | r = re.compile(myre)
63 | maxp = -1
64 | for m in re.finditer(r,func):
65 | curp = int(m.group(1))
66 | maxp = curp if curp > maxp else maxp
67 | if check:
68 | if maxp == -1:
69 | raise Exception("wrong function format")
70 | if maxp + 1 != len(start_params):
71 | raise Exception("the length of the start_params != the length of the parameter verctor of the function")
72 | fa={'x' : x, 'y' : y,'err' : err}
73 | res = mpfit.mpfit(myfunc,start_params,functkw=fa,**kw)
74 | yfit = eval(func, hash, {'x':x, 'p': res.params})
75 | if full_output:
76 | return (res, yfit)
77 | else:
78 | return (res.params, yfit)
79 |
--------------------------------------------------------------------------------
/astrolib/premat.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from numpy import array, sin, cos, zeros, pi, zeros
3 |
4 | def premat(equinox1, equinox2, fk4=False):
5 | """
6 | NAME:
7 | PREMAT
8 | PURPOSE:
9 | Return the precession matrix needed to go from EQUINOX1 to EQUINOX2.
10 | EXPLANTION:
11 | This matrix is used by the procedures PRECESS and BARYVEL to precess
12 | astronomical coordinates
13 |
14 | CALLING SEQUENCE:
15 | matrix = PREMAT( equinox1, equinox2, [ /FK4 ] )
16 |
17 | INPUTS:
18 | EQUINOX1 - Original equinox of coordinates, numeric scalar.
19 | EQUINOX2 - Equinox of precessed coordinates.
20 |
21 | OUTPUT:
22 | matrix - double precision 3 x 3 precession matrix, used to precess
23 | equatorial rectangular coordinates
24 |
25 | OPTIONAL INPUT KEYWORDS:
26 | /FK4 - If this keyword is set, the FK4 (B1950.0) system precession
27 | angles are used to compute the precession matrix. The
28 | default is to use FK5 (J2000.0) precession angles
29 |
30 | EXAMPLES:
31 | Return the precession matrix from 1950.0 to 1975.0 in the FK4 system
32 |
33 | IDL> matrix = PREMAT( 1950.0, 1975.0, /FK4)
34 |
35 | PROCEDURE:
36 | FK4 constants from "Computational Spherical Astronomy" by Taff (1983),
37 | p. 24. (FK4). FK5 constants from "Astronomical Almanac Explanatory
38 | Supplement 1992, page 104 Table 3.211.1.
39 |
40 | REVISION HISTORY
41 | Written, Wayne Landsman, HSTX Corporation, June 1994
42 | Converted to IDL V5.0 W. Landsman September 1997
43 | """
44 |
45 | deg_to_rad = pi / 180.0e0
46 | sec_to_rad = deg_to_rad / 3600.e0
47 |
48 | t = 0.001e0 * (equinox2 - equinox1)
49 |
50 | if not fk4:
51 | st = 0.001e0 * (equinox1 - 2000.e0)
52 | # Compute 3 rotation angles
53 | a = sec_to_rad * t * (23062.181e0 + st * (139.656e0 + 0.0139e0 * st) + t * (30.188e0 - 0.344e0 * st + 17.998e0 * t))
54 |
55 | b = sec_to_rad * t * t * (79.280e0 + 0.410e0 * st + 0.205e0 * t) + a
56 |
57 | c = sec_to_rad * t * (20043.109e0 - st * (85.33e0 + 0.217e0 * st) + t * (-42.665e0 - 0.217e0 * st - 41.833e0 * t))
58 |
59 | else:
60 |
61 | st = 0.001e0 * (equinox1 - 1900.e0)
62 | # Compute 3 rotation angles
63 |
64 | a = sec_to_rad * t * (23042.53e0 + st * (139.75e0 + 0.06e0 * st) + t * (30.23e0 - 0.27e0 * st + 18.0e0 * t))
65 |
66 | b = sec_to_rad * t * t * (79.27e0 + 0.66e0 * st + 0.32e0 * t) + a
67 |
68 | c = sec_to_rad * t * (20046.85e0 - st * (85.33e0 + 0.37e0 * st) + t * (-42.67e0 - 0.37e0 * st - 41.8e0 * t))
69 |
70 |
71 | sina = sin(a)
72 | sinb = sin(b)
73 | sinc = sin(c)
74 | cosa = cos(a)
75 | cosb = cos(b)
76 | cosc = cos(c)
77 |
78 | r = zeros((3, 3))
79 | r[0,:] = array([cosa * cosb * cosc - sina * sinb, sina * cosb + cosa * sinb * cosc, cosa * sinc])
80 | r[1,:] = array([-cosa * sinb - sina * cosb * cosc, cosa * cosb - sina * sinb * cosc, -sina * sinc])
81 | r[2,:] = array([-cosb * sinc, -sinb * sinc, cosc])
82 |
83 | return r
84 |
85 |
--------------------------------------------------------------------------------
/my_utils/match_lists.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2009-2010 Sergey Koposov
2 | # This file is part of astrolibpy
3 | #
4 | # astrolibpy is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # astrolibpy is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with astrolibpy. If not, see .
16 |
17 | import scipy.spatial.kdtree
18 | import numpy as np
19 | from scipy import version
20 | from numpy import sin, cos, deg2rad, rad2deg, arcsin
21 |
22 | scipy_version = ('.'.join(version.version.split('.')[0:2])).split('.')[0:2]
23 |
24 |
25 | def cosd(x):
26 | return cos(deg2rad(x))
27 |
28 |
29 | def sind(x):
30 | return sin(deg2rad(x))
31 |
32 |
33 | def getxyz(r, d):
34 | return [cosd(r) * cosd(d), sind(r) * cosd(d), sind(d)]
35 |
36 |
37 | def get_indices(D, ind):
38 | """ Return the indices of points that match
39 | The input is the distances and index array returned by match_lists
40 | I.e.
41 | > D,ind=match_lists.match_lists([1,1], [2,3], [1.1,1.2,6,],
42 | [2.1,2.2,10], 0.3)
43 | > print (match_lists.get_indices(D,ind))
44 | """
45 | x1 = np.isfinite(D)
46 | x2 = ind[x1]
47 | return np.nonzero(x1)[0], x2
48 |
49 |
50 | def match_lists(ra1, dec1, ra2, dec2, dist, numNei=1):
51 | """crossmatches the list of objects (ra1,dec1) with
52 | another list of objects (ra2,dec2) with the matching radius "dist"
53 | The routines searches for up to numNei closest neighbors
54 | the routine returns the distance to the neighbor and the list
55 | of indices of the neighbor. Everything is in degrees.
56 | if no match is found the distance is NaN.
57 | Example:
58 | > dist, ind = match_lists(ra1,dec1,ra2,dec2, 1./3600)
59 | > goodmatch_ind = numpy.isfinite(dist)
60 | > plot(ra1[goodmatch_ind],ra2[ind[goodmatch_ind]])
61 | Another example:
62 | > print match_lists( [1,1], [2,3], [1.1,1.2,6,],
63 | [2.1,2.2,10], 0.3, numNei=2)
64 | (array([[ 0.1413761 , 0.28274768],
65 | [ inf, inf]]),
66 | array([[0, 1],
67 | [3, 3]]))
68 | """
69 | mindist = 2 * sind(dist / 2.)
70 | xyz1 = np.array(getxyz(ra1, dec1))
71 | xyz2 = np.array(getxyz(ra2, dec2))
72 |
73 | if (int(scipy_version[0]) == 0) and (int(scipy_version[1]) < 8):
74 | # If old scipy version is detected then we use KDTree instead of
75 | # cKDTtree because there is a bug in the cKDTree
76 | # http://projects.scipy.org/scipy/ticket/1178
77 | tree2 = scipy.spatial.KDTree(xyz2.T)
78 | else:
79 | tree2 = scipy.spatial.cKDTree(xyz2.T)
80 | del xyz2
81 | ret = tree2.query(xyz1.T, numNei, 0, 2, mindist)
82 | del xyz1
83 | dist, ind = ret
84 | finite = np.isfinite(dist)
85 | dist[finite] = rad2deg(2 * arcsin(dist[finite] / 2))
86 | return dist, ind
87 |
--------------------------------------------------------------------------------
/astrolib/zang.py:
--------------------------------------------------------------------------------
1 | from numpy import pi
2 | from lumdist import lumdist
3 |
4 | def zang(dl, z, h0=None, k=None, lambda0=None, omega_m=None, q0=None,
5 | silent=None):
6 | """
7 | NAME:
8 | ZANG
9 | PURPOSE:
10 | Determine the angular size of an object as a function of redshift
11 | EXPLANATION:
12 | Requires an input size in kpc and returns an angular size in arc seconds
13 | Default cosmology has a Hubble constant of 70 km/s/Mpc, Omega (matter)
14 | =0.3 and a normalized cosmological constant Lambda = 0.7; however these
15 | values can be changed with appropriate keywords.
16 |
17 | CALLING SEQUENCE:
18 | angsiz = zang( dl, [ z, H0 =, Omega_m =, Lambda0 = , q0 = , k =,
19 | /SILENT] )
20 |
21 | INPUTS:
22 | dl - linear size of the object *in kpc*, non-negative scalar or vector
23 | z - redshift of object, postive scalar or vector
24 | Either dl and z must have the same number of elements, or at least
25 | one of them must be a vector.
26 | OPTIONAL INPUT KEYWORDS
27 | H0 - Hubble constant in km/s/Mpc, default is 70
28 |
29 | No more than two of the following four parameters should be
30 | specified. None of them need be specified, default values are given
31 | k - curvature constant, normalized to the closure density. Default is
32 | 0, indicating a flat universe
33 | Omega_m - Matter density, normalized to the closure density, default
34 | is 0.3. Must be non-negative
35 | Lambda0 - Cosmological constant, normalized to the closure density,
36 | default is 0.7
37 | q0 - Deceleration parameter, numeric scalar = -R*(R'')/(R')^2, default
38 | is -0.55
39 |
40 | Note that Omega_m + lambda0 + k = 1 and q0 = 0.5*omega_m - lambda0
41 | OUTPUT:
42 | angsiz - Angular size of the object at the given redshift in
43 | arc seconds
44 | EXAMPLE:
45 | (1) What would be the angular size of galaxy of diameter 50 kpc at a redshift
46 | of 1.5 in an open universe with Lambda = 0 and Omega (matter) = 0.3.
47 | Assume the default Hubble constant value of 70 km/s/Mpc.
48 |
49 | IDL> print,zang(50,1.5, Lambda = 0,omega_m = 0.3)
50 | ====> 6.58 arc seconds
51 |
52 | (2) Now plot the angular size of a 50 kpc diameter galaxy as a function of
53 | redshift for the default cosmology (Lambda = 0.7, Omega_m=0.3) up to
54 | z = 0.5
55 | IDL> z = findgen(50)/10. + 0.1 ;Angular size undefined at z = 0
56 | IDL> plot,z,zang(50,z),xtit='z',ytit='Angular Size (")'
57 | NOTES:
58 | This procedure underwent a major revision in April 2000 to allow for a
59 | cosmological constant, ***including a change of the calling sequence***
60 |
61 | Be sure to supply the input linear size dl in units of kpc.
62 | PROCEDURES CALLED:
63 | LUMDIST() -- Calculates the luminosity distance
64 | REVISION HISTORY:
65 | Written J. Hill STX July, 1988
66 | Converted to IDL V5.0 W. Landsman September 1997
67 | Major rewrite to call LUMDIST function W. Landsman April 2000
68 | Convert to python S. Koposov 2010
69 | """
70 | _radeg = 180.0 / pi
71 | d = lumdist(z, h0=h0, k=k, lambda0=lambda0, omega_m=omega_m, q0=q0,
72 | silent=silent)
73 |
74 | # Angular distance is equal to the luminosity distance times (1+z)^2
75 | return _radeg * 3600. * dl * (1. + z) ** 2 / (1000. * d)
76 |
77 |
--------------------------------------------------------------------------------
/plotting/idlplotInd.py:
--------------------------------------------------------------------------------
1 | from collections.abc import Iterable
2 | import idlplot
3 | import matplotlib.pyplot as plt
4 | import numpy as np
5 | """
6 | This module is a set wrappers around idlplot designed to make
7 | the plots of subsets of the data: e.g.
8 | plot(x,y,ind=ind)
9 | instead of plot(x[ind],y[ind])
10 |
11 | """
12 |
13 |
14 | def tvhist2d(a, b, *args, **kw):
15 | ind = kw.get('ind')
16 |
17 | if ind is None:
18 | return idlplot.tvhist2d(a, b, *args, **kw)
19 | else:
20 | weights = kw.get('weights')
21 | if weights is not None:
22 | kw['weights'] = kw['weights'][ind]
23 | del kw['ind']
24 | return idlplot.tvhist2d(a[ind], b[ind], *args, **kw)
25 |
26 |
27 | def plothist(a, *args, **kw):
28 | ind = kw.get('ind')
29 |
30 | if ind is None:
31 | ret = idlplot.plothist(a, *args, **kw)
32 | else:
33 | weights = kw.get('weights')
34 | if weights is not None:
35 | if not np.isscalar(kw['weights']):
36 | kw['weights'] = kw['weights'][ind]
37 | del kw['ind']
38 | ret = idlplot.plothist(a[ind], *args, **kw)
39 | return ret
40 |
41 |
42 | def plot(a, b=None, **kw):
43 | ind = kw.get('ind')
44 |
45 | if ind is None:
46 | idlplot.plot(a, b, **kw)
47 | else:
48 | del kw['ind']
49 | if b is not None:
50 | idlplot.plot(a[ind], b[ind], **kw)
51 | else:
52 | idlplot.plot(a[ind], None, **kw)
53 |
54 |
55 | def plot_scatter(a, b, s=None, c=None, **kw):
56 | ind = kw.get('ind')
57 |
58 | if ind is None:
59 | idlplot.plot_scatter(a, b, s=s, c=c, **kw)
60 | else:
61 | del kw['ind']
62 | if c is not None and isinstance(c, Iterable):
63 | c = c[ind]
64 | if s is not None and isinstance(s, Iterable):
65 | s = s[ind]
66 | idlplot.plot_scatter(a[ind], b[ind], s=s, c=c, **kw)
67 |
68 |
69 | def oplot(a, b=None, **kw):
70 | ind = kw.get('ind')
71 |
72 | if ind is None:
73 | idlplot.oplot(a, b, **kw)
74 | else:
75 | del kw['ind']
76 | if b is not None:
77 | idlplot.oplot(a[ind], b[ind], **kw)
78 | else:
79 | idlplot.oplot(a[ind], **kw)
80 |
81 |
82 | def errorfixer(var, ind):
83 | var = np.asarray(var)
84 | if var.ndim == 2 and var.shape[0] == 2:
85 | var1 = [var[0][ind], var[1][ind]]
86 | else:
87 | var1 = var[ind]
88 | return var1
89 |
90 |
91 | def ploterror(a, b, c, *args, **kw):
92 | ind = kw.get('ind')
93 |
94 | if ind is None:
95 | idlplot.ploterror(a, b, c, *args, **kw)
96 | else:
97 | del kw['ind']
98 | ll = len(args)
99 | args1 = [None] * ll
100 | c1 = errorfixer(c, ind)
101 |
102 | for i in range(ll):
103 | args1[i] = errorfixer(args[i], ind)
104 | idlplot.ploterror(a[ind], b[ind], c1, *args1, **kw)
105 |
106 |
107 | def scatter(a, b, c=None, s=None, *args, **kw):
108 | ind = kw.get('ind')
109 | if ind is None:
110 | plt.scatter(a, b, c=c, s=s, *args, **kw)
111 | else:
112 | del kw['ind']
113 | if c is not None:
114 | c = c[ind]
115 | if s is not None:
116 | s = s[ind]
117 | plt.scatter(a[ind], b[ind], c=c, s=s, *args, **kw)
118 |
119 |
120 | tvhist2d.__doc__ = idlplot.tvhist2d.__doc__
121 | plot.__doc__ = idlplot.plot.__doc__
122 | plot_scatter.__doc__ = idlplot.plot_scatter.__doc__
123 | oplot.__doc__ = idlplot.oplot.__doc__
124 | ploterror.__doc__ = idlplot.ploterror.__doc__
125 | plothist.__doc__ = idlplot.plothist.__doc__
126 |
--------------------------------------------------------------------------------
/astrolib/convolve.py:
--------------------------------------------------------------------------------
1 | from numpy import *
2 | from numpy.fft import fft2, ifft2
3 |
4 | def convolve(image, psf, ft_psf=None, ft_image=None, no_ft=None, correlate=None, auto_correlation=None):
5 | """
6 | NAME:
7 | CONVOLVE
8 | PURPOSE:
9 | Convolution of an image with a Point Spread Function (PSF)
10 | EXPLANATION:
11 | The default is to compute the convolution using a product of
12 | Fourier transforms (for speed).
13 |
14 | CALLING SEQUENCE:
15 |
16 | imconv = convolve( image1, psf, FT_PSF = psf_FT )
17 | or:
18 | correl = convolve( image1, image2, /CORREL )
19 | or:
20 | correl = convolve( image, /AUTO )
21 |
22 | INPUTS:
23 | image = 2-D array (matrix) to be convolved with psf
24 | psf = the Point Spread Function, (size < or = to size of image).
25 |
26 | OPTIONAL INPUT KEYWORDS:
27 |
28 | FT_PSF = passes out/in the Fourier transform of the PSF,
29 | (so that it can be re-used the next time function is called).
30 | FT_IMAGE = passes out/in the Fourier transform of image.
31 |
32 | /CORRELATE uses the conjugate of the Fourier transform of PSF,
33 | to compute the cross-correlation of image and PSF,
34 | (equivalent to IDL function convol() with NO rotation of PSF)
35 |
36 | /AUTO_CORR computes the auto-correlation function of image using FFT.
37 |
38 | /NO_FT overrides the use of FFT, using IDL function convol() instead.
39 | (then PSF is rotated by 180 degrees to give same result)
40 | METHOD:
41 | When using FFT, PSF is centered & expanded to size of image.
42 | HISTORY:
43 | written, Frank Varosi, NASA/GSFC 1992.
44 | Appropriate precision type for result depending on input image
45 | Markus Hundertmark February 2006
46 | Fix the bug causing the recomputation of FFT(psf) and/or FFT(image)
47 | Sergey Koposov December 2006
48 | """
49 |
50 | n_params = 2
51 | psf_ft = ft_psf
52 | imft = ft_image
53 | noft = no_ft
54 | auto = auto_correlation
55 |
56 | sp = array(shape(psf_ft))
57 | sif = array(shape(imft))
58 | sim = array(shape(image))
59 | sc = sim / 2
60 | npix = array(image, copy=0).size
61 |
62 | if image.ndim!=2 or noft!=None:
63 | if (auto is not None):
64 | message("auto-correlation only for images with FFT", inf=True)
65 | return image
66 | else:
67 | if (correlate is not None):
68 | return convol(image, psf)
69 | else:
70 | return convol(image, rotate(psf, 2))
71 |
72 | if imft==None or (imft.ndim!=2) or imft.shape!=im.shape: #add the type check
73 | imft = ifft2(image)
74 |
75 | if (auto is not None):
76 | return roll(roll(npix * real(fft2(imft * conjugate(imft))), sc[0], 0),sc[1],1)
77 |
78 | if (ft_psf==None or ft_psf.ndim!=2 or ft_psf.shape!=image.shape or
79 | ft_psf.dtype!=image.dtype):
80 | sp = array(shape(psf))
81 |
82 | loc = maximum((sc - sp / 2), 0) #center PSF in new array,
83 | s = maximum((sp / 2 - sc), 0) #handle all cases: smaller or bigger
84 | l = minimum((s + sim - 1), (sp - 1))
85 | psf_ft = conjugate(image) * 0 #initialise with correct size+type according
86 | #to logic of conj and set values to 0 (type of ft_psf is conserved)
87 | psf_ft[loc[1]:loc[1]+l[1]-s[1]+1,loc[0]:loc[0]+l[0]-s[0]+1] = \
88 | psf[s[1]:(l[1])+1,s[0]:(l[0])+1]
89 | psf_ft = ifft2(psf_ft)
90 |
91 | if (correlate is not None):
92 | conv = npix * real(fft2(imft * conjugate(psf_ft)))
93 | else:
94 | conv = npix * real(fft2(imft * psf_ft))
95 |
96 | sc = sc + (sim % 2) #shift correction for odd size images.
97 |
98 | return roll(roll(conv, sc[0],0), sc[1],1)
99 |
100 |
--------------------------------------------------------------------------------
/astrolib/cosmo_param.py:
--------------------------------------------------------------------------------
1 | def cosmo_param(omega_m=None, omega_lambda=None, omega_k=None, q0=None):
2 | """
3 | NAME:
4 | COSMO_PARAM
5 | PURPOSE:
6 | Derive full set of cosmological density parameters from a partial set
7 | EXPLANATION:
8 | This procedure is called by LUMDIST and GALAGE to allow the user a choice
9 | in defining any two of four cosmological density parameters.
10 |
11 | Given any two of the four input parameters -- (1) the normalized matter
12 | density Omega_m (2) the normalized cosmological constant, Omega_lambda
13 | (3) the normalized curvature term, Omega_k and (4) the deceleration
14 | parameter q0 -- this program will derive the remaining two. Here
15 | "normalized" means divided by the closure density so that
16 | Omega_m + Omega_lambda + Omega_k = 1. For a more
17 | precise definition see Carroll, Press, & Turner (1992, ArAA, 30, 499).
18 |
19 | If less than two parameters are defined, this procedure sets default
20 | values of Omega_k=0 (flat space), Omega_lambda = 0.7, Omega_m = 0.3
21 | and q0 = -0.55
22 | CALLING SEQUENCE:
23 | COSMO_PARAM, Omega_m, Omega_lambda, Omega_k, q0
24 |
25 | INPUT-OUTPUTS:
26 | Omega_M - normalized matter energy density, non-negative numeric scalar
27 | Omega_Lambda - Normalized cosmological constant, numeric scalar
28 | Omega_k - normalized curvature parameter, numeric scalar. This is zero
29 | for a flat universe
30 | q0 - Deceleration parameter, numeric scalar = -R*(R'')/(R')^2
31 | = 0.5*Omega_m - Omega_lambda
32 | NOTES:
33 | If more than two parameters are defined upon input (overspecification),
34 | then the first two defined parameters in the ordered list Omega_m,
35 | Omega_lambda, Omega_k, q0 are used to define the cosmology.
36 | EXAMPLE:
37 | Suppose one has Omega_m = 0.3, and Omega_k = 0.5 then to determine
38 | Omega_lambda and q0
39 |
40 | IDL> cosmo_param, 0.3, omega_lambda, 0.5, q0
41 |
42 | which will return omega_lambda = 0.2 and q0 = -2.45
43 | REVISION HISTORY:
44 | W. Landsman Raytheon ITSS April 2000
45 | """
46 |
47 | nk = omega_k is not None
48 | nlambda = omega_lambda is not None
49 | nomega = omega_m is not None
50 | nq0 = q0 is not None
51 | # Check which two parameters are defined, and then determine the other two
52 |
53 | if nomega and nlambda:
54 | if not nk:
55 | omega_k = 1 - omega_m - omega_lambda
56 | if not nq0:
57 | q0 = omega_m / 2. - omega_lambda
58 |
59 | if nomega and nk:
60 | if not nlambda:
61 | omega_lambda = 1. - omega_m - omega_k
62 | if not nq0:
63 | q0 = -1 + omega_k + 3 * omega_m / 2
64 |
65 | if nlambda and nk:
66 | if not nomega:
67 | omega_m = 1. - omega_lambda - omega_k
68 | if not nq0:
69 | q0 = (1 - omega_k - 3. * omega_lambda) / 2.
70 |
71 | if nomega and nq0:
72 | if not nk:
73 | omega_k = 1 + q0 - 3 * omega_m / 2.
74 | if not nlambda:
75 | omega_lambda = 1. - omega_m - omega_k
76 |
77 | if nlambda and nq0:
78 | if not nk:
79 | omega_k = 1 - 2 * q0 - 3 * omega_lambda
80 | if not nomega:
81 | omega_m = 1. - omega_lambda - omega_k
82 |
83 | if nk and nq0:
84 | if not nomega:
85 | omega_m = (1 + q0 - omega_k) * 2 / 3.
86 | if not nlambda:
87 | omega_lambda = 1. - omega_m - omega_k
88 |
89 | #Set default values
90 | if omega_k is None:
91 | omega_k = 0 #Default is flat space
92 | if omega_lambda is None:
93 | omega_lambda = 0.7
94 | if omega_m is None:
95 | omega_m = 1 - omega_lambda
96 | if q0 is None:
97 | q0 = (1 - omega_k - 3 * omega_lambda) / 2.
98 |
99 | return omega_m, omega_lambda, omega_k, q0
100 |
101 |
--------------------------------------------------------------------------------
/astrolib/helio_jd.py:
--------------------------------------------------------------------------------
1 | from numpy import array, cos, sin, tan, pi, poly1d, deg2rad
2 | from xyz import xyz
3 | from bprecess import bprecess
4 |
5 | def helio_jd(date, ra, dec, b1950=False, time_diff=False):
6 | """
7 | NAME:
8 | HELIO_JD
9 | PURPOSE:
10 | Convert geocentric (reduced) Julian date to heliocentric Julian date
11 | EXPLANATION:
12 | This procedure correct for the extra light travel time between the Earth
13 | and the Sun.
14 |
15 | An online calculator for this quantity is available at
16 | http://www.physics.sfasu.edu/astro/javascript/hjd.html
17 | CALLING SEQUENCE:
18 | jdhelio = HELIO_JD( date, ra, dec, /B1950, /TIME_DIFF)
19 |
20 | INPUTS
21 | date - reduced Julian date (= JD - 2400000), scalar or vector, MUST
22 | be double precision
23 | ra,dec - scalars giving right ascension and declination in DEGREES
24 | Equinox is J2000 unless the /B1950 keyword is set
25 |
26 | OUTPUTS:
27 | jdhelio - heliocentric reduced Julian date. If /TIME_DIFF is set, then
28 | HELIO_JD() instead returns the time difference in seconds
29 | between the geocentric and heliocentric Julian date.
30 |
31 | OPTIONAL INPUT KEYWORDS
32 | /B1950 - if set, then input coordinates are assumed to be in equinox
33 | B1950 coordinates.
34 | /TIME_DIFF - if set, then HELIO_JD() returns the time difference
35 | (heliocentric JD - geocentric JD ) in seconds
36 |
37 | EXAMPLE:
38 | What is the heliocentric Julian date of an observation of V402 Cygni
39 | (J2000: RA = 20 9 7.8, Dec = 37 09 07) taken June 15, 1973 at 11:40 UT?
40 |
41 | IDL> juldate, [1973,6,15,11,40], jd ;Get geocentric Julian date
42 | IDL> hjd = helio_jd( jd, ten(20,9,7.8)*15., ten(37,9,7) )
43 |
44 | ==> hjd = 41848.9881
45 |
46 | Wayne Warren (Raytheon ITSS) has compared the results of HELIO_JD with the
47 | FORTRAN subroutines in the STARLINK SLALIB library (see
48 | http://star-www.rl.ac.uk/).
49 | Time Diff (sec)
50 | Date RA(2000) Dec(2000) STARLINK IDL
51 |
52 | 1999-10-29T00:00:00.0 21 08 25. -67 22 00. -59.0 -59.0
53 | 1999-10-29T00:00:00.0 02 56 33.4 +00 26 55. 474.1 474.1
54 | 1940-12-11T06:55:00.0 07 34 41.9 -00 30 42. 366.3 370.2
55 | 1992-02-29T03:15:56.2 12 56 27.4 +42 10 17. 350.8 350.9
56 | 2000-03-01T10:26:31.8 14 28 36.7 -20 42 11. 243.7 243.7
57 | 2100-02-26T09:18:24.2 08 26 51.7 +85 47 28. 104.0 108.8
58 | PROCEDURES CALLED:
59 | bprecess, xyz
60 |
61 | REVISION HISTORY:
62 | Algorithm from the book Astronomical Photometry by Henden, p. 114
63 | Written, W. Landsman STX June, 1989
64 | Make J2000 default equinox, add B1950, /TIME_DIFF keywords, compute
65 | variation of the obliquity W. Landsman November 1999
66 | Converted to python Sergey Koposov July 2010
67 | """
68 |
69 | #Because XYZ uses default B1950 coordinates, we'll convert everything to B1950
70 |
71 | if not b1950:
72 | ra1, dec1 = bprecess(ra, dec)
73 | else:
74 | ra1 = ra
75 | dec1 = dec
76 |
77 |
78 | delta_t = (array(date).astype(float) - 33282.42345905e0) / 36525.0e0
79 | epsilon_sec = poly1d([44.836e0, -46.8495, -0.00429, 0.00181][::-1])(delta_t)
80 | epsilon = deg2rad(23.433333e0 + epsilon_sec / 3600.0e0)
81 | ra1 = deg2rad(ra1)
82 | dec1 = deg2rad(dec1)
83 |
84 | x, y, z, tmp, tmp, tmp = xyz(date)
85 |
86 | #Find extra distance light must travel in AU, multiply by 1.49598e13 cm/AU,
87 | #and divide by the speed of light, and multiply by 86400 second/year
88 |
89 | time = -499.00522e0 * (cos(dec1) * cos(ra1) * x + (tan(epsilon) * sin(dec1) + cos(dec1) * sin(ra1)) * y)
90 | if time_diff:
91 | return time
92 | else:
93 | return array(date).astype(float) + time / 86400.0e0
94 |
95 |
96 |
--------------------------------------------------------------------------------
/plotting/lasso_plot.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2010-2019 Sergey Koposov
2 | # This file is part of astrolibpy
3 | #
4 | # astrolibpy is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # astrolibpy is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with astrolibpy. If not, see .
16 |
17 | from __future__ import print_function
18 | from matplotlib.widgets import Lasso
19 | import matplotlib.path as mplpa
20 | from matplotlib.pyplot import gca
21 | import numpy as np
22 | import quick_hist
23 |
24 | class lasso_plot:
25 | """ The class is designed to select the datapoints by drawing the region
26 | around them.
27 | Example:
28 | plt.plot(xs, ys) # first plot the data
29 | las = lasso_plot.lasso_plot(xs,ys)
30 | Now click on the plot and do not release the mouse button till
31 | you draw your region
32 | After that the variable las.mask will contain the boolean mask of the
33 | points inside the region and las.verts will contain the vertices of the
34 | polygon you've just drawn
35 | The option bins is helpful when the dataset is very large. Then
36 | the data is binned first before checking whether it is inside the
37 | contour
38 | plt.plot(xs, ys)
39 | las = lasso_plot.lasso_plot(xs,ys,bins=200)
40 | """
41 |
42 | def __init__(self, xs, ys, bins=None):
43 | self.axes = gca()
44 | self.canvas = self.axes.figure.canvas
45 | self.xys = (np.asarray(xs), np.asarray(ys))
46 | self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
47 | self.mask = None
48 | self.verts = None
49 | self.bins = bins
50 |
51 | def __getstate__(self):
52 | """ Custom pickle method to get rid of canvas/axes/lasso objects"""
53 | state = self.__dict__.copy()
54 | del state['canvas']
55 | del state['axes']
56 | del state['lasso']
57 | return state
58 |
59 | def callback(self, verts):
60 | self.verts = np.array(verts)
61 | mask = self.inside(self.xys[0], self.xys[1], self.bins)
62 | self.mask = mask
63 | self.canvas.draw_idle()
64 | self.canvas.widgetlock.release(self.lasso)
65 | self.canvas.mpl_disconnect(self.cid)
66 | del self.xys
67 |
68 | def inside(self, xs, ys, bins=None):
69 | """ Check if points xs,ys are inside the hand-selected mask """
70 | return inside(xs, ys, self.verts, bins)
71 |
72 | def onpress(self, event):
73 | if self.canvas.widgetlock.locked():
74 | return
75 | if event.inaxes is None:
76 | return
77 | self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata),
78 | self.callback)
79 | # acquire a lock on the widget drawing
80 | self.canvas.widgetlock(self.lasso)
81 |
82 |
83 | def inside(xs, ys, verts, bins=None):
84 | """ Check if points xs,ys are inside a mask specified by an array
85 | of vertices Nx2"""
86 | xys = np.array([xs, ys]).T
87 |
88 | path = mplpa.Path(verts)
89 | if bins is None:
90 | mask = path.contains_points(xys)
91 | ind = np.nonzero(mask)[0]
92 | else:
93 | if hasattr(bins, '__iter__'):
94 | if len(bins) == 2:
95 | nbins = bins
96 | else:
97 | raise Exception(
98 | 'The bins parameter must be a scalar or a tuple with 2 elements'
99 | )
100 | else:
101 | nbins = [bins, bins]
102 | minx, maxx = verts[:, 0].min(), verts[:, 0].max()
103 | miny, maxy = verts[:, 1].min(), verts[:, 1].max()
104 | hh, pos = quick_hist.quick_hist(xys.T,
105 | nbins=nbins,
106 | range=[[minx, maxx], [miny, maxy]],
107 | getPos=True)
108 | xbincens = np.linspace(minx, maxx, bins + 1, True)
109 | ybincens = np.linspace(miny, maxy, bins + 1, True)
110 |
111 | xbincens = .5 * (xbincens[1:] + xbincens[:-1])
112 | ybincens = .5 * (ybincens[1:] + ybincens[:-1])
113 | xbincens = xbincens[:, None] + ybincens[None, :] * 0
114 | ybincens = ybincens[None, :] + xbincens[:, None] * 0
115 | xybincens = np.array([xbincens.flatten(), ybincens.flatten()])
116 |
117 | mask = path.contains_points(xybincens.T)
118 | mask = mask[pos] & (pos >= 0)
119 | return mask
120 |
--------------------------------------------------------------------------------
/astrolib/helcorr.py:
--------------------------------------------------------------------------------
1 | from numpy import *
2 | from baryvel import baryvel
3 | from daycnv import daycnv
4 | from precess import precess
5 | from helio_jd import helio_jd
6 | _radeg = 180.0 / pi
7 |
8 | def helcorr(obs_long, obs_lat, obs_alt, ra2000, dec2000, jd, debug=False):
9 |
10 | #calculates heliocentric Julian date, baricentric and heliocentric radial
11 | #velocity corrections from:
12 | #
13 | #INPUT:
14 | # Longitude of observatory (degrees, western direction is positive)
15 | # Latitude of observatory (degrees)
16 | # Altitude of observatory (meters)
17 | # Right ascension of object for epoch 2000.0 (hours)
18 | # Declination of object for epoch 2000.0 (degrees)
19 | # Julian date for the middle of exposure
20 | #[DEBUG=] set keyword to get additional results for debugging
21 | #
22 | #OUTPUT:
23 | # baricentric correction - correction for rotation of earth,
24 | # rotation of earth center about the eart-moon barycenter, eart-moon
25 | # barycenter about the center of the Sun.
26 | # Heliocentric Julian date for middle of exposure
27 | #
28 | #Algorithms used are taken from the IRAF task noao.astutils.rvcorrect
29 | #and some procedures of the IDL Astrolib are used as well.
30 | #Accuracy is about 0.5 seconds in time and about 1 m/s in velocity.
31 | #
32 | #History:
33 | #written by Peter Mittermayer, Nov 8,2003
34 | #2005-January-13 Kudryavtsev Made more accurate calculation of the sideral time.
35 | # Conformity with MIDAS compute/barycorr is checked.
36 | #2005-June-20 Kochukhov Included precession of RA2000 and DEC2000 to current epoch
37 |
38 |
39 | #covert JD to Gregorian calendar date
40 | xjd = array(2400000.).astype(float) + jd
41 | year,month,day,ut=daycnv(xjd)
42 |
43 | #current epoch
44 | epoch = year + month / 12. + day / 365.
45 |
46 | #precess ra2000 and dec2000 to current epoch
47 | ra,dec=precess(ra2000*15., dec2000, 2000.0, epoch)
48 | #calculate heliocentric julian date
49 | hjd = array(helio_jd(jd, ra, dec)).astype(float)
50 |
51 | #DIURNAL VELOCITY (see IRAF task noao.astutil.rvcorrect)
52 | #convert geodetic latitude into geocentric latitude to correct
53 | #for rotation of earth
54 | dlat = -(11. * 60. + 32.743) * sin(2 * obs_lat / _radeg) + 1.1633 * sin(4 * obs_lat / _radeg) - 0.0026 * sin(6 * obs_lat / _radeg)
55 | lat = obs_lat + dlat / 3600
56 |
57 | #calculate distance of observer from earth center
58 | r = 6378160.0 * (0.998327073 + 0.001676438 * cos(2 * lat / _radeg) - 0.00000351 * cos(4 * lat / _radeg) + 0.000000008 * cos(6 * lat / _radeg)) + obs_alt
59 |
60 | #calculate rotational velocity (perpendicular to the radius vector) in km/s
61 | #23.934469591229 is the siderial day in hours for 1986
62 | v = 2. * pi * (r / 1000.) / (23.934469591229 * 3600.)
63 |
64 | #calculating local mean siderial time (see astronomical almanach)
65 | tu = (jd - 51545.0) / 36525
66 | gmst = 6.697374558 + ut + (236.555367908 * (jd - 51545.0) + 0.093104 * tu ** 2 - 6.2e-6 * tu ** 3) / 3600
67 | lmst = (gmst - obs_long / 15) % 24
68 |
69 | #projection of rotational velocity along the line of sight
70 | vdiurnal = v * cos(lat / _radeg) * cos(dec / _radeg) * sin((ra - lmst * 15) / _radeg)
71 |
72 | #BARICENTRIC and HELIOCENTRIC VELOCITIES
73 | vh,vb=baryvel(xjd, 0)
74 |
75 | #project to line of sight
76 | vbar = vb[0] * cos(dec / _radeg) * cos(ra / _radeg) + vb[1] * cos(dec / _radeg) * sin(ra / _radeg) + vb[2] * sin(dec / _radeg)
77 | vhel = vh[0] * cos(dec / _radeg) * cos(ra / _radeg) + vh[1] * cos(dec / _radeg) * sin(ra / _radeg) + vh[2] * sin(dec / _radeg)
78 |
79 | corr = (vdiurnal + vbar) #using baricentric velocity for correction
80 |
81 | if debug:
82 | print ''
83 | print '----- HELCORR.PRO - DEBUG INFO - START ----'
84 | print '(obs_long,obs_lat,obs_alt) Observatory coordinates [deg,m]: ', obs_long, obs_lat, obs_alt
85 | print '(ra,dec) Object coordinates (for epoch 2000.0) [deg]: ', ra, dec
86 | print '(ut) Universal time (middle of exposure) [hrs]: ', ut#, format='(A,F20.12)'
87 | print '(jd) Julian date (middle of exposure) (JD-2400000): ', jd#, format='(A,F20.12)'
88 | print '(hjd) Heliocentric Julian date (middle of exposure) (HJD-2400000): ', hjd#, format='(A,F20.12)'
89 | print '(gmst) Greenwich mean siderial time [hrs]: ', gmst % 24
90 | print '(lmst) Local mean siderial time [hrs]: ', lmst
91 | print '(dlat) Latitude correction [deg]: ', dlat
92 | print '(lat) Geocentric latitude of observer [deg]: ', lat
93 | print '(r) Distance of observer from center of earth [m]: ', r
94 | print '(v) Rotational velocity of earth at the position of the observer [km/s]: ', v
95 | print '(vdiurnal) Projected earth rotation and earth-moon revolution [km/s]: ', vdiurnal
96 | print '(vbar) Baricentric velocity [km/s]: ', vbar
97 | print '(vhel) Heliocentric velocity [km/s]: ', vhel
98 | print '(corr) Vdiurnal+vbar [km/s]: ', corr#, format='(A,F12.9)'
99 | print '----- HELCORR.PRO - DEBUG INFO - END -----'
100 | print ''
101 |
102 |
103 | return (corr, hjd)
104 |
105 |
--------------------------------------------------------------------------------
/astrolib/galage.py:
--------------------------------------------------------------------------------
1 | from numpy import array, sqrt, ndarray
2 | from cosmo_param import cosmo_param
3 | from scipy.integrate import quad
4 |
5 | def dtdz(z, lambda0=None, q0=None):
6 |
7 | term1 = (1.0e0 + z)
8 | term2 = 2.0e0 * (q0 + lambda0) * z + 1.0e0 - lambda0
9 | term3 = (1.0e0 + z) * (1.0e0 + z)
10 | return 1.0 / (term1 * sqrt(term2 * term3 + lambda0))
11 |
12 |
13 |
14 | def galage(z, zform, h0=None, omega_m=None, lambda0=None, k=None, q0=None, silent=None):
15 | """ NAME:
16 | GALAGE
17 |
18 | PURPOSE:
19 | Determine the age of a galaxy given its redshift and a formation redshift.
20 |
21 | CALLING SEQUENCE:
22 | age = galage(z, [zform, H0 =, k=, lambda0 =, Omega_m= , q0 =, /SILENT])'
23 |
24 | INPUTS:
25 | z - positive numeric vector or scalar of measured redshifts
26 | zform - redshift of galaxy formation (> z), numeric positive scalar
27 | To determine the age of the universe at a given redshift, set zform
28 | to a large number (e.g. ~1000).
29 |
30 | OPTIONAL KEYWORD INPUTS:
31 | H0 - Hubble constant in km/s/Mpc, positive scalar, default is 70
32 | /SILENT - If set, then the adopted cosmological parameters are not
33 | displayed at the terminal.
34 |
35 | No more than two of the following four parameters should be
36 | specified. None of them need be specified -- the adopted defaults
37 | are given.
38 | k - curvature constant, normalized to the closure density. Default is
39 | 0, (indicating a flat universe)
40 | Omega_m - Matter density, normalized to the closure density, default
41 | is 0.3. Must be non-negative
42 | Lambda0 - Cosmological constant, normalized to the closure density,
43 | default is 0.7
44 | q0 - Deceleration parameter, numeric scalar = -R*(R'')/(R')^2, default
45 | is -0.55
46 |
47 | OUTPUTS:
48 | age - age of galaxy in years, will have the same number of elements
49 | as the input Z vector
50 |
51 | EXAMPLE:
52 | (1) Determine the age of a galaxy observed at z = 1.5 in a cosmology with
53 | Omega_matter = 0.3 and Lambda = 0.0. Assume the formation redshift was
54 | at z = 25, and use the default Hubble constant (=70 km/s/Mpc)
55 |
56 | IDL> print,galage(1.5,25,Omega_m=0.3, Lambda = 0)
57 | ===> 3.35 Gyr
58 |
59 | (2) Plot the age of a galaxy in Gyr out to a redshift of z = 5, assuming
60 | the default cosmology (omega_m=0.3, lambda=0.7), and zform = 100
61 |
62 | IDL> z = findgen(50)/10.
63 | IDL> plot,z,galage(z,100)/1e9,xtit='z',ytit = 'Age (Gyr)'
64 |
65 | PROCEDURE:
66 | For a given formation time zform and a measured z, integrate dt/dz from
67 | zform to z. Analytic formula of dt/dz in Gardner, PASP 110:291-305, 1998
68 | March (eq. 7)
69 |
70 | COMMENTS:
71 | (1) Integrates using the IDL Astronomy Library procedure QSIMP. (The
72 | intrinsic IDL QSIMP() function is not called because of its ridiculous
73 | restriction that only scalar arguments can be passed to the integrating
74 | function.) The function 'dtdz' is defined at the beginning of the
75 | routine (so it can compile first).
76 |
77 | (2) Should probably be fixed to use a different integrator from QSIMP when
78 | computing age from an "infinite" redshift of formation. But using a
79 | large value of zform seems to work adequately.
80 |
81 | (3) An alternative set of IDL procedures for computing cosmological
82 | parameters is available at
83 | http://cerebus.as.arizona.edu/~ioannis/research/red/
84 | PROCEDURES CALLED:
85 | COSMO_PARAM, QSIMP
86 | HISTORY:
87 | STIS version by P. Plait (ACC) June 1999
88 | IDL Astro Version W. Landsman (Raytheon ITSS) April 2000
89 | Avoid integer overflow for more than 32767 redshifts July 2001
90 | Convert to python S. Koposov 2010
91 | """
92 | if h0 is None:
93 | h0 = 70.0
94 | omega_m, lambda0, k, q0 = cosmo_param(omega_m, lambda0, k, q0)
95 |
96 | if silent is not None:
97 | print 'GALAGE: H0:', h0, ' Omega_m:', omega_m, ' Lambda0', lambda0, ' q0: ', q0, ' k: ', k#, format='(A,I3,A,f5.2,A,f5.2,A,f5.2,A,F5.2)'
98 |
99 | scal = False
100 | if isinstance(z, list):
101 | z = array(z)
102 | elif isinstance(z, ndarray):
103 | pass
104 | else:
105 | z = array([z])
106 | scal = True
107 |
108 | nz = len(z)
109 | age = z * 0. #Return same dimensions and data type as Z
110 |
111 | #
112 | # use qsimp to integrate dt/dz to get age for each z
113 | # watch out for null case of z >= zform
114 | #
115 |
116 | for i in range(nz):
117 | if (z[i] >= zform):
118 | age_z = 0
119 | else:
120 | #qsimp('dtdz', z[i], zform, age_z, q0=q0, lambda0=lambda0)
121 | age_z = quad(dtdz, z[i], zform, args=(lambda0, q0))[0]
122 | age[i] = age_z
123 |
124 | # convert units of age: km/s/Mpc to years, divide by H0
125 | # 3.085678e19 km --> 1 Mpc
126 | # 3.15567e+07 sec --> 1 year
127 | if scal:
128 | age = age[0]
129 | return age * 3.085678e+19 / 3.15567e+7 / h0
130 |
131 |
--------------------------------------------------------------------------------
/astrolib/euler.py:
--------------------------------------------------------------------------------
1 | from numpy import (array, sin, cos, pi, deg2rad, rad2deg, arctan2, arcsin,
2 | minimum)
3 |
4 |
5 | def euler(ai, bi, select=1, fk4=False):
6 | """
7 | NAME:
8 | EULER
9 | PURPOSE:
10 | Transform between Galactic, celestial, and ecliptic coordinates.
11 | EXPLANATION:
12 | Use the procedure ASTRO to use this routine interactively
13 |
14 | CALLING SEQUENCE:
15 | AO, BO = EULER(AI, BI, [SELECT=1, FK4=False])
16 |
17 | INPUTS:
18 | AI - Input Longitude in DEGREES, scalar or vector. If only two
19 | parameters are supplied, then AI and BI will be modified to
20 | contain the output longitude and latitude.
21 | BI - Input Latitude in DEGREES
22 |
23 | OPTIONAL INPUT:
24 | SELECT - Integer (1-6) specifying type of coordinate transformation.
25 |
26 | SELECT From To | SELECT From To
27 | 1 RA-Dec (2000) Galactic | 4 Ecliptic RA-Dec
28 | 2 Galactic RA-DEC | 5 Ecliptic Galactic
29 | 3 RA-Dec Ecliptic | 6 Galactic Ecliptic
30 |
31 | If not supplied as a parameter or keyword, then EULER will prompt for
32 | the value of SELECT
33 | Celestial coordinates (RA, Dec) should be given in equinox J2000
34 | unless the /FK4 keyword is set.
35 | OUTPUTS:
36 | AO - Output Longitude in DEGREES
37 | BO - Output Latitude in DEGREES
38 |
39 | INPUT KEYWORD:
40 | /FK4 - If this keyword is set and non-zero, then input and output
41 | celestial and ecliptic coordinates should be given in equinox
42 | B1950.
43 | /SELECT - The coordinate conversion integer (1-6) may
44 | alternatively be
45 | specified as a keyword
46 | NOTES:
47 | EULER was changed in December 1998 to use J2000 coordinates as the
48 | default, ** and may be incompatible with earlier versions***.
49 | REVISION HISTORY:
50 | Written W. Landsman, February 1987
51 | Adapted from Fortran by Daryl Yentis NRL
52 | Converted to IDL V5.0 W. Landsman September 1997
53 | Made J2000 the default, added /FK4 keyword W. Landsman December 1998
54 | Add option to specify SELECT as a keyword W. Landsman March 2003
55 | """
56 |
57 | # J2000 coordinate conversions are based on the following constants
58 | # (see the Hipparcos explanatory supplement).
59 | # eps = 23.4392911111d Obliquity of the ecliptic
60 | # alphaG = 192.85948d Right Ascension of Galactic North Pole
61 | # deltaG = 27.12825d Declination of Galactic North Pole
62 | # lomega = 32.93192d Galactic longitude of celestial equator
63 | # alphaE = 180.02322d Ecliptic longitude of Galactic North Pole
64 | # deltaE = 29.811438523d Ecliptic latitude of Galactic North Pole
65 | # Eomega = 6.3839743d Galactic longitude of ecliptic equator
66 |
67 | if fk4:
68 | # equinox = '(B1950)'
69 | psi = array([
70 | 0.57595865315e0, 4.9261918136e0, 0.00000000000e0, 0.0000000000e0,
71 | 0.11129056012e0, 4.7005372834e0
72 | ])
73 | stheta = array([
74 | 0.88781538514e0, -0.88781538514e0, 0.39788119938e0,
75 | -0.39788119938e0, 0.86766174755e0, -0.86766174755e0
76 | ])
77 | ctheta = array([
78 | 0.46019978478e0, 0.46019978478e0, 0.91743694670e0, 0.91743694670e0,
79 | 0.49715499774e0, 0.49715499774e0
80 | ])
81 | phi = array([
82 | 4.9261918136e0, 0.57595865315e0, 0.0000000000e0, 0.00000000000e0,
83 | 4.7005372834e0, 0.11129056012e0
84 | ])
85 | else:
86 | # equinox = '(J2000)'
87 | psi = array([
88 | 0.57477043300e0, 4.9368292465e0, 0.00000000000e0, 0.0000000000e0,
89 | 0.11142137093e0, 4.71279419371e0
90 | ])
91 | stheta = array([
92 | 0.88998808748e0, -0.88998808748e0, 0.39777715593e0,
93 | -0.39777715593e0, 0.86766622025e0, -0.86766622025e0
94 | ])
95 | ctheta = array([
96 | 0.45598377618e0, 0.45598377618e0, 0.91748206207e0, 0.91748206207e0,
97 | 0.49714719172e0, 0.49714719172e0
98 | ])
99 | phi = array([
100 | 4.9368292465e0, 0.57477043300e0, 0.0000000000e0, 0.00000000000e0,
101 | 4.71279419371e0, 0.11142137093e0
102 | ])
103 | if select not in [1, 2, 3, 4, 5, 6]:
104 | raise ValueError(
105 | 'Select parameter should be an integer between 1 and 6')
106 | i = select - 1
107 | b = deg2rad(bi)
108 | cb = cos(b)
109 | sb = sin(b)
110 | del b
111 | a = deg2rad(ai) - phi[i]
112 | cbsa = cb * sin(a)
113 | b = -stheta[i] * cbsa + ctheta[i] * sb
114 | bo = rad2deg(arcsin(minimum(b, 1.0)))
115 | del b
116 | a = arctan2(ctheta[i] * cbsa + stheta[i] * sb, cb * cos(a))
117 | del cb, cbsa, sb
118 | ao = rad2deg(((a + psi[i] + 4 * pi) % (2 * pi)))
119 |
120 | return (ao, bo)
121 |
--------------------------------------------------------------------------------
/my_utils/clicker.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import scipy.spatial
3 | import numpy as np
4 |
5 |
6 | class MultiClicker:
7 | """ Class to collect the clicked points
8 | You initialize it as
9 | >>> cl = MultiClicker(plt.gcf())
10 | Then all the clicks will be recorded in cl.points
11 | If you click the right-hand button, the recording will stop.
12 | You can also stop recording by calling
13 | >>> cl.stop()
14 | """
15 |
16 | def __init__(self, fig):
17 | self.cid = None
18 | self.points = []
19 |
20 | def onclick(event):
21 | try:
22 | print(
23 | 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
24 | (event.button, event.x, event.y, event.xdata, event.ydata))
25 | if event.button == 3:
26 | self.stop()
27 | else:
28 | self.points.append((event.xdata, event.ydata))
29 | except: # noqa
30 | raise
31 | print('printing failed')
32 |
33 | self.canvas = fig.canvas
34 | self.cid = self.canvas.mpl_connect('button_press_event', onclick)
35 |
36 | def stop(self):
37 | self.canvas.mpl_disconnect(self.cid)
38 |
39 |
40 | class NearbyClicker:
41 | """
42 | Class to call function on clicked points
43 | If you have plotted the xs,ys points
44 | and defined function
45 | def callback(i)
46 | Then when you create a clicker
47 | >>> NearbyClicker(plt.gcf(), xs, ys, callback)
48 | At each click a point that is closest to the clicked location is
49 | recorded and the callback function is called with the integer
50 | number of this point
51 | """
52 |
53 | def __init__(self, fig, xs, ys, callback):
54 | self.cid = None
55 | self.xs = xs
56 | self.ys = ys
57 | self.tree = scipy.spatial.cKDTree(np.array([xs, ys]).T)
58 |
59 | def onclick(event):
60 | try:
61 | if event.button == 3:
62 | self.stop()
63 | else:
64 | d, pos = self.tree.query(np.r_[event.xdata, event.ydata])
65 | print('Clicked %f %f ; Selected %d: %f %f' %
66 | (event.xdata, event.ydata, pos, self.xs[pos],
67 | self.ys[pos]))
68 | callback(pos)
69 | except: # noqa
70 | print('callback failed')
71 |
72 | self.canvas = fig.canvas
73 | self.cid = self.canvas.mpl_connect('button_press_event', onclick)
74 |
75 | def stop(self):
76 | self.canvas.mpl_disconnect(self.cid)
77 |
78 |
79 | class CallbackClicker:
80 | """
81 | Class to call function on clicked location
82 | If you have plotted the xs,ys points
83 | and defined function
84 | def callback(x,y)
85 | Then when you create a clicker
86 | >>> NearbyClicker(plt.gcf(), callback)
87 | At each click a the callback function is called with the location
88 | """
89 |
90 | def __init__(self, fig, callback):
91 | self.cid = None
92 |
93 | def onclick(event):
94 | try:
95 | if event.button == 3:
96 | self.stop()
97 | else:
98 | print('Clicked %f %f ' % (event.xdata, event.ydata))
99 | callback(event.xdata, event.ydata)
100 | except: # noqa
101 | print('callback failed')
102 |
103 | self.canvas = fig.canvas
104 | self.cid = self.canvas.mpl_connect('button_press_event', onclick)
105 |
106 | def stop(self):
107 | self.canvas.mpl_disconnect(self.cid)
108 |
109 |
110 | def clicker(fig, xobj=None):
111 | """
112 | This function records the coordinates of a single click on the figure
113 | """
114 | cid = None
115 |
116 | def onclick(event):
117 | try:
118 | print('cid=%s button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
119 | (cid, event.button, event.x, event.y, event.xdata,
120 | event.ydata))
121 | if xobj is not None:
122 | if isinstance(xobj, dict):
123 | xobj['x'] = event.xdata
124 | xobj['y'] = event.ydata
125 | except: # noqa
126 | print('printing failed')
127 | event.canvas.mpl_disconnect(cid)
128 |
129 | cid = fig.canvas.mpl_connect('button_press_event', onclick)
130 |
131 |
132 | def clicker_multi(fig):
133 | """
134 | This function records the coordinates of a multiple clicks
135 | on the figure
136 | """
137 | cid = None
138 | res = []
139 |
140 | def onclick(event):
141 | try:
142 | print('cid=%s button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
143 | (cid, event.button, event.x, event.y, event.xdata,
144 | event.ydata))
145 | if event.button == 3:
146 | event.canvas.mpl_disconnect(cid)
147 | else:
148 | res.append((event.xdata, event.ydata))
149 | except: # noqa
150 | print('printing failed')
151 |
152 | cid = fig.canvas.mpl_connect('button_press_event', onclick)
153 | return res
154 |
--------------------------------------------------------------------------------
/astrolib/lumdist.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | """
3 | NAME:
4 | LUMDIST
5 |
6 | PURPOSE:
7 | Calculate luminosity distance (in Mpc) of an object given its redshift
8 | EXPLANATION:
9 | The luminosity distance in the Friedmann-Robertson-Walker model is
10 | taken from Caroll, Press, and Turner (1992, ARAA, 30, 499), p. 511
11 | Uses a closed form (Mattig equation) to compute the distance when the
12 | cosmological constant is zero. Otherwise integrates the function using
13 | QSIMP.
14 | CALLING SEQUENCE:
15 | result = lumdist(z, [H0 = , k = , Omega_M =, Lambda0 = , q0 = ,/SILENT])
16 |
17 | INPUTS:
18 | z = redshift, positive scalar or vector
19 |
20 | OPTIONAL KEYWORD INPUTS:
21 | /SILENT - If set, the program will not display adopted cosmological
22 | parameters at the terminal.
23 | H0: Hubble parameter in km/s/Mpc, default is 70
24 |
25 | No more than two of the following four parameters should be
26 | specified. None of them need be specified -- the adopted defaults
27 | are given.
28 | k - curvature constant, normalized to the closure density. Default is
29 | 0, indicating a flat universe
30 | Omega_m - Matter density, normalized to the closure density, default
31 | is 0.3. Must be non-negative
32 | Lambda0 - Cosmological constant, normalized to the closure density,
33 | default is 0.7
34 | q0 - Deceleration parameter, numeric scalar = -R*(R'')/(R')^2, default
35 | is -0.55
36 |
37 | OUTPUTS:
38 | The result of the function is the luminosity distance (in Mpc) for each
39 | input value of z.
40 |
41 | EXAMPLE:
42 | (1) Plot the distance of a galaxy in Mpc as a function of redshift out
43 | to z = 5.0, assuming the default cosmology (Omega_m=0.3, Lambda = 0.7,
44 | H0 = 70 km/s/Mpc)
45 |
46 | IDL> z = findgen(50)/10.
47 | IDL> plot,z,lumdist(z),xtit='z',ytit='Distance (Mpc)'
48 |
49 | Now overplot the relation for zero cosmological constant and
50 | Omega_m=0.3
51 | IDL> oplot,z,lumdist(z,lambda=0,omega=0.3),linestyle=1
52 | COMMENTS:
53 | (1) Integrates using the IDL Astronomy Version procedure QSIMP. (The
54 | intrinsic IDL QSIMP function is not called because of its ridiculous
55 | restriction that only scalar arguments can be passed to the integrating
56 | function.)
57 | (2) Can fail to converge at high redshift for closed universes with
58 | non-zero lambda. This can presumably be fixed by replacing QSIMP with
59 | an integrator that can handle a singularity
60 | PROCEDURES CALLED:
61 | COSMO_PARAM, QSIMP
62 | REVISION HISTORY:
63 | Written W. Landsman Raytheon ITSS April 2000
64 | Avoid integer overflow for more than 32767 redshifts July 2001
65 | Use double precision J. Moustakas/W. Landsman April 2008
66 | Convert to python S. Koposov 2010
67 | """
68 |
69 | from numpy import array, ndarray, sqrt, sin, sinh, maximum
70 | from cosmo_param import cosmo_param
71 | from scipy.integrate import quad
72 | from math import sqrt as msqrt
73 |
74 | def ldist(z, q0=None, lambda0=None):
75 |
76 | term1 = (1. + z) ** 2
77 | term2 = 1. + 2. * (q0 + lambda0) * z
78 | term3 = z * (2. + z) * lambda0
79 | denom = (term1 * term2 - term3)
80 | if denom>0:
81 | out = 1. / msqrt(denom) # since the function is used with scalar arguments
82 | # I use math.sqrt instead of numpy.sqrt for
83 | # performance reasons
84 | else:
85 | out = 0.
86 | return out
87 |
88 |
89 | def lumdist(z, h0=None, k=None, lambda0=None, omega_m=None, q0=None, silent=None):
90 | '''Syntax: result = lumdist(z, H0 = ,k=, Lambda0 = ])
91 | Returns luminosity distance in Mpc'''
92 |
93 | scal=False
94 | scalret = lambda x : x[0] if scal else x
95 |
96 | if isinstance(z, list):
97 | z = array(z)
98 | elif isinstance(z, ndarray):
99 | pass
100 | else:
101 | scal = True
102 | z = array([z])
103 | n = len(z)
104 |
105 | omega_m, lambda0, k, q0 = cosmo_param(omega_m, lambda0, k, q0)
106 |
107 | # Check keywords
108 | c = 2.99792458e5 # speed of light in km/s
109 | if h0 is None:
110 | h0 = 70
111 | if not silent:
112 | print( 'LUMDIST: H0:', h0, ' Omega_m:', omega_m, ' Lambda0', lambda0, ' q0: ', q0, ' k: ', k)
113 |
114 | # For the case of Lambda = 0, we use the closed form from equation 5.238 of
115 | # Astrophysical Formulae (Lang 1998). This avoids terms that almost cancel
116 | # at small q0*z better than the more familiar Mattig formula.
117 | #
118 | if lambda0 == 0:
119 | denom = sqrt(1 + 2 * q0 * z) + 1 + q0 * z
120 | dlum = (c * z / h0) * (1 + z * (1 - q0) / denom)
121 | return scalret(dlum)
122 |
123 | # For non-zero lambda
124 | else:
125 | dlum = z * 0.0
126 | for i in range(n):
127 | if z[i] <= 0.0:
128 | dlum[i] = 0.0
129 | else:
130 | lz = quad(ldist, 0, z[i], args=(q0, lambda0))
131 | dlum[i] = lz[0]
132 |
133 | if k > 0:
134 | dlum = sinh(sqrt(k) * dlum) / sqrt(k)
135 | else:
136 | if k < 0:
137 | dlum = maximum(sin(sqrt(-k) * dlum) / sqrt(-k), 0)
138 | return scalret(c * (1 + z) * dlum / h0)
139 |
140 |
--------------------------------------------------------------------------------
/astrolib/precess.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from numpy import sin, cos, deg2rad, transpose, dot, arcsin, arctan2, zeros,\
3 | ndarray, array, rad2deg, pi
4 | from premat import premat
5 |
6 | def precess(ra0, dec0, equinox1, equinox2, doprint=False, fk4=False, radian=False):
7 | """
8 | NAME:
9 | PRECESS
10 | PURPOSE:
11 | Precess coordinates from EQUINOX1 to EQUINOX2.
12 | EXPLANATION:
13 | For interactive display, one can use the procedure ASTRO which calls
14 | PRECESS or use the /PRINT keyword. The default (RA,DEC) system is
15 | FK5 based on epoch J2000.0 but FK4 based on B1950.0 is available via
16 | the /FK4 keyword.
17 |
18 | Use BPRECESS and JPRECESS to convert between FK4 and FK5 systems
19 | CALLING SEQUENCE:
20 | PRECESS, ra, dec, [ equinox1, equinox2, /PRINT, /FK4, /RADIAN ]
21 |
22 | INPUT - OUTPUT:
23 | RA - Input right ascension (scalar or vector) in DEGREES, unless the
24 | /RADIAN keyword is set
25 | DEC - Input declination in DEGREES (scalar or vector), unless the
26 | /RADIAN keyword is set
27 |
28 | The input RA and DEC are modified by PRECESS to give the
29 | values after precession.
30 |
31 | OPTIONAL INPUTS:
32 | EQUINOX1 - Original equinox of coordinates, numeric scalar. If
33 | omitted, then PRECESS will query for EQUINOX1 and EQUINOX2.
34 | EQUINOX2 - Equinox of precessed coordinates.
35 |
36 | OPTIONAL INPUT KEYWORDS:
37 | /PRINT - If this keyword is set and non-zero, then the precessed
38 | coordinates are displayed at the terminal. Cannot be used
39 | with the /RADIAN keyword
40 | /FK4 - If this keyword is set and non-zero, the FK4 (B1950.0) system
41 | will be used otherwise FK5 (J2000.0) will be used instead.
42 | /RADIAN - If this keyword is set and non-zero, then the input and
43 | output RA and DEC vectors are in radians rather than degrees
44 |
45 | RESTRICTIONS:
46 | Accuracy of precession decreases for declination values near 90
47 | degrees. PRECESS should not be used more than 2.5 centuries from
48 | 2000 on the FK5 system (1950.0 on the FK4 system).
49 |
50 | EXAMPLES:
51 | (1) The Pole Star has J2000.0 coordinates (2h, 31m, 46.3s,
52 | 89d 15' 50.6"); compute its coordinates at J1985.0
53 |
54 | IDL> precess, ten(2,31,46.3)*15, ten(89,15,50.6), 2000, 1985, /PRINT
55 |
56 | ====> 2h 16m 22.73s, 89d 11' 47.3"
57 |
58 | (2) Precess the B1950 coordinates of Eps Ind (RA = 21h 59m,33.053s,
59 | DEC = (-56d, 59', 33.053") to equinox B1975.
60 |
61 | IDL> ra = ten(21, 59, 33.053)*15
62 | IDL> dec = ten(-56, 59, 33.053)
63 | IDL> precess, ra, dec ,1950, 1975, /fk4
64 |
65 | PROCEDURE:
66 | Algorithm from Computational Spherical Astronomy by Taff (1983),
67 | p. 24. (FK4). FK5 constants from "Astronomical Almanac Explanatory
68 | Supplement 1992, page 104 Table 3.211.1.
69 |
70 | PROCEDURE CALLED:
71 | Function PREMAT - computes precession matrix
72 |
73 | REVISION HISTORY
74 | Written, Wayne Landsman, STI Corporation August 1986
75 | Correct negative output RA values February 1989
76 | Added /PRINT keyword W. Landsman November, 1991
77 | Provided FK5 (J2000.0) I. Freedman January 1994
78 | Precession Matrix computation now in PREMAT W. Landsman June 1994
79 | Added /RADIAN keyword W. Landsman June 1997
80 | Converted to IDL V5.0 W. Landsman September 1997
81 | Correct negative output RA values when /RADIAN used March 1999
82 | Work for arrays, not just vectors W. Landsman September 2003
83 | Convert to Python Sergey Koposov July 2010
84 | """
85 | scal = True
86 | if isinstance(ra0, ndarray):
87 | ra = ra0.copy()
88 | dec = dec0.copy()
89 | scal = False
90 | else:
91 | ra=array([ra0])
92 | dec=array([dec0])
93 | npts = ra.size
94 |
95 | if not radian:
96 | ra_rad = deg2rad(ra) #Convert to double precision if not already
97 | dec_rad = deg2rad(dec)
98 | else:
99 | ra_rad = ra
100 | dec_rad = dec
101 |
102 | a = cos(dec_rad)
103 |
104 | x = zeros((npts, 3))
105 | x[:,0] = a * cos(ra_rad)
106 | x[:,1] = a * sin(ra_rad)
107 | x[:,2] = sin(dec_rad)
108 |
109 | # Use PREMAT function to get precession matrix from Equinox1 to Equinox2
110 |
111 | r = premat(equinox1, equinox2, fk4=fk4)
112 |
113 | x2 = transpose(dot(transpose(r), transpose(x))) #rotate to get output direction cosines
114 |
115 | ra_rad = zeros(npts) + arctan2(x2[:,1], x2[:,0])
116 | dec_rad = zeros(npts) + arcsin(x2[:,2])
117 |
118 | if not radian:
119 | ra = rad2deg(ra_rad)
120 | ra = ra + (ra < 0.) * 360.e0 #RA between 0 and 360 degrees
121 | dec = rad2deg(dec_rad)
122 | else:
123 | ra = ra_rad
124 | dec = dec_rad
125 | ra = ra + (ra < 0.) * 2.0e0 * pi
126 |
127 | if doprint:
128 | print( 'Equinox (%.2f): %f,%f' % (equinox2, ra, dec))
129 | if scal:
130 | ra, dec = ra[0], dec[0]
131 | return ra, dec
132 |
133 |
--------------------------------------------------------------------------------
/my_utils/pg2hdf5.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import psycopg2
3 | import threading
4 | import h5py
5 | import argparse
6 |
7 | from queue import Queue, Empty
8 |
9 | strLength = 20
10 | __pgTypeHash = {
11 | 16: bool,
12 | 18: str,
13 | 20: 'i8',
14 | 21: 'i2',
15 | 23: 'i4',
16 | 1007: 'i4',
17 | 25: '|U%d',
18 | 700: 'f4',
19 | 701: 'f8',
20 | 1005: 'i2',
21 | 1007: 'i4',
22 | 1016: 'i8',
23 | 1021: 'f4',
24 | 1022: 'f8',
25 | 1042: '|U%d', # character()
26 | 1043: '|U%d', # varchar
27 | 1700: 'f8', # numeric
28 | 1114: ' u=154 v = -493 w = 97 ;km/s
51 |
52 | (2) Use the Hipparcos Input and Output Catalog IDL databases (see
53 | http://idlastro.gsfc.nasa.gov/ftp/zdbase/) to obtain space velocities
54 | for all stars within 10 pc with radial velocities > 10 km/s
55 |
56 | dbopen,'hipparcos,hic' ;Need Hipparcos output and input catalogs
57 | list = dbfind('plx>100,vrad>10') ;Plx > 100 mas, Vrad > 10 km/s
58 | dbext,list,'pmra,pmdec,vrad,ra,dec,plx',pmra,pmdec,vrad,ra,dec,plx
59 | ra = ra*15. ;Need right ascension in degrees
60 | GAL_UVW,u,v,w,ra=ra,dec=dec,pmra=pmra,pmdec=pmdec,vrad=vrad,plx = plx
61 | forprint,u,v,w ;Display results
62 | METHOD:
63 | Follows the general outline of Johnson & Soderblom (1987, AJ, 93,864)
64 | except that U is positive outward toward the Galactic *anti*center, and
65 | the J2000 transformation matrix to Galactic coordinates is taken from
66 | the introduction to the Hipparcos catalog.
67 | REVISION HISTORY:
68 | Written, W. Landsman December 2000
69 | fix the bug occuring if the input arrays are longer than 32767
70 | and update the Sun velocity Sergey Koposov June 2008
71 | vectorization of the loop -- performance on large arrays
72 | is now 10 times higher Sergey Koposov December 2008
73 | """
74 |
75 | n_params = 3
76 |
77 | if n_params == 0:
78 | print( 'Syntax - GAL_UVW, U, V, W, [/LSR, RA=, DEC=, PMRA= ,PMDEC=, VRAD=')
79 | print( ' Distance=, PLX=')
80 | print( ' U, V, W - output Galactic space velocities (km/s)')
81 | return None
82 |
83 | if ra is None or dec is None:
84 | raise Exception('ERROR - The RA, Dec (J2000) position keywords must be supplied (degrees)')
85 | if plx is None and distance is None:
86 | raise Exception('ERROR - Either a parallax or distance must be specified')
87 | if distance is not None:
88 | if numpy.any(distance==0):
89 | raise Exception('ERROR - All distances must be > 0')
90 | plx = 1e3 / distance #Parallax in milli-arcseconds
91 | if plx is not None and numpy.any(plx==0):
92 | raise Exception('ERROR - Parallaxes must be > 0')
93 |
94 | cosd = numpy.cos(numpy.deg2rad(dec))
95 | sind = numpy.sin(numpy.deg2rad(dec))
96 | cosa = numpy.cos(numpy.deg2rad(ra))
97 | sina = numpy.sin(numpy.deg2rad(ra))
98 |
99 | k = 4.74047 #Equivalent of 1 A.U/yr in km/s
100 | a_g = numpy.array([[0.0548755604, +0.4941094279, -0.8676661490],
101 | [0.8734370902, -0.4448296300, -0.1980763734],
102 | [0.4838350155, 0.7469822445, +0.4559837762]])
103 |
104 | vec1 = vrad
105 | vec2 = k * pmra / plx
106 | vec3 = k * pmdec / plx
107 |
108 | u = (a_g[0,0] * cosa * cosd + a_g[1,0] * sina * cosd + a_g[2,0] * sind) * vec1 + (-a_g[0,0] * sina + a_g[1,0] * cosa) * vec2 + (-a_g[0,0] * cosa * sind - a_g[1,0] * sina * sind + a_g[2,0] * cosd) * vec3
109 | v = (a_g[0,1] * cosa * cosd + a_g[1,1] * sina * cosd + a_g[2,1] * sind) * vec1 + (-a_g[0,1] * sina + a_g[1,1] * cosa) * vec2 + (-a_g[0,1] * cosa * sind - a_g[1,1] * sina * sind + a_g[2,1] * cosd) * vec3
110 | w = (a_g[0,2] * cosa * cosd + a_g[1,2] * sina * cosd + a_g[2,2] * sind) * vec1 + (-a_g[0,2] * sina + a_g[1,2] * cosa) * vec2 + (-a_g[0,2] * cosa * sind - a_g[1,2] * sina * sind + a_g[2,2] * cosd) * vec3
111 |
112 | lsr_vel = numpy.array([-8.5, 13.38, 6.49]) # notice the sign of the first velocity
113 | #component, it is negative because
114 | # in this program U points toward anticenter
115 | if (lsr is not None):
116 | u = u + lsr_vel[0]
117 | v = v + lsr_vel[1]
118 | w = w + lsr_vel[2]
119 |
120 | return (u,v,w)
121 |
122 |
--------------------------------------------------------------------------------
/astrolib/xyz.py:
--------------------------------------------------------------------------------
1 | from numpy import sqrt, pi, cos, sin
2 | from precess_xyz import precess_xyz
3 |
4 | def xyz(date, equinox=None):
5 | """
6 | NAME:
7 | XYZ
8 | PURPOSE:
9 | Calculate geocentric X,Y, and Z and velocity coordinates of the Sun
10 | EXPLANATION:
11 | Calculates geocentric X,Y, and Z vectors and velocity coordinates
12 | (dx, dy and dz) of the Sun. (The positive X axis is directed towards
13 | the equinox, the y-axis, towards the point on the equator at right
14 | ascension 6h, and the z axis toward the north pole of the equator).
15 | Typical position accuracy is <1e-4 AU (15000 km).
16 |
17 | CALLING SEQUENCE:
18 | XYZ, date, x, y, z, [ xvel, yvel, zvel, EQUINOX = ]
19 |
20 | INPUT:
21 | date: reduced julian date (=JD - 2400000), scalar or vector
22 |
23 | OUTPUT:
24 | x,y,z: scalars or vectors giving heliocentric rectangular coordinates
25 | (in A.U) for each date supplied. Note that sqrt(x^2 + y^2
26 | + z^2) gives the Earth-Sun distance for the given date.
27 | xvel, yvel, zvel: velocity vectors corresponding to X, Y and Z.
28 |
29 | OPTIONAL KEYWORD INPUT:
30 | EQUINOX: equinox of output. Default is 1950.
31 |
32 | EXAMPLE:
33 | What were the rectangular coordinates and velocities of the Sun on
34 | Jan 22, 1999 0h UT (= JD 2451200.5) in J2000 coords? NOTE:
35 | Astronomical Almanac (AA) is in TDT, so add 64 seconds to
36 | UT to convert.
37 |
38 | IDL> xyz,51200.5+64.d/86400.d,x,y,z,xv,yv,zv,equinox = 2000
39 |
40 | Compare to Astronomical Almanac (1999 page C20)
41 | X (AU) Y (AU) Z (AU)
42 | XYZ: 0.51456871 -0.76963263 -0.33376880
43 | AA: 0.51453130 -0.7697110 -0.3337152
44 | abs(err): 0.00003739 0.00007839 0.00005360
45 | abs(err)
46 | (km): 5609 11759 8040
47 |
48 | NOTE: Velocities in AA are for Earth/Moon barycenter
49 | (a very minor offset) see AA 1999 page E3
50 | X VEL (AU/DAY) YVEL (AU/DAY) Z VEL (AU/DAY)
51 | XYZ: -0.014947268 -0.0083148382 -0.0036068577
52 | AA: -0.01494574 -0.00831185 -0.00360365
53 | abs(err): 0.000001583 0.0000029886 0.0000032077
54 | abs(err)
55 | (km/sec): 0.00265 0.00519 0.00557
56 |
57 | PROCEDURE CALLS:
58 | PRECESS_XYZ
59 | REVISION HISTORY
60 | Original algorithm from Almanac for Computers, Doggett et al. USNO 1978
61 | Adapted from the book Astronomical Photometry by A. Henden
62 | Written W. Landsman STX June 1989
63 | Correct error in X coefficient W. Landsman HSTX January 1995
64 | Added velocities, more terms to positions and EQUINOX keyword,
65 | some minor adjustments to calculations
66 | P. Plait/ACC March 24, 1999
67 | """
68 |
69 | picon = pi / 180.0e0
70 | t = (date - 15020.0e0) / 36525.0e0 #Relative Julian century from 1900
71 |
72 | # NOTE: longitude arguments below are given in *equinox* of date.
73 | # Precess these to equinox 1950 to give everything an even footing.
74 | # Compute argument of precession from equinox of date back to 1950
75 | pp = (1.396041e0 + 0.000308e0 * (t + 0.5e0)) * (t - 0.499998e0)
76 |
77 | # Compute mean solar longitude, precessed back to 1950
78 | el = 279.696678e0 + 36000.76892e0 * t + 0.000303e0 * t * t - pp
79 |
80 | # Compute Mean longitude of the Moon
81 | c = 270.434164e0 + 480960.e0 * t + 307.883142e0 * t - 0.001133e0 * t * t - pp
82 |
83 | # Compute longitude of Moon's ascending node
84 | n = 259.183275e0 - 1800.e0 * t - 134.142008e0 * t + 0.002078e0 * t * t - pp
85 |
86 | # Compute mean solar anomaly
87 | g = 358.475833e0 + 35999.04975e0 * t - 0.00015e0 * t * t
88 |
89 | # Compute the mean jupiter anomaly
90 | j = 225.444651e0 + 2880.0e0 * t + 154.906654e0 * t * t
91 |
92 | # Compute mean anomaly of Venus
93 | v = 212.603219e0 + 58320.e0 * t + 197.803875e0 * t + 0.001286e0 * t * t
94 |
95 | # Compute mean anomaly of Mars
96 | m = 319.529425e0 + 19080.e0 * t + 59.8585e0 * t + 0.000181e0 * t * t
97 |
98 | # Convert degrees to radians for trig functions
99 | el = el * picon
100 | g = g * picon
101 | j = j * picon
102 | c = c * picon
103 | v = v * picon
104 | n = n * picon
105 | m = m * picon
106 |
107 | # Calculate X,Y,Z using trigonometric series
108 | x = 0.999860e0 * cos(el) - 0.025127e0 * cos(g - el) + 0.008374e0 * cos(g + el) + 0.000105e0 * cos(g + g + el) + 0.000063e0 * t * cos(g - el) + 0.000035e0 * cos(g + g - el) - 0.000026e0 * sin(g - el - j) - 0.000021e0 * t * cos(g + el) + 0.000018e0 * sin(2.e0 * g + el - 2.e0 * v) + 0.000017e0 * cos(c) - 0.000014e0 * cos(c - 2.e0 * el) + 0.000012e0 * cos(4.e0 * g + el - 8.e0 * m + 3.e0 * j) - 0.000012e0 * cos(4.e0 * g - el - 8.e0 * m + 3.e0 * j) - 0.000012e0 * cos(g + el - v) + 0.000011e0 * cos(2.e0 * g + el - 2.e0 * v) + 0.000011e0 * cos(2.e0 * g - el - 2.e0 * j)
109 |
110 |
111 | y = 0.917308e0 * sin(el) + 0.023053e0 * sin(g - el) + 0.007683e0 * sin(g + el) + 0.000097e0 * sin(g + g + el) - 0.000057e0 * t * sin(g - el) - 0.000032e0 * sin(g + g - el) - 0.000024e0 * cos(g - el - j) - 0.000019e0 * t * sin(g + el) - 0.000017e0 * cos(2.e0 * g + el - 2.e0 * v) + 0.000016e0 * sin(c) + 0.000013e0 * sin(c - 2.e0 * el) + 0.000011e0 * sin(4.e0 * g + el - 8.e0 * m + 3.e0 * j) + 0.000011e0 * sin(4.e0 * g - el - 8.e0 * m + 3.e0 * j) - 0.000011e0 * sin(g + el - v) + 0.000010e0 * sin(2.e0 * g + el - 2.e0 * v) - 0.000010e0 * sin(2.e0 * g - el - 2.e0 * j)
112 |
113 |
114 | z = 0.397825e0 * sin(el) + 0.009998e0 * sin(g - el) + 0.003332e0 * sin(g + el) + 0.000042e0 * sin(g + g + el) - 0.000025e0 * t * sin(g - el) - 0.000014e0 * sin(g + g - el) - 0.000010e0 * cos(g - el - j)
115 |
116 | #Precess_to new equator?
117 | if equinox is not None:
118 | x, y, z = precess_xyz(x, y, z, 1950, equinox)
119 |
120 | xvel = -0.017200e0 * sin(el) - 0.000288e0 * sin(g + el) - 0.000005e0 * sin(2.e0 * g + el) - 0.000004e0 * sin(c) + 0.000003e0 * sin(c - 2.e0 * el) + 0.000001e0 * t * sin(g + el) - 0.000001e0 * sin(2.e0 * g - el)
121 |
122 | yvel = 0.015780 * cos(el) + 0.000264 * cos(g + el) + 0.000005 * cos(2.e0 * g + el) + 0.000004 * cos(c) + 0.000003 * cos(c - 2.e0 * el) - 0.000001 * t * cos(g + el)
123 |
124 | zvel = 0.006843 * cos(el) + 0.000115 * cos(g + el) + 0.000002 * cos(2.e0 * g + el) + 0.000002 * cos(c) + 0.000001 * cos(c - 2.e0 * el)
125 |
126 | #Precess to new equator?
127 |
128 | if equinox is not None:
129 | xvel, yvel, zvel = precess_xyz(xvel, yvel, zvel, 1950, equinox)
130 |
131 | return x, y, z, xvel, yvel, zvel
132 |
133 |
--------------------------------------------------------------------------------
/utils/idlsave.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Copyright (C) 2009-2022 Sergey Koposov
3 | # This file is part of astrolibpy
4 | #
5 | # astrolibpy is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # astrolibpy is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with astrolibpy. If not, see .
17 | """
18 | To work with idlsave you need first to do
19 | from idlsave import idlsave
20 |
21 | Then you can save and restore the variables:
22 | > x=2
23 | > y=3
24 | > idlsave.save('xx.sav','x,y', x, y)
25 | OR
26 | > exec(idlsave.save('xx.sav','x,y'))
27 |
28 | To restore you need to do:
29 | > exec (idlsave.restore('xx.sav'))
30 |
31 | """
32 | from __future__ import print_function
33 | try:
34 | import cPickle as pickle
35 | except ImportError:
36 | import pickle
37 | import re
38 | import struct
39 |
40 |
41 | class idlsave:
42 | """ The class designed for saving and restoring python variables to
43 | files
44 | """
45 | dhash = {}
46 |
47 | def __init(self):
48 | pass
49 |
50 | @staticmethod
51 | def versionId(version):
52 | return 'IDLSAVE-v%04d' % version
53 |
54 | @staticmethod
55 | def parseVersion(s):
56 | m = re.match(r'IDLSAVE-v(\d\d\d\d)', s)
57 | if m is None:
58 | return 1
59 | else:
60 | return int(m.group(1))
61 |
62 | @staticmethod
63 | def __cureString(s):
64 | return s.replace('\n', '').replace(' ', '').replace('\t', '')
65 |
66 | @staticmethod
67 | def __splitString(s):
68 | return idlsave.__cureString(s).split(',')
69 |
70 | @staticmethod
71 | def save(filename=None, names=None, *args, **kw):
72 | """
73 | Saves your variable in a file, in such a way that you can easily
74 | retrieve them later.
75 | Example:
76 | > x = 2
77 | > y = [3,4,5]
78 | > idlsave.save("mydat.psav", 'x,y', x, y)
79 | or
80 | > exec(idlsave.save("myday.psav",'x,y'))
81 | Now you can leave python. You can later restore the x,y, variables
82 | using idlsave.restore
83 |
84 | Storage format for version 2 files is the following:
85 | The first 8 bytes store the offset of the pickled dictionary of
86 | offsets. The dictionary of offsets stores the
87 | offset of each pickled variable in the file.
88 | The keys in the dictionary are variable names.
89 | """
90 |
91 | if len(args) == 0:
92 | return "idlsave.save(\"%s\",\"%s\",%s)" % (
93 | filename, idlsave.__cureString(names), names)
94 |
95 | if isinstance(names, str):
96 | names = idlsave.__splitString(names)
97 | if len(names) != len(args):
98 | raise Exception("The number of variable names should \
99 | be equal to the number of variables)")
100 | f = open(filename, "wb")
101 | version = kw.get('version', 2)
102 | curhash = {}
103 | for a in range(len(names)):
104 | curhash[names[a]] = args[a]
105 | if 'protocol' not in kw:
106 | protocol = pickle.HIGHEST_PROTOCOL
107 | else:
108 | protocol = kw['protocol']
109 | if version == 1:
110 | pickle.dump(curhash, f, protocol)
111 | elif version == 2:
112 | f.write(idlsave.versionId(version).encode('ascii'))
113 | headlen1 = f.tell()
114 | f.write(struct.pack('!q', 0))
115 | offsets = dict([(name, 0) for name in names])
116 | for name in names:
117 | offsets[name] = f.tell()
118 | pickle.dump(curhash[name], f, protocol)
119 | offOffs = f.tell()
120 | pickle.dump(offsets, f, protocol)
121 | f.seek(headlen1)
122 | f.write(struct.pack('!q', offOffs))
123 | f.close()
124 | del curhash
125 | return None
126 |
127 | @staticmethod
128 | def restore(filename=None,
129 | names=None,
130 | asdict=False,
131 | version=None,
132 | printVars=False):
133 | """Restores the variables stored in a file by idlsave.save routine
134 | Example:
135 | > exec(idlsave.restore("mydat.psav"))
136 | Note that you MUST use this exact form exec(idlsave.restore(...))
137 | Or you can restore only the variables that you want:
138 | > ra, dec = idlsave.restore("mysav.psav", "ra,dec")
139 | """
140 | f = open(filename, "rb")
141 | vid = idlsave.versionId(1)
142 | try:
143 | prefix = f.read(len(vid)).decode('ascii')
144 | except: # noqa
145 | version = 1
146 | if version is None:
147 | version = idlsave.parseVersion(prefix)
148 | if version == 1:
149 | f.seek(0) # there is no header in the version1 files
150 |
151 | if version == 1:
152 | vard = pickle.load(f)
153 | idlsave.dhash = vard
154 | f.close()
155 | if names is None:
156 | if asdict:
157 | ret = idlsave.dhash.copy()
158 | del idlsave.dhash
159 | return ret
160 | buf = ",".join(idlsave.dhash.keys())
161 | if len(idlsave.dhash) == 1:
162 | buf = buf + ','
163 | buf = buf + \
164 | "=idlsave.getallvars(printVars=%s)" % (str(printVars))
165 | return buf
166 | else:
167 | names = idlsave.__splitString(names)
168 | res = [idlsave.dhash[a] for a in names]
169 | del idlsave.dhash
170 | return res
171 | elif version == 2:
172 | offOff = struct.unpack('!q', f.read(8))[0]
173 | f.seek(offOff)
174 | offsets = pickle.load(f)
175 | if names is None:
176 | names1 = offsets.keys()
177 | else:
178 | names1 = idlsave.__splitString(names)
179 | retd = {}
180 | for name in names1:
181 | off = offsets[name]
182 | try:
183 | f.seek(off)
184 | retd[name] = pickle.load(f)
185 | except UnicodeDecodeError:
186 | f.seek(off)
187 | retd[name] = pickle.load(f, encoding='latin1')
188 | f.close()
189 | if asdict:
190 | return retd
191 | if names is None:
192 | idlsave.dhash = retd
193 | buf = ",".join(idlsave.dhash.keys())
194 | if len(idlsave.dhash) == 1:
195 | buf = buf + ','
196 | buf = buf + "=idlsave.getallvars(%s)" % str(printVars)
197 | return buf # return the string for exec
198 | else:
199 | res = [retd[a] for a in names1]
200 | return res
201 |
202 | @staticmethod
203 | def getallvars(printVars=False):
204 | tup = tuple(a for a in idlsave.dhash.values())
205 | if printVars:
206 | print(','.join([k for k in idlsave.dhash.keys()]))
207 | del idlsave.dhash
208 | return tup
209 |
--------------------------------------------------------------------------------
/my_utils/crossmatcher.py:
--------------------------------------------------------------------------------
1 | import sqlutilpy
2 | import numpy as np
3 |
4 |
5 | def doit(tabname,
6 | ra,
7 | dec,
8 | colstring,
9 | radeccols=('ra', 'dec'),
10 | pmradeccols=('pmra', 'pmdec'),
11 | epoch=None,
12 | rad=1.,
13 | extra=None,
14 | epochcol=None,
15 | max_pm_offset=30,
16 | yourradeccols=('ra', 'dec'),
17 | yourepochcol='epoch',
18 | tab_alias='tt',
19 | host=None,
20 | port=None,
21 | db=None,
22 | user=None,
23 | password=None,
24 | asDict=False,
25 | conn=None,
26 | preamb=None):
27 | """
28 | Performs the nearest neighbor crossmatch within specified radius
29 | with the remote table the input is given by ra,dec columns
30 |
31 | Parameters:
32 | -----------
33 |
34 | tabname: string
35 | The name of the table to crossmatch against
36 | ra: numpy
37 | The numpy array with right ascension
38 | dec : numpy
39 | The numpy array with declinations
40 | colstring: string
41 | The comma sepated list of columns that you want to retrieve
42 | epoch: numpy (optional)
43 | If specified we try to use proper motions for the xmatch
44 | radeccols: tuple (optional)
45 | The tuple of two strings with the name of ra,dec columns in
46 | the remote table. Default ('ra','dec')
47 | pmradeccols: tuple (optional)
48 | The tuple of proper motion columns in the table
49 | epochcol: str
50 | The name of the column with epoch
51 | rad: float (optional)
52 | The cross-match radius in arcseconds (default 1)
53 | max_pm_offset: float (optional)
54 | The maximum offset in arcsec allowed. If proper motions
55 | are used
56 | extra: string allows you to specify and additional SQL Where condition
57 | tab_alias: string
58 | The alias for the table that you are crossmatching against, so you can
59 | refer to its columns
60 | host,port,db,user,password: string
61 | The connection parameters to the DB if needed
62 | asDict: bool
63 | if True instead of returning a tuple a dictionary is returned
64 | preamb: string (optional)
65 | additional commands to be executed before the query
66 | conn: connection object(optional)
67 | An explicit connection to the DB can be provided
68 |
69 | Example:
70 | --------
71 | > ra = np.arange(10)
72 | > dec = np.arange(10)+5
73 | > gmag,rmag= crossmatcher.doit('sdssdr9.phototag', ra,dec,
74 | 'psfmag_g,psfmag_r', rad=2.)
75 |
76 | """
77 | racol, deccol = radeccols
78 | if extra is None:
79 | extra = 'true'
80 | your_ra, your_dec = yourradeccols
81 | preamb = '' or preamb
82 | kw = dict(
83 | preamb=('set enable_seqscan to off;' + 'set enable_mergejoin to off;' +
84 | 'set enable_hashjoin to off;' + (preamb or '')),
85 | host=host,
86 | db=db,
87 | user=user,
88 | port=(port or 5432),
89 | password=password,
90 | asDict=asDict,
91 | conn=conn)
92 |
93 | if epoch is None:
94 | RES = sqlutilpy.local_join(
95 | str.format(
96 | """
97 | select {colstring} from
98 | ( select * from mytable order by
99 | q3c_ang2ipix({your_ra},{your_dec})
100 | ) as m
101 | left join lateral (select * from {tabname} as s where
102 | q3c_join(m.{your_ra}, m.{your_dec},
103 | s.{racol}, s.{deccol}, {rad}/3600.) and {extra}
104 | order by q3c_dist(m.{your_ra}, m.{your_dec},
105 | s.{racol},s.{deccol}) asc limit 1) as {tab_alias}
106 | on true order by xid """, **locals()), 'mytable',
107 | (ra, dec, np.arange(len(ra))), (your_ra, your_dec, 'xid'), **kw)
108 | else:
109 | try:
110 | nep = len(epoch)
111 | except TypeError:
112 | epoch = np.zeros(len(ra)) + epoch
113 | else:
114 | if nep != len(ra):
115 | raise Exception(
116 | 'length of the epoch must be equal to length of positions')
117 | maxap = max_pm_offset + rad
118 | pmracol, pmdeccol = pmradeccols
119 | dist_str = f'''q3c_dist_pm(
120 | s.{racol},s.{deccol}, s.{pmracol}, s.{pmdeccol}, 1,
121 | s.{epochcol}, m.{your_ra}, m.{your_dec},
122 | m.{yourepochcol})'''
123 | RES = sqlutilpy.local_join(
124 | str.format(
125 | """
126 | select {colstring} from
127 | ( select * from mytable order by
128 | q3c_ang2ipix({your_ra},{your_dec})
129 | ) as m
130 | left join lateral (select * from {tabname} as s where
131 | q3c_join(m.{your_ra}, m.{your_dec},
132 | s.{racol}, s.{deccol}, {maxap}/3600.) and {extra}
133 | and {dist_str}<{rad}/3600.
134 | order by {dist_str} asc limit 1) as {tab_alias}
135 | on true order by xid """,
136 | **locals()), 'mytable', (ra, dec, np.arange(len(ra)), epoch),
137 | (your_ra, your_dec, 'xid', yourepochcol), **kw)
138 |
139 | return RES
140 |
141 |
142 | def doit_by_key(tabname,
143 | keys,
144 | colstring,
145 | key_col=None,
146 | extra=None,
147 | yourkeycol='id',
148 | tab_alias='tt',
149 | host=None,
150 | port=None,
151 | db=None,
152 | user=None,
153 | password=None,
154 | asDict=False,
155 | conn=None,
156 | preamb=None):
157 | """
158 | Performs the crossmatch by id
159 | with the remote table
160 |
161 | Parameters:
162 | -----------
163 |
164 | tabname: string
165 | The name of the table to crossmatch against
166 | keys: numpy
167 | The numpy array with ids that will be used for matching
168 | colstring: string
169 | The comma sepated list of columns that you want to retrieve
170 | key_col: string
171 | The name of the column in the table used to xmatch (i.e. 'source_id')
172 | extra: string allows you to specify and additional SQL Where condition
173 | tab_alias: string
174 | The alias for the table that you are crossmatching against, so you can
175 | refer to its columns
176 | host,port,db,user,password: string
177 | The connection parameters to the DB if needed
178 | asDict: bool
179 | if True instead of returning a tuple a dictionary is returned
180 | preamb: string (optional)
181 | additional commands to be executed before the query
182 | conn: connection object(optional)
183 | An explicit connection to the DB can be provided
184 |
185 | Example:
186 | --------
187 | > ids = np.arange(10)
188 | > my_source_id = np.array([44,42323232])
189 | > rv,= crossmatcher.doit_by_key( "gaia_dr3.gaia_source",
190 | > my_source_id, 'radial_velocity' key_col='source_id')
191 | """
192 | if extra is None:
193 | extra = 'true'
194 | preamb = '' or preamb
195 | RES = sqlutilpy.local_join(str.format(
196 | """
197 | select {colstring}
198 | from mytable as m
199 | left join lateral
200 | (select * from {tabname} as s where m.id=s.{key_col}
201 | and {extra} limit 1) as {tab_alias}
202 | on true order by m.xid """, **locals()),
203 | 'mytable', (keys, np.arange(len(keys))),
204 | ('id', 'xid'),
205 | preamb=((preamb or '')),
206 | host=host,
207 | db=db,
208 | user=user,
209 | port=(port or 5432),
210 | password=password,
211 | asDict=asDict,
212 | conn=conn)
213 | return RES
214 |
--------------------------------------------------------------------------------
/my_utils/quick_hist.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2009-2010 Sergey Koposov
2 | # This file is part of astrolibpy
3 | #
4 | # astrolibpy is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # astrolibpy is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with astrolibpy. If not, see .
16 |
17 | from __future__ import print_function
18 | from functools import reduce
19 | import warnings
20 | import numpy as np
21 | import hashlib
22 | import importlib
23 | import os
24 |
25 |
26 | def _getcode():
27 | cdef = """
28 | void hister(
29 | double cur_range0,
30 | double cur_range1,
31 | int cur_nbins,
32 | int cur_mult,
33 | double *cur_arr,
34 | int64_t *poss,
35 | int64_t *ind,
36 | int nx);
37 |
38 | void adder_now(
39 | int64_t* res,
40 | int64_t* poss,
41 | int newlen);
42 |
43 | void adder_wei(
44 | double* res,
45 | int64_t* poss,
46 | double* weights,
47 | int newlen);
48 |
49 | """
50 |
51 | src = """
52 | static void hister(
53 | double cur_range0,
54 | double cur_range1,
55 | int cur_nbins,
56 | int cur_mult,
57 | double *cur_arr,
58 | int64_t *poss,
59 | int64_t *ind,
60 | int nx)
61 | {
62 | int64_t i, cur_pos;
63 | double curfac = cur_nbins * 1./ (cur_range1- cur_range0);
64 | for(i=0;i=0 ) && (cur_pos xs=np.random.uniform(size=100); ys= np.random.uniform(size=100)
134 | > hh = quick_hist((xs,ys), range=[(0,1),(0,1)], nbins=[20,10])
135 | Arguments:
136 | arr -- tuple of N-arrays
137 | range -- list of tuples of ranges
138 | nbins -- list of numbers of bins
139 | Keywords:
140 | weights -- weighting for the histogram
141 | getPos -- return the 1D vector of the positions within the histogram
142 | (-1 if the point is outside the range)
143 | """
144 | nd = len(arrs)
145 | if range is None:
146 | range = []
147 | for i in np.arange(nd):
148 | range.append((arrs[0].min(), arrs[0].max()))
149 | if nbins is None:
150 | nbins = [10] * nd
151 |
152 | if len(nbins) != nd:
153 | raise ValueError('The array of nbins MUST have the same length as the'
154 | 'number of input data vectors')
155 | if len(range) != nd:
156 | raise ValueError('The array of ranges MUST have the same length'
157 | 'as the number of input data vectors')
158 |
159 | nx = arrs[0].size
160 | for curarr in arrs:
161 | if (curarr.size) != nx:
162 | raise ValueError('All the input arrays MUST have the same length!')
163 | if weights is not None:
164 | if (weights.size) != nx:
165 | raise ValueError('The weights array MUST have the same length as'
166 | ' the input arrays')
167 | # convert all the bins into integers
168 | nbins = [int(_tmp) for _tmp in nbins]
169 |
170 | poss = np.zeros((nx, ), dtype=np.int64)
171 | ind = np.ones((nx, ), dtype=np.int64)
172 | nbins_rev = nbins + []
173 | nbins_rev.reverse()
174 | mults = (reduce(lambda x, y: x + [y * x[-1]], nbins_rev, [1]))[:-1]
175 | mults.reverse()
176 | assert (poss.flags['C_CONTIGUOUS'])
177 | assert (ind.flags['C_CONTIGUOUS'])
178 | slow = False
179 | modname = _getlibname()
180 |
181 | for i in np.arange(nd):
182 | cur_arr = np.ascontiguousarray(arrs[i], dtype=np.float64)
183 | cur_range0 = float(range[i][0])
184 | cur_range1 = float(range[i][1])
185 | cur_nbins = int(nbins[i])
186 | cur_mult = int(mults[i])
187 | try:
188 | try:
189 | M = importlib.import_module(modname)
190 | # from _quick_hist import ffi, lib
191 | except ModuleNotFoundError:
192 | _buildlib()
193 | M = importlib.import_module(modname)
194 | poss_ffi = M.ffi.cast('int64_t *', M.ffi.from_buffer(poss))
195 | ind_ffi = M.ffi.cast('int64_t *', M.ffi.from_buffer(ind))
196 | cur_arr_ffi = M.ffi.cast('double *', M.ffi.from_buffer(cur_arr))
197 |
198 | M.lib.hister(cur_range0, cur_range1, cur_nbins, cur_mult,
199 | cur_arr_ffi, poss_ffi, ind_ffi, nx)
200 | except: # noqa
201 | warnings.warn("Sorry the compiled version didn't work :(,"
202 | "executing a slower Python-only version.")
203 | slow = True
204 | cur_pos = (cur_arr - cur_range0) * (cur_nbins * 1. /
205 | (cur_range1 - cur_range0))
206 | cur_pos = np.floor(cur_pos).astype(np.int64)
207 | ind = ind * ((cur_pos >= 0) & (cur_pos < cur_nbins))
208 | poss += cur_pos * cur_mult
209 |
210 | ind = ind.astype(bool)
211 |
212 | poss = poss[ind]
213 | newlen = len(poss)
214 |
215 | nret = np.array(nbins, dtype=np.int64).prod()
216 |
217 | if weights is not None:
218 | res = np.zeros(nret, dtype=np.float64)
219 | weightsind = np.ascontiguousarray(weights[ind], dtype=np.float64)
220 | else:
221 | res = np.zeros(nret, dtype=np.int64)
222 |
223 | if not getPos:
224 | del ind
225 |
226 | assert (res.flags['C_CONTIGUOUS'])
227 | assert (poss.flags['C_CONTIGUOUS'])
228 |
229 | if not slow:
230 | poss_ffi = M.ffi.cast('int64_t *', M.ffi.from_buffer(poss))
231 |
232 | if weights is not None:
233 | weightsind_ffi = M.ffi.cast('double *',
234 | M.ffi.from_buffer(weightsind))
235 | res_ffi = M.ffi.cast('double *', M.ffi.from_buffer(res))
236 | M.lib.adder_wei(res_ffi, poss_ffi, weightsind_ffi, newlen)
237 | else:
238 | res_ffi = M.ffi.cast('int64_t *', M.ffi.from_buffer(res))
239 | M.lib.adder_now(res_ffi, poss_ffi, newlen)
240 | else:
241 | if weights is None:
242 | for i in np.arange(len(poss)):
243 | res[poss[i]] += 1
244 | else:
245 | for i in np.arange(len(poss)):
246 | res[poss[i]] += weightsind[i]
247 | if not getPos:
248 | return res.reshape(nbins)
249 | else:
250 | H = np.zeros(len(ind), dtype=np.int64) - 1
251 | H[ind] = poss
252 | return res.reshape(nbins), H
253 |
--------------------------------------------------------------------------------
/my_utils/adabinner.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2009-2010 Sergey Koposov
2 | # This file is part of astrolibpy
3 | #
4 | # astrolibpy is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # astrolibpy is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with astrolibpy. If not, see .
16 |
17 | import numpy.random, numpy, quick_hist, scipy.stats, random
18 |
19 | __doc__ = """
20 | Adaptive binner module
21 | Functions:
22 | hist:
23 | 1D adaptive histogram
24 | hist2d:
25 | 2D adaptive histogram
26 |
27 | """
28 |
29 |
30 | def __doit2d(x, y, hi1=None, hi2=None, thresh=None):
31 | hhs = {}
32 | for curhi in range(hi1, hi2 + 1):
33 | hh = quick_hist.quick_hist((x, y),
34 | range=((0, 1), (0, 1)),
35 | nbins=[2**curhi, 2**curhi])
36 | hhs[curhi] = hh
37 | pixcen = []
38 | hh0 = hhs[hi2] * 1 # accumulator of the result
39 | area = hh0 * 0
40 |
41 | two = 2
42 | poiss = scipy.stats.poisson(thresh)
43 |
44 | DeepenOrNot = lambda x: random.random() < poiss.cdf(x)
45 |
46 | def doitit(it, i, j):
47 | curhhs = hhs[it]
48 | if it == hi2:
49 | hh[i:i + 2, j:j + 2] = curhhs[i:i + 2, j:j + 2]
50 | area[i:i + 2, j:j + 2] = 2**(-it)
51 | pixcen.append((i + .5, j + .5))
52 | else:
53 | for ii in range(i, i + 2):
54 | for jj in range(j, j + 2):
55 | curval = curhhs[ii, jj]
56 | if DeepenOrNot(curval):
57 | doitit(it + 1, ii * two, jj * two)
58 | else:
59 | dx = 2**(hi2 - it)
60 | hh0[ii * dx:(ii + 1) * dx,
61 | jj * dx:(jj + 1) * dx] = curval
62 | area[ii * dx:(ii + 1) * dx,
63 | jj * dx:(jj + 1) * dx] = 2**(-it)
64 | pixcen.append(
65 | (ii * dx + dx / 2. + 0.5, jj * dx + dx / 2. + 0.5))
66 |
67 | n1 = 2**hi1
68 | dn = 2**(hi2 - hi1)
69 |
70 | for i in range(n1):
71 | for j in range(n1):
72 | if DeepenOrNot(hhs[hi1][i, j]):
73 | doitit(hi1 + 1, i * two, j * two)
74 | else:
75 | hh0[i * dn:(i + 1) * dn, j * dn:(j + 1) * dn] = hhs[hi1][i, j]
76 | area[i * dn:(i + 1) * dn, j * dn:(j + 1) * dn] = 2**(-hi1)
77 | pixcen.append((i * dn + dn / 2. + 0.5, j * dn + dn / 2. + 0.5))
78 | area = (2**hi1 * area)**2 # in smallest pixels squared
79 | return hh0 * 1. / area, pixcen, area
80 |
81 |
82 | def __doit1d(x, hi1=None, hi2=None, thresh=None):
83 | hhs = {}
84 | for curhi in range(hi1, hi2 + 1):
85 | hh = quick_hist.quick_hist((x, ), range=((0, 1), ), nbins=[2**curhi])
86 | hhs[curhi] = hh
87 |
88 | hh0 = hhs[hi2] * 1 # accumulator of the result
89 | area = hh0 * 0
90 |
91 | two = 2
92 | poiss = scipy.stats.poisson(thresh)
93 |
94 | DeepenOrNot = lambda x: random.random() < poiss.cdf(x)
95 |
96 | def doitit(it, i):
97 | curhhs = hhs[it]
98 | if it == hi2:
99 | hh[i:i + 2] = curhhs[i:i + 2]
100 | area[i:i + 2] = 2**(-it)
101 | else:
102 | for ii in range(i, i + 2):
103 | curval = curhhs[ii]
104 | if DeepenOrNot(curval):
105 | doitit(it + 1, ii * two)
106 | else:
107 | dx = 2**(hi2 - it)
108 | hh0[ii * dx:(ii + 1) * dx] = curval
109 | area[ii * dx:(ii + 1) * dx] = 2**(-it)
110 |
111 | n1 = 2**hi1
112 | dn = 2**(hi2 - hi1)
113 |
114 | for i in range(n1):
115 | if DeepenOrNot(hhs[hi1][i]):
116 | doitit(hi1 + 1, i * two)
117 | else:
118 | hh0[i * dn:(i + 1) * dn] = hhs[hi1][i]
119 | area[i * dn:(i + 1) * dn] = 2**(-hi1)
120 | return hh0 * 1. / (2**hi1 * area)
121 |
122 |
123 | def hist2d(x,
124 | y,
125 | xmin=None,
126 | xmax=None,
127 | ymin=None,
128 | ymax=None,
129 | hi=[2, 10],
130 | thresh=30,
131 | full_output=False):
132 | """
133 | This function does the 2D histogram with adaptive binning
134 | Example:
135 | >> hist2d(xs,ys, hi=[3,6], thresh=30)
136 | >> hh,xloc,yloc,pixcen,area = hist2d(xra,dec,full_output=True,thresh=100)
137 |
138 | Keyword parameters:
139 | ------------------
140 | hi
141 | the list of two integer values: they describe how coarse the
142 | largest bin and how fine is the smallest bin, e.g.
143 | [2,5] means the largest possible bin has a size
144 | of 1/2**2 of the your dataset and the smallest bin has a
145 | size of 1/2**5
146 | thresh
147 | the minimum number of points within a bin allowed (
148 | if the number is smaller than the threshold then further
149 | decreasing of the bin size is not allowed by the algorithm)
150 | xmin,xmax,ymin,ymax
151 | x-ranges and y-ranges. If not specified, they are determined
152 | from the x.min(),x.max(),y.min(),y.max()
153 | full_output
154 | Boolean controlling whether to output just just the histogram(full_output=False)
155 | or output the tuple with the histogram, grid-centers in x, grid-centers in y,
156 | pixel-centers, and area
157 | """
158 | xmin = x.min() if xmin is None else xmin
159 | ymin = y.min() if ymin is None else ymin
160 | xmax = x.max() if xmax is None else xmax
161 | ymax = y.max() if ymax is None else ymax
162 |
163 | xmod = (x - xmin) / (xmax - xmin)
164 | ymod = (y - ymin) / (ymax - ymin)
165 |
166 | ind = (xmod >= 0) & (xmod <= 1) & (ymod >= 0) & (ymod <= 1)
167 | hh, pixcen, area = __doit2d(xmod[ind],
168 | ymod[ind],
169 | hi1=hi[0],
170 | hi2=hi[1],
171 | thresh=thresh)
172 | xloc = numpy.linspace(xmin, xmax, hh.shape[0], False)
173 | yloc = numpy.linspace(ymin, ymax, hh.shape[0], False)
174 | xloc += 0.5 * (xloc[1] - xloc[0])
175 | yloc += 0.5 * (yloc[1] - yloc[0])
176 |
177 | if full_output:
178 | out = hh, xloc, yloc, pixcen, area
179 | else:
180 | out = hh
181 | return out
182 |
183 |
184 | def hist(x, xmin=None, xmax=None, hi=[2, 10], thresh=30):
185 | """
186 | This function does the 1D histogram with adaptive binning
187 | Example:
188 | >> loc, hh = hist(xs, hi=[3,6], thresh=30)
189 |
190 | Keyword parameters:
191 | ------------------
192 | hi
193 | the list of two integer values: they describe how coarse the
194 | largest bin and how fine is the smallest bin, e.g.
195 | [2,5] means the largest possible bin has a size
196 | of 1/2**2 of the your dataset and the smallest bin has a
197 | size of 1/2**5
198 | thresh
199 | the minimum number of points within a bin allowed (
200 | if the number is smaller than the threshold then further
201 | decreasing of the bin size is not allowed by the algorithm)
202 | xmin,xmax
203 | x-range. If not specified, they are determined
204 | from the x.min(),x.max()
205 | --------------------------------------------
206 | Returns:
207 | the histogram and the bin edges vector
208 | """
209 | xmin = x.min() if xmin is None else xmin
210 | xmax = x.max() if xmax is None else xmax
211 |
212 | xmod = (x - xmin) / (xmax - xmin)
213 |
214 | ind = (xmod >= 0) & (xmod <= 1)
215 | hh = __doit1d(xmod[ind], hi1=hi[0], hi2=hi[1], thresh=thresh)
216 | loc = numpy.linspace(xmin, xmax, len(hh) + 1, True)
217 | return hh, loc
218 |
--------------------------------------------------------------------------------
/my_utils/sky_plotter.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | import healpy
4 |
5 | # Flip factor for astronomical convention (flips the longitude direction)
6 | flip = -1
7 |
8 |
9 | class Formatter:
10 | """
11 | Formatter for displaying coordinates in the Mollweide projection.
12 | Converts longitude and latitude from radians to degrees and applies
13 | a shift in right ascension (RA).
14 | """
15 |
16 | def __init__(self, ra_shift=0):
17 | """
18 | Parameters
19 | ----------
20 | ra_shift : float
21 | Shift in right ascension (degrees).
22 | """
23 | self.ra_shift = ra_shift
24 |
25 | def __call__(self, lon, lat):
26 | """
27 | Format the coordinates for display.
28 |
29 | Parameters
30 | ----------
31 | lon : float
32 | Longitude in radians.
33 | lat : float
34 | Latitude in radians.
35 |
36 | Returns
37 | -------
38 | str
39 | Formatted string with longitude and latitude in degrees.
40 | """
41 | lon, lat = np.rad2deg([lon, lat])
42 | return '%f,%f' % (flip * lon + self.ra_shift, lat)
43 |
44 |
45 | class Info:
46 | """
47 | Container for storing additional information about the plot,
48 | such as the RA shift.
49 | """
50 |
51 | def __init__(self, ra_shift):
52 | """
53 | Parameters
54 | ----------
55 | ra_shift : float
56 | Shift in right ascension (degrees).
57 | """
58 | self.ra_shift = ra_shift
59 |
60 |
61 | def make_axes(ra_shift=None, dra_label=30, plot_grid=True, grid_linestyle=':'):
62 | """
63 | Create a Mollweide projection plot with customized RA labels.
64 |
65 | Parameters
66 | ----------
67 | ra_shift : float, optional
68 | Shift in right ascension (degrees). Default is 0.
69 | dra_label : int, optional
70 | Step size for RA labels (degrees). Default is 30.
71 | """
72 | if ra_shift is None:
73 | ra_shift = 0
74 | ax = plt.subplot(111, projection='mollweide')
75 |
76 | # Generate RA tick positions and labels
77 | xticks = np.arange(0, 360, dra_label)
78 | xticks_shift = (flip * xticks + ra_shift + 360 + 180) % 360 - 180
79 | xtick_labels = xticks.astype(int)
80 | xtick_labels = ['{:d}$^o$'.format(i) for i in xtick_labels]
81 |
82 | # Set RA ticks and labels
83 | plt.xticks(ticks=np.radians(xticks_shift), labels=xtick_labels, rotation=0)
84 | plt.grid(plot_grid, linestyle=grid_linestyle)
85 |
86 | # Set custom coordinate formatter
87 | ax.format_coord = Formatter(ra_shift)
88 |
89 | # Store additional information in the axes object
90 | ax._extra = Info(ra_shift)
91 |
92 |
93 | def _line_unwrapper(ra, dec):
94 | """
95 | Handle line wrapping at the edges of the Mollweide projection.
96 |
97 | Parameters
98 | ----------
99 | ra : array-like
100 | Right ascension (radians).
101 | dec : array-like
102 | Declination (radians).
103 |
104 | Returns
105 | -------
106 | tuple
107 | Arrays of RA and Dec with NaNs inserted to avoid wrapping.
108 | """
109 | dra = np.diff(ra)
110 | cross = np.abs(dra) > np.pi # Detect line crossings
111 | x1 = _insert_nans(ra, cross)
112 | y1 = _insert_nans(dec, cross)
113 | return x1, y1
114 |
115 |
116 | def _insert_nans(x, ind):
117 | """
118 | Insert NaNs into an array to handle discontinuities.
119 |
120 | Parameters
121 | ----------
122 | x : array-like
123 | Original 1D array.
124 | ind : array-like
125 | Boolean array indicating where to insert NaNs.
126 |
127 | Returns
128 | -------
129 | array
130 | New array with NaNs inserted.
131 | """
132 | N = len(x)
133 | num_nan = np.count_nonzero(ind) # Number of NaNs to insert
134 |
135 | # Create a new array with space for NaNs
136 | x1 = np.full(N + num_nan, np.nan, dtype=float)
137 |
138 | # Compute positions for original values
139 | shift_array = np.insert(np.cumsum(ind), 0, 0)
140 | positions = np.arange(N) + shift_array
141 |
142 | # Insert original values into the new array
143 | x1[positions] = x
144 |
145 | return x1
146 |
147 |
148 | def scatter(ra, dec, ra_shift=None, dra_label=30, overplot=False, **kwargs):
149 | """
150 | Scatter plot in Mollweide projection.
151 |
152 | Parameters
153 | ----------
154 | ra : array-like
155 | Right ascension (degrees).
156 | dec : array-like
157 | Declination (degrees).
158 | ra_shift : float, optional
159 | Shift in right ascension (degrees). Default is None.
160 | dra_label : int, optional
161 | Step size for RA labels (degrees). Default is 30.
162 | overplot : bool, optional
163 | If True, reuse the existing axes. Default is False.
164 | kwargs : dict
165 | Additional arguments passed to `plt.scatter`.
166 | """
167 | if not overplot:
168 | make_axes(ra_shift=ra_shift, dra_label=dra_label)
169 | else:
170 | ra_shift = plt.gca()._extra.ra_shift
171 |
172 | # Convert RA and Dec to radians and apply RA shift
173 | ra_rad = np.deg2rad(flip * np.asarray(ra) + ra_shift)
174 | ra_rad = (ra_rad + 11 * np.pi) % (2 *
175 | np.pi) - np.pi # Wrap RA to [-pi, pi]
176 | dec_rad = np.deg2rad(dec)
177 |
178 | # Plot the scatter points
179 | plt.scatter(ra_rad, dec_rad, **kwargs)
180 |
181 |
182 | def plot(ra, dec, ra_shift=None, dra_label=30, overplot=False, **kwargs):
183 | """
184 | Line plot in Mollweide projection.
185 |
186 | Parameters
187 | ----------
188 | ra : array-like
189 | Right ascension (degrees).
190 | dec : array-like
191 | Declination (degrees).
192 | ra_shift : float, optional
193 | Shift in right ascension (degrees). Default is None.
194 | dra_label : int, optional
195 | Step size for RA labels (degrees). Default is 30.
196 | overplot : bool, optional
197 | If True, reuse the existing axes. Default is False.
198 | kwargs : dict
199 | Additional arguments passed to `plt.plot`.
200 | """
201 | if not overplot:
202 | make_axes(ra_shift=ra_shift, dra_label=dra_label)
203 | ra_shift = ra_shift or 0
204 | else:
205 | ra_shift = plt.gca()._extra.ra_shift
206 |
207 | # Convert RA and Dec to radians and apply RA shift
208 | ra_rad = np.deg2rad(flip * np.asarray(ra) + ra_shift)
209 | ra_rad = (ra_rad + 11 * np.pi) % (2 *
210 | np.pi) - np.pi # Wrap RA to [-pi, pi]
211 | dec_rad = np.deg2rad(dec)
212 |
213 | # Handle line wrapping
214 | ra_rad1, dec_rad1 = _line_unwrapper(ra_rad, dec_rad)
215 |
216 | # Plot the line
217 | plt.plot(ra_rad1, dec_rad1, **kwargs)
218 |
219 |
220 | def hpx_show(im,
221 | ra_shift=None,
222 | overplot=False,
223 | nest=True,
224 | dra_label=30,
225 | pix_per_deg=10,
226 | **kwargs):
227 | """
228 | Plot a HEALPix array on a Mollweide projection.
229 |
230 | Parameters
231 | ----------
232 | im : ndarray
233 | HEALPix array (length 12 * nside^2).
234 | The assumption that the array is in the same coordinate
235 | system as the plot.
236 | ra_shift : float, optional
237 | Shift in right ascension (degrees). Default is None.
238 | overplot : bool, optional
239 | If True, reuse the existing axes. Default is False.
240 | nest : bool, optional
241 | If True, use nested HEALPix ordering. Default is True.
242 | pix_per_deg : float, optional
243 | Resolution of the plot (pixels per degree). Default is 10.
244 | kwargs : dict
245 | Additional arguments passed to `pcolormesh`.
246 |
247 | Returns
248 | -------
249 | QuadMesh
250 | The plotted HEALPix map.
251 | """
252 | if not overplot:
253 | make_axes(ra_shift=ra_shift, dra_label=dra_label)
254 | ra_shift = ra_shift or 0
255 | else:
256 | ra_shift = plt.gca()._extra.ra_shift
257 |
258 | # Generate a grid of longitude and latitude
259 | nlon = int(360 * pix_per_deg)
260 | nlat = int(180 * pix_per_deg)
261 | lon_rad = np.radians(np.linspace(-180, 180, nlon))
262 | lat_rad = np.radians(np.linspace(-90, 90, nlat))
263 | lon2d, lat2d = np.meshgrid(lon_rad, lat_rad)
264 |
265 | # Compute HEALPix pixel indices
266 | nside = int(round((len(im) / 12)**0.5))
267 | assert len(im) == 12 * nside**2
268 | hpx = healpy.ang2pix(nside,
269 | flip * (np.rad2deg(lon2d) - ra_shift),
270 | np.rad2deg(lat2d),
271 | lonlat=True,
272 | nest=nest)
273 |
274 | # Map HEALPix values to the grid
275 | arr = im[hpx]
276 |
277 | # Plot the HEALPix map
278 | ax = plt.gca()
279 | R = ax.pcolormesh(lon2d, lat2d, arr, **kwargs)
280 | return R
281 |
--------------------------------------------------------------------------------
/astrolib/bprecess.py:
--------------------------------------------------------------------------------
1 | from numpy import array, sqrt, zeros, sin, cos, arange, arcsin,\
2 | arctan2, transpose, concatenate, ndarray, pi, dot, deg2rad,\
3 | rad2deg
4 |
5 | def bprecess(ra0, dec0, mu_radec=None, parallax=None, rad_vel=None, epoch=None):
6 | """
7 | NAME:
8 | BPRECESS
9 | PURPOSE:
10 | Precess positions from J2000.0 (FK5) to B1950.0 (FK4)
11 | EXPLANATION:
12 | Calculates the mean place of a star at B1950.0 on the FK4 system from
13 | the mean place at J2000.0 on the FK5 system.
14 |
15 | CALLING SEQUENCE:
16 | bprecess, ra, dec, ra_1950, dec_1950, [ MU_RADEC = , PARALLAX =
17 | RAD_VEL =, EPOCH = ]
18 |
19 | INPUTS:
20 | RA,DEC - Input J2000 right ascension and declination in *degrees*.
21 | Scalar or N element vector
22 |
23 | OUTPUTS:
24 | RA_1950, DEC_1950 - The corresponding B1950 right ascension and
25 | declination in *degrees*. Same number of elements as
26 | RA,DEC but always double precision.
27 |
28 | OPTIONAL INPUT-OUTPUT KEYWORDS
29 | MU_RADEC - 2xN element double precision vector containing the proper
30 | motion in seconds of arc per tropical *century* in right
31 | ascension and declination.
32 | PARALLAX - N_element vector giving stellar parallax (seconds of arc)
33 | RAD_VEL - N_element vector giving radial velocity in km/s
34 |
35 | The values of MU_RADEC, PARALLAX, and RADVEL will all be modified
36 | upon output to contain the values of these quantities in the
37 | B1950 system. The parallax and radial velocity will have a very
38 | minor influence on the B1950 position.
39 |
40 | EPOCH - scalar giving epoch of original observations, default 2000.0d
41 | This keyword value is only used if the MU_RADEC keyword is not set.
42 | NOTES:
43 | The algorithm is taken from the Explanatory Supplement to the
44 | Astronomical Almanac 1992, page 186.
45 | Also see Aoki et al (1983), A&A, 128,263
46 |
47 | BPRECESS distinguishes between the following two cases:
48 | (1) The proper motion is known and non-zero
49 | (2) the proper motion is unknown or known to be exactly zero (i.e.
50 | extragalactic radio sources). In this case, the reverse of
51 | the algorithm in Appendix 2 of Aoki et al. (1983) is used to
52 | ensure that the output proper motion is exactly zero. Better
53 | precision can be achieved in this case by inputting the EPOCH
54 | of the original observations.
55 |
56 | The error in using the IDL procedure PRECESS for converting between
57 | B1950 and J1950 can be up to 12", mainly in right ascension. If
58 | better accuracy than this is needed then BPRECESS should be used.
59 |
60 | An unsystematic comparison of BPRECESS with the IPAC precession
61 | routine (http://nedwww.ipac.caltech.edu/forms/calculator.html) always
62 | gives differences less than 0.15".
63 | EXAMPLE:
64 | The SAO2000 catalogue gives the J2000 position and proper motion for
65 | the star HD 119288. Find the B1950 position.
66 |
67 | RA(2000) = 13h 42m 12.740s Dec(2000) = 8d 23' 17.69''
68 | Mu(RA) = -.0257 s/yr Mu(Dec) = -.090 ''/yr
69 |
70 | IDL> mu_radec = 100D* [ -15D*.0257, -0.090 ]
71 | IDL> ra = ten(13, 42, 12.740)*15.D
72 | IDL> dec = ten(8, 23, 17.69)
73 | IDL> bprecess, ra, dec, ra1950, dec1950, mu_radec = mu_radec
74 | IDL> print, adstring(ra1950, dec1950,2)
75 | ===> 13h 39m 44.526s +08d 38' 28.63"
76 |
77 | REVISION HISTORY:
78 | Written, W. Landsman October, 1992
79 | Vectorized, W. Landsman February, 1994
80 | Treat case where proper motion not known or exactly zero November 1994
81 | Handling of arrays larger than 32767 Lars L. Christensen, march, 1995
82 | Converted to IDL V5.0 W. Landsman September 1997
83 | Fixed bug where A term not initialized for vector input
84 | W. Landsman February 2000
85 | Converted to python Sergey Koposov july 2010
86 | """
87 |
88 | scal = True
89 | if isinstance(ra0, ndarray):
90 | ra = ra0
91 | dec = dec0
92 | n = ra.size
93 | scal = False
94 | else:
95 | n = 1
96 | ra = array([ra0])
97 | dec = array([dec0])
98 |
99 | if rad_vel is None:
100 | rad_vel = zeros(n)
101 | else:
102 | if not isinstance(rad_vel, ndarray):
103 | rad_vel = array([rad_vel],dtype=float)
104 | if rad_vel.size != n:
105 | raise Exception('ERROR - RAD_VEL keyword vector must be of the same length as RA and DEC')
106 |
107 | if (mu_radec is not None):
108 | if (array(mu_radec).size != 2 * n):
109 | raise Exception('ERROR - MU_RADEC keyword (proper motion) be dimensioned (2,' + strtrim(n, 2) + ')')
110 | mu_radec = mu_radec * 1.
111 |
112 | if parallax is None:
113 | parallax = zeros(n)
114 | else:
115 | if not isinstance(parallax, ndarray):
116 | parallax = array([parallax],dtype=float)
117 |
118 | if epoch is None:
119 | epoch = 2000.0e0
120 |
121 | radeg = 180.e0 / pi
122 | sec_to_radian = lambda x : deg2rad(x/3600.)
123 |
124 | m = array([array([+0.9999256795e0, -0.0111814828e0, -0.0048590040e0, -0.000551e0, -0.238560e0, +0.435730e0]),
125 | array([+0.0111814828e0, +0.9999374849e0, -0.0000271557e0, +0.238509e0, -0.002667e0, -0.008541e0]),
126 | array([+0.0048590039e0, -0.0000271771e0, +0.9999881946e0, -0.435614e0, +0.012254e0, +0.002117e0]),
127 | array([-0.00000242389840e0, +0.00000002710544e0, +0.00000001177742e0, +0.99990432e0, -0.01118145e0, -0.00485852e0]),
128 | array([-0.00000002710544e0, -0.00000242392702e0, +0.00000000006585e0, +0.01118145e0, +0.99991613e0, -0.00002716e0]),
129 | array([-0.00000001177742e0, +0.00000000006585e0, -0.00000242404995e0, +0.00485852e0, -0.00002717e0, +0.99996684e0])])
130 |
131 | a_dot = 1e-3 * array([1.244e0, -1.579e0, -0.660e0]) #in arc seconds per century
132 |
133 | ra_rad = deg2rad(ra)
134 | dec_rad = deg2rad(dec)
135 | cosra = cos(ra_rad)
136 | sinra = sin(ra_rad)
137 | cosdec = cos(dec_rad)
138 | sindec = sin(dec_rad)
139 |
140 | dec_1950 = dec * 0.
141 | ra_1950 = ra * 0.
142 |
143 | for i in range(n):
144 |
145 | # Following statement moved inside loop in Feb 2000.
146 | a = 1e-6 * array([-1.62557e0, -0.31919e0, -0.13843e0]) #in radians
147 |
148 | r0 = array([cosra[i] * cosdec[i], sinra[i] * cosdec[i], sindec[i]])
149 |
150 | if (mu_radec is not None):
151 |
152 | mu_a = mu_radec[i,0]
153 | mu_d = mu_radec[i,1]
154 | r0_dot = array([-mu_a * sinra[i] * cosdec[i] - mu_d * cosra[i] * sindec[i], mu_a * cosra[i] * cosdec[i] - mu_d * sinra[i] * sindec[i], mu_d * cosdec[i]]) + 21.095e0 * rad_vel[i] * parallax[i] * r0
155 |
156 | else:
157 | r0_dot = array([0.0e0, 0.0e0, 0.0e0])
158 |
159 | r_0 = concatenate((r0, r0_dot))
160 | r_1 = transpose(dot(transpose(m), transpose(r_0)))
161 |
162 | # Include the effects of the E-terms of aberration to form r and r_dot.
163 |
164 | r1 = r_1[0:3]
165 | r1_dot = r_1[3:6]
166 |
167 | if mu_radec is None:
168 | r1 = r1 + sec_to_radian ( r1_dot * (epoch - 1950.0e0) / 100. )
169 | a = a + sec_to_radian ( a_dot * (epoch - 1950.0e0) / 100. )
170 |
171 | x1 = r_1[0] ; y1 = r_1[1] ; z1 = r_1[2]
172 | rmag = sqrt(x1 ** 2 + y1 ** 2 + z1 ** 2)
173 |
174 |
175 | s1 = r1 / rmag ; s1_dot = r1_dot / rmag
176 |
177 | s = s1
178 | for j in arange(0, 3):
179 | r = s1 + a - ((s * a).sum()) * s
180 | s = r / rmag
181 | x = r[0] ; y = r[1] ; z = r[2]
182 | r2 = x ** 2 + y ** 2 + z ** 2
183 | rmag = sqrt(r2)
184 |
185 | if mu_radec is not None:
186 | r_dot = s1_dot + a_dot - ((s * a_dot).sum()) * s
187 | x_dot = r_dot[0] ; y_dot = r_dot[1] ; z_dot = r_dot[2]
188 | mu_radec[i,0] = (x * y_dot - y * x_dot) / (x ** 2 + y ** 2)
189 | mu_radec[i,1] = (z_dot * (x ** 2 + y ** 2) - z * (x * x_dot + y * y_dot)) / (r2 * sqrt(x ** 2 + y ** 2))
190 |
191 | dec_1950[i] = arcsin(z / rmag)
192 | ra_1950[i] = arctan2(y, x)
193 |
194 | if parallax[i] > 0.:
195 | rad_vel[i] = (x * x_dot + y * y_dot + z * z_dot) / (21.095 * parallax[i] * rmag)
196 | parallax[i] = parallax[i] / rmag
197 |
198 | neg = (ra_1950 < 0)
199 | if neg.any() > 0:
200 | ra_1950[neg] = ra_1950[neg] + 2.e0 * pi
201 |
202 | ra_1950 = rad2deg(ra_1950)
203 | dec_1950 = rad2deg(dec_1950)
204 |
205 | # Make output scalar if input was scalar
206 | if scal:
207 | return ra_1950[0],dec_1950[0]
208 | else:
209 | return ra_1950, dec_1950
210 |
211 |
--------------------------------------------------------------------------------
/my_utils/correct_pm.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import astropy.coordinates as acoo
3 | import astropy.units as auni
4 |
5 | # Use v4.0 defaults
6 | GCPARAMS = acoo.galactocentric_frame_defaults.get_from_registry(
7 | "v4.0")['parameters']
8 |
9 | kms = auni.km / auni.s
10 | masyr = auni.mas / auni.year
11 | kpc = auni.kpc
12 |
13 | # --- Pre-calculate constants and solar velocity vector ---
14 |
15 | # Conversion factor: (km/s) / (kpc * mas/yr)
16 | # k_masyr_kpc = (kms / (kpc * masyr)).to_value(1) # ~4.74047
17 | k_masyr_kpc = 4.740470463498976
18 |
19 | # Get the Sun's velocity vector relative to the GC in Galactocentric Cartesian
20 | # coordinates (U, V, W)
21 | v_sun_gal_xyz = GCPARAMS['galcen_v_sun'].get_d_xyz().to_value(
22 | kms) # [U, V, W] in km/s
23 |
24 |
25 | # We need the Sun's velocity vector expressed in ICRS Cartesian coordinates
26 | # (vx, vy, vz).
27 | # The original Astropy code effectively calculates the apparent motion seen
28 | # by the Sun
29 | # due to an object at rest in the Galactocentric frame. This corresponds to
30 | # transforming the *negative* of the Sun's velocity vector (-U, -V, -W) from
31 | # the Galactocentric frame to the ICRS frame.
32 | # We can get this precise vector by performing the Astropy calculation once.
33 | def _get_apparent_solar_velocity_icrs(params):
34 | """
35 | Helper to get the ICRS velocity vector corresponding to solar motion
36 | relative to the GC frame origin, consistent with the original code's logic.
37 | """
38 | # Use a dummy coordinate transformation
39 | # A point at rest (0 velocity) in Galactocentric frame
40 | gc_rest = acoo.Galactocentric(
41 | x=0 * kpc,
42 | y=0 * kpc,
43 | z=0 * kpc, # Position doesn't affect velocity transform
44 | v_x=0 * kms,
45 | v_y=0 * kms,
46 | v_z=0 * kms,
47 | **params) # Pass GCPARAMS for frame definition
48 | # Transform this point *to* ICRS. Its velocity in ICRS represents the
49 | # apparent velocity induced by the Sun's motion relative to the GC frame.
50 | icrs_apparent = gc_rest.transform_to(acoo.ICRS())
51 | # Return the Cartesian velocity components in ICRS
52 | return icrs_apparent.velocity.d_xyz.to_value(kms)
53 |
54 |
55 | # Calculate this vector once using the specified GCPARAMS
56 | V_APPARENT_XYZ_ICRS = _get_apparent_solar_velocity_icrs(GCPARAMS)
57 | vx, vy, vz = V_APPARENT_XYZ_ICRS # km/s
58 |
59 |
60 | def correct_vel(ra, dec, vel, vlsr=None):
61 | """
62 | Corrects the radial velocity for the speed of the Sun using direct
63 | calculation.
64 |
65 | Arguments:
66 | ra - RA in deg (array or scalar)
67 | dec -- Declination in deg (array or scalar)
68 | vel -- heliocentric rv in km/s (array or scalar)
69 | vlsr (optional) -- ignored, kept for interface compatibility
70 | split (optional) -- ignored, calculations are vectorized
71 |
72 | Returns:
73 | radial velocity corrected for solar reflex motion (km/s)
74 | """
75 | if vlsr is not None:
76 | print('WARNING vlsr is ignored')
77 |
78 | # Ensure inputs are numpy arrays for vectorized operations
79 | is_scalar = np.isscalar(ra) and np.isscalar(dec) and np.isscalar(vel)
80 | ra = np.atleast_1d(ra)
81 | dec = np.atleast_1d(dec)
82 | vel = np.atleast_1d(vel)
83 |
84 | # Convert angles to radians
85 | ra_rad = np.deg2rad(ra)
86 | dec_rad = np.deg2rad(dec)
87 |
88 | # Calculate unit vector components in line-of-sight direction (p_hat)
89 | cos_dec = np.cos(dec_rad)
90 | sin_dec = np.sin(dec_rad)
91 | del dec_rad
92 | cos_ra = np.cos(ra_rad)
93 | sin_ra = np.sin(ra_rad)
94 | del ra_rad
95 | # Unit vector p_hat = (cos(dec)cos(ra), cos(dec)sin(ra), sin(dec))
96 | px = cos_dec * cos_ra
97 | py = cos_dec * sin_ra
98 | pz = sin_dec
99 | del cos_dec, sin_dec, cos_ra, sin_ra
100 | # Project apparent solar velocity (V_APPARENT_XYZ_ICRS) onto the line
101 | # of sight (p_hat)
102 | # This gives the radial velocity component *caused* by solar motion
103 | # (like C1.rv in original)
104 | # delta_rv = vx * px + vy * py + vz * pz # km/s
105 | # Use einsum for potentially better performance/clarity with large arrays
106 | delta_rv = np.dot(V_APPARENT_XYZ_ICRS,
107 | np.stack([px, py, pz], axis=0)) # CORRECTED using np.dot
108 | # Corrected velocity = Observed velocity - component due to Sun's motion
109 | corrected_vel = vel - delta_rv
110 |
111 | # Return scalar if input was scalar
112 | if is_scalar:
113 | return corrected_vel.item()
114 | return corrected_vel
115 |
116 |
117 | def correct_pm(ra, dec, pmra, pmdec, dist, vlsr=None):
118 | """
119 | Corrects the proper motion for the speed of the Sun using direct
120 | calculation.
121 |
122 | Arguments:
123 | ra - RA in deg (array or scalar)
124 | dec -- Declination in deg (array or scalar)
125 | pmra -- pm in RA in mas/yr (with cosine term) (array or scalar)
126 | pmdec -- pm in declination in mas/yr (array or scalar)
127 | dist -- distance in kpc (array or scalar)
128 | split (optional) -- ignored, calculations are vectorized
129 | vlsr (optional) -- ignored, kept for interface compatibility
130 |
131 | Returns:
132 | (pmra, pmdec) tuple with proper motions corrected for Sun's motion
133 | (mas/yr)
134 | """
135 | if vlsr is not None:
136 | print('WARNING vlsr is ignored')
137 |
138 | # Ensure inputs are numpy arrays
139 | is_scalar = (np.isscalar(ra) and np.isscalar(dec) and np.isscalar(pmra)
140 | and np.isscalar(pmdec) and np.isscalar(dist))
141 | ra = np.atleast_1d(ra)
142 | dec = np.atleast_1d(dec)
143 | pmra = np.atleast_1d(pmra)
144 | pmdec = np.atleast_1d(pmdec)
145 | dist = np.atleast_1d(dist)
146 |
147 | # Handle case where dist is scalar but others are arrays
148 | if dist.size == 1 and ra.size > 1:
149 | dist = np.full_like(ra, dist.item())
150 | elif dist.size != ra.size:
151 | raise ValueError("Shape mismatch between coordinates and distance")
152 |
153 | # Convert angles to radians
154 | ra_rad = np.deg2rad(ra)
155 | dec_rad = np.deg2rad(dec)
156 |
157 | # Calculate unit vector components for RA and Dec directions
158 | sin_ra = np.sin(ra_rad)
159 | cos_ra = np.cos(ra_rad)
160 | sin_dec = np.sin(dec_rad)
161 | cos_dec = np.cos(dec_rad)
162 | del ra_rad, dec_rad
163 | # RA direction unit vector (ra_hat = (-sin(ra), cos(ra), 0))
164 | ra_hat_x = -sin_ra
165 | ra_hat_y = cos_ra
166 | ra_hat_z = np.zeros_like(sin_ra) # Explicitly zero for clarity
167 |
168 | # Dec direction unit vector
169 | # (dec_hat = (-sin(dec)cos(ra), -sin(dec)sin(ra), cos(dec)))
170 | dec_hat_x = -sin_dec * cos_ra
171 | dec_hat_y = -sin_dec * sin_ra
172 | dec_hat_z = cos_dec
173 | del sin_ra, cos_ra, cos_dec, sin_dec
174 | # Project apparent solar velocity (V_APPARENT_XYZ_ICRS) onto RA
175 | # and Dec directions
176 | # This gives the tangential velocity components *caused* by solar motion
177 | # v_ra = vx * ra_hat_x + vy * ra_hat_y + vz * ra_hat_z
178 | # v_dec = vx * dec_hat_x + vy * dec_hat_y + vz * dec_hat_z
179 | v_ra = np.dot(V_APPARENT_XYZ_ICRS,
180 | np.stack([ra_hat_x, ra_hat_y, ra_hat_z],
181 | axis=0)) # CORRECTED using np.dot
182 | v_dec = np.dot(V_APPARENT_XYZ_ICRS,
183 | np.stack([dec_hat_x, dec_hat_y, dec_hat_z],
184 | axis=0)) # CORRECTED using np.dot
185 | # Convert tangential velocities (km/s) to proper motions (mas/yr)
186 | # delta_pm = v_tangential / (distance_kpc * k_masyr_kpc)
187 | # Avoid division by zero or very small distances if necessary
188 | with np.errstate(divide='ignore',
189 | invalid='ignore'): # Suppress warnings for dist=0
190 | delta_pmra_cosdec = v_ra / (dist * k_masyr_kpc) # mas/yr
191 | delta_pmdec = v_dec / (dist * k_masyr_kpc) # mas/yr
192 |
193 | # Handle potential NaNs/Infs resulting from dist=0 or very small dist
194 | delta_pmra_cosdec[~np.isfinite(delta_pmra_cosdec
195 | )] = np.nan # Or np.nan if preferred
196 | delta_pmdec[~np.isfinite(delta_pmdec
197 | )] = np.nan # Or np.nan if preferred
198 |
199 | # Corrected PM = Observed PM - component due to Sun's motion
200 | corrected_pmra = pmra - delta_pmra_cosdec
201 | corrected_pmdec = pmdec - delta_pmdec
202 |
203 | # Return scalars if input was scalar
204 | if is_scalar:
205 | return corrected_pmra.item(), corrected_pmdec.item()
206 | return corrected_pmra, corrected_pmdec
207 |
208 |
209 | # --- Example Usage and Comparison (Optional) ---
210 | if __name__ == "__main__":
211 | # Import original functions for comparison
212 | from correct_pm import correct_pm as correct_pm_orig
213 | from correct_pm import correct_vel as correct_vel_orig
214 |
215 | # Sample Data (e.g., 5 stars)
216 | N_stars = 5000
217 | ra_deg = np.random.uniform(0, 360, N_stars)
218 | dec_deg = np.random.uniform(-90, 90, N_stars)
219 | pmra_masyr = np.random.normal(0, 5, N_stars) # pm_ra * cos(dec)
220 | pmdec_masyr = np.random.normal(0, 5, N_stars)
221 | dist_kpc = np.random.uniform(0.1, 10, N_stars)
222 | vel_kms = np.random.normal(0, 50, N_stars)
223 |
224 | # --- Test Velocity Correction ---
225 | print("--- Velocity Correction Test ---")
226 | corrected_vel_orig = correct_vel_orig(ra_deg, dec_deg, vel_kms)
227 | corrected_vel_fast = correct_vel(ra_deg, dec_deg, vel_kms)
228 |
229 | print("Original Astropy Corrected Vel:", corrected_vel_orig)
230 | print("Fast Numpy Corrected Vel: ", corrected_vel_fast)
231 | print("Difference:", corrected_vel_orig - corrected_vel_fast)
232 | print("Max absolute difference:",
233 | np.max(np.abs(corrected_vel_orig - corrected_vel_fast)))
234 |
235 | # --- Test Proper Motion Correction ---
236 | print("\n--- Proper Motion Correction Test ---")
237 | pmra_corr_orig, pmdec_corr_orig = correct_pm_orig(ra_deg, dec_deg,
238 | pmra_masyr, pmdec_masyr,
239 | dist_kpc)
240 | pmra_corr_fast, pmdec_corr_fast = correct_pm(ra_deg, dec_deg, pmra_masyr,
241 | pmdec_masyr, dist_kpc)
242 |
243 | print("Original Astropy Corrected PMRA:", pmra_corr_orig)
244 | print("Fast Numpy Corrected PMRA: ", pmra_corr_fast)
245 | print("Difference PMRA:", pmra_corr_orig - pmra_corr_fast)
246 | print("Max absolute difference PMRA:",
247 | np.max(np.abs(pmra_corr_orig - pmra_corr_fast)))
248 |
249 | print("\nOriginal Astropy Corrected PMDEC:", pmdec_corr_orig)
250 | print("Fast Numpy Corrected PMDEC: ", pmdec_corr_fast)
251 | print("Difference PMDEC:", pmdec_corr_orig - pmdec_corr_fast)
252 | print("Max absolute difference PMDEC:",
253 | np.max(np.abs(pmdec_corr_orig - pmdec_corr_fast)))
254 |
255 | # --- Test Scalar Input ---
256 | print("\n--- Scalar Input Test ---")
257 | ra_s, dec_s, pmra_s, pmdec_s, dist_s, vel_s = ra_deg[0], dec_deg[
258 | 0], pmra_masyr[0], pmdec_masyr[0], dist_kpc[0], vel_kms[0]
259 |
260 | vel_orig_s = correct_vel_orig(ra_s, dec_s, vel_s)
261 | vel_fast_s = correct_vel(ra_s, dec_s, vel_s)
262 | print(f"Scalar Vel Orig: {vel_orig_s:.5f}, Fast: {vel_fast_s:.5f},"
263 | f"Diff: {vel_orig_s - vel_fast_s:.2e}")
264 |
265 | pm_orig_s = correct_pm_orig(ra_s, dec_s, pmra_s, pmdec_s, dist_s)
266 | pm_fast_s = correct_pm(ra_s, dec_s, pmra_s, pmdec_s, dist_s)
267 | print(f"Scalar PMRA Orig: {pm_orig_s[0]:.5f}, Fast: {pm_fast_s[0]:.5f},"
268 | f" Diff: {pm_orig_s[0] - pm_fast_s[0]:.2e}")
269 | print(f"Scalar PMDEC Orig: {pm_orig_s[1]:.5f}, Fast: {pm_fast_s[1]:.5f},"
270 | f" Diff: {pm_orig_s[1] - pm_fast_s[1]:.2e}")
271 |
272 | # --- Test Scalar Input2 ---
273 | print("\n--- Scalar Input Test ---")
274 | ra_s, dec_s, pmra_s, pmdec_s, dist_s, vel_s = ra_deg[0], dec_deg[
275 | 0], pmra_masyr[0], pmdec_masyr[0], dist_kpc[0], vel_kms[0]
276 |
277 | pmra_corr_orig, pmdec_corr_orig = correct_pm_orig(ra_deg, dec_deg,
278 | pmra_masyr, pmdec_masyr,
279 | dist_s)
280 | pmra_corr_fast, pmdec_corr_fast = correct_pm(ra_deg, dec_deg, pmra_masyr,
281 | pmdec_masyr, dist_s)
282 | print("Original Astropy Corrected PMRA:", pmra_corr_orig)
283 | print("Fast Numpy Corrected PMRA: ", pmra_corr_fast)
284 | print("Difference PMRA:", pmra_corr_orig - pmra_corr_fast)
285 | print("Max absolute difference PMRA:",
286 | np.max(np.abs(pmra_corr_orig - pmra_corr_fast)))
287 |
288 | print("\nOriginal Astropy Corrected PMDEC:", pmdec_corr_orig)
289 | print("Fast Numpy Corrected PMDEC: ", pmdec_corr_fast)
290 | print("Difference PMDEC:", pmdec_corr_orig - pmdec_corr_fast)
291 | print("Max absolute difference PMDEC:",
292 | np.max(np.abs(pmdec_corr_orig - pmdec_corr_fast)))
293 |
--------------------------------------------------------------------------------
/astrolib/baryvel.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from numpy import sin, cos, array, reshape, transpose, dot, pi, sqrt
3 | from premat import premat
4 | def baryvel(dje, deq=0):
5 | """
6 | NAME:
7 | BARYVEL
8 | PURPOSE:
9 | Calculates heliocentric and barycentric velocity components of Earth.
10 |
11 | EXPLANATION:
12 | BARYVEL takes into account the Earth-Moon motion, and is useful for
13 | radial velocity work to an accuracy of ~1 m/s.
14 |
15 | CALLING SEQUENCE:
16 | dvel_hel, dvel_bary = baryvel(dje, deq)
17 |
18 | INPUTS:
19 | DJE - (scalar) Julian ephemeris date.
20 | DEQ - (scalar) epoch of mean equinox of dvelh and dvelb. If deq=0
21 | then deq is assumed to be equal to dje.
22 | OUTPUTS:
23 | DVELH: (vector(3)) heliocentric velocity component. in km/s
24 | DVELB: (vector(3)) barycentric velocity component. in km/s
25 |
26 | The 3-vectors DVELH and DVELB are given in a right-handed coordinate
27 | system with the +X axis toward the Vernal Equinox, and +Z axis
28 | toward the celestial pole.
29 |
30 | OPTIONAL KEYWORD SET:
31 | JPL - if /JPL set, then BARYVEL will call the procedure JPLEPHINTERP
32 | to compute the Earth velocity using the full JPL ephemeris.
33 | The JPL ephemeris FITS file JPLEPH.405 must exist in either the
34 | current directory, or in the directory specified by the
35 | environment variable ASTRO_DATA. Alternatively, the JPL keyword
36 | can be set to the full path and name of the ephemeris file.
37 | A copy of the JPL ephemeris FITS file is available in
38 | http://idlastro.gsfc.nasa.gov/ftp/data/
39 | PROCEDURES CALLED:
40 | Function PREMAT() -- computes precession matrix
41 | JPLEPHREAD, JPLEPHINTERP, TDB2TDT - if /JPL keyword is set
42 | NOTES:
43 | Algorithm taken from FORTRAN program of Stumpff (1980, A&A Suppl, 41,1)
44 | Stumpf claimed an accuracy of 42 cm/s for the velocity. A
45 | comparison with the JPL FORTRAN planetary ephemeris program PLEPH
46 | found agreement to within about 65 cm/s between 1986 and 1994
47 |
48 | If /JPL is set (using JPLEPH.405 ephemeris file) then velocities are
49 | given in the ICRS system; otherwise in the FK4 system.
50 | EXAMPLE:
51 | Compute the radial velocity of the Earth toward Altair on 15-Feb-1994
52 | using both the original Stumpf algorithm and the JPL ephemeris
53 |
54 | IDL> jdcnv, 1994, 2, 15, 0, jd ;==> JD = 2449398.5
55 | IDL> baryvel, jd, 2000, vh, vb ;Original algorithm
56 | ==> vh = [-17.07243, -22.81121, -9.889315] ;Heliocentric km/s
57 | ==> vb = [-17.08083, -22.80471, -9.886582] ;Barycentric km/s
58 | IDL> baryvel, jd, 2000, vh, vb, /jpl ;JPL ephemeris
59 | ==> vh = [-17.07236, -22.81126, -9.889419] ;Heliocentric km/s
60 | ==> vb = [-17.08083, -22.80484, -9.886409] ;Barycentric km/s
61 |
62 | IDL> ra = ten(19,50,46.77)*15/!RADEG ;RA in radians
63 | IDL> dec = ten(08,52,3.5)/!RADEG ;Dec in radians
64 | IDL> v = vb[0]*cos(dec)*cos(ra) + $ ;Project velocity toward star
65 | vb[1]*cos(dec)*sin(ra) + vb[2]*sin(dec)
66 |
67 | REVISION HISTORY:
68 | Jeff Valenti, U.C. Berkeley Translated BARVEL.FOR to IDL.
69 | W. Landsman, Cleaned up program sent by Chris McCarthy (SfSU) June 1994
70 | Converted to IDL V5.0 W. Landsman September 1997
71 | Added /JPL keyword W. Landsman July 2001
72 | Documentation update W. Landsman Dec 2005
73 | Converted to Python S. Koposov 2009-2010
74 | """
75 |
76 |
77 | #Define constants
78 | dc2pi = 2 * pi
79 | cc2pi = 2 * pi
80 | dc1 = 1.0e0
81 | dcto = 2415020.0e0
82 | dcjul = 36525.0e0 #days in Julian year
83 | dcbes = 0.313e0
84 | dctrop = 365.24219572e0 #days in tropical year (...572 insig)
85 | dc1900 = 1900.0e0
86 | au = 1.4959787e8
87 |
88 | #Constants dcfel(i,k) of fast changing elements.
89 | dcfel = array([1.7400353e00, 6.2833195099091e02, 5.2796e-6, 6.2565836e00, 6.2830194572674e02, -2.6180e-6, 4.7199666e00, 8.3997091449254e03, -1.9780e-5, 1.9636505e-1, 8.4334662911720e03, -5.6044e-5, 4.1547339e00, 5.2993466764997e01, 5.8845e-6, 4.6524223e00, 2.1354275911213e01, 5.6797e-6, 4.2620486e00, 7.5025342197656e00, 5.5317e-6, 1.4740694e00, 3.8377331909193e00, 5.6093e-6])
90 | dcfel = reshape(dcfel, (8, 3))
91 |
92 | #constants dceps and ccsel(i,k) of slowly changing elements.
93 | dceps = array([4.093198e-1, -2.271110e-4, -2.860401e-8])
94 | ccsel = array([1.675104e-2, -4.179579e-5, -1.260516e-7, 2.220221e-1, 2.809917e-2, 1.852532e-5, 1.589963e00, 3.418075e-2, 1.430200e-5, 2.994089e00, 2.590824e-2, 4.155840e-6, 8.155457e-1, 2.486352e-2, 6.836840e-6, 1.735614e00, 1.763719e-2, 6.370440e-6, 1.968564e00, 1.524020e-2, -2.517152e-6, 1.282417e00, 8.703393e-3, 2.289292e-5, 2.280820e00, 1.918010e-2, 4.484520e-6, 4.833473e-2, 1.641773e-4, -4.654200e-7, 5.589232e-2, -3.455092e-4, -7.388560e-7, 4.634443e-2, -2.658234e-5, 7.757000e-8, 8.997041e-3, 6.329728e-6, -1.939256e-9, 2.284178e-2, -9.941590e-5, 6.787400e-8, 4.350267e-2, -6.839749e-5, -2.714956e-7, 1.348204e-2, 1.091504e-5, 6.903760e-7, 3.106570e-2, -1.665665e-4, -1.590188e-7])
95 | ccsel = reshape(ccsel, (17, 3))
96 |
97 | #Constants of the arguments of the short-period perturbations.
98 | dcargs = array([5.0974222e0, -7.8604195454652e2, 3.9584962e0, -5.7533848094674e2, 1.6338070e0, -1.1506769618935e3, 2.5487111e0, -3.9302097727326e2, 4.9255514e0, -5.8849265665348e2, 1.3363463e0, -5.5076098609303e2, 1.6072053e0, -5.2237501616674e2, 1.3629480e0, -1.1790629318198e3, 5.5657014e0, -1.0977134971135e3, 5.0708205e0, -1.5774000881978e2, 3.9318944e0, 5.2963464780000e1, 4.8989497e0, 3.9809289073258e1, 1.3097446e0, 7.7540959633708e1, 3.5147141e0, 7.9618578146517e1, 3.5413158e0, -5.4868336758022e2])
99 | dcargs = reshape(dcargs, (15, 2))
100 |
101 | #Amplitudes ccamps(n,k) of the short-period perturbations.
102 | ccamps = array([-2.279594e-5, 1.407414e-5, 8.273188e-6, 1.340565e-5, -2.490817e-7, -3.494537e-5, 2.860401e-7, 1.289448e-7, 1.627237e-5, -1.823138e-7, 6.593466e-7, 1.322572e-5, 9.258695e-6, -4.674248e-7, -3.646275e-7, 1.140767e-5, -2.049792e-5, -4.747930e-6, -2.638763e-6, -1.245408e-7, 9.516893e-6, -2.748894e-6, -1.319381e-6, -4.549908e-6, -1.864821e-7, 7.310990e-6, -1.924710e-6, -8.772849e-7, -3.334143e-6, -1.745256e-7, -2.603449e-6, 7.359472e-6, 3.168357e-6, 1.119056e-6, -1.655307e-7, -3.228859e-6, 1.308997e-7, 1.013137e-7, 2.403899e-6, -3.736225e-7, 3.442177e-7, 2.671323e-6, 1.832858e-6, -2.394688e-7, -3.478444e-7, 8.702406e-6, -8.421214e-6, -1.372341e-6, -1.455234e-6, -4.998479e-8, -1.488378e-6, -1.251789e-5, 5.226868e-7, -2.049301e-7, 0.e0, -8.043059e-6, -2.991300e-6, 1.473654e-7, -3.154542e-7, 0.e0, 3.699128e-6, -3.316126e-6, 2.901257e-7, 3.407826e-7, 0.e0, 2.550120e-6, -1.241123e-6, 9.901116e-8, 2.210482e-7, 0.e0, -6.351059e-7, 2.341650e-6, 1.061492e-6, 2.878231e-7, 0.e0])
103 | ccamps = reshape(ccamps, (15, 5))
104 |
105 | #Constants csec3 and ccsec(n,k) of the secular perturbations in longitude.
106 | ccsec3 = -7.757020e-8
107 | ccsec = array([1.289600e-6, 5.550147e-1, 2.076942e00, 3.102810e-5, 4.035027e00, 3.525565e-1, 9.124190e-6, 9.990265e-1, 2.622706e00, 9.793240e-7, 5.508259e00, 1.559103e01])
108 | ccsec = reshape(ccsec, (4, 3))
109 |
110 | #Sidereal rates.
111 | dcsld = 1.990987e-7 #sidereal rate in longitude
112 | ccsgd = 1.990969e-7 #sidereal rate in mean anomaly
113 |
114 | #Constants used in the calculation of the lunar contribution.
115 | cckm = 3.122140e-5
116 | ccmld = 2.661699e-6
117 | ccfdi = 2.399485e-7
118 |
119 | #Constants dcargm(i,k) of the arguments of the perturbations of the motion
120 | # of the moon.
121 | dcargm = array([5.1679830e0, 8.3286911095275e3, 5.4913150e0, -7.2140632838100e3, 5.9598530e0, 1.5542754389685e4])
122 | dcargm = reshape(dcargm, (3, 2))
123 |
124 | #Amplitudes ccampm(n,k) of the perturbations of the moon.
125 | ccampm = array([1.097594e-1, 2.896773e-7, 5.450474e-2, 1.438491e-7, -2.223581e-2, 5.083103e-8, 1.002548e-2, -2.291823e-8, 1.148966e-2, 5.658888e-8, 8.249439e-3, 4.063015e-8])
126 | ccampm = reshape(ccampm, (3, 4))
127 |
128 | #ccpamv(k)=a*m*dl,dt (planets), dc1mme=1-mass(earth+moon)
129 | ccpamv = array([8.326827e-11, 1.843484e-11, 1.988712e-12, 1.881276e-12])
130 | dc1mme = 0.99999696e0
131 |
132 | #Time arguments.
133 | dt = (dje - dcto) / dcjul
134 | tvec = array([1e0, dt, dt * dt])
135 |
136 | #Values of all elements for the instant(aneous?) dje.
137 | temp = (transpose(dot(transpose(tvec), transpose(dcfel)))) % dc2pi
138 | dml = temp[0]
139 | forbel = temp[1:8]
140 | g = forbel[0] #old fortran equivalence
141 |
142 | deps = (tvec * dceps).sum() % dc2pi
143 | sorbel = (transpose(dot(transpose(tvec), transpose(ccsel)))) % dc2pi
144 | e = sorbel[0] #old fortran equivalence
145 |
146 | #Secular perturbations in longitude.
147 | dummy = cos(2.0)
148 | sn = sin((transpose(dot(transpose(tvec[0:2]), transpose(ccsec[:,1:3])))) % cc2pi)
149 |
150 | #Periodic perturbations of the emb (earth-moon barycenter).
151 | pertl = (ccsec[:,0] * sn).sum() + dt * ccsec3 * sn[2]
152 | pertld = 0.0
153 | pertr = 0.0
154 | pertrd = 0.0
155 | for k in range(0, 15):
156 | a = (dcargs[k,0] + dt * dcargs[k,1]) % dc2pi
157 | cosa = cos(a)
158 | sina = sin(a)
159 | pertl = pertl + ccamps[k,0] * cosa + ccamps[k,1] * sina
160 | pertr = pertr + ccamps[k,2] * cosa + ccamps[k,3] * sina
161 | if k < 11:
162 | pertld = pertld + (ccamps[k,1] * cosa - ccamps[k,0] * sina) * ccamps[k,4]
163 | pertrd = pertrd + (ccamps[k,3] * cosa - ccamps[k,2] * sina) * ccamps[k,4]
164 |
165 | #Elliptic part of the motion of the emb.
166 | phi = (e * e / 4e0) * (((8e0 / e) - e) * sin(g) + 5 * sin(2 * g) + (13 / 3e0) * e * sin(3 * g))
167 | f = g + phi
168 | sinf = sin(f)
169 | cosf = cos(f)
170 | dpsi = (dc1 - e * e) / (dc1 + e * cosf)
171 | phid = 2 * e * ccsgd * ((1 + 1.5 * e * e) * cosf + e * (1.25 - 0.5 * sinf * sinf))
172 | psid = ccsgd * e * sinf / sqrt(dc1 - e * e)
173 |
174 | #Perturbed heliocentric motion of the emb.
175 | d1pdro = dc1 + pertr
176 | drd = d1pdro * (psid + dpsi * pertrd)
177 | drld = d1pdro * dpsi * (dcsld + phid + pertld)
178 | dtl = (dml + phi + pertl) % dc2pi
179 | dsinls = sin(dtl)
180 | dcosls = cos(dtl)
181 | dxhd = drd * dcosls - drld * dsinls
182 | dyhd = drd * dsinls + drld * dcosls
183 |
184 | #Influence of eccentricity, evection and variation on the geocentric
185 | # motion of the moon.
186 | pertl = 0.0
187 | pertld = 0.0
188 | pertp = 0.0
189 | pertpd = 0.0
190 | for k in range(0, 3):
191 | a = (dcargm[k,0] + dt * dcargm[k,1]) % dc2pi
192 | sina = sin(a)
193 | cosa = cos(a)
194 | pertl = pertl + ccampm[k,0] * sina
195 | pertld = pertld + ccampm[k,1] * cosa
196 | pertp = pertp + ccampm[k,2] * cosa
197 | pertpd = pertpd - ccampm[k,3] * sina
198 |
199 | #Heliocentric motion of the earth.
200 | tl = forbel[1] + pertl
201 | sinlm = sin(tl)
202 | coslm = cos(tl)
203 | sigma = cckm / (1.0 + pertp)
204 | a = sigma * (ccmld + pertld)
205 | b = sigma * pertpd
206 | dxhd = dxhd + a * sinlm + b * coslm
207 | dyhd = dyhd - a * coslm + b * sinlm
208 | dzhd = -sigma * ccfdi * cos(forbel[2])
209 |
210 | #Barycentric motion of the earth.
211 | dxbd = dxhd * dc1mme
212 | dybd = dyhd * dc1mme
213 | dzbd = dzhd * dc1mme
214 | for k in range(0, 4):
215 | plon = forbel[k + 3]
216 | pomg = sorbel[k + 1]
217 | pecc = sorbel[k + 9]
218 | tl = (plon + 2.0 * pecc * sin(plon - pomg)) % cc2pi
219 | dxbd = dxbd + ccpamv[k] * (sin(tl) + pecc * sin(pomg))
220 | dybd = dybd - ccpamv[k] * (cos(tl) + pecc * cos(pomg))
221 | dzbd = dzbd - ccpamv[k] * sorbel[k + 13] * cos(plon - sorbel[k + 5])
222 |
223 |
224 | #Transition to mean equator of date.
225 | dcosep = cos(deps)
226 | dsinep = sin(deps)
227 | dyahd = dcosep * dyhd - dsinep * dzhd
228 | dzahd = dsinep * dyhd + dcosep * dzhd
229 | dyabd = dcosep * dybd - dsinep * dzbd
230 | dzabd = dsinep * dybd + dcosep * dzbd
231 |
232 | #Epoch of mean equinox (deq) of zero implies that we should use
233 | # Julian ephemeris date (dje) as epoch of mean equinox.
234 | if deq == 0:
235 | dvelh = au * (array([dxhd, dyahd, dzahd]))
236 | dvelb = au * (array([dxbd, dyabd, dzabd]))
237 | return (dvelh,dvelb)
238 |
239 | #General precession from epoch dje to deq.
240 | deqdat = (dje - dcto - dcbes) / dctrop + dc1900
241 | prema = premat(deqdat, deq, fk4=True)
242 |
243 | dvelh = au * (transpose(dot(transpose(prema), transpose(array([dxhd, dyahd, dzahd])))))
244 | dvelb = au * (transpose(dot(transpose(prema), transpose(array([dxbd, dyabd, dzabd])))))
245 |
246 | return (dvelh, dvelb)
247 |
248 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------