<commit_before>import json
from .variables import load_variables, SimpleColumn, BIDSVariableCollection
from . import transform
from collections import namedtuple
from six import string_types
import pandas as pd
import numpy as np

DesignMatrix = namedtuple('DesignMatrix', ('data', 'image', 'entities'))

class Analysis(object):

    ''' Represents an entire BIDS-Model analysis.
    Args:
        layouts (BIDSLayout or list): One or more BIDSLayout objects to pull
            variables from.
        model (str or dict): a BIDS model specification. Can either be a
            string giving the path of the JSON model spec, or an already-loaded
            dict containing the model info.
        collection (BIDSVariableCollection): Optional BIDSVariableCollection
            object used to load/manage variables. If None, a new collection is
            initialized from the provided layouts.
        selectors (dict): Optional keyword arguments to pass onto the
            collection; these will be passed on to the Layout's .get() method,
            and can be used to restrict variables.
    '''

    def __init__(self, model, collection=None, layouts=None, **selectors):

        if layouts is None and collection is None:
            raise ValueError("At least one of the 'layout' and 'collection' "
                             "arguments must be passed.")

        if isinstance(model, str):
            model = json.load(open(model))
        self.model = model

        if 'input' in model:
            selectors.update(model['input'])

        if collection is None:
            collection = load_variables(layouts, **selectors)

        self.collection = collection

        self._load_blocks(model['blocks'])

    @property
    def layout(self):
        return self.collection.layout  # for convenience

    def __iter__(self):
        for b in self.blocks:
            yield b

    def __getitem__(self, index):
        if isinstance(index, int):
            return self.blocks[index]
        return list(filter(lambda x: x.name == index, self.blocks))[0]

    def _load_blocks(self, blocks):
        self.blocks = []
        for i, b in enumerate(blocks):
            self.blocks.append(Block(self, index=i, **b))

    def setup(self, apply_transformations=True):
        ''' Set up the sequence of blocks--applying transformations,
        generating outputs, etc. '''

        # pass a copy of the collection through the pipeline (columns mutate)
        _collection = self.collection.clone()

        for b in self.blocks:
            b.setup(_collection, apply_transformations=apply_transformations)
            _collection = b.output_collection.clone()

class Block(object):

    ''' Represents a single analysis block from a BIDS-Model specification.
    Args:
        analysis (Analysis): The parent Analysis this Block belongs to.
        level (str): The BIDS keyword to use as the grouping variable; must be
            one of ['run', 'session', 'subject', or 'dataset'].
        index (int): The numerical index of the current Block within the
            sequence of blocks.
        name (str): Optional name to assign to the block. Must be specified
            in order to enable name-based indexing in the parent Analysis.
        transformations (list): List of BIDS-Model transformations to apply.
        model (dict): The 'model' part of the BIDS-Model block specification.
        contrasts (list): List of contrasts to apply to the parameter estimates
            generated when the model is fit.
    '''

    def __init__(self, analysis, level, index, name=None, transformations=None,
                 model=None, contrasts=None):

        self.analysis = analysis
        self.level = level
        self.index = index
        self.name = name
        self.transformations = transformations or []
        self.model = model or None
        self.contrasts = contrasts or []
        self._design_matrix = None
        self.input_collection = None
        self.output_collection = None

    def _get_design_matrix(self, **selectors):
        if self._design_matrix is None:
            raise ValueError("Block hasn't been set up yet; please call "
                             "setup() before you try to retrieve the DM.")
        # subset the data if needed
        data = self._design_matrix
        if selectors:
            # TODO: make sure this handles constraints on int columns properly
            bad_keys = list(set(selectors.keys()) - set(data.columns))
            if bad_keys:
                raise ValueError("The following query constraints do not map "
                                 "onto existing columns: %s." % bad_keys)
            query = ' and '.join(["{} in {}".format(k, v)
                                  for k, v in selectors.items()])
            data = data.query(query)
        return data

    def _drop_columns(self, data, drop_entities=True, drop_timing=False):

        entities = []
        if drop_entities:
            entities += ['run', 'session', 'subject', 'task']
        if drop_timing:
            entities += ['onset', 'duration']
        common_ents = list(set(entities) & set(data.columns))
        return data.drop(common_ents, axis=1)

    def _get_groupby_cols(self):
        # Get a list of keywords that define the grouping at the current level.
        # Note that we need to include all entities *above* the current one--
        # e.g., if the block level is 'run', this means we actually want to
        # groupby(['subject', 'session', 'run']), otherwise we would only
        # end up with n(runs) groups.
        hierarchy = ['subject', 'session', 'run']

        if self.level is None:
            return None
        elif self.level not in hierarchy:  # e.g., for 'dataset'
            return []
        pos = hierarchy.index(self.level)
        return hierarchy[:(pos + 1)]

    def apply_transformations(self):
        ''' Apply all transformations to the variables in the collection.
        '''
        for t in self.transformations:
            kwargs = dict(t)
            func = kwargs.pop('name')
            cols = kwargs.pop('input', None)

            if isinstance(func, string_types):
                if not hasattr(transform, func):
                    raise ValueError("No transformation '%s' found!" % func)
                func = getattr(transform, func)
                func(self.input_collection, cols, **kwargs)

        # Also apply variable selection even if it's not represented in
        # its own transformation.
        if self.model is not None and 'variables' in self.model:
            # TODO: add a "select" transformation and construct a call to it
            # here instead of filtering directly on the collection.
            coll = self.input_collection
            coll.columns = {k: v for k, v in coll.columns.items()
                            if k in self.model['variables']}

    def generate_output_collection(self, keep_input_columns=True):

        data = self._get_design_matrix()

        # Figure out which column names to keep
        contrast_names = [c['name'] for c in self.contrasts]
        if keep_input_columns:
            sel_cols = list(data['condition'].unique())
            contrast_names = sel_cols + contrast_names

        ent_cols = self._get_groupby_cols()
        ent_cols = list(set(ent_cols) & set(data.columns))

        contrast_names = list(set(contrast_names) -
                              set(self.input_collection.entities))

        # Set the same (unit) weights for all rows
        unit_weights = pd.Series(np.ones(len(contrast_names)),
                                 index=contrast_names)

        if ent_cols:
            data = data.groupby(ent_cols).apply(lambda x: unit_weights)

        # Generate a new BIDSVariableCollection to pass to next block
        ic = self.input_collection

        collection = BIDSVariableCollection(ic.layout, entities=ent_cols)

        for col_name in data.columns:
            col_data = data[col_name].reset_index()
            col_data = col_data.rename(columns={col_name: 'amplitude'})
            col = SimpleColumn(collection, col_name, col_data)
            collection.columns[col_name] = col

        self.output_collection = collection

    def get_contrasts(self, format='matrix', **selectors):
        ''' Return contrast information for the current block.
        Args:
            format (str): What format to return the contrast specifications in.
                Valid options are:
                    'matrix' or 'df': Returns a pandas DataFrame with each
                        contrast as a row and each of the existing design
                        matrix columns as a column. This format makes it easy
                        to matrix-multiply existing in-memory images by the
                        contrast definition matrix in one shot.
                    'patsy': Returns a list of strings, where each string gives
                        a patsy-compatible definition of the contrast. E.g.,
                        if there are conditions 'A' and 'B', and the weights
                        are [1, -1], the returned string would be "A-B".
                    'dict': Returns the BIDS-Model contrast specification
                        as a dict loaded from the original json.
                    'json': Returns the json string containing the raw contrast
                        specification found in the original BIDS-Model spec.
            selectors (dict): Optional keyword arguments to further constrain
                the data retrieved.
        Returns:
            See format argument for returned object formats.
        '''
        if format == 'dict':
            return self.contrasts

        if format == 'json':
            return json.dumps(self.contrasts)

        # Construct contrast x variable matrix
        pass

    def get_Xy(self, drop_entities=True, **selectors):
        ''' Return X and y information for all groups defined by the current
        level.
        Args:
            selectors (dict): Optional keyword arguments to further constrain
                the data retrieved.
        Returns:
            A list of triples, where each triple contains data for a single
                group, and the elements reflect (in order):
                    - The design matrix containing all of the predictors (X);
                    - The filename of the 4D image associated with the
                      current group/design matrix;
                    - A dict of entities defining the current group (e.g.,
                      {'subject': '03', 'run': 1})
        '''
        data = self._get_design_matrix(**selectors)
        ent_cols = self._get_groupby_cols()

        tuples = []
        ent_cols = list(set(ent_cols) & set(data.columns))

        # If there are no entities to group on, return the whole dataset
        if not ent_cols:
            return [(data, None, {})]

        # Otherwise loop over groups and construct a tuple for each one
        for name, g in data.groupby(ent_cols):
            ent_data = g[ent_cols].drop_duplicates().iloc[0, :]
            ents = ent_data.to_dict()
            if 'run' in ent_cols:
                img = self.analysis.layout.get(return_type='file', type='bold',
                                               modality='func',
                                               extensions='.nii.gz', **ents)
                img = img[0]
            else:
                img = None
            group_data = self._drop_columns(g.copy(),
                                            drop_entities=drop_entities)
            record = DesignMatrix(group_data, img, ents)
            tuples.append(record)
        return tuples

    def iter_Xy(self, **selectors):
        ''' Convenience method that returns an iterator over tuples returned
        by get_Xy(). See get_Xy() for arguments and return format. '''
        return (t for t in self.get_Xy(**selectors))

    def setup(self, collection, apply_transformations=True,
              generate_output_collection=True):
        ''' Set up the Block and construct the design matrix.
        Args:
            collection (BIDSVariableCollection): The variable collection to
                use. Note that the setup process will often mutate the
                collection instance.
            last_level (str): The level of the previous Block in the analysis,
                if any.
            apply_transformations (bool): If True (default), apply any
                transformations in the block before constructing the design
                matrix.
            generate_output_collection (bool): If True (default), generate the
                output collection to pass to the next block as its input.
        '''
        self.input_collection = collection
        self.output_collection = None

        if self.transformations and apply_transformations:
            self.apply_transformations()

        gb = self._get_groupby_cols()

        self._design_matrix = collection.get_design_matrix(groupby=gb).copy()

        if self.generate_output_collection:
            self.generate_output_collection()
