diff --git a/fact/__init__.py b/fact/__init__.py index 2775ca2..42ae1f7 100644 --- a/fact/__init__.py +++ b/fact/__init__.py @@ -1,4 +1,5 @@ from .time import fjd, iso2dt, run2dt, facttime, night, night_integer, datestr +from . import plotting __all__ = [ 'fjd', diff --git a/fact/credentials/__init__.py b/fact/credentials/__init__.py new file mode 100644 index 0000000..250d32e --- /dev/null +++ b/fact/credentials/__init__.py @@ -0,0 +1,59 @@ +from functools import lru_cache +try: + from configparser import SafeConfigParser +except ImportError: + from ConfigParser import SafeConfigParser +from getpass import getpass +from simplecrypt import decrypt +from io import StringIO +from pkg_resources import resource_stream +from sqlalchemy import create_engine + + +__all__ = ['get_credentials'] + + +@lru_cache(1) +def get_credentials(): + ''' + Get a SafeConfigParser instance with FACT credentials + On the first call, you will be prompted for the FACT password + + The folling credentials are stored: + - telegram + - token + + - database + - user + - password + - host + - database + + - twilio + - sid + - auth_token + - number + + use get_credentials().get(group, element) to retrieve elements + ''' + with resource_stream('fact', 'credentials/credentials.encrypted') as f: + print('Please enter the current, universal FACT password') + passwd = getpass() + decrypted = decrypt(passwd, f.read()).decode('utf-8') + + config = SafeConfigParser() + config.readfp(StringIO(decrypted)) + + return config + +@lru_cache(2) +def rundb(isdc=False): + + creds = get_credentials() + if isdc: + spec = 'mysql+pymysql://{user}:{password}@lp-fact/{database}' + else: + spec = 'mysql+pymysql://{user}:{password}@{host}/{database}' + + return create_engine(spec.format(**creds['database'])) + diff --git a/fact/credentials/credentials.encrypted b/fact/credentials/credentials.encrypted new file mode 100644 index 0000000..2d8a7e7 Binary files /dev/null and b/fact/credentials/credentials.encrypted differ diff --git a/fact/encrypt_credentials.py b/fact/encrypt_credentials.py new file mode 100644 index 0000000..10215d9 --- /dev/null +++ b/fact/encrypt_credentials.py @@ -0,0 +1,10 @@ +from getpass import getpass +from simplecrypt import encrypt + + +with open('credentials.ini', 'rb') as infile: + config = infile.read() + +with open('fact_credentials/credentials.encrypted', 'wb') as outfile: + password = getpass() + outfile.write(encrypt(password, config)) diff --git a/fact/pixels.py b/fact/pixels.py new file mode 100644 index 0000000..719e1fd --- /dev/null +++ b/fact/pixels.py @@ -0,0 +1,121 @@ +import pkg_resources as res +import numpy as np +from functools import lru_cache + + +pixel_mapping = np.genfromtxt( + res.resource_filename('fact', 'resources/FACTmap111030.txt'), + names=[ + 'softID', 'hardID', 'geom_i', 'geom_j', + 'G-APD', 'V_op', 'HV_B', 'HV_C', + 'pos_X', 'pos_Y', 'radius' + ], + dtype=None, +) + +GEOM_2_SOFTID = { + (i, j): soft for i, j, soft in zip( + pixel_mapping['geom_i'], pixel_mapping['geom_j'], pixel_mapping['softID'] + )} + + +@np.vectorize +def geom2soft(i, j): + return GEOM_2_SOFTID[(i, j)] + + +def softid2chid(softid): + return hardid2chid(pixel_mapping['hardID'])[softid] + + +def softid2hardid(softid): + return pixel_mapping['hardID'][softid] + + +def hardid2chid(hardid): + crate = hardid // 1000 + board = (hardid // 100) % 10 + patch = (hardid // 10) % 10 + pixel = (hardid % 10) + return pixel + 9 * patch + 36 * board + 360 * crate + + +CHID_2_SOFTID = np.empty(1440, dtype=int) +for softid in range(1440): + hardid = pixel_mapping['hardID'][softid] + chid = hardid2chid(hardid) + CHID_2_SOFTID[chid] = softid + + +def chid2softid(chid): + return CHID_2_SOFTID[chid] + + +def hardid2softid(hardid): + return chid2softid(hardid2chid(hardid)) + + +def get_pixel_coords(mapfile=None, + rotate=True, + columns=[0, 9, 10, 11], + skip_header=1, + skip_footer=0, + delimiter=',', + unpack=True, + ): + ''' + Calculate the pixel coordinates from the standard pixel-map file + by default it gets rotated by 90 degrees clockwise to show the same + orientation as MARS and fact-tools + + Arguments + --------- + mapfile : str + path/to/pixelmap.csv, if None than the package resource is used + [defailt: None] + rotate : bool + if True the view is rotated by 90 degrees counter-clockwise + [default: True] + colums : list-like + the columns in the file for softID, chid, x, y + default: [0, 9, 10, 11] + ''' + + if mapfile is None: + mapfile = res.resource_filename('fact', 'resources/pixel-map.csv') + + softID, chid, pixel_x_soft, pixel_y_soft = np.genfromtxt( + mapfile, + skip_header=skip_header, + skip_footer=skip_footer, + delimiter=delimiter, + usecols=columns, + unpack=unpack, + ) + + pixel_x_soft *= 9.5 + pixel_y_soft *= 9.5 + + pixel_x_chid = pixel_x_soft[chid2softid(np.arange(1440))] + pixel_y_chid = pixel_y_soft[chid2softid(np.arange(1440))] + + # rotate by 90 degrees to show correct orientation + if rotate is True: + pixel_x = - pixel_y_chid + pixel_y = pixel_x_chid + else: + pixel_x = pixel_x_chid + pixel_y = pixel_y_chid + + return pixel_x, pixel_y + + +@lru_cache(maxsize=1) +def bias_to_trigger_patch_map(): + by_chid = pixel_mapping['hardID'].argsort() + + bias_channel = pixel_mapping[by_chid]['HV_B'] * 32 + pixel_mapping[by_chid]['HV_C'] + + _, idx = np.unique(bias_channel, return_index=True) + + return bias_channel[np.sort(idx)] diff --git a/fact/plotting/__init__.py b/fact/plotting/__init__.py index 65c10a6..a00efc9 100755 --- a/fact/plotting/__init__.py +++ b/fact/plotting/__init__.py @@ -15,15 +15,14 @@ on a pixel bases ''' import warnings -from .utils import get_pixel_coords +from .utils import calc_text_size, calc_linewidth from .core import mark_pixel, camera, pixelids - +from ..pixels import get_pixel_coords, bias_to_trigger_patch_map __all__ = [ 'camera', 'mark_pixel', 'pixelids', - 'get_pixel_coords', ] try: diff --git a/fact/plotting/core.py b/fact/plotting/core.py index 23f799e..fc06ed0 100644 --- a/fact/plotting/core.py +++ b/fact/plotting/core.py @@ -4,7 +4,8 @@ import numpy as np import matplotlib.pyplot as plt -from .utils import get_pixel_coords, calc_linewidth, calc_text_size +from ..pixels import get_pixel_coords +from .utils import calc_linewidth, calc_text_size lastpixel = -1 diff --git a/fact/plotting/utils.py b/fact/plotting/utils.py index 3f84aa8..62d977e 100644 --- a/fact/plotting/utils.py +++ b/fact/plotting/utils.py @@ -1,8 +1,6 @@ -import numpy as np -import pkg_resources as res import matplotlib.pyplot as plt -__all__ = ['get_pixel_coords', 'calc_linewidth', 'calc_text_size'] +__all__ = ['calc_linewidth', 'calc_text_size'] def calc_linewidth(ax=None): @@ -46,62 +44,3 @@ def calc_text_size(ax=None): textsize = linewidth*5 return textsize - - -def get_pixel_coords(mapfile=None, - rotate=True, - columns=[0, 9, 10, 11], - skip_header=1, - skip_footer=0, - delimiter=",", - unpack=True, - ): - """ - Calculate the pixel coordinates from the standard pixel-map file - by default it gets rotated by 90 degrees clockwise to show the same - orientation as MARS and fact-tools - - Arguments - --------- - mapfile : str - path/to/pixelmap.csv, if None than the package resource is used - [defailt: None] - rotate : bool - if True the view is rotated by 90 degrees counter-clockwise - [default: True] - colums : list-like - the columns in the file for softID, chid, x, y - default: [0, 9, 10, 11] - """ - - if mapfile is None: - mapfile = res.resource_filename("fact", "resources/pixel-map.csv") - - softID, chid, pixel_x_soft, pixel_y_soft = np.genfromtxt( - mapfile, - skip_header=skip_header, - skip_footer=skip_footer, - delimiter=delimiter, - usecols=columns, - unpack=unpack, - ) - - pixel_x_chid = np.zeros(1440) - pixel_y_chid = np.zeros(1440) - - pixel_x_soft *= 9.5 - pixel_y_soft *= 9.5 - - for i in range(1440): - pixel_x_chid[chid[i]] = pixel_x_soft[i] - pixel_y_chid[chid[i]] = pixel_y_soft[i] - - # rotate by 90 degrees to show correct orientation - if rotate is True: - pixel_x = - pixel_y_chid - pixel_y = pixel_x_chid - else: - pixel_x = pixel_x_chid - pixel_y = pixel_y_chid - - return pixel_x, pixel_y diff --git a/fact/plotting/viewer.py b/fact/plotting/viewer.py index a670850..08106d0 100644 --- a/fact/plotting/viewer.py +++ b/fact/plotting/viewer.py @@ -4,7 +4,8 @@ from matplotlib.figure import Figure import numpy as np import os -from .utils import get_pixel_coords, calc_linewidth +from .utils import calc_linewidth +from ..pixels import get_pixel_coords from . import camera # tkinter is named differently in python2 and python3 diff --git a/resources/FACTmap111030.txt b/fact/resources/FACTmap111030.txt similarity index 100% rename from resources/FACTmap111030.txt rename to fact/resources/FACTmap111030.txt diff --git a/setup.py b/setup.py index d75abb5..f0f1fd7 100644 --- a/setup.py +++ b/setup.py @@ -50,13 +50,17 @@ author_email='maximilian.noethe@tu-dortmund.de', license='MIT', packages=packages, - package_data={'': ['resources/*']}, + package_data={ + '': ['resources/*', 'credentials/credentials.encrypted']}, install_requires=[ 'numpy', 'scipy', 'matplotlib>=1.4', 'python-dateutil', 'pymongo>=2.7', + 'simple-crypt', + 'setuptools', + 'sqlalchemy', ], ext_modules=ext_modules, scripts=[],