Skip to content

Commit

Permalink
Merge branch 'master' into factory_v3
Browse files Browse the repository at this point in the history
* master:
  Major coordinate refactoring, fixes cta-observatory#899, cta-observatory#900, cta-observatory#505, cta-observatory#416 (cta-observatory#896)
  speed up is_compatible; makes event_source factory faster (cta-observatory#927)
  Prefix containers (cta-observatory#833)
  remove optional deps in order to fix tests (cta-observatory#925)
  Charge Resolution Update (cta-observatory#827)
  Remove serializer, fixes cta-observatory#887 (cta-observatory#913)
  deleted summary.html - accidentally committed file (cta-observatory#919)

# Conflicts:
#	ctapipe/tools/extract_charge_resolution.py
#	examples/simple_event_writer.py
  • Loading branch information
watsonjj committed Jan 23, 2019
2 parents 210626c + cc1567d commit 7d0f868
Show file tree
Hide file tree
Showing 56 changed files with 2,200 additions and 3,221 deletions.
58 changes: 22 additions & 36 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
language: python
sudo: required
language: generic

python:
# not used directly, but this sets TRAVIS_PYTHON_VERSION so we can use it
# in anaconda as well (we don't support python less than 3.5)
- 3.5
- 3.6
matrix:
include:
- os: linux
python: 3.6
env:
- PYTHON_VERSION=3.6
- os: linux
python: 3.7
env:
- PYTHON_VERSION=3.7
# - os: osx
# python: 3.6
# env:
# - PYTHON_VERSION=3.6
# - os: osx
# python: 3.7
# env:
# - PYTHON_VERSION=3.7

os:
- linux
# - osx # currently osx python projects are not supported in Travis

env:
global:
- TARGET_SOFTWARE=$HOME/Software/target_software
- LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/Software/TargetDriver/install/lib:$HOME/Software/TargetIO/install/lib:$HOME/Software/TargetCalib/install/lib
- TARGETCALIBPATH=$HOME/Software/TargetCalib/install

before_install:

# Use utf8 encoding. Should be default, but this is insurance
# against future changes

- export PYTHONIOENCODING=UTF8
- export MPLBACKEND=agg
- export MPLBACKEND=Agg

# Install miniconda following instructions at
# http://conda.pydata.org/docs/travis.html
Expand All @@ -40,32 +43,15 @@ before_install:
- conda update -q conda # get latest conda version
# Useful for debugging any issues with conda
- conda info -a

# Make sure that interactive matplotlib backends work
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- git fetch --tags

install:
- conda create --name cta-dev python=$TRAVIS_PYTHON_VERSION
- conda env update -n cta-dev --file environment.yml
- conda create --name cta-dev python=$PYTHON_VERSION
- travis_wait 20 conda env update -n cta-dev --file py${PYTHON_VERSION}_env.yaml
- source activate cta-dev
- ulimit -s 16000 # increase stack size limit, for libhessio
- pip install travis-sphinx
- pip install codecov
# ----- SST1M:
- pip install https://github.com/cta-sst-1m/protozfitsreader/archive/v1.4.2.tar.gz
# ----- end of SST1M
# ----- target_software
- conda install -c conda-forge cfitsio
- conda install swig
- mkdir -p $HOME/Software
- cd $HOME/Software
- git clone https://github.com/watsonjj/target_software.git
- cd $TARGET_SOFTWARE
- ./install.sh
- cd $TRAVIS_BUILD_DIR
# ----- end of target_software
- python setup.py develop

script:
Expand Down
2 changes: 1 addition & 1 deletion ctapipe/analysis/camera/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Analysis modules specifically related to camera properties.
"""

from .chargeresolution import *
from .charge_resolution import *
135 changes: 135 additions & 0 deletions ctapipe/analysis/camera/charge_resolution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import numpy as np
import pandas as pd

__all__ = ['ChargeResolutionCalculator']


class ChargeResolutionCalculator:
def __init__(self, mc_true=True):
"""
Calculates the charge resolution with an efficient, low-memory,
interative approach, allowing the contribution of data/events
without reading the entire dataset into memory.
Utilises Pandas DataFrames, and makes no assumptions on the order of
the data, and does not require the true charge to be integer (as may
be the case for lab measurements where an average illumination
is used).
A list is filled with a dataframe for each contribution, and only
amalgamated into a single dataframe (reducing memory) once the memory
of the list becomes large (or at the end of the filling),
reducing the time required to produce the output.
Parameters
----------
mc_true : bool
Indicate if the "true charge" values are from the sim_telarray
files, and therefore without poisson error. The poisson error will
therefore be included in the charge resolution calculation.
Attributes
----------
self._mc_true : bool
self._df_list : list
self._df : pd.DataFrame
self._n_bytes : int
Monitors the number of bytes being held in memory
"""
self._mc_true = mc_true
self._df_list = []
self._df = pd.DataFrame()
self._n_bytes = 0
self._max_bytes = 1E9

@staticmethod
def rmse_abs(sum_, n):
return np.sqrt(sum_ / n)

@staticmethod
def rmse(true, sum_, n):
return ChargeResolutionCalculator.rmse_abs(sum_, n) / np.abs(true)

@staticmethod
def charge_res_abs(true, sum_, n):
return np.sqrt((sum_ / n) + true)

@staticmethod
def charge_res(true, sum_, n):
return (ChargeResolutionCalculator.charge_res_abs(true, sum_, n)
/ np.abs(true))

def add(self, pixel, true, measured):
"""
Contribute additional values to the Charge Resolution
Parameters
----------
pixel : ndarray
1D array containing the pixel for each entry
true : ndarray
1D array containing the true charge for each entry
measured : ndarray
1D array containing the measured charge for each entry
"""
diff2 = np.power(measured - true, 2)
df = pd.DataFrame(dict(
pixel=pixel,
true=true,
sum=diff2,
n=np.uint32(1)
))
self._df_list.append(df)
self._n_bytes += df.memory_usage(index=True, deep=True).sum()
if self._n_bytes > self._max_bytes:
self._amalgamate()

def _amalgamate(self):
"""
Concatenate the dataframes inside the list, and sum together
values per pixel and true charge in order to reduce memory use.
"""
self._df = pd.concat([self._df, *self._df_list], ignore_index=True)
self._df = self._df.groupby(['pixel', 'true']).sum().reset_index()
self._n_bytes = 0
self._df_list = []

def finish(self):
"""
Perform the final amalgamation, and calculate the charge resolution
from the resulting sums
Returns
-------
df_p : pd.DataFrame
Dataframe containing the charge resolution per pixel
df_c : pd.DataFrame
Dataframe containing the charge resolution for the entire camera
"""
self._amalgamate()

self._df = self._df.loc[self._df['true'] != 0]

df_p = self._df.copy()
true = df_p['true'].values
sum_ = df_p['sum'].values
n = df_p['n'].values
if self._mc_true:
df_p['charge_resolution'] = self.charge_res(true, sum_, n)
df_p['charge_resolution_abs'] = self.charge_res_abs(true, sum_, n)
else:
df_p['charge_resolution'] = self.rmse(true, sum_, n)
df_p['charge_resolution_abs'] = self.rmse_abs(sum_, n)
df_c = self._df.copy().groupby('true').sum().reset_index()
df_c = df_c.drop(columns='pixel')
true = df_c['true'].values
sum_ = df_c['sum'].values
n = df_c['n'].values
if self._mc_true:
df_c['charge_resolution'] = self.charge_res(true, sum_, n)
df_c['charge_resolution_abs'] = self.charge_res_abs(true, sum_, n)
else:
df_c['charge_resolution'] = self.rmse(true, sum_, n)
df_c['charge_resolution_abs'] = self.rmse_abs(sum_, n)

return df_p, df_c
Loading

0 comments on commit 7d0f868

Please sign in to comment.