<commit_msg>use select transformation to trim variables<commit_after>import json
from .variables import load_variables, SimpleColumn, BIDSVariableCollection
from . import transform
from collections import namedtuple
from six import string_types
import pandas as pd
import numpy as np

DesignMatrix = namedtuple('DesignMatrix', ('data', 'image', 'entities'))

class Analysis(object):

    ''' Represents an entire BIDS-Model analysis.
    Args:
        layouts (BIDSLayout or list): One or more BIDSLayout objects to pull
            variables from.
        model (str or dict): a BIDS model specification. Can either be a
            string giving the path of the JSON model spec, or an already-loaded
            dict containing the model info.
        collection (BIDSVariableCollection): Optional BIDSVariableCollection
            object used to load/manage variables. If None, a new collection is
            initialized from the provided layouts.
        selectors (dict): Optional keyword arguments to pass onto the
            collection; these will be passed on to the Layout's .get() method,
            and can be used to restrict variables.
    '''

    def __init__(self, model, collection=None, layouts=None, **selectors):

        if layouts is None and collection is None:
            raise ValueError("At least one of the 'layout' and 'collection' "
                             "arguments must be passed.")

        if isinstance(model, str):
            model = json.load(open(model))
        self.model = model

        if 'input' in model:
            selectors.update(model['input'])

        if collection is None:
            collection = load_variables(layouts, **selectors)

        self.collection = collection

        self._load_blocks(model['blocks'])

    @property
    def layout(self):
        return self.collection.layout  # for convenience

    def __iter__(self):
        for b in self.blocks:
            yield b

    def __getitem__(self, index):
        if isinstance(index, int):
            return self.blocks[index]
        return list(filter(lambda x: x.name == index, self.blocks))[0]

    def _load_blocks(self, blocks):
        self.blocks = []
        for i, b in enumerate(blocks):
            self.blocks.append(Block(self, index=i, **b))

    def setup(self, apply_transformations=True):
        ''' Set up the sequence of blocks--applying transformations,
        generating outputs, etc. '''

        # pass a copy of the collection through the pipeline (columns mutate)
        _collection = self.collection.clone()

        for b in self.blocks:
            b.setup(_collection, apply_transformations=apply_transformations)
            _collection = b.output_collection.clone()

class Block(object):

    ''' Represents a single analysis block from a BIDS-Model specification.
    Args:
        analysis (Analysis): The parent Analysis this Block belongs to.
        level (str): The BIDS keyword to use as the grouping variable; must be
            one of ['run', 'session', 'subject', or 'dataset'].
        index (int): The numerical index of the current Block within the
            sequence of blocks.
        name (str): Optional name to assign to the block. Must be specified
            in order to enable name-based indexing in the parent Analysis.
        transformations (list): List of BIDS-Model transformations to apply.
        model (dict): The 'model' part of the BIDS-Model block specification.
        contrasts (list): List of contrasts to apply to the parameter estimates
            generated when the model is fit.
    '''

    def __init__(self, analysis, level, index, name=None, transformations=None,
                 model=None, contrasts=None):

        self.analysis = analysis
        self.level = level
        self.index = index
        self.name = name
        self.transformations = transformations or []
        self.model = model or None
        self.contrasts = contrasts or []
        self._design_matrix = None
        self.input_collection = None
        self.output_collection = None

    def _get_design_matrix(self, **selectors):
        if self._design_matrix is None:
            raise ValueError("Block hasn't been set up yet; please call "
                             "setup() before you try to retrieve the DM.")
        # subset the data if needed
        data = self._design_matrix
        if selectors:
            # TODO: make sure this handles constraints on int columns properly
            bad_keys = list(set(selectors.keys()) - set(data.columns))
            if bad_keys:
                raise ValueError("The following query constraints do not map "
                                 "onto existing columns: %s." % bad_keys)
            query = ' and '.join(["{} in {}".format(k, v)
                                  for k, v in selectors.items()])
            data = data.query(query)
        return data

    def _drop_columns(self, data, drop_entities=True, drop_timing=False):

        entities = []
        if drop_entities:
            entities += ['run', 'session', 'subject', 'task']
        if drop_timing:
            entities += ['onset', 'duration']
        common_ents = list(set(entities) & set(data.columns))
        return data.drop(common_ents, axis=1)

    def _get_groupby_cols(self):
        # Get a list of keywords that define the grouping at the current level.
        # Note that we need to include all entities *above* the current one--
        # e.g., if the block level is 'run', this means we actually want to
        # groupby(['subject', 'session', 'run']), otherwise we would only
        # end up with n(runs) groups.
        hierarchy = ['subject', 'session', 'run']

        if self.level is None:
            return None
        elif self.level not in hierarchy:  # e.g., for 'dataset'
            return []
        pos = hierarchy.index(self.level)
        return hierarchy[:(pos + 1)]

    def apply_transformations(self):
        ''' Apply all transformations to the variables in the collection.
        '''
        for t in self.transformations:
            kwargs = dict(t)
            func = kwargs.pop('name')
            cols = kwargs.pop('input', None)

            if isinstance(func, string_types):
                if not hasattr(transform, func):
                    raise ValueError("No transformation '%s' found!" % func)
                func = getattr(transform, func)
                func(self.input_collection, cols, **kwargs)

        # Also apply variable selection even if it's not represented in
        # its own transformation.
        if self.model is not None and 'variables' in self.model:
            transform.select(self.input_collection, self.model['variables'])

    def generate_output_collection(self, keep_input_columns=True):

        data = self._get_design_matrix()

        # Figure out which column names to keep
        contrast_names = [c['name'] for c in self.contrasts]
        if keep_input_columns:
            sel_cols = list(data['condition'].unique())
            contrast_names = sel_cols + contrast_names

        ent_cols = self._get_groupby_cols()
        ent_cols = list(set(ent_cols) & set(data.columns))

        contrast_names = list(set(contrast_names) -
                              set(self.input_collection.entities))

        # Set the same (unit) weights for all rows
        unit_weights = pd.Series(np.ones(len(contrast_names)),
                                 index=contrast_names)

        if ent_cols:
            data = data.groupby(ent_cols).apply(lambda x: unit_weights)

        # Generate a new BIDSVariableCollection to pass to next block
        ic = self.input_collection

        collection = BIDSVariableCollection(ic.layout, entities=ent_cols)

        for col_name in data.columns:
            col_data = data[col_name].reset_index()
            col_data = col_data.rename(columns={col_name: 'amplitude'})
            col = SimpleColumn(collection, col_name, col_data)
            collection.columns[col_name] = col

        self.output_collection = collection

    def get_contrasts(self, format='matrix', **selectors):
        ''' Return contrast information for the current block.
        Args:
            format (str): What format to return the contrast specifications in.
                Valid options are:
                    'matrix' or 'df': Returns a pandas DataFrame with each
                        contrast as a row and each of the existing design
                        matrix columns as a column. This format makes it easy
                        to matrix-multiply existing in-memory images by the
                        contrast definition matrix in one shot.
                    'patsy': Returns a list of strings, where each string gives
                        a patsy-compatible definition of the contrast. E.g.,
                        if there are conditions 'A' and 'B', and the weights
                        are [1, -1], the returned string would be "A-B".
                    'dict': Returns the BIDS-Model contrast specification
                        as a dict loaded from the original json.
                    'json': Returns the json string containing the raw contrast
                        specification found in the original BIDS-Model spec.
            selectors (dict): Optional keyword arguments to further constrain
                the data retrieved.
        Returns:
            See format argument for returned object formats.
        '''
        if format == 'dict':
            return self.contrasts

        if format == 'json':
            return json.dumps(self.contrasts)

        # Construct contrast x variable matrix
        pass

    def get_Xy(self, drop_entities=True, **selectors):
        ''' Return X and y information for all groups defined by the current
        level.
        Args:
            selectors (dict): Optional keyword arguments to further constrain
                the data retrieved.
        Returns:
            A list of triples, where each triple contains data for a single
                group, and the elements reflect (in order):
                    - The design matrix containing all of the predictors (X);
                    - The filename of the 4D image associated with the
                      current group/design matrix;
                    - A dict of entities defining the current group (e.g.,
                      {'subject': '03', 'run': 1})
        '''
        data = self._get_design_matrix(**selectors)
        ent_cols = self._get_groupby_cols()

        tuples = []
        ent_cols = list(set(ent_cols) & set(data.columns))

        # If there are no entities to group on, return the whole dataset
        if not ent_cols:
            return [(data, None, {})]

        # Otherwise loop over groups and construct a tuple for each one
        for name, g in data.groupby(ent_cols):
            ent_data = g[ent_cols].drop_duplicates().iloc[0, :]
            ents = ent_data.to_dict()
            if 'run' in ent_cols:
                img = self.analysis.layout.get(return_type='file', type='bold',
                                               modality='func',
                                               extensions='.nii.gz', **ents)
                img = img[0]
            else:
                img = None
            group_data = self._drop_columns(g.copy(),
                                            drop_entities=drop_entities)
            record = DesignMatrix(group_data, img, ents)
            tuples.append(record)
        return tuples

    def iter_Xy(self, **selectors):
        ''' Convenience method that returns an iterator over tuples returned
        by get_Xy(). See get_Xy() for arguments and return format. '''
        return (t for t in self.get_Xy(**selectors))

    def setup(self, collection, apply_transformations=True,
              generate_output_collection=True):
        ''' Set up the Block and construct the design matrix.
        Args:
            collection (BIDSVariableCollection): The variable collection to
                use. Note that the setup process will often mutate the
                collection instance.
            last_level (str): The level of the previous Block in the analysis,
                if any.
            apply_transformations (bool): If True (default), apply any
                transformations in the block before constructing the design
                matrix.
            generate_output_collection (bool): If True (default), generate the
                output collection to pass to the next block as its input.
        '''
        self.input_collection = collection
        self.output_collection = None

        if self.transformations and apply_transformations:
            self.apply_transformations()

        gb = self._get_groupby_cols()

        self._design_matrix = collection.get_design_matrix(groupby=gb).copy()

        if self.generate_output_collection:
            self.generate_output_collection()
<|endoftext|>


<commit_before>#    Copyright 2016 SAS Project Authors. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

import multiprocessing

import geojson
import numpy as np
from concurrent import futures
from reference_models.geo import census_tract, utils, vincenty, nlcd
from reference_models.propagation import wf_hybrid
from reference_modesl.antenna import antenna
from shapely import geometry, ops

THRESHOLD_PER_10MHZ = -96
RX_HEIGHT = 1.5

census_tract_driver = census_tract.CensusTractDriver()
nlcd_driver = nlcd.NlcdDriver()

def _CalculatePropLossForEachPointAndContour(install_param, antenna_gain, latitude, longitude):
  db_loss = np.zeros(len(latitude), dtype=np.float64)
  for index, lat_lon in enumerate(zip(latitude, longitude)):
    lat, lon = lat_lon
    code = nlcd_driver.GetLandCoverCodes(lat, lon)
    region_type = nlcd.GetRegionType(code)
    db_loss[index] = wf_hybrid.CalcHybridPropagationLoss(install_param['latitude'],
                                                         install_param['longitude'],
                                                         install_param['height'],
                                                         lat, lon, RX_HEIGHT,
                                                         install_param['indoorDeployment'],
                                                         region=region_type).db_loss

  db_loss = 10.0 ** (db_loss / 10.0)
  index_cond, _ = np.where(install_param['eirpCapability'] - db_loss + antenna_gain > THRESHOLD_PER_10MHZ)
  return index_cond.shape[0] / 5

def _HammingFilter(x, window_len=15):
  s = np.r_[x[-(window_len / 2):], x, x[0:window_len / 2]]
  w = np.hamming(window_len)
  y = np.convolve(w / w.sum(), s, mode='valid')
  return y

def _GetPolygon(device):
  install_param = device['installationParam']
  # Get all the Function Partials
  # Compute all the Points in 0-359 every 200m upto 40km
  distance = np.arange(0.2, 40.2, 0.2)
  latitude, longitude, _ = zip(*[vincenty.GeodesicPoints(install_param['latitude'],
                                                         install_param['longitude'],
                                                         distance, azimuth)
                                 for azimuth in np.arange(0, 360)])
  # Compute the Gain for all Direction
  antenna_gain = antenna.GetStandardAntennaGains(np.arange(0, 360),
                                                 install_param['antennaAzimuth']
                                                 if 'antennaAzimuth' in install_param.keys() else None,
                                                 install_param['antennaBeamwidth'],
                                                 install_param['antennaGain'])
  # Compute the Path Loss, and contour based on Gain and Path Loss Comparing with Threshold
  # Smoothing Contour using Hamming Filter
  contour_pts = _HammingFilter([_CalculatePropLossForEachPointAndContour(install_param, gain, lat, lon)
                                for lat, lon, gain in zip(latitude, longitude, antenna_gain)])

  # Generating lat, lon for Contour
  contour_lat, contour_lon, _ = [vincenty.GeodesicPoint(install_param['latitude'],
                                                        install_param['longitude'], cn, az)
                                 for cn, az in zip(contour_pts, range(0, 360))]
  return geometry.shape(zip(contour_lon, contour_lat)).buffer(0)

def _ClipPpaByCensusTract(contour_union, pal_records):
  # Get the Census Tract for Each Pal Record and Convert it to Shapely Geometry
  census_tracts_for_pal = [geometry.shape(census_tract_driver.GetCensusTract(pal['license']
                                                                             ['licenseAreaIdentifier'])
                                          ['features'][0]['geometry']).buffer(0) for pal in pal_records]
  census_tracts_union = ops.cascaded_union(census_tracts_for_pal)
  return contour_union.intersection(census_tracts_union)

def _ConvertToGeoJson(ppa_polygon):
  if ppa_polygon.type == 'MultiPolygon':
    ppa_geojson = geojson.FeatureCollection(
      [geojson.Feature(geometry=polygon for polygon in ppa_polygon)])
  else:
    ppa_geojson = geojson.FeatureCollection(
      [geojson.Feature(geometry=ppa_polygon)])
  return ppa_geojson

def ConfigureCensusTractDriver(census_tract_dir=None):
  """Configure the Census Tract driver.

  Inputs:
    census_tract_dir: if specified, changes the census tract default directory.
  """
  if census_tract_dir is not None:
    census_tract_driver.SetCensusTractDirectory(census_tract_dir)

def ConfigureNlcdDriver(nlcd_dir=None, cache_size=None):
  """Configure the NLCD driver.

  Inputs:
    nlcd_dir: if specified, changes the NLCD Data default directory.
    cache_size:  if specified, change the NLCD tile cache size.
  Note: The memory usage is about cache_size * 50MB.

  """
  if nlcd_dir is not None:
    nlcd_driver.SetTerrainDirectory(nlcd_dir)
  if cache_size is not None:
    nlcd_driver.SetCacheSize(cache_size)

def PpaCreationModel(devices, pal_records):
  """Create a PPA Polygon based on the PAL Records and Device Information
  Args:
    devices: (List) A list containing device information.
    pal_records: (List) A list containing pal records.
  Returns:
     A GeoJSON Dictionary of PPA Polygon
  """
  # TODO: Add Validation for Inputs
  pool = futures.ProcessPoolExecutor(multiprocessing.cpu_count())
  # Create Contour for each CBSD
  device_polygon = pool.map(_GetPolygon, devices)
  # Create Union of all the CBSD Contours and Check for hole
  # after Census Tract Clipping
  contour_union = ops.cascaded_union(device_polygon)
  ppa_polygon = _ClipPpaByCensusTract(contour_union, pal_records)
  return _ConvertToGeoJson(utils.PolyWithoutSmallHoles(ppa_polygon))
<commit_msg>Updated Copyright Year and Function Name<commit_after>#    Copyright 2016-2018 SAS Project Authors. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

import multiprocessing

import geojson
import numpy as np
from concurrent import futures
from reference_models.geo import census_tract, utils, vincenty, nlcd
from reference_models.propagation import wf_hybrid
from reference_modesl.antenna import antenna
from shapely import geometry, ops

THRESHOLD_PER_10MHZ = -96
RX_HEIGHT = 1.5

census_tract_driver = census_tract.CensusTractDriver()
nlcd_driver = nlcd.NlcdDriver()

def _CalculateDbLossForEachPointAndGetContour(install_param, antenna_gain, latitude, longitude):
  db_loss = np.zeros(len(latitude), dtype=np.float64)
  for index, lat_lon in enumerate(zip(latitude, longitude)):
    lat, lon = lat_lon
    code = nlcd_driver.GetLandCoverCodes(lat, lon)
    region_type = nlcd.GetRegionType(code)
    db_loss[index] = wf_hybrid.CalcHybridPropagationLoss(install_param['latitude'],
                                                         install_param['longitude'],
                                                         install_param['height'],
                                                         lat, lon, RX_HEIGHT,
                                                         install_param['indoorDeployment'],
                                                         region=region_type).db_loss

  db_loss = 10.0 ** (db_loss / 10.0)
  index_cond, _ = np.where(install_param['eirpCapability'] - db_loss + antenna_gain > THRESHOLD_PER_10MHZ)
  return index_cond.shape[0] / 5

def _HammingFilter(x, window_len=15):
  s = np.r_[x[-(window_len / 2):], x, x[0:window_len / 2]]
  w = np.hamming(window_len)
  y = np.convolve(w / w.sum(), s, mode='valid')
  return y

def _GetPolygon(device):
  install_param = device['installationParam']
  # Get all the Function Partials
  # Compute all the Points in 0-359 every 200m upto 40km
  distance = np.arange(0.2, 40.2, 0.2)
  latitude, longitude, _ = zip(*[vincenty.GeodesicPoints(install_param['latitude'],
                                                         install_param['longitude'],
                                                         distance, azimuth)
                                 for azimuth in np.arange(0, 360)])
  # Compute the Gain for all Direction
  antenna_gain = antenna.GetStandardAntennaGains(np.arange(0, 360),
                                                 install_param['antennaAzimuth']
                                                 if 'antennaAzimuth' in install_param.keys() else None,
                                                 install_param['antennaBeamwidth'],
                                                 install_param['antennaGain'])
  # Compute the Path Loss, and contour based on Gain and Path Loss Comparing with Threshold
  # Smoothing Contour using Hamming Filter
  contour_pts = _HammingFilter([_CalculateDbLossForEachPointAndGetContour(install_param, gain, lat, lon)
                                for lat, lon, gain in zip(latitude, longitude, antenna_gain)])

  # Generating lat, lon for Contour
  contour_lat, contour_lon, _ = [vincenty.GeodesicPoint(install_param['latitude'],
                                                        install_param['longitude'], cn, az)
                                 for cn, az in zip(contour_pts, np.arange(0, 360))]
  return geometry.shape(zip(contour_lon, contour_lat)).buffer(0)

def _ClipPpaByCensusTract(contour_union, pal_records):
  # Get the Census Tract for Each Pal Record and Convert it to Shapely Geometry
  census_tracts_for_pal = [geometry.shape(census_tract_driver.GetCensusTract(pal['license']
                                                                             ['licenseAreaIdentifier'])
                                          ['features'][0]['geometry']).buffer(0) for pal in pal_records]
  census_tracts_union = ops.cascaded_union(census_tracts_for_pal)
  return contour_union.intersection(census_tracts_union)

def _ConvertToGeoJson(ppa_polygon):
  if ppa_polygon.type == 'MultiPolygon':
    ppa_geojson = geojson.FeatureCollection(
      [geojson.Feature(geometry=polygon for polygon in ppa_polygon)])
  else:
    ppa_geojson = geojson.FeatureCollection(
      [geojson.Feature(geometry=ppa_polygon)])
  return ppa_geojson

def ConfigureCensusTractDriver(census_tract_dir=None):
  """Configure the Census Tract driver.

  Inputs:
    census_tract_dir: if specified, changes the census tract default directory.
  """
  if census_tract_dir is not None:
    census_tract_driver.SetCensusTractDirectory(census_tract_dir)

def ConfigureNlcdDriver(nlcd_dir=None, cache_size=None):
  """Configure the NLCD driver.

  Inputs:
    nlcd_dir: if specified, changes the NLCD Data default directory.
    cache_size:  if specified, change the NLCD tile cache size.
  Note: The memory usage is about cache_size * 50MB.

  """
  if nlcd_dir is not None:
    nlcd_driver.SetTerrainDirectory(nlcd_dir)
  if cache_size is not None:
    nlcd_driver.SetCacheSize(cache_size)

def PpaCreationModel(devices, pal_records):
  """Create a PPA Polygon based on the PAL Records and Device Information
  Args:
    devices: (List) A list containing device information.
    pal_records: (List) A list containing pal records.
  Returns:
     A GeoJSON Dictionary of PPA Polygon
  """
  # TODO: Add Validation for Inputs
  pool = futures.ProcessPoolExecutor(multiprocessing.cpu_count())
  # Create Contour for each CBSD
  device_polygon = pool.map(_GetPolygon, devices)
  # Create Union of all the CBSD Contours and Check for hole
  # after Census Tract Clipping
  contour_union = ops.cascaded_union(device_polygon)
  ppa_polygon = _ClipPpaByCensusTract(contour_union, pal_records)
  return _ConvertToGeoJson(utils.PolyWithoutSmallHoles(ppa_polygon))
<|endoftext|>


<commit_before>from .models import Client
from .models import Contact
from .models import Estimate
from .models import Invoice
from .models import Profile
from .models import Project
from .models import Task
from .models import Time
from django import forms

class ClientForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = '__all__'

class ContactForm(forms.ModelForm):
    class Meta:
        model = Contact
        fields = '__all__'

class EstimateForm(forms.ModelForm):
    class Meta:
        model = Estimate
        fields = ('issue_date', 'client', 'subject')

class InvoiceForm(forms.ModelForm):
    """
    Issue Date, Last Payment Date, Invoice ID, PO Number, Client, Subject,
    Invoice Amount, Paid Amount, Balance, Subtotal, Discount, Tax, Tax2,
    Currency, Currency Symbol, Document Type
    """

    class Meta:
        model = Invoice
        fields = ('project', 'issue_date', 'po_number', 'subject')

class MailForm(forms.Form):
    subject = forms.CharField()
    message = forms.CharField(widget=forms.Textarea())

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('rate', 'unit')

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = ('active', 'client', 'name', 'code', 'start_date', 'end_date',
                  'task', 'team')

class TaskForm(forms.ModelForm):
    class Meta:
        model = Task
        fields = ('active', 'name', 'rate', 'unit')

class TimeForm(forms.ModelForm):
    class Meta:
        model = Time
        fields = ('date', 'hours', 'notes', 'client', 'project', 'task')
<commit_msg>Update<commit_after>from .models import Client
from .models import Contact
from .models import Estimate
from .models import Invoice
from .models import Profile
from .models import Project
from .models import Task
from .models import Time
from django import forms

class ClientForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = '__all__'

class ContactForm(forms.ModelForm):
    class Meta:
        model = Contact
        fields = '__all__'

class EstimateForm(forms.ModelForm):
    class Meta:
        model = Estimate
        fields = ('issue_date', 'client', 'subject')

class InvoiceForm(forms.ModelForm):
    """
    Issue Date, Last Payment Date, Invoice ID, PO Number, Client, Subject,
    Invoice Amount, Paid Amount, Balance, Subtotal, Discount, Tax, Tax2,
    Currency, Currency Symbol, Document Type
    """

    class Meta:
        model = Invoice
        fields = ('project', 'issue_date', 'subject')

class MailForm(forms.Form):
    subject = forms.CharField()
    message = forms.CharField(widget=forms.Textarea())

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('rate', 'unit')

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = ('active', 'client', 'name', 'code', 'start_date', 'end_date',
                  'task', 'team')

class TaskForm(forms.ModelForm):
    class Meta:
        model = Task
        fields = ('active', 'name', 'rate', 'unit')

class TimeForm(forms.ModelForm):
    class Meta:
        model = Time
        fields = ('date', 'hours', 'notes', 'client', 'project', 'task')
<|endoftext|>


<commit_before>import logging

from .base import SdoBase
from .constants import *
from .exceptions import *

logger = logging.getLogger(__name__)

class SdoServer(SdoBase):
    """Creates an SDO server."""

    def __init__(self, rx_cobid, tx_cobid, node):
        """
        :param int rx_cobid:
            COB-ID that the server receives on (usually 0x600 + node ID)
        :param int tx_cobid:
            COB-ID that the server responds with (usually 0x580 + node ID)
        :param canopen.LocalNode od:
            Node object owning the server
        """
        SdoBase.__init__(self, rx_cobid, tx_cobid, node.object_dictionary)
        self._node = node
        self._buffer = None
        self._toggle = 0
        self._index = None
        self._subindex = None
        self.last_received_error = 0x00000000

    def on_request(self, can_id, data, timestamp):
        command, = struct.unpack_from("B", data, 0)
        ccs = command & 0xE0

        try:
            if ccs == REQUEST_UPLOAD:
                self.init_upload(data)
            elif ccs == REQUEST_SEGMENT_UPLOAD:
                self.segmented_upload(command)
            elif ccs == REQUEST_DOWNLOAD:
                self.init_download(data)
            elif ccs == REQUEST_SEGMENT_DOWNLOAD:
                self.segmented_download(command, data)
            elif ccs == REQUEST_BLOCK_UPLOAD:
                self.block_upload(data)
            elif ccs == REQUEST_BLOCK_DOWNLOAD:
                self.block_download(data)
            elif ccs == REQUEST_ABORTED:
                self.request_aborted(data)
            else:
                self.abort(0x05040001)
        except SdoAbortedError as exc:
            self.abort(exc.code)
        except KeyError as exc:
            self.abort(0x06020000)
        except Exception as exc:
            self.abort()
            logger.exception(exc)

    def init_upload(self, request):
        _, index, subindex = SDO_STRUCT.unpack_from(request)
        self._index = index
        self._subindex = subindex
        res_command = RESPONSE_UPLOAD | SIZE_SPECIFIED
        response = bytearray(8)

        data = self._node.get_data(index, subindex, check_readable=True)
        size = len(data)
        if size <= 4:
            logger.info("Expedited upload for 0x%X:%d", index, subindex)
            res_command |= EXPEDITED
            res_command |= (4 - size) << 2
            response[4:4 + size] = data
        else:
            logger.info("Initiating segmented upload for 0x%X:%d", index, subindex)
            struct.pack_into("<L", response, 4, size)
            self._buffer = bytearray(data)
            self._toggle = 0

        SDO_STRUCT.pack_into(response, 0, res_command, index, subindex)
        self.send_response(response)

    def segmented_upload(self, command):
        if command & TOGGLE_BIT != self._toggle:
            # Toggle bit mismatch
            raise SdoAbortedError(0x05030000)
        data = self._buffer[:7]
        size = len(data)

        # Remove sent data from buffer
        del self._buffer[:7]

        res_command = RESPONSE_SEGMENT_UPLOAD
        # Add toggle bit
        res_command |= self._toggle
        # Add nof bytes not used
        res_command |= (7 - size) << 1
        if not self._buffer:
            # Nothing left in buffer
            res_command |= NO_MORE_DATA
        # Toggle bit for next message
        self._toggle ^= TOGGLE_BIT

        response = bytearray(8)
        response[0] = res_command
        response[1:1 + size] = data
        self.send_response(response)

    def block_upload(self, data):
        # We currently don't support BLOCK UPLOAD
        # according to CIA301 the server is allowed
        # to switch to regular upload
        logger.info("Received block upload, switch to regular SDO upload")
        self.init_upload(data)

    def request_aborted(self, data):
        _, index, subindex, code = struct.unpack_from("<BHBL", data)
        self.last_received_error = code
        logger.info("Received request aborted for 0x%X:%d with code 0x%X", index, subindex, code)

    def block_download(self, data):
        # We currently don't support BLOCK DOWNLOAD
        logger.error("Block download is not supported")
        self.abort(0x05040001)

    def init_download(self, request):
        # TODO: Check if writable
        command, index, subindex = SDO_STRUCT.unpack_from(request)
        self._index = index
        self._subindex = subindex
        res_command = RESPONSE_DOWNLOAD
        response = bytearray(8)

        if command & EXPEDITED:
            logger.info("Expedited download for 0x%X:%d", index, subindex)
            if command & SIZE_SPECIFIED:
                size = 4 - ((command >> 2) & 0x3)
            else:
                size = 4
            self.download(index, subindex, request[4:4 + size])
        else:
            logger.info("Initiating segmented download for 0x%X:%d", index, subindex)
            if command & SIZE_SPECIFIED:
                size, = struct.unpack_from("<L", request, 4)
                logger.info("Size is %d bytes", size)
            self._buffer = bytearray()
            self._toggle = 0

        SDO_STRUCT.pack_into(response, 0, res_command, index, subindex)
        self.send_response(response)

    def segmented_download(self, command, request):
        if command & TOGGLE_BIT != self._toggle:
            # Toggle bit mismatch
            raise SdoAbortedError(0x05030000)
        last_byte = 8 - ((command >> 1) & 0x7)
        self._buffer.extend(request[1:last_byte])

        if command & NO_MORE_DATA:
            self._node.set_data(self._index,
                                self._subindex,
                                self._buffer,
                                check_writable=True)

        res_command = RESPONSE_SEGMENT_DOWNLOAD
        # Add toggle bit
        res_command |= self._toggle
        # Toggle bit for next message
        self._toggle ^= TOGGLE_BIT

        response = bytearray(8)
        response[0] = res_command
        self.send_response(response)

    def send_response(self, response):
        self.network.send_message(self.tx_cobid, response)

    def abort(self, abort_code=0x08000000):
        """Abort current transfer."""
        data = struct.pack("<BHBL", RESPONSE_ABORTED,
                           self._index, self._subindex, abort_code)
        self.send_response(data)
        # logger.error("Transfer aborted with code 0x{:08X}".format(abort_code))

    def upload(self, index, subindex):
        """May be called to make a read operation without an Object Dictionary.

        :param int index:
            Index of object to read.
        :param int subindex:
            Sub-index of object to read.

        :return: A data object.
        :rtype: bytes

        :raises canopen.SdoAbortedError:
            When node responds with an error.
        """
        return self._node.get_data(index, subindex)

    def download(self, index, subindex, data, force_segment=False):
        """May be called to make a write operation without an Object Dictionary.

        :param int index:
            Index of object to write.
        :param int subindex:
            Sub-index of object to write.
        :param bytes data:
            Data to be written.

        :raises canopen.SdoAbortedError:
            When node responds with an error.
        """
        return self._node.set_data(index, subindex, data)
<commit_msg>Check writeable for SDO upload<commit_after>import logging

from .base import SdoBase
from .constants import *
from .exceptions import *

logger = logging.getLogger(__name__)

class SdoServer(SdoBase):
    """Creates an SDO server."""

    def __init__(self, rx_cobid, tx_cobid, node):
        """
        :param int rx_cobid:
            COB-ID that the server receives on (usually 0x600 + node ID)
        :param int tx_cobid:
            COB-ID that the server responds with (usually 0x580 + node ID)
        :param canopen.LocalNode od:
            Node object owning the server
        """
        SdoBase.__init__(self, rx_cobid, tx_cobid, node.object_dictionary)
        self._node = node
        self._buffer = None
        self._toggle = 0
        self._index = None
        self._subindex = None
        self.last_received_error = 0x00000000

    def on_request(self, can_id, data, timestamp):
        command, = struct.unpack_from("B", data, 0)
        ccs = command & 0xE0

        try:
            if ccs == REQUEST_UPLOAD:
                self.init_upload(data)
            elif ccs == REQUEST_SEGMENT_UPLOAD:
                self.segmented_upload(command)
            elif ccs == REQUEST_DOWNLOAD:
                self.init_download(data)
            elif ccs == REQUEST_SEGMENT_DOWNLOAD:
                self.segmented_download(command, data)
            elif ccs == REQUEST_BLOCK_UPLOAD:
                self.block_upload(data)
            elif ccs == REQUEST_BLOCK_DOWNLOAD:
                self.block_download(data)
            elif ccs == REQUEST_ABORTED:
                self.request_aborted(data)
            else:
                self.abort(0x05040001)
        except SdoAbortedError as exc:
            self.abort(exc.code)
        except KeyError as exc:
            self.abort(0x06020000)
        except Exception as exc:
            self.abort()
            logger.exception(exc)

    def init_upload(self, request):
        _, index, subindex = SDO_STRUCT.unpack_from(request)
        self._index = index
        self._subindex = subindex
        res_command = RESPONSE_UPLOAD | SIZE_SPECIFIED
        response = bytearray(8)

        data = self._node.get_data(index, subindex, check_readable=True)
        size = len(data)
        if size <= 4:
            logger.info("Expedited upload for 0x%X:%d", index, subindex)
            res_command |= EXPEDITED
            res_command |= (4 - size) << 2
            response[4:4 + size] = data
        else:
            logger.info("Initiating segmented upload for 0x%X:%d", index, subindex)
            struct.pack_into("<L", response, 4, size)
            self._buffer = bytearray(data)
            self._toggle = 0

        SDO_STRUCT.pack_into(response, 0, res_command, index, subindex)
        self.send_response(response)

    def segmented_upload(self, command):
        if command & TOGGLE_BIT != self._toggle:
            # Toggle bit mismatch
            raise SdoAbortedError(0x05030000)
        data = self._buffer[:7]
        size = len(data)

        # Remove sent data from buffer
        del self._buffer[:7]

        res_command = RESPONSE_SEGMENT_UPLOAD
        # Add toggle bit
        res_command |= self._toggle
        # Add nof bytes not used
        res_command |= (7 - size) << 1
        if not self._buffer:
            # Nothing left in buffer
            res_command |= NO_MORE_DATA
        # Toggle bit for next message
        self._toggle ^= TOGGLE_BIT

        response = bytearray(8)
        response[0] = res_command
        response[1:1 + size] = data
        self.send_response(response)

    def block_upload(self, data):
        # We currently don't support BLOCK UPLOAD
        # according to CIA301 the server is allowed
        # to switch to regular upload
        logger.info("Received block upload, switch to regular SDO upload")
        self.init_upload(data)

    def request_aborted(self, data):
        _, index, subindex, code = struct.unpack_from("<BHBL", data)
        self.last_received_error = code
        logger.info("Received request aborted for 0x%X:%d with code 0x%X", index, subindex, code)

    def block_download(self, data):
        # We currently don't support BLOCK DOWNLOAD
        logger.error("Block download is not supported")
        self.abort(0x05040001)

    def init_download(self, request):
        # TODO: Check if writable
        command, index, subindex = SDO_STRUCT.unpack_from(request)
        self._index = index
        self._subindex = subindex
        res_command = RESPONSE_DOWNLOAD
        response = bytearray(8)

        if command & EXPEDITED:
            logger.info("Expedited download for 0x%X:%d", index, subindex)
            if command & SIZE_SPECIFIED:
                size = 4 - ((command >> 2) & 0x3)
            else:
                size = 4
            self.download(index, subindex, request[4:4 + size])
        else:
            logger.info("Initiating segmented download for 0x%X:%d", index, subindex)
            if command & SIZE_SPECIFIED:
                size, = struct.unpack_from("<L", request, 4)
                logger.info("Size is %d bytes", size)
            self._buffer = bytearray()
            self._toggle = 0

        SDO_STRUCT.pack_into(response, 0, res_command, index, subindex)
        self.send_response(response)

    def segmented_download(self, command, request):
        if command & TOGGLE_BIT != self._toggle:
            # Toggle bit mismatch
            raise SdoAbortedError(0x05030000)
        last_byte = 8 - ((command >> 1) & 0x7)
        self._buffer.extend(request[1:last_byte])

        if command & NO_MORE_DATA:
            self._node.set_data(self._index,
                                self._subindex,
                                self._buffer,
                                check_writable=True)

        res_command = RESPONSE_SEGMENT_DOWNLOAD
        # Add toggle bit
        res_command |= self._toggle
        # Toggle bit for next message
        self._toggle ^= TOGGLE_BIT

        response = bytearray(8)
        response[0] = res_command
        self.send_response(response)

    def send_response(self, response):
        self.network.send_message(self.tx_cobid, response)

    def abort(self, abort_code=0x08000000):
        """Abort current transfer."""
        data = struct.pack("<BHBL", RESPONSE_ABORTED,
                           self._index, self._subindex, abort_code)
        self.send_response(data)
        # logger.error("Transfer aborted with code 0x{:08X}".format(abort_code))

    def upload(self, index, subindex):
        """May be called to make a read operation without an Object Dictionary.

        :param int index:
            Index of object to read.
        :param int subindex:
            Sub-index of object to read.

        :return: A data object.
        :rtype: bytes

        :raises canopen.SdoAbortedError:
            When node responds with an error.
        """
        return self._node.get_data(index, subindex)

    def download(self, index, subindex, data, force_segment=False):
        """May be called to make a write operation without an Object Dictionary.

        :param int index:
            Index of object to write.
        :param int subindex:
            Sub-index of object to write.
        :param bytes data:
            Data to be written.

        :raises canopen.SdoAbortedError:
            When node responds with an error.
        """
        return self._node.set_data(index, subindex, data, check_writable=True)
<|endoftext|>


<commit_before>"""Definition of complexity classes."""

import numpy as np

class NotFittedError(Exception):
    pass

class ComplexityClass(object):
    """ Abstract class that fits complexity classes to timing data.
    """

    def __init__(self):
        # list of parameters of the fitted function class as returned by the
        # last square method np.linalg.lstsq
        self.coeff = None

    def fit(self, n, t):
        """ Fit complexity class parameters to timing data.

        Input:
        ------

        n -- Array of values of N for which execution time has been measured.

        t -- Array of execution times for each N in `ns`.

        Output:
        -------

        residuals -- Sum of square errors of fit
        """
        x = self._transform_n(n)
        y = self._transform_time(t)
        coeff, residuals, rank, s = np.linalg.lstsq(x, y)
        self.coeff = coeff
        return residuals[0]

    def compute(self, n):
        """ Compute the value of the fitted function at `n`. """
        if self.coeff is None:
            raise NotFittedError()

        # Result is linear combination of the terms with the fitted
        # coefficients
        x = self._transform_n(n)
        tot = 0
        for i in range(len(self.coeff)):
            tot += self.coeff[i] * x[:, i]
        return tot

    def __str__(self):
        prefix = '{}: '.format(self.__class__.__name__)

        if self.coeff is None:
            return prefix + ': not yet fitted'
        return prefix + self.format_str().format(*tuple(self.coeff))

    # --- abstract methods

    @classmethod
    def format_str(cls):
        """ Return a string describing the fitted function.

        The string must contain one formatting argument for each coefficient.
        """
        return 'FORMAT STRING NOT DEFINED'

    def _transform_n(self, n):
        """ Terms of the linear combination defining the complexity class.

        Output format: number of Ns x number of coefficients .
        """
        raise NotImplementedError()

    def _transform_time(self, t):
        """ Transform time as needed for fitting.
        (e.g., t->log(t)) for exponential class.
        """
        return t

# --- Concrete implementations of the most popular complexity classes

class Constant(ComplexityClass):
    def _transform_n(self, n):
        return np.ones((len(n), 1))

    @classmethod
    def format_str(cls):
        return 'time = {:.2G}'

class Linear(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*n'

class Quadratic(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n * n]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*n^2'

class Cubic(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n ** 3]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*n^3'

class Logarithmic(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), np.log(n)]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*log(n)'

class Linearithmic(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n * np.log(n)]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*n*log(n)'

class Polynomial(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), np.log(n)]).T

    def _transform_time(self, t):
        return np.log(t)

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} * x^{:.2G}'

class Exponential(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n]).T

    def _transform_time(self, t):
        return np.log(t)

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} * {:.2G}^n'

ALL_CLASSES = [Constant, Linear, Quadratic, Cubic, Polynomial,
               Logarithmic, Linearithmic, Exponential]
<commit_msg>Set the `rcond` parameter of numpy lstsq() to `-1`<commit_after>"""Definition of complexity classes."""

import numpy as np

class NotFittedError(Exception):
    pass

class ComplexityClass(object):
    """ Abstract class that fits complexity classes to timing data.
    """

    def __init__(self):
        # list of parameters of the fitted function class as returned by the
        # last square method np.linalg.lstsq
        self.coeff = None

    def fit(self, n, t):
        """ Fit complexity class parameters to timing data.

        Input:
        ------

        n -- Array of values of N for which execution time has been measured.

        t -- Array of execution times for each N in `ns`.

        Output:
        -------

        residuals -- Sum of square errors of fit
        """
        x = self._transform_n(n)
        y = self._transform_time(t)
        coeff, residuals, rank, s = np.linalg.lstsq(x, y, rcond=-1)
        self.coeff = coeff
        return residuals[0]

    def compute(self, n):
        """ Compute the value of the fitted function at `n`. """
        if self.coeff is None:
            raise NotFittedError()

        # Result is linear combination of the terms with the fitted
        # coefficients
        x = self._transform_n(n)
        tot = 0
        for i in range(len(self.coeff)):
            tot += self.coeff[i] * x[:, i]
        return tot

    def __str__(self):
        prefix = '{}: '.format(self.__class__.__name__)

        if self.coeff is None:
            return prefix + ': not yet fitted'
        return prefix + self.format_str().format(*tuple(self.coeff))

    # --- abstract methods

    @classmethod
    def format_str(cls):
        """ Return a string describing the fitted function.

        The string must contain one formatting argument for each coefficient.
        """
        return 'FORMAT STRING NOT DEFINED'

    def _transform_n(self, n):
        """ Terms of the linear combination defining the complexity class.

        Output format: number of Ns x number of coefficients .
        """
        raise NotImplementedError()

    def _transform_time(self, t):
        """ Transform time as needed for fitting.
        (e.g., t->log(t)) for exponential class.
        """
        return t

# --- Concrete implementations of the most popular complexity classes

class Constant(ComplexityClass):
    def _transform_n(self, n):
        return np.ones((len(n), 1))

    @classmethod
    def format_str(cls):
        return 'time = {:.2G}'

class Linear(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*n'

class Quadratic(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n * n]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*n^2'

class Cubic(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n ** 3]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*n^3'

class Logarithmic(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), np.log(n)]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*log(n)'

class Linearithmic(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n * np.log(n)]).T

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} + {:.2G}*n*log(n)'

class Polynomial(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), np.log(n)]).T

    def _transform_time(self, t):
        return np.log(t)

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} * x^{:.2G}'

class Exponential(ComplexityClass):
    def _transform_n(self, n):
        return np.vstack([np.ones(len(n)), n]).T

    def _transform_time(self, t):
        return np.log(t)

    @classmethod
    def format_str(cls):
        return 'time = {:.2G} * {:.2G}^n'

ALL_CLASSES = [Constant, Linear, Quadratic, Cubic, Polynomial,
               Logarithmic, Linearithmic, Exponential]
<|endoftext|>


<commit_before>from .models import Client
from .models import Company
from .models import Contact
from .models import Estimate
from .models import Invoice
from .models import Newsletter
from .models import Note
from .models import Profile
from .models import Project
from .models import Report
from .models import Service
from .models import Settings
from .models import Task
from .models import Time
from django import forms

class ClientForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = '__all__'

class CompanyForm(forms.ModelForm):
    class Meta:
        model = Company
        fields = '__all__'
        widgets = {
            'notes': forms.widgets.TextInput(attrs={'class': 'tinymce'}),
        }

class ContactForm(forms.ModelForm):
    class Meta:
        model = Contact
        fields = '__all__'

class EstimateForm(forms.ModelForm):
    class Meta:
        model = Estimate
        fields = ('document_id', 'issue_date', 'client', 'subject',
                  'accepted_date')

class InvoiceForm(forms.ModelForm):
    """
    Issue Date, Last Payment Date, Invoice ID, PO Number, Client, Subject,
    Invoice Amount, Paid Amount, Balance, Subtotal, Discount, Tax, Tax2,
    Currency, Currency Symbol, Document Type
    """

    class Meta:
        model = Invoice
        fields = (
            'document_id',
            'po_number',
            'project',
            'issue_date',
            'last_payment_date',
            'subject', )

class MailForm(forms.Form):
    test = forms.BooleanField(required=False)
    subject = forms.CharField(required=False)
    message = forms.CharField(widget=forms.Textarea(), required=False)

class NewsletterForm(forms.ModelForm):
    class Meta:
        model = Newsletter
        fields = (
            'contacts',
            'text', )
        widgets = {
            'text': forms.widgets.TextInput(attrs={'class': 'tinymce'}),
        }

    contacts = forms.ModelChoiceField(queryset=Contact.objects.none())

    def __init__(self, *args, **kwargs):

        super(NewsletterForm, self).__init__(*args, **kwargs)
        qs = kwargs.pop('contacts')
        self.fields['contacts'].queryset = Contact.objects.filter(
            subscribed=True).exclude(email__isnull=True)

class NoteForm(forms.ModelForm):
    class Meta:
        model = Note
        fields = ('note', )
        widgets = {
            'note': forms.widgets.TextInput(attrs={'class': 'tinymce'}),
        }

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('active', 'published', 'bio', 'rate')

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = ('active', 'hidden', 'budget', 'client', 'name', 'notes',
                  'start_date', 'end_date', 'task', 'team')

class ReportForm(forms.ModelForm):
    class Meta:
        model = Report
        fields = '__all__'

class ServiceForm(forms.ModelForm):
    class Meta:
        model = Service
        fields = '__all__'

class SettingsForm(forms.ModelForm):
    class Meta:
        model = Settings
        fields = '__all__'

class TaskForm(forms.ModelForm):
    class Meta:
        model = Task
        fields = ('active', 'name', 'rate', 'unit', 'color')

class TimeAdminForm(forms.ModelForm):
    class Meta:
        model = Time
        fields = ('date', 'hours', 'notes', 'client', 'project', 'task',
                  'user', 'estimate', 'invoice', 'invoiced')

class TimeForm(forms.ModelForm):
    class Meta:
        model = Time
        fields = ('date', 'hours', 'notes', 'client', 'project', 'task')
<commit_msg>Update<commit_after>from .models import Client
from .models import Company
from .models import Contact
from .models import Estimate
from .models import Invoice
from .models import Newsletter
from .models import Note
from .models import Profile
from .models import Project
from .models import Report
from .models import Service
from .models import Settings
from .models import Task
from .models import Time
from django import forms

class ClientForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = '__all__'

class CompanyForm(forms.ModelForm):
    class Meta:
        model = Company
        fields = '__all__'
        widgets = {
            'notes': forms.widgets.TextInput(attrs={'class': 'tinymce'}),
        }

class ContactForm(forms.ModelForm):
    class Meta:
        model = Contact
        fields = '__all__'

class EstimateForm(forms.ModelForm):
    class Meta:
        model = Estimate
        fields = ('document_id', 'issue_date', 'client', 'subject',
                  'accepted_date')

class InvoiceForm(forms.ModelForm):
    """
    Issue Date, Last Payment Date, Invoice ID, PO Number, Client, Subject,
    Invoice Amount, Paid Amount, Balance, Subtotal, Discount, Tax, Tax2,
    Currency, Currency Symbol, Document Type
    """

    class Meta:
        model = Invoice
        fields = (
            'document_id',
            'po_number',
            'project',
            'issue_date',
            'last_payment_date',
            'subject', )

class MailForm(forms.Form):
    test = forms.BooleanField(required=False)
    subject = forms.CharField(required=False)
    message = forms.CharField(widget=forms.Textarea(), required=False)

class NewsletterForm(forms.ModelForm):
    class Meta:
        model = Newsletter
        fields = (
            'contacts',
            'text', )
        widgets = {
            'text': forms.widgets.TextInput(attrs={'class': 'tinymce'}),
        }

class NoteForm(forms.ModelForm):
    class Meta:
        model = Note
        fields = ('note', )
        widgets = {
            'note': forms.widgets.TextInput(attrs={'class': 'tinymce'}),
        }

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('active', 'published', 'bio', 'rate')

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = ('active', 'hidden', 'budget', 'client', 'name', 'notes',
                  'start_date', 'end_date', 'task', 'team')

class ReportForm(forms.ModelForm):
    class Meta:
        model = Report
        fields = '__all__'

class ServiceForm(forms.ModelForm):
    class Meta:
        model = Service
        fields = '__all__'

class SettingsForm(forms.ModelForm):
    class Meta:
        model = Settings
        fields = '__all__'

class TaskForm(forms.ModelForm):
    class Meta:
        model = Task
        fields = ('active', 'name', 'rate', 'unit', 'color')

class TimeAdminForm(forms.ModelForm):
    class Meta:
        model = Time
        fields = ('date', 'hours', 'notes', 'client', 'project', 'task',
                  'user', 'estimate', 'invoice', 'invoiced')

class TimeForm(forms.ModelForm):
    class Meta:
        model = Time
        fields = ('date', 'hours', 'notes', 'client', 'project', 'task')
<|endoftext|>


<commit_before>#!/usr/bin/env python3

import sys
import os
import math

import numpy
import matplotlib.pyplot as plt

sys.path.append('./climatemaps')

import climatemaps

DATA_OUT_DIR = './website/data'

TYPES = {
    'precipitation': {
        'filepath': 'data/precipitation/cpre6190.dat',
        'conversion_factor': 0.1,  # (millimetres/day) *10
        'config': climatemaps.contour.ContourPlotConfig(0.1, 16, colormap=plt.cm.jet_r, unit='mm/day', logscale=True)
    },
    'cloud': {
        'filepath': 'data/cloud/ccld6190.dat',
        'conversion_factor': 1,
        'config': climatemaps.contour.ContourPlotConfig(0, 100, colormap=plt.cm.jet_r, unit='%')
    },
    'mintemp': {
        'filepath': 'data/mintemp/ctmn6190.dat',
        'conversion_factor': 0.1,
        'config': climatemaps.contour.ContourPlotConfig(-40, 28, colormap=plt.cm.jet, unit='C')
    },
    'maxtemp': {
        'filepath': 'data/maxtemp/ctmx6190.dat',
        'conversion_factor': 0.1,
        'config': climatemaps.contour.ContourPlotConfig(-20, 50, colormap=plt.cm.jet, unit='C')
    },
    'wetdays': {
        'filepath': 'data/wetdays/cwet6190.dat',
        'conversion_factor': 0.1,
        'config': climatemaps.contour.ContourPlotConfig(0, 30, colormap=plt.cm.jet_r, unit='days')
    },
    'wind': {
        'filepath': 'data/wind/cwnd6190.dat',
        'conversion_factor': 0.1,
        'config': climatemaps.contour.ContourPlotConfig(0, 10, colormap=plt.cm.jet, unit='m/s')
    },
    'radiation': {
        'filepath': 'data/radiation/crad6190.dat',
        'conversion_factor': 1.0,
        'config': climatemaps.contour.ContourPlotConfig(0, 300, colormap=plt.cm.jet, unit='W/m^2')
    },
}

def main():
    for data_type, settings in TYPES.items():
        for month in range(1, 13):
        # for month in range(1, 3):
            latrange, lonrange, Z = climatemaps.data.import_climate_data(settings['filepath'], month, settings['conversion_factor'])
            contourmap = climatemaps.contour.Contour(settings['config'], lonrange, latrange, Z)
            contourmap.create_contour_data(DATA_OUT_DIR, data_type, month)
    for month in range(1, 13):
        create_optimal_map(month)

def create_optimal_map(month):
    settings = TYPES['precipitation']
    latrange, lonrange, Zpre = climatemaps.data.import_climate_data(settings['filepath'], month, settings['conversion_factor'])

    settings = TYPES['cloud']
    latrange, lonrange, Zcloud = climatemaps.data.import_climate_data(settings['filepath'], month, settings['conversion_factor'])

    settings = TYPES['maxtemp']
    latrange, lonrange, Ztmax = climatemaps.data.import_climate_data(settings['filepath'], month, settings['conversion_factor'])

    for x in numpy.nditer(Zpre, op_flags=['readwrite']):
        if x/16.0 > 1.0:
            x[...] = 0.0
        else:
            x[...] = 1.0 - x/16.0

    for x in numpy.nditer(Ztmax, op_flags=['readwrite']):
        temp_ideal = 22
        x[...] = 1.0 - math.pow((x-temp_ideal)/10.0, 2)

    Zscore_cloud = (100 - Zcloud)/100

    Z = (Zpre + Zscore_cloud + Ztmax) / 3.0 * 10.0

    for x in numpy.nditer(Z, op_flags=['readwrite']):
        x[...] = max(x, 0.0)

    config = climatemaps.contour.ContourPlotConfig(0.0, 9.0, colormap=plt.cm.RdYlGn, unit='')
    contourmap = climatemaps.contour.Contour(config, lonrange, latrange, Z)
    contourmap.create_contour_data(DATA_OUT_DIR, 'optimal', month)
    print('month done: ' + str(month))

if __name__ == "__main__":
    main()
<commit_msg>Fix local relative import of climatemaps module<commit_after>#!/usr/bin/env python3

import sys
import os
import math

import numpy
import matplotlib.pyplot as plt

sys.path.append('../climatemaps')

import climatemaps

DATA_OUT_DIR = './website/data'

TYPES = {
    'precipitation': {
        'filepath': 'data/precipitation/cpre6190.dat',
        'conversion_factor': 0.1,  # (millimetres/day) *10
        'config': climatemaps.contour.ContourPlotConfig(0.1, 16, colormap=plt.cm.jet_r, unit='mm/day', logscale=True)
    },
    'cloud': {
        'filepath': 'data/cloud/ccld6190.dat',
        'conversion_factor': 1,
        'config': climatemaps.contour.ContourPlotConfig(0, 100, colormap=plt.cm.jet_r, unit='%')
    },
    'mintemp': {
        'filepath': 'data/mintemp/ctmn6190.dat',
        'conversion_factor': 0.1,
        'config': climatemaps.contour.ContourPlotConfig(-40, 28, colormap=plt.cm.jet, unit='C')
    },
    'maxtemp': {
        'filepath': 'data/maxtemp/ctmx6190.dat',
        'conversion_factor': 0.1,
        'config': climatemaps.contour.ContourPlotConfig(-20, 50, colormap=plt.cm.jet, unit='C')
    },
    'wetdays': {
        'filepath': 'data/wetdays/cwet6190.dat',
        'conversion_factor': 0.1,
        'config': climatemaps.contour.ContourPlotConfig(0, 30, colormap=plt.cm.jet_r, unit='days')
    },
    'wind': {
        'filepath': 'data/wind/cwnd6190.dat',
        'conversion_factor': 0.1,
        'config': climatemaps.contour.ContourPlotConfig(0, 10, colormap=plt.cm.jet, unit='m/s')
    },
    'radiation': {
        'filepath': 'data/radiation/crad6190.dat',
        'conversion_factor': 1.0,
        'config': climatemaps.contour.ContourPlotConfig(0, 300, colormap=plt.cm.jet, unit='W/m^2')
    },
}

def main():
    for data_type, settings in TYPES.items():
        for month in range(1, 13):
        # for month in range(1, 3):
            latrange, lonrange, Z = climatemaps.data.import_climate_data(settings['filepath'], month, settings['conversion_factor'])
            contourmap = climatemaps.contour.Contour(settings['config'], lonrange, latrange, Z)
            contourmap.create_contour_data(DATA_OUT_DIR, data_type, month)
    for month in range(1, 13):
        create_optimal_map(month)

def create_optimal_map(month):
    settings = TYPES['precipitation']
    latrange, lonrange, Zpre = climatemaps.data.import_climate_data(settings['filepath'], month, settings['conversion_factor'])

    settings = TYPES['cloud']
    latrange, lonrange, Zcloud = climatemaps.data.import_climate_data(settings['filepath'], month, settings['conversion_factor'])

    settings = TYPES['maxtemp']
    latrange, lonrange, Ztmax = climatemaps.data.import_climate_data(settings['filepath'], month, settings['conversion_factor'])

    for x in numpy.nditer(Zpre, op_flags=['readwrite']):
        if x/16.0 > 1.0:
            x[...] = 0.0
        else:
            x[...] = 1.0 - x/16.0

    for x in numpy.nditer(Ztmax, op_flags=['readwrite']):
        temp_ideal = 22
        x[...] = 1.0 - math.pow((x-temp_ideal)/10.0, 2)

    Zscore_cloud = (100 - Zcloud)/100

    Z = (Zpre + Zscore_cloud + Ztmax) / 3.0 * 10.0

    for x in numpy.nditer(Z, op_flags=['readwrite']):
        x[...] = max(x, 0.0)

    config = climatemaps.contour.ContourPlotConfig(0.0, 9.0, colormap=plt.cm.RdYlGn, unit='')
    contourmap = climatemaps.contour.Contour(config, lonrange, latrange, Z)
    contourmap.create_contour_data(DATA_OUT_DIR, 'optimal', month)
    print('month done: ' + str(month))

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>#!/usr/bin/env python2.7

import sqlite3 as lite
import json
from time import time
from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
from twisted.internet.endpoints import UNIXServerEndpoint as ServerEndpoint

class Module(Protocol):
	def __init__(self, db_conn):
		print 'nothing'
		#nothing for now but we should create the attributes ...

	def dataReceived(self, data):
		try:
			json_data = json.loads(data)
		except ValueError:
			self.err_decode_data()
			return

		if not 'code' in json_data:
			self.err_code_not_found()
			return

		code = str(json_data['code'])
		if code == 'get_cur':
			self.get_cur(json_data)
		elif code == 'get_at':
			self.get_at(json_data)
		elif code == 'get_from_to':
			self.get_from_to(json_data)
		elif code == 'answer':
			self.load_answer(json_data
		else:
			self.err_code_not_found()

	def error(self, msg):
# TODO log errors
		print msg
		re = {'success': False}
		self.transport.write(json.dumps(re))

	def err_decode_data(self):
		self.error('Impossible to decode the received data')

	def err_code_not_found(self):
		self.error('Code not found in the query')

	def get_cur(self, data):
		entry_objs = data['objs']
		for attr in list_attr:
			if attr.name in entry_objs:
				self.update_attrs()
				out = {}
				out['code'] = "answer"
				out['asking_attr'] = data['asking_attr']
				out['obj']=attr
				out_json = json.dumps(out)
				self.transport.write(out_json)

	def get_at(self, data):
		#just send it to the db
		self.transport.write(db_data)

	def get_from_to(self, data):
		#just send it to the db
		self.transport.write(db_data)

	def update_attrs(self):
		for attr in list_attr:
			if len(attr.list_depend) > 0:

				# avant d'envoyer la demeande je vasi faire une liste qui va check si j'ai reçu mes info pr l'appel bloquant
				#rmq il faut que ce tableau soit la list depend ....
				#on la clear à chaque fois que on s'en ert comme sa elle peut servir de global pr traveerser les fonctions
				#a refaire sous al forme d'un tin de dico

				#envoie de la demande
				out = {}
				out['code'] = "get_cur"
				out['asking_attr']=attr.name
				out['objs'] = attr.list_depend
				out_json = json.dumps(out)
				self.transport.write(out_json)

				test=true;
				while test != true:

					#I want to wait here but how
					#maybe creating an event (is there away in python ??)

					#verif si on a recup toute les valeurs
					test = true
					for cle, value in attr.list_depend:
						if value = 0:
							test = false
							break

				#here we need to update the attribute
				#but idk how f_eval works ...

				#and now we clear list_depend so we signal that we need to ask for data next time
				for cle in attr.list_depend:
					attr.list_depend[cle] = 0

	def load_answer(self,data):
		for elem in list_attr:
			if elem.name = data['asking_attr']:
				obj=data['obj']
				elem.list_depend[obj.name]=obj

		#here we need to launch an event to signal we have gotted some infos
		#to ask the funstions to continu and check if they have all the info they need

if __name__ == '__main__':
	factory = Factory()
	factory.protocol = Module
	port = reactor.listenUNIX('module.sock', factory)
	reactor.run()
<commit_msg>Correction rapide<commit_after>#!/usr/bin/env python2.7

import sqlite3 as lite
import json
from time import time
from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
from twisted.internet.endpoints import UNIXServerEndpoint as ServerEndpoint

class ModuleConnection(Protocol):
    def __init__(self, module):
        self.module = module

    def dataReceived(self, data):
        try:
            json_data = json.loads(data)
        except ValueError:
            self.err_decode_data()
            return

        if not 'code' in json_data:
            self.err_code_not_found()
            return

        code = str(json_data['code'])
        if code == 'get_cur':
            self.get_cur(json_data)
        elif code == 'get_at':
            self.get_at(json_data)
        elif code == 'get_from_to':
            self.get_from_to(json_data)
        elif code == 'answer':
            self.load_answer(json_data
        else:
            self.err_code_not_found()

    def error(self, msg):
# TODO log errors
        print msg
        re = {'success': False}
        self.transport.write(json.dumps(re))

    def err_decode_data(self):
        self.error('Impossible to decode the received data')

    def err_code_not_found(self):
        self.error('Code not found in the query')

    def err_field_error(self):
        self.error('Field not found')

    def get_cur(self, data):
        try:
            entry_objs = data['objs']
        except (TypeError, KeyError):
            self.err_decode_data()
            return

        ls_attr = []
        for attr in entry_objs:
            try:
                get = getattr(self.module, attr)
                ls_attr[attr] = get()
            except (AttributeError, IOError):
                self.err_field_error()
                return

        res = {}
        res['success'] = True
        res['objs'] = ls_attr
        self.transport.write(json.dumps(res))

    def get_at(self, data):
        try:
            entry_objs = data['objs']
            t = float(data['time'])
        except (TypeError, KeyError):
            self.err_decode_data()
            return

        ls_attr = []
        for attr in entry_objs:
            try:
                get = getattr(self.module, attr)
                ls_attr[attr] = get(t=t)
            except (AttributeError, IOError):
                self.err_field_error()
                return

        res = {}
        res['success'] = True
        res['objs'] = ls_attr
        self.transport.write(json.dumps(res))

    def get_from_to(self, data):
        try:
            entry_objs = data['objs']
            fr = float(data['time_begin'])
            to = float(data['time_end'])
        except (TypeError, KeyError):
            self.err_decode_data()
            return

        ls_attr = []
        for attr in entry_objs:
            try:
                get = getattr(self.module, attr)
                ls_attr[attr] = get(fr=fr, to=to)
            except (AttributeError, IOError):
                self.err_field_error()
                return

        res = {}
        res['success'] = True
        res['objs'] = ls_attr
        self.transport.write(json.dumps(res))

class ModuleConnectionFactory(Factory):
    def __init__(self, module):
        self.module = module

    def buildProtocol(self, addr):
        return ModuleConnection(self.module)

if __name__ == '__main__':
    module = None
    endpoint = ServerEndpoint(reactor, module.socket_filename)
    endpoint.listen(ModuleConnectionFactory(module))
    reactor.run()
<|endoftext|>