diff --git a/docs/.buildinfo b/docs/.buildinfo deleted file mode 100644 index 68e7d4d..0000000 --- a/docs/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: cb1faa8f14eeb0b5445f344124e1e3b5 -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/.nojekyll b/docs/.nojekyll deleted file mode 100644 index e69de29..0000000 diff --git a/docs/_modules/index.html b/docs/_modules/index.html deleted file mode 100644 index 30c2d6a..0000000 --- a/docs/_modules/index.html +++ /dev/null @@ -1,257 +0,0 @@ - - - - - - - - - - - Overview: module code — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/ensemble_data.html b/docs/_modules/physical_validation/data/ensemble_data.html deleted file mode 100644 index 288ffbd..0000000 --- a/docs/_modules/physical_validation/data/ensemble_data.html +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - - - - - - physical_validation.data.ensemble_data — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.ensemble_data
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.ensemble_data

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-Data structures carrying simulation data.
-"""
-import warnings
-
-from ..util import error as pv_error
-
-
-
[docs]class EnsembleData(object): - r"""EnsembleData: Holds data defining the ensemble - - The ensemble is a string indicating the thermodynamical ensemble a simulation was - performed in, and is any of 'NVE', 'NVT', 'NPT', 'muVT'. - Depending on the ensemble, EnsembleData then holds additional information defining - the ensemble, such as the number of particles N, the chemical potential mu, the - volume V, the pressure P, the constant energy E or the temperature T. While any - of these additional information are optional, most of them are needed by certain - tests, such that not fully defining the ensemble results in warnings. The notable - exception to this rule is the constant energy E for the NVE, which is not needed - by any test and can hence be omitted without raising a warning. - """ - -
[docs] @staticmethod - def ensembles(): - return ('NVE', - 'NVT', - 'NPT', - 'muVT')
- - def __init__(self, ensemble, - natoms=None, mu=None, - volume=None, pressure=None, - energy=None, temperature=None): - self.__ensemble = None - self.__n = None - self.__mu = None - self.__v = None - self.__p = None - self.__e = None - self.__t = None - - if ensemble not in self.ensembles(): - raise pv_error.InputError('ensemble', - 'Given ensemble unknown.') - self.__ensemble = ensemble - - if ensemble == 'NVE': - if natoms is None: - warnings.warn(ensemble + ' with undefined natoms.') - if volume is None: - warnings.warn(ensemble + ' with undefined volume.') - # if energy is None: - # warnings.warn(ensemble + ' with undefined energy.') - self.__n = natoms - self.__v = volume - self.__e = energy - if ensemble == 'NVT': - if natoms is None: - warnings.warn(ensemble + ' with undefined natoms.') - if volume is None: - warnings.warn(ensemble + ' with undefined volume.') - if temperature is None: - warnings.warn(ensemble + ' with undefined temperature.') - self.__n = natoms - self.__v = volume - self.__t = temperature - if ensemble == 'NPT': - if natoms is None: - warnings.warn(ensemble + ' with undefined natoms.') - if pressure is None: - warnings.warn(ensemble + ' with undefined pressure.') - if temperature is None: - warnings.warn(ensemble + ' with undefined temperature.') - self.__n = natoms - self.__p = pressure - self.__t = temperature - if ensemble == 'muVT': - if mu is None: - warnings.warn(ensemble + ' with undefined mu.') - if volume is None: - warnings.warn(ensemble + ' with undefined volume.') - if temperature is None: - warnings.warn(ensemble + ' with undefined temperature.') - self.__mu = mu - self.__v = volume - self.__t = temperature - - @property - def ensemble(self): - """Get ensemble""" - return self.__ensemble - - @property - def natoms(self): - """Get natoms""" - return self.__n - - @property - def mu(self): - """Get mu""" - return self.__mu - - @property - def volume(self): - """Get volume""" - return self.__v - - @property - def pressure(self): - """Get pressure""" - return self.__p - - @property - def energy(self): - """Get energy""" - return self.__e - - @property - def temperature(self): - """Get temperature""" - return self.__t
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/flatfile_parser.html b/docs/_modules/physical_validation/data/flatfile_parser.html deleted file mode 100644 index ce50626..0000000 --- a/docs/_modules/physical_validation/data/flatfile_parser.html +++ /dev/null @@ -1,414 +0,0 @@ - - - - - - - - - - - physical_validation.data.flatfile_parser — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.flatfile_parser
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.flatfile_parser

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-flatfile_parser.py
-"""
-from . import parser
-from . import SimulationData, TrajectoryData, ObservableData
-
-
-
[docs]class FlatfileParser(parser.Parser): - """ - FlatfileParser - """ - - def __init__(self): - super(FlatfileParser, self).__init__() - -
[docs] def get_simulation_data(self, units=None, ensemble=None, system=None, dt=None, - position_file=None, velocity_file=None, - kinetic_ene_file=None, potential_ene_file=None, - total_ene_file=None, volume_file=None, - pressure_file=None, temperature_file=None, - const_of_mot_file=None): - r"""Read simulation data from flat files - - Returns a SimulationData object created from (optionally) provided UnitData, EnsembleData - and SystemData, as well as TrajectoryData and ObservableData objects created from flat - files. The files are expected to be in one of the following formats: - - * xyz-format - trajectory files (position_file, velocity_file) - - three numbers per line, separated by white space - - frames delimited by a completely blank line - - any character after (and including) a '#' are ignored - * 1d-format - all other files - - one number per line - - any character after (and including) a '#' are ignored - - Parameters - ---------- - units: UnitData, optional - A UnitData object representing the units used in the simulation - ensemble: EnsembleData, optional - A EnsembleData object representing the ensemble the simulation has been performed in - system: SystemData, optional - A SystemData object representing the atoms and molecules in the system - dt: float, optional - The time step used in the simulation - position_file: str, optional - Path to a file in xyz-format containing the position trajectory - velocity_file: str, optional - Path to a file in xyz-format containing the velocity trajectory - kinetic_ene_file: str, optional - Path to a file in 1d-format containing the kinetic energy trajectory - potential_ene_file: str, optional - Path to a file in 1d-format containing the potential energy trajectory - total_ene_file: str, optional - Path to a file in 1d-format containing the total energy trajectory - volume_file: str, optional - Path to a file in 1d-format containing the volume trajectory - pressure_file: str, optional - Path to a file in 1d-format containing the pressure trajectory - temperature_file: str, optional - Path to a file in 1d-format containing the temperature trajectory - const_of_mot_file: str, optional - Path to a file in 1d-format containing the constant of motion trajectory - - Returns - ------- - result: SimulationData - A SimulationData filled with the provided ensemble and - system objects as well as the trajectory data found in the - edr and trr / gro files. - - """ - - trj_dict = { - 'position': position_file, - 'velocity': velocity_file - } - - if any(trj_dict.values()): - trajectory = TrajectoryData() - for key, filename in trj_dict.items(): - if filename is None: - continue - trajectory[key] = self.__read_xyz(filename) - else: - trajectory = None - - obs_dict = { - 'kinetic_energy': kinetic_ene_file, - 'potential_energy': potential_ene_file, - 'total_energy': total_ene_file, - 'volume': volume_file, - 'pressure': pressure_file, - 'temperature': temperature_file, - 'constant_of_motion': const_of_mot_file - } - - if any(obs_dict.values()): - observables = ObservableData() - for key, filename in obs_dict.items(): - if filename is None: - continue - observables[key] = self.__read_1d(filename) - else: - observables = None - - result = SimulationData(units=units, dt=dt, system=system, ensemble=ensemble, - observables=observables, trajectory=trajectory) - - return result
- - @staticmethod - def __read_xyz(filename): - result = [] - with open(filename) as f: - frame = [] - for line in f: - if not line: - # blank line - if frame: - result.append(frame) - frame = [] - continue - line = line.split('#', maxsplit=1)[0].strip() - if not line: - # only comment on this line - continue - xyz = line.split()[0:3] - frame.append([float(n) for n in xyz]) - if frame: - result.append(frame) - return result - - @staticmethod - def __read_1d(filename): - result = [] - with open(filename) as f: - for line in f: - line = line.split('#', maxsplit=1)[0].strip() - if not line: - # blank or comment-only line - continue - result.append(float(line.strip())) - return result
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/gromacs_parser.html b/docs/_modules/physical_validation/data/gromacs_parser.html deleted file mode 100644 index 91245ea..0000000 --- a/docs/_modules/physical_validation/data/gromacs_parser.html +++ /dev/null @@ -1,536 +0,0 @@ - - - - - - - - - - - physical_validation.data.gromacs_parser — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.gromacs_parser
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.gromacs_parser

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-gromacs_parser.py
-"""
-import warnings
-import numpy as np
-
-from . import parser
-# py2.7 compatibility
-from .simulation_data import SimulationData
-from .unit_data import UnitData
-from .ensemble_data import EnsembleData
-from .system_data import SystemData
-from .observable_data import ObservableData
-from .trajectory_data import TrajectoryData
-# replace lines above by this when py2.7 support is dropped:
-# from . import SimulationData, UnitData, EnsembleData, SystemData, ObservableData, TrajectoryData
-from ..util.gromacs_interface import GromacsInterface
-from ..util import error as pv_error
-
-
-
[docs]class GromacsParser(parser.Parser): - """ - GromacsParser - """ - -
[docs] @staticmethod - def units(): - # Gromacs uses kJ/mol - return UnitData( - kb=8.314462435405199e-3, - energy_str='kJ/mol', - energy_conversion=1.0, - length_str='nm', - length_conversion=1.0, - volume_str='nm^3', - volume_conversion=1.0, - temperature_str='K', - temperature_conversion=1.0, - pressure_str='bar', - pressure_conversion=1.0, - time_str='ps', - time_conversion=1.0)
- - def __init__(self, exe=None, includepath=None): - r""" - Create a GromacsParser object - - Parameters - ---------- - exe: str, optional - Path to a gmx executable (or simply the executable name, if it is in the path) - Default: Looks for `gmx`, then for `gmx_d` in the path. If neither is found, `exe` is - set to None, and any parsing including simulation trajectories (`edr`, `trr` - and `gro` arguments in `get_simulation_data()`) will fail. - includepath: str or List[str], optional - Path or list of paths to location(s) of topology file. Is used for the lookup of - `#include` statements in topologies. - Default: None - no additional topology location. Lookup will be restricted to current - directory and location of the `top` file given to `get_simulation_data()`, - plus any include locations added to the `mdp` file. - """ - super(GromacsParser, self).__init__() - self.__interface = GromacsInterface(exe=exe, includepath=includepath) - # gmx energy codes - self.__gmx_energy_names = {'kinetic_energy': 'Kinetic-En.', - 'potential_energy': 'Potential', - 'total_energy': 'Total-Energy', - 'volume': 'Volume', - 'pressure': 'Pressure', - 'temperature': 'Temperature', - 'constant_of_motion': 'Conserved-En.'} - -
[docs] def get_simulation_data(self, - mdp=None, top=None, edr=None, - trr=None, gro=None): - r""" - - Parameters - ---------- - mdp: str, optional - A string pointing to a .mdp file - top: str, optional - A string pointing to a .top file - edr: str, optional - A string pointing to a .edr file - trr: str, optional - A string pointing to a .trr file - gro: str, optional - A string pointing to a .gro file (Note: if also trr is given, gro is ignored) - - Returns - ------- - result: SimulationData - A SimulationData filled with the provided ensemble and - system objects as well as the trajectory data found in the - edr and trr / gro files. - - """ - result = SimulationData() - result.units = self.units() - - # trajectories (might be used later for the box...) - trajectory_dict = None - if trr is not None: - if gro is not None: - warnings.warn('`trr` and `gro` given. Ignoring `gro`.') - - trajectory_dict = self.__interface.read_trr(trr) - result.trajectory = TrajectoryData( - trajectory_dict['position'], - trajectory_dict['velocity']) - elif gro is not None: - trajectory_dict = self.__interface.read_gro(gro) - result.trajectory = TrajectoryData( - trajectory_dict['position'], - trajectory_dict['velocity']) - - # simulation parameters & system - if mdp is not None and top is not None: - mdp_options = self.__interface.read_mdp(mdp) - define = None - include = None - if 'define' in mdp_options: - define = mdp_options['define'] - if 'include' in mdp_options: - include = mdp_options['include'] - molecules = self.__interface.read_system_from_top(top, define=define, include=include) - - if 'dt' in mdp_options: - result.dt = float(mdp_options['dt']) - - natoms = 0 - mass = [] - constraints_per_molec = [] - angles = ('constraints' in mdp_options and - mdp_options['constraints'] == 'all-angles') - angles_h = (angles or - 'constraints' in mdp_options and - mdp_options['constraints'] == 'h-angles') - bonds = (angles_h or - 'constraints' in mdp_options and - mdp_options['constraints'] == 'all-bonds') - bonds_h = (bonds or - 'constraints' in mdp_options and - mdp_options['constraints'] == 'h-bonds') - - molecule_idx = [] - next_molec = 0 - molec_bonds = [] - molec_bonds_constrained = [] - for molecule in molecules: - natoms += molecule['nmolecs'] * molecule['natoms'] - for n in range(0, molecule['nmolecs']): - molecule_idx.append(next_molec) - next_molec += molecule['natoms'] - mass.extend(molecule['mass'] * molecule['nmolecs']) - constraints = 0 - constrained_bonds = [] - all_bonds = molecule['bonds'] + molecule['bondsh'] - if molecule['settles']: - constraints = 3 - constrained_bonds = all_bonds - else: - if bonds: - constraints += molecule['nbonds'][0] - constrained_bonds.extend(molecule['bonds']) - if bonds_h: - constraints += molecule['nbonds'][1] - constrained_bonds.extend(molecule['bondsh']) - if angles: - constraints += molecule['nangles'][0] - if angles_h: - constraints += molecule['nangles'][1] - constraints_per_molec.extend([constraints] * molecule['nmolecs']) - molec_bonds.extend([all_bonds] * molecule['nmolecs']) - molec_bonds_constrained.extend([constrained_bonds] * molecule['nmolecs']) - - topology = SystemData() - topology.natoms = natoms - topology.mass = mass - topology.molecule_idx = molecule_idx - topology.nconstraints = np.sum(constraints_per_molec) - topology.nconstraints_per_molecule = constraints_per_molec - topology.ndof_reduction_tra = 3 - topology.ndof_reduction_rot = 0 - if 'comm-mode' in mdp_options: - if mdp_options['comm-mode'] == 'linear': - topology.ndof_reduction_tra = 3 - elif mdp_options['comm-mode'] == 'angular': - topology.ndof_reduction_tra = 3 - topology.ndof_reduction_rot = 3 - if mdp_options['comm-mode'] == 'none': - topology.ndof_reduction_tra = 0 - topology.bonds = molec_bonds - topology.constrained_bonds = molec_bonds_constrained - result.system = topology - - thermostat = ('tcoupl' in mdp_options and - mdp_options['tcoupl'] and - mdp_options['tcoupl'] != 'no') - stochastic_dyn = ('integrator' in mdp_options and - mdp_options['integrator'] in ['sd', 'sd2', 'bd']) - constant_temp = thermostat or stochastic_dyn - temperature = None - if constant_temp: - ref_t = [float(t) for t in mdp_options['ref-t'].split()] - if len(ref_t) == 1 or np.allclose(ref_t, [ref_t[0]]*len(ref_t)): - temperature = ref_t[0] - else: - raise pv_error.InputError('mdp', - 'Ensemble definition ambiguous: Different t-ref values found.') - - constant_press = ('pcoupl' in mdp_options and - mdp_options['pcoupl'] and - mdp_options['pcoupl'] != 'no') - volume = None - pressure = None - if constant_press: - ref_p = [float(p) for p in mdp_options['ref-p'].split()] - if len(ref_p) == 1 or np.allclose(ref_p, [ref_p[0]]*len(ref_p)): - pressure = ref_p[0] - else: - raise pv_error.InputError('mdp', - 'Ensemble definition ambiguous: Different p-ref values found.') - else: - if trajectory_dict is not None: - box = trajectory_dict['box'][0] - # Different box shapes? - volume = box[0]*box[1]*box[2] - else: - warnings.warn('Constant volume simulation with undefined volume.') - - if constant_temp and constant_press: - ens = 'NPT' - elif constant_temp: - ens = 'NVT' - else: - ens = 'NVE' - - if ens == 'NVE': - self.__gmx_energy_names['constant_of_motion'] = 'Total-Energy' - else: - self.__gmx_energy_names['constant_of_motion'] = 'Conserved-En.' - - result.ensemble = EnsembleData( - ens, - natoms=natoms, - volume=volume, pressure=pressure, - temperature=temperature - ) - - if edr is not None: - observable_dict = self.__interface.get_quantities(edr, - self.__gmx_energy_names.values(), - args=['-dp']) - - # constant volume simulations don't write out the volume in .edr file - if (observable_dict['Volume'] is None and - result.ensemble is not None and - result.ensemble.volume is not None): - nframes = observable_dict['Pressure'].size - observable_dict['Volume'] = np.ones(nframes) * result.ensemble.volume - - result.observables = ObservableData() - for key, gmxkey in self.__gmx_energy_names.items(): - result.observables[key] = observable_dict[gmxkey] - - return result
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/observable_data.html b/docs/_modules/physical_validation/data/observable_data.html deleted file mode 100644 index 4894a00..0000000 --- a/docs/_modules/physical_validation/data/observable_data.html +++ /dev/null @@ -1,543 +0,0 @@ - - - - - - - - - - - physical_validation.data.observable_data — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.observable_data
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.observable_data

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-Data structures carrying simulation data.
-"""
-import warnings
-import numpy as np
-
-import physical_validation.util.error as pv_error
-
-
-
[docs]class ObservableData(object): - r"""ObservableData: The trajectory of (macroscopic) observables during the simulation - - Stores a number of different observables: - 'kinetic_energy': the kinetic energy of the system, - 'potential_energy': the potential energy of the system, - 'total_energy': the total energy of the system, - 'volume': the volume of the system box, - 'pressure': the pressure of the system, - 'temperature': the temperature of the system, - 'constant_of_motion': a constant of motion of the trajectory. - - The observable trajectories can be accessed either using the getters of an object, as in - observables.kinetic_energy - or using the key notation, as in - observables['kinetic_energy'] - """ -
[docs] @staticmethod - def observables(): - return ['kinetic_energy', - 'potential_energy', - 'total_energy', - 'volume', - 'pressure', - 'temperature', - 'constant_of_motion']
- - def __init__(self, - kinetic_energy=None, potential_energy=None, total_energy=None, - volume=None, pressure=None, temperature=None, constant_of_motion=None): - self.__kinetic_energy = None - self.__potential_energy = None - self.__total_energy = None - self.__volume = None - self.__pressure = None - self.__temperature = None - self.__constant_of_motion = None - self.__nframes = -1 - self.__kinetic_energy_per_molec = None - - self.kinetic_energy = kinetic_energy - self.potential_energy = potential_energy - self.total_energy = total_energy - self.volume = volume - self.pressure = pressure - self.temperature = temperature - self.constant_of_motion = constant_of_motion - - self.__getters = { - 'kinetic_energy': ObservableData.kinetic_energy.__get__, - 'potential_energy': ObservableData.potential_energy.__get__, - 'total_energy': ObservableData.total_energy.__get__, - 'volume': ObservableData.volume.__get__, - 'pressure': ObservableData.pressure.__get__, - 'temperature': ObservableData.temperature.__get__, - 'constant_of_motion': ObservableData.constant_of_motion.__get__ - } - - self.__setters = { - 'kinetic_energy': ObservableData.kinetic_energy.__set__, - 'potential_energy': ObservableData.potential_energy.__set__, - 'total_energy': ObservableData.total_energy.__set__, - 'volume': ObservableData.volume.__set__, - 'pressure': ObservableData.pressure.__set__, - 'temperature': ObservableData.temperature.__set__, - 'constant_of_motion': ObservableData.constant_of_motion.__set__ - } - -
[docs] def get(self, key): - return self[key]
- - def __getitem__(self, key): - if key not in self.observables(): - raise KeyError - return self.__getters[key](self) - -
[docs] def set(self, key, value): - self[key] = value
- - def __setitem__(self, key, value): - if key not in self.observables(): - raise KeyError - self.__setters[key](self, value) - - @property - def kinetic_energy(self): - """Get kinetic_energy""" - return self.__kinetic_energy - - @kinetic_energy.setter - def kinetic_energy(self, kinetic_energy): - """Set kinetic_energy""" - if kinetic_energy is None: - self.__kinetic_energy = None - return - kinetic_energy = np.array(kinetic_energy) - if kinetic_energy.ndim != 1: - raise pv_error.InputError('kinetic_energy', - 'Expected 1-dimensional array.') - if self.nframes == -1: - self.__nframes = kinetic_energy.size - elif self.nframes != kinetic_energy.size: - warnings.warn('Mismatch in number of frames. ' - 'Setting `nframes = None`.') - self.__nframes = None - self.__kinetic_energy = kinetic_energy - - @property - def potential_energy(self): - """Get potential_energy""" - return self.__potential_energy - - @potential_energy.setter - def potential_energy(self, potential_energy): - """Set potential_energy""" - if potential_energy is None: - self.__potential_energy = None - return - potential_energy = np.array(potential_energy) - if potential_energy.ndim != 1: - raise pv_error.InputError('potential_energy', - 'Expected 1-dimensional array.') - if self.nframes == -1: - self.__nframes = potential_energy.size - elif self.nframes != potential_energy.size: - warnings.warn('Mismatch in number of frames. ' - 'Setting `nframes = None`.') - self.__nframes = None - self.__potential_energy = potential_energy - - @property - def total_energy(self): - """Get total_energy""" - return self.__total_energy - - @total_energy.setter - def total_energy(self, total_energy): - """Set total_energy""" - if total_energy is None: - self.__total_energy = None - return - total_energy = np.array(total_energy) - if total_energy.ndim != 1: - raise pv_error.InputError('total_energy', - 'Expected 1-dimensional array.') - if self.nframes == -1: - self.__nframes = total_energy.size - elif self.nframes != total_energy.size: - warnings.warn('Mismatch in number of frames. ' - 'Setting `nframes = None`.') - self.__nframes = None - self.__total_energy = total_energy - - @property - def volume(self): - """Get volume""" - return self.__volume - - @volume.setter - def volume(self, volume): - """Set volume""" - if volume is None: - self.__volume = None - return - volume = np.array(volume) - if volume.ndim != 1: - raise pv_error.InputError('volume', - 'Expected 1-dimensional array.') - if self.nframes == -1: - self.__nframes = volume.size - elif self.nframes != volume.size: - warnings.warn('Mismatch in number of frames. ' - 'Setting `nframes = None`.') - self.__nframes = None - self.__volume = volume - - @property - def pressure(self): - """Get pressure""" - return self.__pressure - - @pressure.setter - def pressure(self, pressure): - """Set pressure""" - if pressure is None: - self.__pressure = None - return - pressure = np.array(pressure) - if pressure.ndim != 1: - raise pv_error.InputError('pressure', - 'Expected 1-dimensional array.') - if self.nframes == -1: - self.__nframes = pressure.size - elif self.nframes != pressure.size: - warnings.warn('Mismatch in number of frames. ' - 'Setting `nframes = None`.') - self.__nframes = None - self.__pressure = pressure - - @property - def temperature(self): - """Get temperature""" - return self.__temperature - - @temperature.setter - def temperature(self, temperature): - """Set temperature""" - if temperature is None: - self.__temperature = None - return - temperature = np.array(temperature) - if temperature.ndim != 1: - raise pv_error.InputError('temperature', - 'Expected 1-dimensional array.') - if self.nframes == -1: - self.__nframes = temperature.size - elif self.nframes != temperature.size: - warnings.warn('Mismatch in number of frames. ' - 'Setting `nframes = None`.') - self.__nframes = None - self.__temperature = temperature - - @property - def constant_of_motion(self): - """Get constant_of_motion""" - return self.__constant_of_motion - - @constant_of_motion.setter - def constant_of_motion(self, constant_of_motion): - """Set constant_of_motion""" - if constant_of_motion is None: - self.__constant_of_motion = None - return - constant_of_motion = np.array(constant_of_motion) - if constant_of_motion.ndim != 1: - raise pv_error.InputError('constant_of_motion', - 'Expected 1-dimensional array.') - if self.nframes == -1: - self.__nframes = constant_of_motion.size - elif self.nframes != constant_of_motion.size: - warnings.warn('Mismatch in number of frames. ' - 'Setting `nframes = None`.') - self.__nframes = None - self.__constant_of_motion = constant_of_motion - - @property - def nframes(self): - """Get number of frames""" - if self.__nframes is None: - warnings.warn('A mismatch in the number of frames between observables ' - 'was detected. Setting `nframes = None`.') - return self.__nframes - - @property - def kinetic_energy_per_molecule(self): - """Get kinetic_energy per molecule - used internally""" - return self.__kinetic_energy_per_molec - - @kinetic_energy_per_molecule.setter - def kinetic_energy_per_molecule(self, kinetic_energy): - """Set kinetic_energy per molecule - used internally""" - if kinetic_energy is None: - self.__kinetic_energy_per_molec = None - return - # used internally - check for consistency? - self.__kinetic_energy_per_molec = kinetic_energy
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/parser.html b/docs/_modules/physical_validation/data/parser.html deleted file mode 100644 index b18cdb6..0000000 --- a/docs/_modules/physical_validation/data/parser.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - - - - - - - - physical_validation.data.parser — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.parser
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.parser

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-Parsers read output files from MD simulation packages and create
-SimulationData objects with their contents.
-"""
-
-
-
[docs]class Parser(object): - r""" - Parser base class - """ -
[docs] def get_simulation_data(self): - raise NotImplementedError
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/simulation_data.html b/docs/_modules/physical_validation/data/simulation_data.html deleted file mode 100644 index 75b6876..0000000 --- a/docs/_modules/physical_validation/data/simulation_data.html +++ /dev/null @@ -1,446 +0,0 @@ - - - - - - - - - - - physical_validation.data.simulation_data — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.simulation_data
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.simulation_data

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-Data structures carrying simulation data.
-"""
-from ..util import error as pv_error
-# py2.7 compatibility
-from .unit_data import UnitData
-from .ensemble_data import EnsembleData
-from .system_data import SystemData
-from .observable_data import ObservableData
-from .trajectory_data import TrajectoryData
-# replace lines above by this when py2.7 support is dropped:
-# from . import UnitData, EnsembleData, SystemData, ObservableData, TrajectoryData
-
-
-
[docs]class SimulationData(object): - r"""SimulationData: System information and simulation results - - The SimulationData class holds both the information on the system and - the results of a simulation run of that system. SimulationData contains - all information on a simulation run needed by the physical validation - tests. SimulationData objects can either be created directly by calling - the class constructor, or by using a parser returning a SimulationData - object. - """ - -
[docs] @staticmethod - def compatible(data_1, data_2): - r"""Checks whether two simulations are compatible for common validation. - - Parameters - ---------- - data_1 : SimulationData - data_2 : SimulationData - - Returns - ------- - result : bool - - """ - if not isinstance(data_1, SimulationData): - raise pv_error.InputError('data_1', - 'Expected type SimulationData') - if not isinstance(data_2, SimulationData): - raise pv_error.InputError('data_2', - 'Expected type SimulationData') - - return data_1.units == data_2.units
- - def __init__(self, units=None, dt=None, - system=None, ensemble=None, - observables=None, trajectory=None): - self.__units = None - if units is not None: - self.units = units - self.__dt = 0 - if dt is not None: - self.dt = dt - self.__topology = None - if system is not None: - self.system = system - self.__ensemble = None - if ensemble is not None: - self.ensemble = ensemble - self.__observables = None - if observables is not None: - self.observables = observables - self.__trajectory = None - if trajectory is not None: - self.trajectory = trajectory - - @property - def ensemble(self): - r"""EnsembleData: Information on the sampled ensemble - - Returns - ------- - ensemble : EnsembleData - """ - return self.__ensemble - - @ensemble.setter - def ensemble(self, ensemble): - if not isinstance(ensemble, EnsembleData): - raise TypeError('No known conversion from ' + type(ensemble) + - 'to EnsembleData') - self.__ensemble = ensemble - - @property - def units(self): - r"""UnitsData: Information on the sampled units - - Returns - ------- - units : UnitData - """ - return self.__units - - @units.setter - def units(self, units): - if not isinstance(units, UnitData): - raise TypeError('No known conversion from ' + type(units) + - 'to UnitData') - self.__units = units - - @property - def observables(self): - r"""ObservableData: Observables collected during the simulation - - Returns - ------- - observables : ObservableData - """ - return self.__observables - - @observables.setter - def observables(self, observables): - if not isinstance(observables, ObservableData): - raise TypeError('No known conversion from ' + type(observables) + - 'to ObservableData') - self.__observables = observables - - @property - def trajectory(self): - r"""TrajectoryData: Trajectories collected during the simulation - - Returns - ------- - trajectory : TrajectoryData - """ - return self.__trajectory - - @trajectory.setter - def trajectory(self, trajectory): - if not isinstance(trajectory, TrajectoryData): - raise TypeError('No known conversion from ' + type(trajectory) + - 'to TrajectoryData') - self.__trajectory = trajectory - - @property - def system(self): - r"""SystemData: Information on the system's system - - Returns - ------- - system : SystemData - """ - return self.__topology - - @system.setter - def system(self, topology): - if not isinstance(topology, SystemData): - raise TypeError('No known conversion from ' + type(topology) + - 'to SystemData') - self.__topology = topology - - @property - def dt(self): - r""" The timestep of the simulation run. - - Returns - ------- - timestep : float - """ - return self.__dt - - @dt.setter - def dt(self, dt): - dt = float(dt) - self.__dt = dt - -
[docs] def set_ensemble(self, ensemble, - natoms=None, mu=None, - volume=None, pressure=None, - energy=None, temperature=None): - self.__ensemble = EnsembleData(ensemble, - natoms, mu, - volume, pressure, - energy, temperature)
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/system_data.html b/docs/_modules/physical_validation/data/system_data.html deleted file mode 100644 index 94bfafd..0000000 --- a/docs/_modules/physical_validation/data/system_data.html +++ /dev/null @@ -1,503 +0,0 @@ - - - - - - - - - - - physical_validation.data.system_data — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.system_data
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.system_data

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-Data structure carrying information on the simulated system.
-"""
-import warnings
-import numpy as np
-
-from ..util import error as pv_error
-
-
-
[docs]class SystemData(object): - r"""SystemData: Information about the atoms and molecules in the system. - - The information stored in SystemData objects describes the atom and molecules - in the system as far as the physical validation tests need it. - - The system is described in terms of - - * natoms: the total number of atoms in the system - * nconstraints: the total number of constraints in the system - * ndof_reduction_tra: global reduction of translational degrees of freedom (e.g. - due to constraining the center of mass of the system) - * ndof_reduction_rot: global reduction of rotational degrees of freedom (e.g. - due to constraining the center of mass of the system) - - The atoms are described in terms of - - * mass: a list of the mass of every atom in the system - - The molecules are described by - - * molecule_idx: a list with the indices first atoms of every molecule (this assumes - that the atoms are sorted by molecule) - * nconstraints_per_molecule: a list with the number of constraints in every molecule - - Only used internally: - - * ndof_per_molecule: a list with the number of degrees of freedom of every molecule - - Reserved for future use: - - * bonds - * constrained_bonds - - *Notes:* - - * kinetic_energy.mb_ensemble() only requires information on the system - (natoms, nconstraints, ndof_reduction_tra, ndof_reduction_rot) - * kinetic_energy.equipartition() additionally requires information on the atoms and molecules - (mass, molecule_idx, nconstraints_per_molecule) - - All other tests do not require and information from SystemData. - - """ - - def __init__(self, - natoms=None, nconstraints=None, - ndof_reduction_tra=None, ndof_reduction_rot=None, - mass=None, molecule_idx=None, nconstraints_per_molecule=None): - self.__natoms = None - self.__nconstraints = None - self.__ndof_reduction_tra = None - self.__ndof_reduction_rot = None - self.__mass = None - self.__molecule_idx = None - self.__nconstraints_per_molecule = None - self.__ndof_per_molecule = None - self.__bonds = None - self.__constrained_bonds = None - - if natoms is not None: - self.natoms = natoms - if nconstraints is not None: - self.nconstraints = nconstraints - if ndof_reduction_tra is not None: - self.ndof_reduction_tra = ndof_reduction_tra - if ndof_reduction_rot is not None: - self.ndof_reduction_rot = ndof_reduction_rot - if mass is not None: - self.mass = mass - if molecule_idx is not None: - self.molecule_idx = molecule_idx - if nconstraints_per_molecule is not None: - self.nconstraints_per_molecule = nconstraints_per_molecule - - @property - def natoms(self): - """int: Number of atoms in the system - - """ - return self.__natoms - - @natoms.setter - def natoms(self, natoms): - self.__natoms = int(natoms) - - @property - def nconstraints(self): - """float: Total number of constraints in the system - - Does not include the reduction of degrees of freedom in the absence of - external forces. - - """ - return self.__nconstraints - - @nconstraints.setter - def nconstraints(self, nconstraints): - self.__nconstraints = float(nconstraints) - - @property - def ndof_reduction_tra(self): - """float: Number of translational degrees of freedom deducted - from 3*[# of molecules] - - """ - return self.__ndof_reduction_tra - - @ndof_reduction_tra.setter - def ndof_reduction_tra(self, ndof_reduction_tra): - self.__ndof_reduction_tra = float(ndof_reduction_tra) - - @property - def ndof_reduction_rot(self): - """float: Number of rotational degrees of freedom deducted - from 3*[# of molecules] - - """ - return self.__ndof_reduction_rot - - @ndof_reduction_rot.setter - def ndof_reduction_rot(self, ndof_reduction_rot): - self.__ndof_reduction_rot = float(ndof_reduction_rot) - - @property - def mass(self): - """nd-array: Mass vector for the atoms - - Setter accepts array-like objects. - - """ - return self.__mass - - @mass.setter - def mass(self, mass): - mass = np.asarray(mass) - if mass.ndim != 1: - raise pv_error.InputError('mass', - 'Expected 1-dimensional array.') - if self.natoms is None: - self.natoms = mass.size - elif mass.size != self.natoms: - raise pv_error.InputError('mass', - 'Mass vector does not have length == natoms.') - self.__mass = mass - - @property - def molecule_idx(self): - """nd-array: List of index of first atom of each molecule - - Setter accepts array-like objects. - - """ - return self.__molecule_idx - - @molecule_idx.setter - def molecule_idx(self, molecule_idx): - molecule_idx = np.asarray(molecule_idx) - if molecule_idx.ndim != 1: - raise pv_error.InputError('molecule_idx', - 'Expected 1-dimensional array.') - if (self.nconstraints_per_molecule is not None and - self.nconstraints_per_molecule.shape != molecule_idx.shape): - warnings.warn('New `molecule_idx` does not have the same' - 'shape as previously set `nconstraints_per_molecule`.' - 'Setting `nconstraints_per_molecule = None` to avoid' - 'errors.') - self.__nconstraints_per_molecule = None - self.__molecule_idx = molecule_idx - - @property - def nconstraints_per_molecule(self): - """nd-array: List of number of constraints per molecule - - Setter accepts array-like objects. - - """ - return self.__nconstraints_per_molecule - - @nconstraints_per_molecule.setter - def nconstraints_per_molecule(self, nconstraints_per_molecule): - nconstraints_per_molecule = np.array(nconstraints_per_molecule) - if nconstraints_per_molecule.ndim != 1: - raise pv_error.InputError('nconstraints_per_molecule', - 'Expected 1-dimensional array.') - if self.molecule_idx is not None: - if nconstraints_per_molecule.shape != self.molecule_idx.shape: - raise pv_error.InputError('nconstraints_per_molecule', - 'Expected `nconstraints_per_molecule` to have' - 'the same shape as `moldecule_idx`.') - - self.__nconstraints_per_molecule = nconstraints_per_molecule - - @property - def ndof_per_molecule(self): - """nd-array: List of number of degrees of freedom per molecule - - Setter accepts array-like objects. - - """ - return self.__ndof_per_molecule - - @ndof_per_molecule.setter - def ndof_per_molecule(self, ndof_per_molecule): - # used internally - check for consistency? - self.__ndof_per_molecule = ndof_per_molecule - - @property - def bonds(self): - """List[List[int]]: List of bonds per molecule - """ - return self.__bonds - - @bonds.setter - def bonds(self, bonds): - self.__bonds = bonds - - @property - def constrained_bonds(self): - """List[List[int]]: List of constrained bonds per molecule - """ - return self.__constrained_bonds - - @constrained_bonds.setter - def constrained_bonds(self, constrained_bonds): - self.__constrained_bonds = constrained_bonds
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/trajectory_data.html b/docs/_modules/physical_validation/data/trajectory_data.html deleted file mode 100644 index b0ce5c4..0000000 --- a/docs/_modules/physical_validation/data/trajectory_data.html +++ /dev/null @@ -1,384 +0,0 @@ - - - - - - - - - - - physical_validation.data.trajectory_data — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.trajectory_data
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.trajectory_data

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-Data structures carrying simulation data.
-"""
-import warnings
-import numpy as np
-
-import physical_validation.util.error as pv_error
-
-
-
[docs]class TrajectoryData(object): - r"""TrajectoryData: The position and velocity trajectory along the simulation - - The full trajectory is needed to calculate the equipartition of the kinetic energy. - As they are used in connection, the position and velocity trajectories are expected - to have the same shape and number of frames. - - The position and velocity trajectories can be accessed either using the getters - of an object, as in - - * trajectory.position - * trajectory.velocity - - or using the key notation, as in - - * trajectory['position'] - * trajectory['velocity'] - - """ - -
[docs] @staticmethod - def trajectories(): - return ('position', - 'velocity')
- - def __init__(self, position=None, velocity=None): - self.__position = None - self.__velocity = None - self.__nframes = 0 - - if position is not None: - self.position = position - if velocity is not None: - self.velocity = velocity - - self.__getters = { - 'position': TrajectoryData.position.__get__, - 'velocity': TrajectoryData.velocity.__get__ - } - - self.__setters = { - 'position': TrajectoryData.position.__set__, - 'velocity': TrajectoryData.velocity.__set__ - } - -
[docs] def get(self, key): - return self[key]
- - def __getitem__(self, key): - if key not in self.trajectories(): - raise KeyError - return self.__getters[key](self) - -
[docs] def set(self, key, value): - self[key] = value
- - def __setitem__(self, key, value): - if key not in self.trajectories(): - raise KeyError - self.__setters[key](self, value) - - @property - def position(self): - """Get position""" - return self.__position - - @position.setter - def position(self, pos): - """Set position""" - pos = np.array(pos) - if pos.ndim == 2: - # create 3-dimensional array - pos = np.array([pos]) - if pos.ndim != 3: - warnings.warn('Expected 2- or 3-dimensional array.') - if self.__nframes == 0 and self.__velocity is None: - self.__nframes = pos.shape[0] - elif self.__nframes != pos.shape[0]: - raise pv_error.InputError(['pos'], - 'Expected equal number of frames as in velocity trajectory.') - self.__position = pos - - @property - def velocity(self): - """Get velocity""" - return self.__velocity - - @velocity.setter - def velocity(self, vel): - """Set velocity""" - vel = np.array(vel) - if vel.ndim == 2: - # create 3-dimensional array - vel = np.array([vel]) - if vel.ndim != 3: - warnings.warn('Expected 2- or 3-dimensional array.') - if self.__nframes == 0 and self.__position is None: - self.__nframes = vel.shape[0] - elif self.__nframes != vel.shape[0]: - raise pv_error.InputError(['vel'], - 'Expected equal number of frames as in position trajectory.') - self.__velocity = vel - - @property - def nframes(self): - """Get number of frames""" - return self.__nframes
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/data/unit_data.html b/docs/_modules/physical_validation/data/unit_data.html deleted file mode 100644 index 1431a1c..0000000 --- a/docs/_modules/physical_validation/data/unit_data.html +++ /dev/null @@ -1,382 +0,0 @@ - - - - - - - - - - - physical_validation.data.unit_data — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.data.unit_data
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.data.unit_data

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-Data structures carrying simulation data.
-"""
-
-
-
[docs]class UnitData(object): - r"""UnitData: Information about the units used - - The information about units consists of different parts: - - * The name of the units (energy_str, length_str, volume_str, - temperature_str, pressure_str, time_str), - * the value of kB in the used energy units, and - * the conversion factor to GROMACS units (kJ/mol, nm, nm^3, K, bar, ps). - - The names are only used for output (console printing and plotting), and are optional. - The conversion factors and kB are, on the other hand, used in computations and need - to be given. - """ - def __init__(self, kb, energy_conversion, length_conversion, volume_conversion, - temperature_conversion, pressure_conversion, time_conversion, - energy_str='ENE', length_str='LEN', volume_str='VOL', - temperature_str='TEMP', pressure_str='PRESS', time_str='TIME'): - - self.__kb = float(kb) - self.__energy_str = str(energy_str) - self.__energy_conversion = float(energy_conversion) - self.__length_str = str(length_str) - self.__length_conversion = float(length_conversion) - self.__volume_str = str(volume_str) - self.__volume_conversion = float(volume_conversion) - self.__temperature_str = str(temperature_str) - self.__temperature_conversion = float(temperature_conversion) - self.__pressure_str = str(pressure_str) - self.__pressure_conversion = float(pressure_conversion) - self.__time_str = str(time_str) - self.__time_conversion = float(time_conversion) - - def __eq__(self, other): - if not isinstance(other, UnitData): - return False - - return (self.kb == other.kb and - self.energy_conversion == other.energy_conversion and - self.length_conversion == other.length_conversion and - self.volume_conversion == other.volume_conversion and - self.temperature_conversion == other.temperature_conversion and - self.pressure_conversion == other.pressure_conversion and - self.time_conversion == other.time_conversion) - - @property - def kb(self): - """float: The value of the Boltzmann constant""" - return self.__kb - - @property - def energy_str(self): - """str: Energy unit""" - return self.__energy_str - - @property - def length_str(self): - """str: Length unit""" - return self.__length_str - - @property - def volume_str(self): - """str: Volume unit""" - return self.__volume_str - - @property - def temperature_str(self): - """str: Temperature unit""" - return self.__temperature_str - - @property - def pressure_str(self): - """str: Pressure unit""" - return self.__pressure_str - - @property - def time_str(self): - """str: Time unit""" - return self.__time_str - - @property - def energy_conversion(self): - """float: Energy conversion factor, 1 energy_unit = energy_conversion * kJ/mol""" - return self.__energy_conversion - - @property - def length_conversion(self): - """float: Length conversion factor, 1 length_unit = length_conversion * nm""" - return self.__length_conversion - - @property - def volume_conversion(self): - """float: Volume conversion factor, 1 volume_unit = volume_conversion * nm^3""" - return self.__volume_conversion - - @property - def temperature_conversion(self): - """float: Time conversion factor, 1 temperature_unit = temperature_conversion * ps""" - return self.__temperature_conversion - - @property - def pressure_conversion(self): - """float: Pressure conversion factor, 1 pressure_unit = pressure_conversion * bar""" - return self.__pressure_conversion - - @property - def time_conversion(self): - """float: Time conversion factor, 1 time_unit = time_conversion * ps""" - return self.__time_conversion
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/ensemble.html b/docs/_modules/physical_validation/ensemble.html deleted file mode 100644 index 776aba1..0000000 --- a/docs/_modules/physical_validation/ensemble.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - - - - - - physical_validation.ensemble — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.ensemble
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.ensemble

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-This software allows users to perform statistical test to determine if a
-given molecular simulation is consistent with the thermodynamic ensemble
-it is performed in.
-
-Users should cite the JCTC paper: Shirts, M. R. "Simple Quantitative
-Tests to Validate Sampling from Thermodynamic Ensembles",
-J. Chem. Theory Comput., 2013, 9 (2), pp 909-926,
-http://dx.doi.org/10.1021/ct300688p
-"""
-
-import numpy as np
-
-from .util import ensemble
-from .data import SimulationData
-from .util import error as pv_error
-
-
-
[docs]def check(data_sim_one, data_sim_two, - total_energy=False, - screen=False, filename=None, - verbosity=1): - r""" - Check the ensemble. The correct check is inferred from the - simulation data given. - - Parameters - ---------- - data_sim_one : SimulationData - data_sim_two : SimulationData - total_energy : bool - screen : bool - Plot distributions on screen. Default: False. - filename : string - Plot distributions to `filename`.pdf. Default: None. - verbosity : int - Level of verbosity, from 0 (quiet) to 3 (very verbose). - Default: 1 - - Returns - ------- - quantiles : float - The number of quantiles the computed result is off the analytical one. - - """ - if not SimulationData.compatible(data_sim_one, - data_sim_two): - raise pv_error.InputError(['data_sim_one', 'data_sim_two'], - 'Simulation data not compatible.') - - if data_sim_one.ensemble.ensemble != data_sim_two.ensemble.ensemble: - raise pv_error.InputError(['data_sim_one', 'data_sim_two'], - 'The two simulations were sampling different ensembles. ' - 'The simulations are expected to differ in state point ' - '(e.g. target temperature, target pressure), but not ' - 'in their sampled ensemble (e.g. NVT, NPT).') - - sampled_ensemble = data_sim_one.ensemble.ensemble - - if sampled_ensemble == 'NVE' or sampled_ensemble == 'muVE': - raise pv_error.InputError(['data_sim_one', 'data_sim_two'], - 'Test of ensemble ' + sampled_ensemble + ' is not implemented ' - '(yet).') - - if total_energy: - eneq = 'E' - e1 = data_sim_one.observables.total_energy - e2 = data_sim_two.observables.total_energy - else: - eneq = 'U' - e1 = data_sim_one.observables.potential_energy - e2 = data_sim_two.observables.potential_energy - - quantiles = None - - if sampled_ensemble == 'NVT': - quantiles = ensemble.check_1d( - traj1=e1, traj2=e2, - param1=data_sim_one.ensemble.temperature, - param2=data_sim_two.ensemble.temperature, - kb=data_sim_one.units.kb, - quantity=eneq, - dtemp=True, dpress=False, - verbosity=verbosity, - filename=filename, screen=screen - ) - - elif sampled_ensemble == 'NPT': - temperatures = np.array([data_sim_one.ensemble.temperature, - data_sim_two.ensemble.temperature]) - pressures = np.array([data_sim_one.ensemble.pressure, - data_sim_two.ensemble.pressure]) - equal_temps = temperatures[0] == temperatures[1] - equal_press = pressures[0] == pressures[1] - - v1 = data_sim_one.observables.volume - v2 = data_sim_two.observables.volume - - # Calculate conversion from p*V to energy units - # - # GROMACS standard units are - # energy: kJ/mol - # volume: nm^3 - # pressure: bar - # => pV-term: bar * nm^3 == 1e-25 kJ == 6.022140857e-2 kJ/mol - # => pvconvert = 6.022140857e-2 - # UnitData stores conversion factors relative to GROMACS units - # energy: energy_conversion * kJ/mol - # volume: volume_conversion * nm^3 - # pressure: pressure_conversion * bar - # => pV-term: [p]*[V] == pressure_conversion * volume_conversion bar * nm^3 - # Units were checked earlier, so we can use either simulation data structure - pvconvert = 6.022140857e-2 - pvconvert *= (data_sim_one.units.pressure_conversion * - data_sim_one.units.volume_conversion) - pvconvert /= data_sim_one.units.energy_conversion - - if equal_press and not equal_temps: - e1 = e1 + pvconvert * pressures[0] * v1 - e2 = e2 + pvconvert * pressures[1] * v2 - if eneq == 'U': - eneq = 'H' - quantiles = ensemble.check_1d( - traj1=e1, traj2=e2, - param1=temperatures[0], - param2=temperatures[1], - kb=data_sim_one.units.kb, - quantity=eneq, - dtemp=True, dpress=False, - verbosity=verbosity, - filename=filename, screen=screen - ) - elif equal_temps and not equal_press: - quantiles = ensemble.check_1d( - traj1=v1, traj2=v2, - param1=pressures[0], - param2=pressures[1], - kb=data_sim_one.units.kb, - quantity='V', - dtemp=False, dpress=True, - temp=temperatures[0], - pvconvert=pvconvert, - verbosity=verbosity, - filename=filename, screen=screen - ) - else: - traj1 = np.array([e1, v1]) - traj2 = np.array([e2, v2]) - param1 = np.array([temperatures[0], pressures[0]]) - param2 = np.array([temperatures[1], pressures[1]]) - quantiles = ensemble.check_2d( - traj1=traj1, traj2=traj2, - param1=param1, param2=param2, - kb=data_sim_one.units.kb, - pvconvert=pvconvert, - quantity=[eneq, 'V'], - dtempdpress=True, - verbosity=verbosity, - filename=filename, screen=screen - ) - - return quantiles
- - -
[docs]def estimate_interval(data, verbosity=1, total_energy=False): - r""" - In order to perform an ensemble check, two simulations at distinct state - point are needed. Choosing two state points too far apart will result - in poor or zero overlap between the distributions, leading to very noisy - results (due to sample errors in the tails) or a breakdown of the method, - respectively. Choosing two state points very close to each others, on the - other hand, makes it difficult to distinguish the slope from statistical - error in the samples. - - This function implements a rule of thumb based on the standard deviations - of distributions. It takes a single simulation and suggests appropriate - intervals for a second simulation to be used for ensemble checking. - - Parameters - ---------- - data : SimulationData - The performed simulation. - verbosity : int, optional - If 0, no output is printed on screen. If 1, estimated intervals are - printed. If larger, additional information during calculation are - printed. - Default: 1 - total_energy : bool, optional - Use total energy instead of potential energy only. - Default: False - - Returns - ------- - intervals : Dict - If `data` was performed under NVT conditions, `intervals` contains only - one entry: - - * `'dT'`, containing the suggested temperature interval. - - If `data` was performed under NPT conditions, `intervals` contains three - entries: - - * `'dT'`: Suggested temperature interval at constant pressure - * `'dP'`: Suggested pressure interval at constant temperature - * `'dTdP'`: Suggested combined temperature and pressure interval - - """ - - if total_energy: - ene = data.observables.total_energy - else: - ene = data.observables.potential_energy - - if data.ensemble.ensemble == 'NVT': - result = ensemble.estimate_interval( - ens_string='NVT', - ens_temp=data.ensemble.temperature, - energy=ene, - kb=data.units.kb, - verbosity=verbosity, - tunit=data.units.temperature_str - ) - elif data.ensemble.ensemble == 'NPT': - pvconvert = 6.022140857e-2 - pvconvert *= (data.units.pressure_conversion * - data.units.volume_conversion) - pvconvert /= data.units.energy_conversion - result = ensemble.estimate_interval( - ens_string='NPT', - ens_temp=data.ensemble.temperature, - energy=ene, - kb=data.units.kb, - ens_press=data.ensemble.pressure, - volume=data.observables.volume, - pvconvert=pvconvert, - verbosity=verbosity, - tunit=data.units.temperature_str, - punit=data.units.pressure_str - ) - else: - raise NotImplementedError('estimate_interval() not implemented for ensemble ' + - data.ensemble.ensemble) - - return result
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/integrator.html b/docs/_modules/physical_validation/integrator.html deleted file mode 100644 index ecf496d..0000000 --- a/docs/_modules/physical_validation/integrator.html +++ /dev/null @@ -1,357 +0,0 @@ - - - - - - - - - - - physical_validation.integrator — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.integrator
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.integrator

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-"""
-The `integratorconvergence` module is part of the physical_validation
-package, and consists of checks of the convergence of the MD integrator.
-"""
-# py2 compatibility
-from __future__ import absolute_import, division, print_function
-
-from .util import integrator as util_integ
-from .data import SimulationData
-from .util import error as pv_error
-
-
-
[docs]def convergence(simulations, - convergence_test='max_deviation', - verbose=True, slope=False, - screen=False, filename=None): - r""" - Compares the convergence of the fluctuations of conserved quantities - with decreasing simulation time step to theoretical expectations. - - Parameters - ---------- - simulations : list of SimulationData - The (otherwise identical) simulations performed using different - timesteps - convergence_test : str, optional - A function defining the convergence test. Currently, only one - test is implemented: - `max_deviation` - verbose : bool, optional - screen : bool - Plot convergence on screen. Default: False. - filename : string - Plot convergence to `filename`.pdf. Default: None. - - Returns - ------- - result : float - - Notes - ----- - For a simplectic integration algorithm, the fluctuations - :math:`\delta E` of a constant of motion :math:`E` (such as, for - example, the total energy in a NVE simulations) are theoretically - expected to scale like the squared timestep of the integration. - When comparing two otherwise identical simulations performed at - different time step :math:`\Delta t`, the following equality is - hence expected to hold: - - .. math:: - \frac{\Delta t_1}{\Delta t_2} = \frac{\delta E_1}{\delta E_2} - - This function calculates the ratio of the fluctuation for simulations - performed at different timesteps and compares it to the analytically - expected value. If the deviation is larger than `tol`, the test is - considered failed. - - """ - constant_of_motion = {} - - convergence_tests = { - 'max_deviation': util_integ.max_deviation - } - - if convergence_test not in convergence_tests: - raise pv_error.InputError('convergence_test', - 'Unknown convergence test.') - - convergence_test = convergence_tests[convergence_test] - - for s in simulations: - if not isinstance(s, SimulationData): - raise pv_error.InputError('simulations', - 'Expected a list of objects of type SimulationData') - if s.dt <= 0: - raise pv_error.InputError('simulations', - 'Found SimulationData with timestep dt<=0') - key = str(s.dt) - - if key in constant_of_motion: - raise pv_error.InputError('simulations', - 'Found two simulations with identical timestep') - - constant_of_motion[key] = s.observables.constant_of_motion - - return util_integ.check_convergence(constant_of_motion, - convergence_test=convergence_test, - verbose=verbose, slope=slope, - screen=screen, filename=filename)
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/kinetic_energy.html b/docs/_modules/physical_validation/kinetic_energy.html deleted file mode 100644 index 905a754..0000000 --- a/docs/_modules/physical_validation/kinetic_energy.html +++ /dev/null @@ -1,451 +0,0 @@ - - - - - - - - - - - physical_validation.kinetic_energy — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.kinetic_energy
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.kinetic_energy

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-"""
-The `kinetic_energy` module is part of the physical_validation package, and
-consists of checks of the kinetic energy distribution and its
-equipartition.
-"""
-from __future__ import print_function
-from __future__ import division
-
-from .util import kinetic_energy as util_kin
-from .data import SimulationData
-
-
-
[docs]def mb_ensemble(data, alpha=None, verbosity=1, - screen=False, filename=None): - r"""Checks if a kinetic energy trajectory is Maxwell-Boltzmann distributed. - - Parameters - ---------- - data : SimulationData - Simulation data object - alpha : float, optional - If a confidence interval is given and verbose=True, the test outputs - a passed / failed message. - verbosity : int, optional - Verbosity level, where 0 is quiet and 3 very chatty. Default: 1. - screen : bool, optional - Plot distributions on screen. Default: False. - filename : string, optional - Plot distributions to `filename`.pdf. Default: None. - - Returns - ------- - result : float - The p value of the test. - - Notes - ----- - This function checks whether the hypothesis that a sample - of kinetic energies is Maxwell-Boltzmann distributed given a specific - target temperature and the number of degrees of freedom in the system, - - .. math:: - P(K) \sim K^{N/2} e^{-\beta K} \, , - - holds under a given confidence level :math:`\alpha`. - The check is performed using the Kolmogorov-Smirnov test provided by - scipy.stats.kstest_. - - .. _scipy.stats.kstest: https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.stats.kstest.html - - .. note:: The Kolmogorov-Smirnov test is known to have two weaknesses. - - #. The test is more sensitive towards deviations around the center - of the distribution than at its tails. We deem this to be acceptable - for most MD applications, but be wary if yours is sensible to the - kinetic distribution tails. - #. The test is not valid if its parameters are guessed from the data - set. Using the target temperature of the MD simulation as an input - is therefore perfectly valid, but using the average temperature - over the trajectory as an input to the test can potentially - invalidate it. - - .. todo:: Can we check the influence of sample size on test results? - - """ - ndof = (data.system.natoms * 3 - - data.system.nconstraints - - data.system.ndof_reduction_tra - - data.system.ndof_reduction_rot) - - return util_kin.check_mb_ensemble(kin=data.observables.kinetic_energy, - temp=data.ensemble.temperature, - ndof=ndof, alpha=alpha, - kb=data.units.kb, verbosity=verbosity, - screen=screen, filename=filename, - ene_unit=data.units.energy_str)
- - -
[docs]def equipartition(data, dtemp=0.1, distribution=False, alpha=0.05, - molec_groups=None, - random_divisions=0, random_groups=0, - verbosity=2, - screen=False, filename=None): - r"""Checks the equipartition of a simulation trajectory. - - Parameters - ---------- - data : SimulationData - Simulation data object - dtemp : float, optional - Fraction of temperature deviation tolerated between groups. Default: 0.1 (10%). - distribution : bool, optional - If not set, the kinetic energies will not be tested for Maxwell-Boltzmann - distribution, but only compared amongst each others. - Default: False. - alpha : float, optional - Confidence for Maxwell-Boltzmann test. Default: 0.05 (5%). - molec_groups : list of array-like (ngroups x ?), optional - List of 1d arrays containing molecule indeces defining groups. Useful to pre-define - groups of molecules (e.g. solute / solvent, liquid mixture species, ...). If None, - no pre-defined molecule groups will be tested. Default: None. - - *Note:* If an empty 1d array is found as last element in the list, the remaining - molecules are collected in this array. This allows, for example, to only - specify the solute, and indicate the solvent by giving an empty array. - random_divisions : int, optional - Number of random division tests attempted. Default: 0 (random division tests off). - random_groups : int, optional - Number of groups the system is randomly divided in. Default: 2. - verbosity : int, optional - Verbosity level, where 0 is quiet and 3 very chatty. Default: 2. - screen : bool - Plot distributions on screen. Default: False. - filename : string - Plot distributions to `filename`.pdf. Default: None. - - Returns - ------- - result : list - List of deviations or p-values (if distribution). Tune up verbosity for details. - - Notes - ----- - This function compares the kinetic energy between groups of degrees of - freedom. Theoretically, the kinetic energy is expected (via the - equipartition theorem) to be equally distributed over all degrees of - freedom. In practice, deviations of temperature between groups of - degrees of freedom up to several degrees K are routinely observed. - Larger deviations can, however, hint to misbehaving simulations, such - as, e.g., frozen degrees of freedom, lack of energy exchange between - degrees of freedom, and transfer of heat from faster to slower - oscillating degrees of freedom. - - Splitting of degrees of freedom is done both on a sub-molecular and on - a molecular level. On a sub-molecular level, the degrees of freedom of - a molecule can be partitioned into rigid-body contributions - (translation of the center-of-mass, rotation around the - center-of-mass) and intra-molecular contributions. On a molecular - level, the single molecules of the system can be divided in groups, - either by function (solute / solvent, different species of liquid - mixtures, ...) or randomly. - - `check_equipartition()` compares the partitioned temperatures of the - entire system and, optionally, of predefined or randomly separated - groups. - - Note: In theory, the kinetic energy of the subgroups are expected to - be individually Maxwell-Boltzmann distributed. As this is seldomly - holding in practice (see above), `check_equipartition()` is by - default checking only for abnormal deviations in average temperatures. - The more strict Maxwell-Boltzmann testing can be invoked by giving the - flag `distribution`. - - """ - if distribution: - temp = data.ensemble.temperature - else: - temp = None - - (result, - data.system.ndof_per_molecule, - data.observables.kinetic_energy_per_molecule) = util_kin.check_equipartition( - positions=data.trajectory['position'], - velocities=data.trajectory['velocity'], - masses=data.system.mass, - molec_idx=data.system.molecule_idx, - molec_nbonds=data.system.nconstraints_per_molecule, - natoms=data.system.natoms, - nmolecs=len(data.system.molecule_idx), - ndof_reduction_tra=data.system.ndof_reduction_tra, - ndof_reduction_rot=data.system.ndof_reduction_rot, - dtemp=dtemp, temp=temp, alpha=alpha, - molec_groups=molec_groups, - random_divisions=random_divisions, - random_groups=random_groups, - ndof_molec=data.system.ndof_per_molecule, - kin_molec=data.observables.kinetic_energy_per_molecule, - verbosity=verbosity, - screen=screen, - filename=filename - ) - - return result
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/util/ensemble.html b/docs/_modules/physical_validation/util/ensemble.html deleted file mode 100644 index 368ac15..0000000 --- a/docs/_modules/physical_validation/util/ensemble.html +++ /dev/null @@ -1,1163 +0,0 @@ - - - - - - - - - - - physical_validation.util.ensemble — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.util.ensemble
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.util.ensemble

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-This file reimplements most functionality of the checkensemble.py code
-originally published on https://github.com/shirtsgroup/checkensemble. It
-serves as the low-level functionality of the high-level module
-:mod:`physical_validation.ensemble`.
-"""
-from __future__ import division
-import numpy as np
-import scipy.optimize
-
-import pymbar
-
-from . import trajectory
-from . import error as pv_error
-from . import plot
-
-
-
[docs]def generate_histograms(traj1, traj2, g1, g2, bins): - - n1 = np.size(traj1) - n2 = np.size(traj2) - - h1 = np.histogram(traj1, bins=bins)[0]/n1 - h2 = np.histogram(traj2, bins=bins)[0]/n2 - dh1 = np.sqrt(g1 * h1 * (1 - h1) / n1) - dh2 = np.sqrt(g2 * h2 * (1 - h2) / n2) - - return h1, h2, dh1, dh2
- - -
[docs]def do_linear_fit(traj1, traj2, g1, g2, bins, - screen=False, filename=None, - trueslope=0.0, trueoffset=0.0, - units=None): - - h1, h2, dh1, dh2 = generate_histograms(traj1, traj2, g1, g2, bins) - - # v copied from checkensemble.py v - ratio = np.log(h2 / h1) - dratio = np.sqrt((dh1/h1)**2 + (dh2/h2)**2) - - usedat = np.isfinite(ratio) - y = ratio[usedat] - nuse = len(y) - weights = 1.0/dratio[usedat] - - xaxis = (bins[:-1] + bins[1:])/2 - x = xaxis[usedat] - - x_mat = np.ones([nuse, 2]) - x_mat[:, 1] = x - - w = np.diag(weights) - wx = np.dot(w, x_mat) - wy = np.dot(w, y) - wx_t = np.transpose(wx) - z = np.dot(wx_t, wx) - wxy = np.dot(wx_t, wy) - - a = np.linalg.solve(z, wxy) - da_matrix = np.transpose(np.linalg.inv(z)) - da = np.zeros(2) - da[0] = np.sqrt(da_matrix[0, 0]) - da[1] = np.sqrt(da_matrix[1, 1]) - - # the true line is y = df + dp*x, where y is ln P_1(X)/P_2(X) - # ^ end copied from checkensemble.py ^ - - do_plot = screen or filename is not None - if do_plot: - true = trueoffset+trueslope*xaxis - fit = a[0] + a[1]*xaxis - - data = [{'x': xaxis, - 'y': ratio, - 'y_err': dratio, - 'name': 'Simulation'}, - {'x': xaxis, - 'y': fit, - 'name': 'Fit to simulation'}, - {'x': xaxis, - 'y': true, - 'name': 'Analytical ratio'}] - - if units is not None: - units = ' [' + units + ']' - else: - units = '' - - annot = ('{:.1f}'.format(abs((a[1] - trueslope) / da[1])) + - ' quantiles') - - plot.plot(data, - legend='best', - title='Log probability ratio', - xlabel='Energy' + units, - ylabel=r'$\log\frac{P_2(E)}{P_1(E)}$', - filename=filename, - screen=screen, - axtext=annot) - - return a, da
- - -
[docs]def do_max_likelihood_fit(traj1, traj2, g1, g2, - init_params=None, - verbose=False): - - # ============================================================= # - # Define (negative) log-likelihood function and its derivatives # - # ============================================================= # - def log_likelihood(a, ene1, ene2): - # Returns negative of eq (8) of check_ensemble paper - # - # Uses log (1/f(x)) == -log(f(x)) - # and log(1 + e^x) == log(e^x (e^-x + 1)) == x + log(1 + e^-x) - # ^(a) ^(b) - # form (a) -> 0 for x->-inf, -> inf for x->inf - # form (b) -> NaN for x->-inf, -> x for x->inf - # combined: -> 0 for x-> -inf, -> x for x-> inf - def log_1_plus_exp(y): - def f(yy): - with np.errstate(over='raise'): - try: - xx = np.log(1 + np.exp(yy)) - except FloatingPointError: - xx = yy + np.log(1 + np.exp(-yy)) - return xx - return np.vectorize(f)(y) - - if a.size == 2: - return (np.sum(log_1_plus_exp(a[0] + a[1]*ene1)) + - np.sum(log_1_plus_exp(-a[0] - a[1]*ene2))) - else: - return (np.sum(log_1_plus_exp(a[0] + a[1]*ene1[0] + a[2]*ene1[1])) + - np.sum(log_1_plus_exp(-a[0] - a[1]*ene2[0] - a[2]*ene2[1]))) - - def da_log_likelihood(a, ene1, ene2): - # Returns the first derivative wrt the parameters a of log_likelihood - # - # d/da0 log(1 + exp(a0 + a1*E)) == exp(a0 + a1*E) / (1 + exp(a0 + a1*E)) - # == 1 / (1 + exp(-a0 - a1*E)) - # d/da1 log(1 + exp(a0 + a1*E)) == E * exp(a0 + a1*E) / (1 + exp(a0 + a1*E)) - # == E / (1 + exp(-a0 - a1*E)) - def inv_1_plus_exp(y): - def f(yy): - with np.errstate(over='raise'): - try: - xx = 1. / (1 + np.exp(yy)) - except FloatingPointError: - xx = 0. - return xx - return np.vectorize(f)(y) - - if a.size == 2: - d = np.zeros(2) - d[0] = (np.sum(inv_1_plus_exp(-a[0] - a[1]*ene1)) - - np.sum(inv_1_plus_exp(a[0] + a[1]*ene2))) - d[1] = (np.sum(inv_1_plus_exp(-a[0] - a[1]*ene1) * ene1) - - np.sum(inv_1_plus_exp(a[0] + a[1]*ene2) * ene2)) - else: - d = np.zeros(3) - d[0] = (np.sum(inv_1_plus_exp(-a[0] - a[1]*ene1[0] - a[2]*ene1[1])) - - np.sum(inv_1_plus_exp(a[0] + a[1]*ene2[0] + a[2]*ene2[1]))) - d[1] = (np.sum(inv_1_plus_exp(-a[0] - a[1]*ene1[0] - a[2]*ene1[1]) * ene1[0]) - - np.sum(inv_1_plus_exp(a[0] + a[1]*ene2[0] + a[2]*ene2[1]) * ene2[0])) - d[2] = (np.sum(inv_1_plus_exp(-a[0] - a[1]*ene1[0] - a[2]*ene1[1]) * ene1[1]) - - np.sum(inv_1_plus_exp(a[0] + a[1]*ene2[0] + a[2]*ene2[1]) * ene2[1])) - - return d - - def hess_log_likelihood(a, ene1, ene2): - # Returns the hessian wrt the parameters a of log_likelihood - # fac1 = 1 / (2 + 2*cosh(a0 + a1*ene1)) - # h1 = [[ fac1, ene1*fac1 ], - # [ ene1*fac1, ene1**2*fac1 ]] - # fac2 = 1 / (2 + 2*cosh(a0 + a1*ene2)) - # h2 = [[ fac2, ene2*fac2 ], - # [ ene2*fac2, ene2**2*fac2 ]] - # h = h1 + h2 - - if a.size == 2: - fac1 = 1 / (2 + 2*np.cosh(a[0] + a[1]*ene1)) - fac2 = 1 / (2 + 2*np.cosh(a[0] + a[1]*ene2)) - - h = np.zeros((2, 2)) - - h[0, 0] = np.sum(fac1) + np.sum(fac2) - h[0, 1] = h[1, 0] = np.sum(ene1 * fac1) + np.sum(ene2 * fac2) - h[1, 1] = np.sum(ene1 * ene1 * fac1) + np.sum(ene2 * ene2 * fac2) - - else: - fac1 = 1 / (2 + 2*np.cosh(a[0] + a[1]*ene1[0] + a[2]*ene1[1])) - fac2 = 1 / (2 + 2*np.cosh(a[0] + a[1]*ene2[0] + a[2]*ene2[1])) - - h = np.zeros((3, 3)) - - h[0, 0] = np.sum(fac1) + np.sum(fac2) - h[1, 1] = np.sum(ene1[0] * ene1[0] * fac1) + np.sum(ene2[0] * ene2[0] * fac2) - h[2, 2] = np.sum(ene1[1] * ene1[1] * fac1) + np.sum(ene2[1] * ene2[1] * fac2) - - h[0, 1] = h[1, 0] = np.sum(ene1[0] * fac1) + np.sum(ene2[0] * fac2) - h[0, 2] = h[2, 0] = np.sum(ene1[1] * fac1) + np.sum(ene2[1] * fac2) - h[1, 2] = h[2, 1] = (np.sum(ene1[0] * ene1[1] * fac1) + - np.sum(ene2[0] * ene2[1] * fac2)) - - return h - - # ==================================================== # - # Minimize the negative of the log likelihood function # - # ==================================================== # - if init_params is None: - init_params = np.zeros(traj1.ndim + 1) - else: - init_params = np.array(init_params) - - min_res = scipy.optimize.minimize( - log_likelihood, - x0=init_params, - args=(traj1, traj2), - method='dogleg', - jac=da_log_likelihood, - hess=hess_log_likelihood - ) - - # fallback options - if not min_res.success: - if verbose: - print('Note: Max-Likelihood minimization failed using \'dogleg\' method. ' - 'Trying to vary initial parameters.') - min_res_1 = scipy.optimize.minimize( - log_likelihood, - x0=init_params * 0.9, - args=(traj1, traj2), - method='dogleg', - jac=da_log_likelihood, - hess=hess_log_likelihood - ) - min_res_2 = scipy.optimize.minimize( - log_likelihood, - x0=init_params * 1.1, - args=(traj1, traj2), - method='dogleg', - jac=da_log_likelihood, - hess=hess_log_likelihood - ) - if min_res_1.success and min_res_2.success and np.allclose(min_res_1.x, min_res_2.x): - min_res = min_res_1 - - if not min_res.success: - # dogleg was unsuccessful using alternative starting point - if verbose: - print('Note: Max-Likelihood minimization failed using \'dogleg\' method. ' - 'Trying method \'nelder-mead\'.') - min_res = scipy.optimize.minimize( - log_likelihood, - x0=init_params * 0.9, - args=(traj1, traj2), - method='nelder-mead' - ) - - if not min_res.success: - raise RuntimeError('MaxLikelihood: Unable to minimize function.') - - final_params = min_res.x - - # ======================= # - # Calculate uncertainties # - # ======================= # - cov = np.linalg.inv(hess_log_likelihood(final_params, traj1, traj2)) - final_error = np.sqrt(np.diag(cov))*np.sqrt(np.average([g1, g2])) - - return final_params, final_error
- - -
[docs]def check_bins(traj1, traj2, bins): - # check for empty bins - h1, _ = np.histogram(traj1, bins=bins) - h2, _ = np.histogram(traj2, bins=bins) - empty = np.where((h1 == 0) | (h2 == 0))[0] - - if np.size(empty) == 0: - return bins - elif np.size(empty) == 1: - empty = empty[0] - if empty > np.size(bins) / 2: - return bins[:empty] - else: - return bins[empty+1:] - else: - # find longest non-empty interval - empty = np.insert(np.append(empty, [40]), 0, [-1]) - max_interval = np.argmax(empty[1:] - empty[:-1]) - left = empty[max_interval] + 1 - right = empty[max_interval + 1] - return bins[left:right]
- - - - - -
[docs]def estimate_interval(ens_string, ens_temp, - energy, kb, - ens_press=None, - volume=None, pvconvert=None, - verbosity=1, cutoff=0.001, - tunit='', punit=''): - result = {} - if ens_string == 'NVT': - # Discard burn-in period and time-correlated frames - energy = trajectory.equilibrate(energy, verbose=(verbosity > 1), name='Energy') - energy = trajectory.decorrelate(energy, verbose=(verbosity > 1), name='Energy') - energy = trajectory.cut_tails(energy, cut=cutoff, verbose=(verbosity > 2), name='Energy') - - # dT - sig = np.std(energy) - result['dT'] = 2*kb*ens_temp*ens_temp/sig - elif ens_string == 'NPT': - enthalpy = energy + pvconvert * ens_press * volume - traj_2d = np.array([energy, volume]) - # Discard burn-in period and time-correlated frames - enthalpy = trajectory.equilibrate(enthalpy, verbose=(verbosity > 1), name='Enthalpy') - enthalpy = trajectory.decorrelate(enthalpy, verbose=(verbosity > 1), name='Enthalpy') - enthalpy = trajectory.cut_tails(enthalpy, cut=cutoff, verbose=(verbosity > 2), name='Enthalpy') - volume_1d = trajectory.equilibrate(volume, verbose=(verbosity > 1), name='Volume') - volume_1d = trajectory.decorrelate(volume_1d, verbose=(verbosity > 1), name='Volume') - volume_1d = trajectory.cut_tails(volume_1d, cut=cutoff, verbose=(verbosity > 2), name='Volume') - traj_2d = trajectory.equilibrate(traj_2d, verbose=(verbosity > 1), name='2D-Trajectory') - traj_2d = trajectory.decorrelate(traj_2d, facs=[1, pvconvert * ens_press], verbose=(verbosity > 1), name='2D-Trajectory') - traj_2d = trajectory.cut_tails(traj_2d, cut=cutoff, verbose=(verbosity > 2), name='2D-Trajectory') - - # dT - sig = np.std(enthalpy) - result['dT'] = 2*kb*ens_temp*ens_temp/sig - # dP - sig = np.std(volume_1d)*pvconvert - result['dP'] = 2*kb*ens_temp/sig - # dTdP - cov = np.cov(traj_2d) - sig = np.sqrt(np.diag(cov)) - sig[1] *= pvconvert - result['dTdP'] = [2*kb*ens_temp*ens_temp/sig[0], - 2*kb*ens_temp/sig[1]] - else: - raise pv_error.InputError('ens_str', 'Unrecognized ensemble string.') - - if verbosity > 0: - print('A rule of thumb states that good error recognition can be expected when\n' - 'spacing the tip of the distributions by about two standard deviations.\n' - 'Based on this rule, and the assumption that the standard deviation of the\n' - 'distributions is largely independent of the state point, here\'s an estimate\n' - 'for the interval given the current simulation:') - if ens_string == 'NVT': - print('Current trajectory: NVT, T = {:.2f} {:s}'.format(ens_temp, tunit)) - print('Suggested interval: dT = {:.1f} {:s}'.format(result['dT'], tunit)) - if ens_string == 'NPT': - print('Current trajectory: NPT, T = {:.2f} {:s}, P = {:.2f} {:s}'.format( - ens_temp, tunit, ens_press, punit)) - print('Suggested interval:') - print(' Temperature-only: dT = {:.1f} {:s}'.format(result['dT'], tunit)) - print(' Pressure-only: dP = {:.1f} {:s}'.format(result['dP'], punit)) - print(' Combined: dT = {:.1f} {:s}, dP = {:.1f} {:s}'.format( - result['dTdP'][0], tunit, result['dTdP'][1], punit))
- - -
[docs]def check_1d(traj1, traj2, param1, param2, kb, - quantity, dtemp=False, dpress=False, dmu=False, - temp=None, pvconvert=None, - nbins=40, cutoff=0.001, seed=None, - verbosity=1, screen=False, filename=None): - r""" - Checks whether the energy trajectories of two simulation performed at - different temperatures have sampled distributions at the analytically - expected ratio. - - Parameters - ---------- - traj1 : array-like - Trajectory of the first simulation - If dtemp: - - * NVT: Potential energy U or total energy E = U + K - * NPT: Enthalpy H = U + pV or total energy E = H + K - - If dpress: - - * NPT: Volume V - - traj2 : array-like - Trajectory of the second simulation - If dtemp: - - * NVT: Potential energy U or total energy E = U + K - * NPT: Enthalpy H = U + pV or total energy E = H + K - - If dpress: - - * NPT: Volume V - - param1 : float - Target temperature or pressure of the first simulation - param2 : float - Target temperature or pressure of the second simulation - kb : float - Boltzmann constant in same units as the energy trajectories - quantity : str - Name of quantity analyzed (used for printing only) - dtemp : bool, optional - Set to True if trajectories were simulated at different temperature - Default: False. - dpress : bool, optional - Set to True if trajectories were simulated at different pressure - Default: False. - temp : float, optional - The temperature in equal temperature, differring pressure NPT simulations. - Needed to print optimal dP. - pvconvert : float, optional - Conversion from pressure * volume to energy units. - Needed to print optimal dP. - dmu : bool, optional - Set to True if trajectories were simulated at different chemical potential - Default: False. - nbins : int, optional - Number of bins used to assess distributions of the trajectories - Default: 40 - cutoff : float, optional - Tail cutoff of distributions. - Default: 0.001 (0.1%) - seed : int, optional - If set, bootstrapping will be reproducible. - Default: None, bootstrapping non-reproducible. - verbosity : int, optional - Verbosity level. - Default: 1 (only most important output) - screen : bool, optional - Plot distributions on screen. - Default: False. - filename : string, optional - Plot distributions to `filename`.pdf. - Default: None. - - Returns - ------- - - """ - - if (not (dtemp or dpress or dmu) or - (dtemp and dpress) or - (dtemp and dmu) or - (dpress and dmu)): - raise pv_error.InputError(['dtemp', 'dpress', 'dmu'], - 'Need to specify exactly one of `dtemp`, `dpress` and `dmu`.') - - if dmu: - raise NotImplementedError('check_1d: Testing of `dmu` not implemented.') - - if seed is not None: - raise NotImplementedError('check_1d: Bootstrapping not implemented.') - - if dpress and (temp is None or pvconvert is None): - raise pv_error.InputError(['dpress', 'temp', 'pvconvert'], - '`ensemble.check_1d` with `dpress=True` requires `temp` and `pvconvert`.') - - # =============================== # - # prepare constants, strings etc. # - # =============================== # - pstring = 'ln(P_2(' + quantity + ')/P_1(' + quantity + '))' - trueslope = 0 - if dtemp: - trueslope = 1/(kb * param1) - 1/(kb * param2) - elif dpress: - trueslope = (param1 - param2) / (kb * temp) * pvconvert - - if verbosity > 1: - print('Analytical slope of {:s}: {:.8f}'.format(pstring, trueslope)) - - quant = {} - - # ==================== # - # prepare trajectories # - # ==================== # - # Discard burn-in period and time-correlated frames - traj1 = trajectory.equilibrate(traj1, verbose=(verbosity > 1), name='Trajectory 1') - traj1 = trajectory.decorrelate(traj1, verbose=(verbosity > 1), name='Trajectory 1') - traj1 = trajectory.cut_tails(traj1, cut=cutoff, verbose=(verbosity > 2), name='Trajectory 1') - traj2 = trajectory.equilibrate(traj2, verbose=(verbosity > 1), name='Trajectory 2') - traj2 = trajectory.decorrelate(traj2, verbose=(verbosity > 1), name='Trajectory 2') - traj2 = trajectory.cut_tails(traj2, cut=cutoff, verbose=(verbosity > 2), name='Trajectory 2') - - # calculate inefficiency - g1 = pymbar.timeseries.statisticalInefficiency(traj1) - g2 = pymbar.timeseries.statisticalInefficiency(traj2) - - # calculate overlap - traj1_full = traj1 - traj2_full = traj2 - traj1, traj2, min_ene, max_ene = trajectory.overlap( - traj1=traj1_full, traj2=traj2_full, - ) - if not min_ene: - raise pv_error.InputError(['traj1', 'traj2'], - 'No overlap between trajectories.') - if verbosity > 0: - print('Overlap is {:.1%} of trajectory 1 and {:.1%} of trajectory 2.'.format( - traj1.shape[0] / traj1_full.shape[0], - traj2.shape[0] / traj2_full.shape[0] - )) - if verbosity > 0 and dtemp: - sig1 = np.std(traj1) - sig2 = np.std(traj2) - dt1 = 2*kb*param1*param1/sig1 - dt2 = 2*kb*param2*param2/sig2 - if verbosity > 1: - print('A rule of thumb states that a good overlap is found when dT/T = (2*kB*T)/(sig),\n' - 'where sig is the standard deviation of the energy distribution.\n' - 'For the current trajectories, dT = {:.1f}, sig1 = {:.1f} and sig2 = {:.1f}.\n' - 'According to the rule of thumb, given T1, a good dT is dT = {:.1f}, and\n' - ' given T2, a good dT is dT = {:.1f}.'.format( - param2-param1, sig1, sig2, dt1, dt2) - ) - print('Rule of thumb estimates that dT = {:.1f} would be optimal ' - '(currently, dT = {:.1f})'.format(.5*(dt1+dt2), param2-param1)) - if verbosity > 0 and dpress: - sig1 = np.std(traj1)*pvconvert - sig2 = np.std(traj2)*pvconvert - dp1 = 2*kb*temp/sig1 - dp2 = 2*kb*temp/sig2 - if verbosity > 1: - print('A rule of thumb states that a good overlap is found when dP = (2*kB*T)/(sig),\n' - 'where sig is the standard deviation of the volume distribution.\n' - 'For the current trajectories, dP = {:.1f}, sig1 = {:.1g} and sig2 = {:.1g}.\n' - 'According to the rule of thumb, given P1, a good dP is dP = {:.1f}, and\n' - ' given P2, a good dP is dP = {:.1f}.'.format( - param2-param1, sig1, sig2, dp1, dp2) - ) - print('Rule of thumb estimates that dP = {:.1f} would be optimal ' - '(currently, dP = {:.1f})'.format(.5*(dp1+dp2), param2-param1)) - - # calculate bins - bins = np.linspace(min_ene, max_ene, nbins+1) - bins = check_bins(traj1, traj2, bins) - if np.size(bins) < 3: - raise pv_error.InputError(['traj1', 'traj2', 'nbins', 'cutoff'], - 'Less than 3 bins were filled in the overlap region.\n' - 'Ensure sufficient overlap between the trajectories, and ' - 'consider increasing `cutoff` or `nbins` if there is ' - 'sufficient overlap but unusually long tails.') - - w_f = -trueslope * traj1_full - w_r = trueslope * traj2_full - - if verbosity > 2: - print('Computing log of partition functions using pymbar.BAR...') - df, ddf = pymbar.BAR(w_f, w_r) - if verbosity > 2: - print('Using {:.5f} for log of partition functions as computed from BAR.'.format(df)) - print('Uncertainty in quantity is {:.5f}.'.format(ddf)) - print('Assuming this is negligible compared to sampling error at individual points.') - - # ========== # - # linear fit # - # ========== # - if verbosity > 2: - print('Computing linear fit parameters (for plotting / comparison)') - - fitvals, dfitvals = do_linear_fit( - traj1=traj1_full, traj2=traj2_full, g1=g1, g2=g2, bins=bins, - screen=screen, filename=filename, - trueslope=trueslope, trueoffset=df, - units=None - ) - - slope = fitvals[1] - dslope = dfitvals[1] - quant['linear'] = [abs((slope - trueslope)/dslope)] - if verbosity > 1: - print_stats( - title='Linear Fit Analysis (analytical error)', - fitvals=fitvals, - dfitvals=dfitvals, - kb=kb, - param1=param1, - param2=param2, - trueslope=trueslope, - temp=temp, pvconvert=pvconvert, - dtemp=dtemp, dpress=dpress, dmu=dmu - ) - - # ================== # - # max-likelihood fit # - # ================== # - if verbosity > 2: - print('Computing the maximum likelihood parameters') - - fitvals, dfitvals = do_max_likelihood_fit(traj1_full, traj2_full, g1, g2, - init_params=[df, trueslope], - verbose=(verbosity > 1)) - - slope = fitvals[1] - dslope = dfitvals[1] - quant['maxLikelihood'] = [abs((slope - trueslope)/dslope)] - if verbosity > 0: - print_stats( - title='Maximum Likelihood Analysis (analytical error)', - fitvals=fitvals, - dfitvals=dfitvals, - kb=kb, - param1=param1, - param2=param2, - trueslope=trueslope, - temp=temp, pvconvert=pvconvert, - dtemp=dtemp, dpress=dpress, dmu=dmu - ) - - return quant['maxLikelihood']
- - -
[docs]def check_2d(traj1, traj2, param1, param2, kb, pvconvert, - quantity, dtempdpress=False, dtempdmu=False, - cutoff=0.001, seed=None, - verbosity=1, screen=False, filename=None): - r""" - Checks whether the energy trajectories of two simulation performed at - different temperatures have sampled distributions at the analytically - expected ratio. - - Parameters - ---------- - traj1 : array-like, 2d - Trajectory of the first simulation - If dtempdpress: - - * traj[0,:]: Potential energy U or total energy E = U + K - * traj[1,:]: Volume V - traj2 : array-like, 2d - Trajectory of the second simulation - If dtempdpress: - - * traj[0,:]: Potential energy U or total energy E = U + K - * traj[1,:]: Volume V - param1 : array-like - If dtempdpress: - Target temperature and pressure of the first simulation - param2 : array-like - If dtempdpress: - Target temperature and pressure of the first simulation - kb : float - Boltzmann constant in same units as the energy trajectories - pvconvert : float - Conversion from pressure * volume to energy units - quantity : List[str] - Names of quantities analyzed (used for printing only) - dtempdpress : bool, optional - Set to True if trajectories were simulated at different - temperature and pressure - Default: False. - dtempdmu : bool, optional - Set to True if trajectories were simulated at different - temperature and chemical potential - Default: False. - cutoff : float - Tail cutoff of distributions. - Default: 0.001 (0.1%) - seed : int - If set, bootstrapping will be reproducible. - Default: None, bootstrapping non-reproducible. - verbosity : int - Verbosity level. - Default: 1 (only most important output) - screen : bool, optional - Plot distributions on screen. - Default: False. - filename : string, optional - Plot distributions to `filename`.pdf. - Default: None. - - Returns - ------- - - """ - - if not (dtempdpress or dtempdmu) or (dtempdpress and dtempdmu): - raise pv_error.InputError(['dtempdpress', 'dtempdmu'], - 'Need to specify exactly one of `dtempdpress` and `dtempdmu`.') - - if dtempdmu: - raise NotImplementedError('check_2d: Testing of `dtempdmu` not implemented.') - - if seed is not None: - raise NotImplementedError('check_2d: Bootstrapping not implemented.') - - if screen or filename is not None: - raise NotImplementedError('check_2d: Plotting not implemented.') - - # =============================== # - # prepare constants, strings etc. # - # =============================== # - pstring = ('ln(P_2(' + quantity[0] + ', ' + quantity[1] + ')/' + - 'P_1(' + quantity[0] + ', ' + quantity[1] + '))') - trueslope = np.zeros(2) - facs = [None, None] - if dtempdpress: - trueslope = np.array([ - 1/(kb * param1[0]) - 1/(kb * param2[0]), - pvconvert*(1/(kb * param1[0]) * param1[1] - 1/(kb * param2[0]) * param2[1]) - ]) - facs = [[1, param1[1]], [1, param2[1]]] - - if verbosity > 1: - print('Analytical slope of {:s}: {:.8f}, {:.8f}'.format( - pstring, trueslope[0], trueslope[1] - )) - - quant = {} - - # ==================== # - # prepare trajectories # - # ==================== # - # Discard burn-in period and time-correlated frames - traj1 = trajectory.equilibrate(traj1, verbose=(verbosity > 1), name='Trajectory 1') - traj1 = trajectory.decorrelate(traj1, facs=facs[0], verbose=(verbosity > 1), name='Trajectory 1') - traj1 = trajectory.cut_tails(traj1, cut=cutoff, verbose=(verbosity > 2), name='Trajectory 1') - traj2 = trajectory.equilibrate(traj2, verbose=(verbosity > 1), name='Trajectory 2') - traj2 = trajectory.decorrelate(traj2, facs=facs[1], verbose=(verbosity > 1), name='Trajectory 2') - traj2 = trajectory.cut_tails(traj2, cut=cutoff, verbose=(verbosity > 2), name='Trajectory 2') - - # calculate inefficiency - g1 = np.array([ - pymbar.timeseries.statisticalInefficiency(traj1[0]), - pymbar.timeseries.statisticalInefficiency(traj1[1]) - ]) - g2 = np.array([ - pymbar.timeseries.statisticalInefficiency(traj2[0]), - pymbar.timeseries.statisticalInefficiency(traj2[1]) - ]) - - # calculate overlap - traj1_full = traj1 - traj2_full = traj2 - traj1, traj2, min_ene, max_ene = trajectory.overlap( - traj1=traj1_full, traj2=traj2_full, - ) - if min_ene is None: - raise pv_error.InputError(['traj1', 'traj2'], - 'No overlap between trajectories.') - if verbosity > 0: - print('Overlap is {:.1%} of trajectory 1 and {:.1%} of trajectory 2.'.format( - traj1.shape[1] / traj1_full.shape[1], - traj2.shape[1] / traj2_full.shape[1] - )) - if verbosity > 0 and dtempdpress: - cov1 = np.cov(traj1) - sig1 = np.sqrt(np.diag(cov1)) - sig1[1] *= pvconvert - cov2 = np.cov(traj2) - sig2 = np.sqrt(np.diag(cov2)) - sig2[1] *= pvconvert - dt1 = 2*kb*param1[0]*param1[0]/sig1[0] - dt2 = 2*kb*param2[0]*param2[0]/sig2[0] - dp1 = 2*kb*param1[0]/sig1[1] - dp2 = 2*kb*param1[0]/sig2[1] - if verbosity > 1: - print('A rule of thumb states that a good overlap can be expected when choosing state\n' - 'points separated by about 2 standard deviations.\n' - 'For the current trajectories, dT = {:.1f}, and dP = {:.1f},\n' - 'with standard deviations sig1 = [{:.1f}, {:.1g}], and sig2 = [{:.1f}, {:.1g}].\n' - 'According to the rule of thumb, given point 1, the estimate is dT = {:.1f}, dP = {:.1f}, and\n' - ' given point 2, the estimate is dT = {:.1f}, dP = {:.1f}.'.format( - param2[0]-param1[0], param2[1]-param1[1], - sig1[0], sig1[1], sig2[0], sig2[1], - dt1, dt2, dp1, dp2) - ) - print('Rule of thumb estimates that (dT,dP) = ({:.1f},{:.1f}) would be optimal ' - '(currently, (dT,dP) = ({:.1f},{:.1f}))'.format(.5*(dt1+dt2), .5*(dp1+dp2), - param2[0]-param1[0], param2[1]-param1[1])) - - w_f = -trueslope[0] * traj1_full[0] - trueslope[1] * traj1_full[1] - w_r = trueslope[0] * traj2_full[0] + trueslope[1] * traj2_full[1] - - if verbosity > 2: - print('Computing log of partition functions using pymbar.BAR...') - df, ddf = pymbar.BAR(w_f, w_r) - if verbosity > 2: - print('Using {:.5f} for log of partition functions as computed from BAR.'.format(df)) - print('Uncertainty in quantity is {:.5f}.'.format(ddf)) - print('Assuming this is negligible compared to sampling error at individual points.') - - # ================== # - # max-likelihood fit # - # ================== # - if verbosity > 2: - print('Computing the maximum likelihood parameters') - - fitvals, dfitvals = do_max_likelihood_fit(traj1_full, traj2_full, g1, g2, - init_params=[df, trueslope[0], trueslope[1]], - verbose=(verbosity > 1)) - - slope = fitvals[1:] - dslope = dfitvals[1:] - quant['maxLikelihood'] = np.abs((slope - trueslope)/dslope) - if verbosity > 0: - print_stats( - title='Maximum Likelihood Analysis (analytical error)', - fitvals=fitvals, - dfitvals=dfitvals, - kb=kb, - param1=param1, - param2=param2, - trueslope=trueslope, - pvconvert=pvconvert, - dtempdpress=dtempdpress, dtempdmu=dtempdmu - ) - - return quant['maxLikelihood']
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/util/error.html b/docs/_modules/physical_validation/util/error.html deleted file mode 100644 index 031cf0d..0000000 --- a/docs/_modules/physical_validation/util/error.html +++ /dev/null @@ -1,323 +0,0 @@ - - - - - - - - - - - physical_validation.util.error — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.util.error
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.util.error

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-Module containing the custom exception classes for the physical_validation
-package.
-"""
-
-
-
[docs]class PhysicalValidationError(Exception): - r"""Base class for exceptions in the physical_validation module.""" - pass
- - -
[docs]class InputError(PhysicalValidationError): - r"""Exception raised for input errors""" - - def __init__(self, argument, message): - r""" - - Parameters - ---------- - argument : string or list of strings - message : string - """ - self.argument = argument - self.message = message
- - -
[docs]class ParserValueNotSetError(PhysicalValidationError): - r""" - Exception raised if a requested data value - was not set by the user previously - """ - - def __init__(self, message): - r""" - - Parameters - ---------- - message : string - """ - self.message = message
- - -
[docs]class FileFormatError(PhysicalValidationError): - r"""Exception raised for files not following expected format""" - - def __init__(self, argument, message): - r""" - - Parameters - ---------- - argument : string or list of strings - message : string - """ - self.argument = argument - self.message = message
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/util/gromacs_interface.html b/docs/_modules/physical_validation/util/gromacs_interface.html deleted file mode 100644 index eabcc82..0000000 --- a/docs/_modules/physical_validation/util/gromacs_interface.html +++ /dev/null @@ -1,785 +0,0 @@ - - - - - - - - - - - physical_validation.util.gromacs_interface — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.util.gromacs_interface
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.util.gromacs_interface

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-GROMACS python interface.
-
-.. warning:: This is a mere place holder, as an official python API is
-   currently being developed by the gromacs development team. It is
-   probably neither especially elegant nor especially safe. Use of this
-   module in any remotely critical application is strongly discouraged.
-"""
-import os
-import sys
-import subprocess
-import re
-import numpy as np
-
-
-
[docs]class GromacsInterface(object): - def __init__(self, exe=None, dp=None, includepath=None): - - self._exe = None - self._dp = False - self._includepath = None - - if dp is not None: - self.dp = dp - - if exe is None: - # check whether 'gmx' / 'gmx_d' is in the path - if self._check_exe(quiet=True, exe='gmx'): - self.exe = 'gmx' - elif self._check_exe(quiet=True, exe='gmx_d'): - self.exe = 'gmx_d' - else: - print('WARNING: gmx executable not found. Set before attempting to run!') - else: - self.exe = exe - - if includepath is not None: - self.includepath = includepath - - @property - def exe(self): - """exe is a string pointing to the gmx executable.""" - return self._exe - - @exe.setter - def exe(self, exe): - if self._check_exe(exe=exe): - if os.path.dirname(exe): - exe = os.path.abspath(exe) - self._exe = exe - - @property - def double(self): - """double is a bool defining whether the simulation was ran at double precision""" - return self._dp - - @double.setter - def double(self, dp): - assert isinstance(dp, bool) - self._dp = dp - - @property - def includepath(self): - """includepath defines a path the parser looks for system files""" - return self._includepath - - @includepath.setter - def includepath(self, path): - try: # py2/3 compatibility - basestring - except NameError: - basestring = str - if isinstance(path, basestring): - path = [path] - self._includepath = path - -
[docs] def get_quantities(self, edr, quantities, cwd=None, - begin=None, end=None, args=None): - - if args is None: - args = [] - - tmp_xvg = 'gmxpy_' + os.path.basename(edr).replace('.edr', '') + '.xvg' - if cwd is not None: - tmp_xvg = os.path.join(cwd, tmp_xvg) - - q_dict = {} - - for q in quantities: - not_found = self._create_xvg(edr, tmp_xvg, [q], cwd=cwd, - begin=begin, end=end, args=args)[1] - if q in not_found: - q_dict[q] = None - continue - - skip_line = re.compile("^[#,@]") - values = [] - times = [] - with open(tmp_xvg, 'r') as xvg: - for line in xvg: - if skip_line.match(line): - continue - times.append(float(line.split()[0])) - values.append(float(line.split()[1])) - - if 'time' in q_dict: - if not np.array_equal(np.array(times), q_dict['time']): - print('WARNING: Time discrepancy in ' + edr) - else: - q_dict['time'] = np.array(times) - q_dict[q] = np.array(values) - - os.remove(tmp_xvg) - - return q_dict
- -
[docs] def read_trr(self, trr): - tmp_dump = 'gmxpy_' + os.path.basename(trr).replace('.trr', '') + '.dump' - with open(tmp_dump, 'w') as dump_file: - proc = self._run('dump', ['-f', trr], stdout=dump_file, stderr=subprocess.PIPE) - proc.wait() - - position = [] - velocity = [] - force = [] - box = [] - with open(tmp_dump) as dump: - x = [] - v = [] - f = [] - b = [] - for line in dump: - if 'frame' in line: - # new frame - if len(x) > 0: - # not the first frame - nothing to save there - position.append(np.array(x)) - velocity.append(np.array(v)) - force.append(np.array(f)) - box.append(np.array(b)) - x = [] - v = [] - f = [] - b = [] - continue - if 'x[' in line: - x.append([float(l.strip()) for l in - line.split('{', 1)[1].split('}')[0].split(',')]) - if 'v[' in line: - v.append([float(l.strip()) for l in - line.split('{', 1)[1].split('}')[0].split(',')]) - if 'f[' in line: - f.append([float(l.strip()) for l in - line.split('{', 1)[1].split('}')[0].split(',')]) - if 'box[' in line: - b.append([float(l.strip()) for l in - line.split('{', 1)[1].split('}')[0].split(',')]) - # end loop over file - save last arrays - position.append(np.array(x)) - velocity.append(np.array(v)) - force.append(np.array(f)) - box.append(np.array(b)) - - result = {} - for key, vector in zip(['position', 'velocity', 'force', 'box'], - [position, velocity, force, box]): - vector = np.array(vector) - if vector.size > 0: - result[key] = vector - else: - result[key] = None - return result
- -
[docs] @staticmethod - def read_gro(gro): - with open(gro) as conf: - x = [] - v = [] - b = [] - title = conf.readline() - while title: - natoms = int(conf.readline().strip()) - for _ in range(natoms): - line = conf.readline()[20:] - line = line.split() - x.append([float(xx) for xx in line[0:3]]) - v.append([float(vv) for vv in line[3:6]]) - - line = conf.readline() - line = line.split() - b.append([float(vv) for vv in line[0:3]]) - title = conf.readline() - - result = {} - for key, vector in zip(['position', 'velocity', 'force', 'box'], - [x, v, [], b]): - vector = np.array(vector) - if vector.size > 0: - result[key] = vector - else: - result[key] = None - return result
- -
[docs] @staticmethod - def read_mdp(mdp): - result = {} - with open(mdp) as f: - for line in f: - line = line.split(';')[0].strip() - if not line: - continue - line = line.split('=') - # unify mdp options - all lower case, only dashes - option = line[0].strip().replace('_', '-').lower() - if option not in ['include', 'define']: - value = line[1].strip().replace('_', '-').lower() - else: - value = line[1].strip() - result[option] = value - return result
- -
[docs] @staticmethod - def write_mdp(options, mdp): - with open(mdp, 'w') as f: - for key, value in options.items(): - f.write('{:24s} = {:s}\n'.format(key, value))
- -
[docs] def read_system_from_top(self, top, define=None, include=None): - if not define: - define = [] - else: - define = [d.strip() for d in define.split('-D') if d.strip()] - if not include: - include = [os.getcwd()] - else: - include = [os.getcwd()] + [i.strip() for i in include.split('-I') if i.strip()] - superblock = None - block = None - nmoleculetypes = 0 - topology = {} - with open(top) as f: - content = self._read_top(f, include=include, define=define) - - for line in content: - if line[0] == '[' and line[-1] == ']': - block = line.strip('[').strip(']').strip() - if block == 'defaults' or block == 'system': - superblock = block - topology[superblock] = {} - if block == 'moleculetype' or block == 'molecule_type': - nmoleculetypes += 1 - superblock = block + '_' + str(nmoleculetypes) - topology[superblock] = {} - continue - if superblock is None or block is None: - raise IOError('Not a valid .top file.') - if block in topology[superblock]: - topology[superblock][block].append(line) - else: - topology[superblock][block] = [line] - - for n in range(1, nmoleculetypes + 1): - superblock = 'moleculetype_' + str(n) - molecule = topology[superblock]['moleculetype'][0].split()[0] - topology[molecule] = topology.pop(superblock) - - atomtype_list = topology['defaults']['atomtypes'] - topology['defaults']['atomtypes'] = {} - for atomtype in atomtype_list: - code = atomtype.split()[0] - topology['defaults']['atomtypes'][code] = atomtype - - molecules = [] - for line in topology['system']['molecules']: - molecule = line.split()[0] - nmolecs = int(line.split()[1]) - natoms = len(topology[molecule]['atoms']) - - masses = [] - for atom in topology[molecule]['atoms']: - if len(atom.split()) >= 8: - masses.append(float(atom.split()[7])) - else: - code = atom.split()[1] - masses.append(float(topology['defaults']['atomtypes'][code].split()[3])) - - nbonds = 0 - nbondsh = 0 - bonds = [] - bondsh = [] - if 'bonds' in topology[molecule]: - for bond in topology[molecule]['bonds']: - bond = bond.split() - a1 = int(bond[0]) - 1 - a2 = int(bond[1]) - 1 - m1 = masses[a1] - m2 = masses[a2] - if m1 > 1.008 and m2 > 1.008: - nbonds += 1 - bonds.append([a1, a2]) - else: - nbondsh += 1 - bondsh.append([a1, a2]) - - nangles = 0 - nanglesh = 0 - angles = [] - anglesh = [] - if 'angles' in topology[molecule]: - for angle in topology[molecule]['angles']: - angle = angle.split() - a1 = int(angle[0]) - 1 - a2 = int(angle[1]) - 1 - a3 = int(angle[2]) - 1 - m1 = masses[a1] - m2 = masses[a2] - m3 = masses[a3] - if m1 > 1.008 and m2 > 1.008 and m3 > 1.008: - nangles += 1 - angles.append([a1, a2, a3]) - else: - nanglesh += 1 - anglesh.append([a1, a2, a3]) - - settle = False - if 'settles' in topology[molecule]: - settle = True - bonds = [] - bondsh = [[0, 1], - [0, 2], - [1, 2]] - - molecules.append({ - 'name': molecule, - 'nmolecs': nmolecs, - 'natoms': natoms, - 'mass': masses, - 'nbonds': [nbonds, nbondsh], - 'bonds': bonds, - 'bondsh': bondsh, - 'nangles': [nangles, nanglesh], - 'angles': angles, - 'anglesh': anglesh, - 'settles': settle - }) - - return molecules
- -
[docs] def grompp(self, mdp, top, gro, tpr=None, - cwd='.', args=None, - stdin=None, stdout=None, stderr=None): - cwd = os.path.abspath(cwd) - assert os.path.exists(os.path.join(cwd, mdp)) - assert os.path.exists(os.path.join(cwd, top)) - assert os.path.exists(os.path.join(cwd, gro)) - - if args is None: - args = [] - - if tpr is None: - tpr = os.path.basename(mdp).replace('.mdp', '') + '.tpr' - else: - assert os.path.exists(os.path.join(cwd, os.path.dirname(tpr))) - - args = ['-f', mdp, '-p', top, '-c', gro, '-o', tpr] + args - proc = self._run('grompp', args, cwd=cwd, - stdin=stdin, stdout=stdout, stderr=stderr) - proc.wait() - return proc.returncode
- -
[docs] def mdrun(self, tpr, edr=None, deffnm=None, cwd='.', args=None, - stdin=None, stdout=None, stderr=None, mpicmd=None): - cwd = os.path.abspath(cwd) - tpr = os.path.join(cwd, tpr) - assert os.path.exists(cwd) - assert os.path.exists(tpr) - - if args is None: - args = [] - - if deffnm is None: - deffnm = os.path.basename(tpr).replace('.tpr', '') - - args = ['-s', tpr, '-deffnm', deffnm] + args - if edr is not None: - args += ['-e', edr] - proc = self._run('mdrun', args, cwd=cwd, - stdin=stdin, stdout=stdout, stderr=stderr, - mpicmd=mpicmd) - proc.wait() - return proc.returncode
- - def _check_exe(self, quiet=False, exe=None): - if exe is None: - exe = self._exe - try: - devnull = open(os.devnull) - exe_out = subprocess.check_output([exe, '--version'], stderr=devnull) - except OSError as e: - if e.errno == os.errno.ENOENT: - # file not found error. - if not quiet: - print('ERROR: gmx executable not found') - print(exe) - return False - else: - raise e - # check that output is as expected - return re.search(br':-\) GROMACS - gmx.* \(-:', exe_out) - - def _run(self, cmd, args, cwd=None, stdin=None, stdout=None, stderr=None, mpicmd=None): - if self.exe is None: - raise RuntimeError('Tried to use GromacsParser before setting gmx executable.') - if mpicmd: - command = [mpicmd, self.exe, cmd] - else: - command = [self.exe, cmd] - command.extend(args) - return subprocess.Popen(command, cwd=cwd, - stdin=stdin, stdout=stdout, stderr=stderr) - - def _create_xvg(self, edr, xvg, quantities, cwd=None, - begin=None, end=None, args=None): - assert os.path.exists(edr) - assert os.path.exists(os.path.abspath(os.path.dirname(xvg))) - - if args is None: - args = [] - - if self._dp: - args.append('-dp') - if begin is not None: - args.extend(['-b', str(begin)]) - if end is not None: - args.extend(['-e', str(end)]) - - quants = '' - for q in quantities: - quants += str(q) + '\n' - - args = ['-f', edr, '-o', xvg] + args - proc = self._run('energy', args, cwd=cwd, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - err = proc.communicate(quants.encode(sys.stdin.encoding))[1] - - encoding = sys.stderr.encoding - if encoding is None: - encoding = 'UTF-8' - - not_found = [] - if 'does not match anything' in err.decode(encoding): - for q in quantities: - if "String '" + q + "' does not match anything" in err.decode(encoding): - not_found.append(q) - - return proc.wait(), not_found - - def _read_top(self, filehandler, include, define): - read = [True] - content = [] - include_dirs = include - if self.includepath: - include_dirs += self.includepath - for line in filehandler: - line = line.split(';')[0].strip() - line = line.split('*')[0].strip() - if not line: - continue - if line[0] == '#': - if line.startswith('#ifdef'): - option = line.replace('#ifdef', '').strip() - if option in define: - read.append(True) - else: - read.append(False) - elif line.startswith('#ifndef'): - option = line.replace('#ifndef', '').strip() - if option not in define: - read.append(True) - else: - read.append(False) - elif line.startswith('#else'): - read[-1] = not read[-1] - elif line.startswith('#endif'): - read.pop() - elif line.startswith('#define') and all(read): - option = line.replace('#define', '').strip() - define.append(option) - elif line.startswith('#include') and all(read): - filename = line.replace('#include', '').strip().replace('"', '').replace('\'', '') - for idir in include_dirs: - try: - ifile = open(os.path.join(idir, filename)) - break - except FileNotFoundError: - pass - else: - msg = ('Include file in .top file not found: ' + - line + '\n' + - 'Include directories: ' + str(include_dirs)) - raise IOError(msg) - if ifile: - subcontent = self._read_top(ifile, - [os.path.dirname(ifile.name)] + include, - define) - content.extend(subcontent) - elif all(read): - raise IOError('Unknown preprocessor directive in .top file: ' + - line) - continue - # end line starts with '#' - - if all(read): - content.append(line) - - return content
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/util/integrator.html b/docs/_modules/physical_validation/util/integrator.html deleted file mode 100644 index 74ea74d..0000000 --- a/docs/_modules/physical_validation/util/integrator.html +++ /dev/null @@ -1,379 +0,0 @@ - - - - - - - - - - - physical_validation.util.integrator — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.util.integrator
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.util.integrator

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-This module contains low-level functionality of the
-`physical_validation.integrator` module. The functions in this module should
-generally not be called directly. Please use the high-level functions from
-`physical_validation.integrator`.
-"""
-import numpy as np
-
-from . import plot
-
-
-
[docs]def calculate_rmsd(data, time=None, slope=False): - assert isinstance(data, np.ndarray) and data.ndim == 1 - assert time is None or isinstance(time, np.ndarray) and time.ndim == 1 - - avg = data.mean() - - if time is None: - time = np.arange(data.size) - - fit = np.polyfit(time, data, 1) - - def f(x): return fit[0]*x + fit[1] - - if slope: - rmsd = 0 - for t, d in zip(time, data): - rmsd += (d - f(t))**2 - rmsd = np.sqrt(rmsd / data.size) - else: - rmsd = data.std() - - return avg, rmsd, fit[0]
- - -
[docs]def max_deviation(dts, rmsds): - dt_ratio_2 = (dts[:-1] / dts[1:])**2 - rmsds = rmsds[:-1] / rmsds[1:] - return np.max(np.abs(1 - rmsds/dt_ratio_2))
- - -
[docs]def check_convergence(const_traj, - convergence_test=max_deviation, - verbose=True, slope=False, - screen=False, filename=None): - - assert isinstance(const_traj, dict) - assert len(const_traj) >= 2 - - if verbose: - print('{:65s}'.format('-'*65)) - print('{:>10s} {:>10s} {:>10s} {:>10s} {:^21s}'.format('dt', 'avg', 'rmsd', 'slope', 'ratio')) - print('{:43s} {:>10s} {:>10s}'.format('', 'dt^2', 'rmsd')) - print('{:65s}'.format('-'*65)) - - prev = None - - results = {} - for dt, traj in sorted(const_traj.items(), key=lambda x: float(x[0]), reverse=True): - assert isinstance(traj, np.ndarray) - assert traj.ndim == 1 or traj.ndim == 2 - dt = float(dt) - - if traj.ndim == 1: - data = traj - time = None - else: - data = traj[1] - time = traj[0] - - results[dt] = calculate_rmsd(data, time, slope) - - if verbose: - if prev is None: - print('{:10.4g} {:10.2f} {:10.2e} {:10.2e} {:>10s} {:>10s}'.format(dt, results[dt][0], results[dt][1], - results[dt][2], '--', '--')) - prev = [dt, results[dt][1]] - else: - print('{:10.4g} {:10.2f} {:10.2e} {:10.2e} {:10.2f} {:10.2f}'.format(dt, results[dt][0], results[dt][1], - results[dt][2], - prev[0]**2/dt**2, - prev[1]/results[dt][1])) - prev = [dt, results[dt][1]] - - if verbose: - print('{:65s}'.format('-'*65)) - - dts = np.sort(np.array([float(dt) for dt in results.keys()]))[::-1] - rmsds = np.array([float(results[dt][1]) for dt in dts]) - - do_plot = screen or filename is not None - - if do_plot: - data = [{'x': dts[1:], - 'y': rmsds[:-1] / rmsds[1:], - 'name': 'Integrator convergence'}, - {'x': dts[1:], - 'y': (dts[:-1] / dts[1:])**2, - 'name': 'Expected convergence'}] - - plot.plot(data, - legend='best', - title='Actual vs. expected convergence', - xlabel='Time step', - ylabel='Convergence', - xlim=(0, dts[1]), - inv_x=True, - filename=filename, - screen=screen) - - return convergence_test(dts, rmsds)
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/util/kinetic_energy.html b/docs/_modules/physical_validation/util/kinetic_energy.html deleted file mode 100644 index e0e3278..0000000 --- a/docs/_modules/physical_validation/util/kinetic_energy.html +++ /dev/null @@ -1,1235 +0,0 @@ - - - - - - - - - - - physical_validation.util.kinetic_energy — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.util.kinetic_energy
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.util.kinetic_energy

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-r"""
-This module contains low-level functionality of the
-`physical_validation.kinetic_energy` module. The functions in this module
-should generally not be called directly. Please use the high-level
-functions from `physical_validation.kinetic energy`.
-"""
-from __future__ import print_function
-from __future__ import division
-
-import scipy.stats as stats
-import numpy as np
-
-from ..util import trajectory
-from . import plot
-
-
-
[docs]def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): - return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
- - -
[docs]def temperature(kin, ndof, kb=8.314e-3): - r""" - Calculates the temperature acccording to the equipartition theorem. - - .. math:: - T(K) = \frac{2K}{N k_B} - - Parameters - ---------- - kin : float - Kinetic energy. - ndof : float - Number of degrees of freedom. - kb : float - Boltzmann constant :math:`k_B`. Default: 8.314e-3 (kJ/mol). - - Returns - ------- - temperature : float - Calculated temperature. - """ - # ndof * kb * T = 2 * kin - if isclose(ndof, 0): - return 0 - return 2 * float(kin) / (float(ndof) * float(kb))
- - -
[docs]def check_mb_ensemble(kin, temp, ndof, alpha, kb=8.314e-3, verbosity=1, - screen=False, filename=None, ene_unit=None): - r""" - Checks if a kinetic energy trajectory is Maxwell-Boltzmann distributed. - - .. warning: This is a low-level function. Additionally to being less - user-friendly, there is a higher probability of erroneous and / or - badly documented behavior due to unexpected inputs. Consider using - the high-level version based on the SimulationData object. See - physical_validation.kinetic_energy.check_mb_ensemble for more - information and full documentation. - - Parameters - ---------- - kin : array-like - Kinetic energy snapshots of the system. - temp : float - Target temperature of the system. Used to construct the - Maxwell-Boltzmann distribution. - ndof : float - Number of degrees of freedom in the system. Used to construct the - Maxwell-Boltzmann distribution. - alpha : float - Confidence. TODO: Check proper statistical definition. - kb : float - Boltzmann constant :math:`k_B`. Default: 8.314e-3 (kJ/mol). - verbosity : int - 0: Silent. - 1: Print result details. - 2: Print additional information. - Default: False. - screen : bool - Plot distributions on screen. Default: False. - filename : string - Plot distributions to `filename`.pdf. Default: None. - ene_unit : string - Energy unit - used for plotting only. - - Returns - ------- - result : float - The p value of the test. - - See Also - -------- - physical_validation.kinetic_energy.check_mb_ensemble : High-level version - """ - - # Discard burn-in period and time-correlated frames - kin = trajectory.equilibrate(kin, verbose=(verbosity > 1), name='Kinetic energy') - kin = trajectory.decorrelate(kin, verbose=(verbosity > 1), name='Kinetic energy') - - kt = kb * temp - d, p = stats.kstest(kin, 'chi2', (ndof, 0, kt/2)) - - do_plot = screen or filename is not None - - if do_plot: - hist_sim, k_sim = np.histogram(kin, bins=25, normed=True) - k_sim = (k_sim[1:] + k_sim[:-1])/2 - - ana_dist = stats.chi2(df=ndof, scale=kt/2) - k_ana = np.linspace(ana_dist.ppf(0.0001), - ana_dist.ppf(0.9999), 100) - hist_ana = ana_dist.pdf(k_ana) - - data = [{'x': k_sim, - 'y': hist_sim * 100, - 'name': 'Simulation result'}, - {'x': k_ana, - 'y': hist_ana * 100, - 'name': 'Maxwell-Boltzmann'}] - - unit = '' - if ene_unit is not None: - unit = ' [' + ene_unit + ']' - - plot.plot(data, - legend='best', - title='Simulation vs. Maxwell-Boltzmann', - xlabel='Kinetic energy' + unit, - ylabel='Probability [%]', - sci_x=True, - filename=filename, - screen=screen) - - if verbosity > 0: - message = ('Kolmogorov-Smirnov test result: p = {:g}\n' - 'Null hypothesis: Kinetic energy is Maxwell-Boltzmann distributed'.format(p)) - if alpha is not None: - if p >= alpha: - message += ('\nConfidence alpha = {:f}\n' - 'Result: Hypothesis stands'.format(alpha)) - elif p < alpha: - message += ('\nConfidence alpha = {:f}\n' - 'Result: Hypothesis rejected'.format(alpha)) - print(message) - - return p
- - -
[docs]def check_equipartition(positions, velocities, masses, - molec_idx, molec_nbonds, - natoms, nmolecs, - ndof_reduction_tra=0, ndof_reduction_rot=0, - dtemp=0.1, temp=None, alpha=0.05, - molec_groups=None, - random_divisions=0, random_groups=2, - ndof_molec=None, kin_molec=None, - verbosity=2, - screen=False, filename=None): - r""" - Checks the equipartition of a simulation trajectory. - - .. warning: This is a low-level function. Additionally to being less - user-friendly, there is a higher probability of erroneous and / or - badly documented behavior due to unexpected inputs. Consider using - the high-level version based on the SimulationData object. See - physical_validation.kinetic_energy.check_equipartition for more - information and full documentation. - - Parameters - ---------- - positions : array-like (nframes x natoms x 3) - 3d array containing the positions of all atoms for all frames - velocities : array-like (nframes x natoms x 3) - 3d array containing the velocities of all atoms for all frames - masses : array-like (natoms x 1) - 1d array containing the masses of all atoms - molec_idx : array-like (nmolecs x 1) - Index of first atom for every molecule - molec_nbonds : array-like (nmolecs x 1) - Number of bonds for every molecule - natoms : int - Number of atoms in the system - nmolecs : int - Number of molecules in the system - ndof_reduction_tra : int, optional - Number of center-of-mass translational degrees of freedom to - remove. Default: 0. - ndof_reduction_rot : int, optional - Number of center-of-mass rotational degrees of freedom to remove. - Default: 0. - dtemp : float, optional - Fraction of temperature deviation tolerated between groups. - Default: 0.05 (5%). - temp : float, optional - Target temperature of the simulation. If None, the kinetic - energies will not be tested for Maxwell-Boltzmann distribution, - but only compared amongst each others. Default: None. - alpha : float, optional - Confidence for Maxwell-Boltzmann test. Default: 0.05 (5%). - molec_groups : List[array-like] (ngroups x ?), optional - List of 1d arrays containing molecule indeces defining groups. - Useful to pre-define groups of molecules (e.g. solute / solvent, - liquid mixture species, ...). If None, no pre-defined molecule - groups will be tested. Default: None. - - *Note:* If an empty 1d array is found as last element in the list, the remaining - molecules are collected in this array. This allows, for example, to only - specify the solute, and indicate the solvent by giving an empty array. - random_divisions : int, optional - Number of random division tests attempted. Default: 0 (random - division tests off). - random_groups : int, optional - Number of groups the system is randomly divided in. Default: 2. - ndof_molec : List[dict], optional - Pass in the degrees of freedom per molecule. Slightly increases speed of repeated - analysis of the same simulation run. - kin_molec : List[List[dict]], optional - Pass in the kinetic energy per molecule. Greatly increases speed of repeated - analysis of the same simulation run. - verbosity : int, optional - Verbosity level, where 0 is quiet and 3 very chatty. Default: 2. - screen : bool - Plot distributions on screen. Default: False. - filename : string - Plot distributions to `filename`.pdf. Default: None. - - Returns - ------- - result : int - Number of equipartition violations. Tune up verbosity for details. - ndof_molec : List[dict] - List of the degrees of freedom per molecule. Can be saved to increase speed of - repeated analysis of the same simulation run. - kin_molec : List[List[dict]] - List of the kinetic energy per molecule per frame. Can be saved to increase speed - of repeated analysis of the same simulation run. - - See Also - -------- - physical_validation.kinetic_energy.check_equipartition : High-level version - - """ - - dict_keys = ['tot', 'tra', 'rni', 'rot', 'int'] - - # for each molecule, calculate total / translational / rotational & internal / - # rotational / internal degrees of freedom - # returns: List[dict] of floats (shape: nmolecs x 5 x 1) - if ndof_molec is None: - ndof_molec = calc_ndof(natoms, nmolecs, molec_idx, molec_nbonds, - ndof_reduction_tra, ndof_reduction_rot) - - # for each frame, calculate total / translational / rotational & internal / - # rotational / internal kinetic energy for each molecule - if kin_molec is None: - kin_molec = [] - for r, v in zip(positions, velocities): - kin_molec.append(calc_molec_kinetic_energy(r, v, masses, - molec_idx, natoms, nmolecs)) - - result = [] - - # test system-wide tot, tra, rni, rot, int - if temp is not None: - # check for Maxwell-Boltzmann distribution of - # partitioned kinetic energy trajectories - result.extend(test_mb_dist(kin_molec=kin_molec, - ndof_molec=ndof_molec, - nmolecs=nmolecs, - temp=temp, - alpha=alpha, - dict_keys=dict_keys, - verbosity=verbosity, - screen=screen, - filename=filename)) - else: - # compare partitioned temperatures to total temperature - result.extend(test_temp_diff(kin_molec=kin_molec, - ndof_molec=ndof_molec, - nmolecs=nmolecs, - dtemp=dtemp, - dict_keys=dict_keys, - verbosity=verbosity, - screen=screen, - filename=filename)) - # divide in random groups - for i in range(random_divisions): - # randomly assign a group index to each molecule - group_idx = np.random.randint(random_groups, size=nmolecs) - # create molecule index for each group - groups = [] - for rg in range(random_groups): - groups.append(np.arange(nmolecs)[group_idx == rg]) - # test each group separately - for rg, group in enumerate(groups): - if verbosity > 0: - print('Testing randomly divided group {:d}'.format(rg)) - if verbosity > 3: - print(group) - if temp is not None: - result.extend(test_mb_dist(kin_molec, ndof_molec, nmolecs, temp, - alpha, dict_keys, group, verbosity)) - else: - result.extend(test_temp_diff(kin_molec, ndof_molec, nmolecs, - dtemp, dict_keys, group, verbosity)) - # test groups against each others - for rg1, group1 in enumerate(groups): - for group2 in groups[rg1 + 1:]: - result.extend(test_temp_diff_groups(kin_molec, ndof_molec, nmolecs, - group1, group2, - dtemp, dict_keys, verbosity)) - - # use predefined group division? - # if no groups, return - if not molec_groups: - return result, ndof_molec, kin_molec - # is last group empty? - last_empty = not molec_groups[-1] - # get rid of empty groups - molec_groups = [g for g in molec_groups if g] - # if no groups now (all were empty), return now - if not molec_groups: - return result, ndof_molec, kin_molec - - if last_empty: - # last group is [] -> insert remaining molecules - combined = [] - for group in molec_groups: - combined.extend(group) - molec_groups[-1] = [m for m in range(nmolecs) if m not in combined] - - for mg, group in enumerate(molec_groups): - if verbosity > 0: - print('Testing predifined divided group {:d}'.format(mg)) - if verbosity > 3: - print(group) - if temp is not None: - result.extend(test_mb_dist(kin_molec, ndof_molec, nmolecs, temp, - alpha, dict_keys, group, verbosity)) - else: - result.extend(test_temp_diff(kin_molec, ndof_molec, nmolecs, - dtemp, dict_keys, group, verbosity)) - # test groups against each others - if len(molec_groups) > 1: - for rg1, group1 in enumerate(molec_groups): - for group2 in molec_groups[rg1 + 1:]: - result.extend(test_temp_diff_groups(kin_molec, ndof_molec, nmolecs, - group1, group2, - dtemp, dict_keys, verbosity)) - - return result, ndof_molec, kin_molec
- - -
[docs]def calc_system_ndof(natoms, nmolecs, nbonds, - stop_com_tra, stop_com_rot): - r""" - Calculates the total / translational / rotational & internal / - rotational / internal degrees of freedom of the system. - - Parameters - ---------- - natoms : int - Total number of atoms in the system - nmolecs : int - Total number of molecules in the system - nbonds : int - Total number of bonds in the system - stop_com_tra : bool - Was the center-of-mass translation removed during the simulation? - stop_com_rot : bool - Was the center-of-mass translation removed during the simulation? - - Returns - ------- - ndof : dict - Dictionary containing the degrees of freedom. - Keys: ['tot', 'tra', 'rni', 'rot', 'int'] - """ - # total ndof - ndof_tot = 3*natoms - nbonds - - # ndof reduction due to COM motion constraining - if stop_com_tra: - ndof_tot -= 3 - if stop_com_rot: - ndof_tot -= 3 - - # translational ndof - ndof_tot_tra = 3*nmolecs - if stop_com_tra: - ndof_tot -= 3 - - # rotational & internal ndof - ndof_tot_rni = ndof_tot - ndof_tot_tra - - # rotational ndof - ndof_tot_rot = 3*nmolecs - if stop_com_tra: - ndof_tot -= 3 - - # internal ndof - ndof_tot_int = ndof_tot_rni - ndof_tot_rot - - # return dict - ndof = {'tot': ndof_tot, - 'tra': ndof_tot_tra, - 'rni': ndof_tot_rni, - 'rot': ndof_tot_rot, - 'int': ndof_tot_int} - return ndof
- - -
[docs]def calc_ndof(natoms, nmolecs, - molec_idx, molec_nbonds, - ndof_reduction_tra, ndof_reduction_rot): - r""" - Calculates the total / translational / rotational & internal / - rotational / internal degrees of freedom per molecule. - - Parameters - ---------- - natoms : int - Total number of atoms in the system - nmolecs : int - Total number of molecules in the system - molec_idx : List[int] - Index of first atom for every molecule - molec_nbonds : List[int] - Number of bonds for every molecule - ndof_reduction_tra : int - Number of center-of-mass translational degrees of freedom to - remove. Default: 0. - ndof_reduction_rot : int - Number of center-of-mass rotational degrees of freedom to remove. - Default: 0. - - Returns - ------- - ndof_molec : List[dict] - List of dictionaries containing the degrees of freedom for each molecule - Keys: ['tot', 'tra', 'rni', 'rot', 'int'] - """ - # check whether there are monoatomic molecules: - nmono = (np.array(molec_idx[1:]) - np.array(molec_idx[:-1]) == 1).sum() - - # ndof to be deducted per molecule - # ndof reduction due to COM motion constraining - ndof_com_tra_pm = ndof_reduction_tra / nmolecs - ndof_com_rot_pm = ndof_reduction_rot / (nmolecs - nmono) - - ndof_molec = [] - # add last idx to molec_idx to ease looping - molec_idx = np.append(molec_idx, [natoms]) - # loop over molecules - for idx_molec, (idx_atm_init, idx_atm_end) in enumerate(zip(molec_idx[:-1], molec_idx[1:])): - natoms = idx_atm_end - idx_atm_init - nbonds = molec_nbonds[idx_molec] - ndof_tot = 3*natoms - nbonds - ndof_com_tra_pm - ndof_com_rot_pm - ndof_tra = 3 - ndof_com_tra_pm - ndof_rni = ndof_tot - ndof_tra - ndof_rot = 3 - ndof_com_rot_pm - ndof_int = ndof_tot - ndof_tra - ndof_rot - if isclose(ndof_int, 0, abs_tol=1e-09): - ndof_int = 0 - if natoms == 1: - ndof_tot = 3 - ndof_com_tra_pm - ndof_tra = 3 - ndof_com_tra_pm - ndof_rni = 0 - ndof_rot = 0 - ndof_int = 0 - ndof_molec.append({'tot': ndof_tot, - 'tra': ndof_tra, - 'rni': ndof_rni, - 'rot': ndof_rot, - 'int': ndof_int}) - - return ndof_molec
- - -
[docs]def calc_molec_kinetic_energy(pos, vel, masses, - molec_idx, natoms, nmolecs): - r""" - Calculates the total / translational / rotational & internal / - rotational / internal kinetic energy per molecule. - - Parameters - ---------- - pos : nd-array (natoms x 3) - 2d array containing the positions of all atoms - vel : nd-array (natoms x 3) - 2d array containing the velocities of all atoms - masses : nd-array (natoms x 1) - 1d array containing the masses of all atoms - molec_idx : nd-array (nmolecs x 1) - Index of first atom for every molecule - natoms : int - Total number of atoms in the system - nmolecs : int - Total number of molecules in the system - - Returns - ------- - kin : List[dict] - List of dictionaries containing the kinetic energies for each molecule - Keys: ['tot', 'tra', 'rni', 'rot', 'int'] - """ - # add last idx to molec_idx to ease looping - molec_idx = np.append(molec_idx, [natoms]) - - # calculate kinetic energy - kin_tot = np.zeros(nmolecs) - kin_tra = np.zeros(nmolecs) - kin_rni = np.zeros(nmolecs) - kin_rot = np.zeros(nmolecs) - kin_int = np.zeros(nmolecs) - # loop over molecules - for idx_molec, (idx_atm_init, idx_atm_end) in enumerate(zip(molec_idx[:-1], molec_idx[1:])): - # if monoatomic molecule - if idx_atm_end == idx_atm_init + 1: - v = vel[idx_atm_init] - m = masses[idx_atm_init] - kin_tot[idx_molec] = .5 * m * np.dot(v, v) - kin_tra[idx_molec] = kin_tot[idx_molec] - kin_rni[idx_molec] = 0 - kin_rot[idx_molec] = 0 - kin_int[idx_molec] = 0 - continue - # compute center of mass position, velocity and total mass - com_r = np.zeros(3) - com_v = np.zeros(3) - com_m = 0 - # loop over atoms in molecule - for r, v, m in zip(pos[idx_atm_init:idx_atm_end], - vel[idx_atm_init:idx_atm_end], - masses[idx_atm_init:idx_atm_end]): - com_r += m*r - com_v += m*v - com_m += m - - # total kinetic energy is straightforward - kin_tot[idx_molec] += .5 * m * np.dot(v, v) - - com_r /= com_m - com_v /= com_m - - # translational kinetic energy - kin_tra[idx_molec] = .5 * com_m * np.dot(com_v, com_v) - # combined rotational and internal kinetic energy - kin_rni[idx_molec] = kin_tot[idx_molec] - kin_tra[idx_molec] - - # compute tensor of inertia and angular momentum - inertia = np.zeros((3, 3)) - angular_mom = np.zeros(3) - # loop over atoms in molecule - for r, v, m in zip(pos[idx_atm_init:idx_atm_end], - vel[idx_atm_init:idx_atm_end], - masses[idx_atm_init:idx_atm_end]): - # relative positions and velocities - rr = r - com_r - rv = v - com_v - rr2 = np.dot(rr, rr) - # inertia tensor: - # (i,i) = m*(r*r - r(i)*r(i)) - # (i,j) = m*r(i)*r(j) (i != j) - atm_inertia = -m*np.tensordot(rr, rr, axes=0) - for i in range(3): - atm_inertia[i][i] += m*rr2 - inertia += atm_inertia - # angular momentum: r x p - angular_mom += m * np.cross(rr, rv) - - # angular velocity of the molecule: inertia^{-1} * angular_mom - angular_v = np.dot(np.linalg.inv(inertia), angular_mom) - - # test_kin = 0 - # for r, v, m in zip(pos[idx_atm_init:idx_atm_end], - # vel[idx_atm_init:idx_atm_end], - # masses[idx_atm_init:idx_atm_end]): - # # relative positions and velocities - # rr = r - com_r - # rv = v - com_v - np.cross(angular_v, rr) - # test_kin += .5 * m * np.dot(rv, rv) - # - # print(test_kin) - - kin_rot[idx_molec] = .5 * np.dot(angular_v, angular_mom) - kin_int[idx_molec] = kin_rni[idx_molec] - kin_rot[idx_molec] - - # end loop over molecules - - return {'tot': kin_tot, - 'tra': kin_tra, - 'rni': kin_rni, - 'rot': kin_rot, - 'int': kin_int}
- - -
[docs]def group_kinetic_energy(kin_molec, nmolecs, molec_group=None): - r""" - Sums up the partitioned kinetic energy for a - given group or the entire system. - - Parameters - ---------- - kin_molec : List[dict] - Partitioned kinetic energies per molecule. - nmolecs : int - Total number of molecules in the system. - molec_group : iterable - Indeces of the group to be summed up. None defaults to all molecules - in the system. Default: None. - - Returns - ------- - kin : dict - Dictionary of partitioned kinetic energy for the group. - """ - # - kin = {'tot': 0, 'tra': 0, 'rni': 0, 'rot': 0, 'int': 0} - # - if molec_group is None: - molec_group = range(nmolecs) - # loop over molecules - for idx_molec in molec_group: - for key in kin.keys(): - kin[key] += kin_molec[key][idx_molec] - - return kin
- - -
[docs]def group_ndof(ndof_molec, nmolecs, molec_group=None): - r""" - Sums up the partitioned degrees of freedom for a - given group or the entire system. - - Parameters - ---------- - ndof_molec : List[dict] - Partitioned degrees of freedom per molecule. - nmolecs : int - Total number of molecules in the system. - molec_group : iterable - Indeces of the group to be summed up. None defaults to all molecules - in the system. Default: None. - - Returns - ------- - ndof : dict - Dictionary of partitioned degrees of freedom for the group. - """ - # - ndof = {'tot': 0, 'tra': 0, 'rni': 0, 'rot': 0, 'int': 0} - # - if molec_group is None: - molec_group = range(nmolecs) - # loop over molecules - for idx_molec in molec_group: - for key in ndof.keys(): - ndof[key] += ndof_molec[idx_molec][key] - - return ndof
- - -
[docs]def calc_temperatures(kin_molec, ndof_molec, nmolecs, molec_group=None): - r""" - Calculates the partitioned temperature for a - given group or the entire system. - - Parameters - ---------- - kin_molec : List[dict] - Partitioned kinetic energies per molecule. - ndof_molec : List[dict] - Partitioned degrees of freedom per molecule. - nmolecs : int - Total number of molecules in the system. - molec_group : iterable - Indeces of the group to be summed up. None defaults to all molecules - in the system. Default: None. - - Returns - ------- - temp : dict - Dictionary of partitioned temperatures for the group. - """ - - kin = group_kinetic_energy(kin_molec, nmolecs, molec_group) - ndof = group_ndof(ndof_molec, nmolecs, molec_group) - - temp = {} - for key in kin: - temp[key] = temperature(kin[key], ndof[key]) - - return temp
- - -
[docs]def test_mb_dist(kin_molec, ndof_molec, nmolecs, - temp, alpha, dict_keys, group=None, - verbosity=0, screen=False, filename=None, - ene_unit=None): - r""" - Tests if the partitioned kinetic energy trajectory of a group (or, - if group is None, of the entire system) are separately Maxwell-Boltzmann - distributed. - - Parameters - ---------- - kin_molec : List[List[dict]] - Partitioned kinetic energies per molecule for every frame. - ndof_molec : List[dict] - Partitioned degrees of freedom per molecule. - nmolecs : int - Total number of molecules in the system. - temp : float - Target temperature of the simulation. - alpha : float - Confidence for Maxwell-Boltzmann test. - dict_keys : List[str] - List of dictionary keys representing the partitions of the degrees - of freedom. - group : iterable - Indeces of the group to be tested. None defaults to all molecules - in the system. Default: None. - verbosity : int - Verbosity level, where 0 is quiet and 3 very chatty. Default: 0. - screen : bool - Plot distributions on screen. Default: False. - filename : string - Plot distributions to `filename`.pdf. Default: None. - ene_unit : string - Energy unit - used for plotting only. - - Returns - ------- - result : List[float] - p value for every partition - """ - # save the partitioned kinetic energy trajectories - group_kin = {key: [] for key in dict_keys} - ndof = group_ndof(ndof_molec, nmolecs, group) - # loop over frames - for k in kin_molec: - frame_kin = group_kinetic_energy(k, nmolecs, group) - for key in dict_keys: - group_kin[key].append(frame_kin[key]) - - result = [] - failed = 0 - # test tot, tra, rni, rot, int - if verbosity > 1: - print('Testing whether\n' - '* total,\n' - '* translational,\n' - '* rotational & internal,\n' - '* rotational, and\n' - '* internal\n' - 'kinetic energies are Maxwell-Boltzmann distributed.') - elif verbosity > 0: - print('Testing whether kinetic energies are Maxwell-Boltzmann distributed.') - - for key in dict_keys: - p = check_mb_ensemble(kin=group_kin[key], temp=temp, ndof=ndof[key], - alpha=alpha, verbosity=verbosity > 2, - screen=screen, filename=filename+'_'+key, - ene_unit=ene_unit) - result.append(p) - if alpha is not None and p < alpha: - failed += 1 - if verbosity > 1 and alpha is not None: - if p >= alpha: - print('* {}: passed'.format(key)) - else: - print('* {}: failed'.format(key)) - - if verbosity > 0 and alpha is not None: - if failed == 0: - print('-> Passed') - else: - print('-> Failed') - - return result
- - -
[docs]def test_temp_diff(kin_molec, ndof_molec, nmolecs, - dtemp, dict_keys, group=None, - verbosity=0, screen=False, filename=None, - ene_unit=None): - r""" - Tests if the partitioned temperatures (averaged over a trajectory) - of a group (or, if group is None, of the entire system) are within a - range `dtemp` of the total temperature. - - Parameters - ---------- - kin_molec : List[List[dict]] - Partitioned kinetic energies per molecule for every frame. - ndof_molec : List[dict] - Partitioned degrees of freedom per molecule. - nmolecs : int - Total number of molecules in the system. - dtemp : float - Target temperature of the simulation. - dict_keys : List[str] - List of dictionary keys representing the partitions of the degrees - of freedom. - group : iterable - Indeces of the group to be tested. None defaults to all molecules - in the system. Default: None. - verbosity : int - Verbosity level, where 0 is quiet and 3 very chatty. Default: 0. - screen : bool - Plot distributions on screen. Default: False. - filename : string - Plot distributions to `filename`.pdf. Default: None. - ene_unit : string - Energy unit - used for plotting only. - - Returns - ------- - result : List[float] - Temperature ratio to the total temperature for every partition. - """ - # save the partitioned temperature trajectories - group_temp = {key: [] for key in dict_keys} - # loop over frames - for k in kin_molec: - frame_temp = calc_temperatures(k, ndof_molec, nmolecs, group) - for key in dict_keys: - group_temp[key].append(frame_temp[key]) - # average temperature - group_temp_avg = {} - for key in dict_keys: - group_temp_avg[key] = np.mean(group_temp[key]) - - failed = 0 - result = [] - if verbosity > 0 and dtemp is not None: - print('Testing whether temperatures') - print(' ' + str(dict_keys[1:])) - print('are within {:.1f}% of temperature'.format(dtemp*100)) - print(' ' + dict_keys[0] + ' (' + str(group_temp_avg[dict_keys[0]]) + ')') - elif verbosity > 0: - print('Testing difference between temperatures') - print(' ' + str(dict_keys[1:])) - print('and') - print(' ' + dict_keys[0] + ' (' + str(group_temp_avg[dict_keys[0]]) + ')') - - temp0 = group_temp_avg[dict_keys[0]] - for key in dict_keys[1:]: - result.append(group_temp_avg[key] / temp0) - if dtemp is not None: - if (1 - dtemp) * temp0 <= group_temp_avg[key] <= (1 + dtemp) * temp0: - if verbosity > 1: - print('* {} ({:f}): passed'.format(key, group_temp_avg[key])) - else: - failed += 1 - if verbosity > 1: - print('* {} ({:f}): failed'.format(key, group_temp_avg[key])) - - if verbosity > 0 and dtemp is not None: - if failed == 0: - print('-> Passed') - else: - print('-> Failed') - - do_plot = screen or filename is not None - if do_plot: - data = [] - for key in dict_keys: - t = group_temp[key] - data.append({'x': range(0, len(t)), - 'y': t, - 'name': 'T(' + key + ')'}) - - unit = '' - if ene_unit is not None: - unit = ' [' + ene_unit + ']' - plot.plot(data, - legend='best', - title='Temperature trajectories', - xlabel='Frames', - ylabel='Temperature' + unit, - sci_x=True, - filename=filename, - screen=screen) - - return result
- - -
[docs]def test_temp_diff_groups(kin_molec, ndof_molec, nmolecs, - group1, group2, - dtemp, dict_keys, verbosity=0): - r""" - Tests if the partitioned temperatures (averaged over a trajectory) - of two groups are (individually) within a range `dtemp` of each others. - - Parameters - ---------- - kin_molec : List[List[dict]] - Partitioned kinetic energies per molecule for every frame. - ndof_molec : List[dict] - Partitioned degrees of freedom per molecule. - nmolecs : int - Total number of molecules in the system. - group1 : iterable - Indeces of the first group to be compared. - group2 : iterable - Indeces of the second group to be compared. - dtemp : float - Target temperature of the simulation. - dict_keys : List[str] - List of dictionary keys representing the partitions of the degrees - of freedom. - verbosity : int - Verbosity level, where 0 is quiet and 3 very chatty. Default: 0. - - Returns - ------- - result : List[float] - Temperature ratio (first group / second group) for every partition. - """ - # save the partitioned temperature trajectories (group1) - group1_temp = {key: [] for key in dict_keys} - # loop over frames - for k in kin_molec: - frame_temp = calc_temperatures(k, ndof_molec, nmolecs, group1) - for key in dict_keys: - group1_temp[key].append(frame_temp[key]) - # average temperature - for key in dict_keys: - group1_temp[key] = np.mean(group1_temp[key]) - - # save the partitioned temperature trajectories (group2) - group2_temp = {key: [] for key in dict_keys} - # loop over frames - for k in kin_molec: - frame_temp = calc_temperatures(k, ndof_molec, nmolecs, group2) - for key in dict_keys: - group2_temp[key].append(frame_temp[key]) - # average temperature - for key in dict_keys: - group2_temp[key] = np.mean(group2_temp[key]) - - result = [] - failed = 0 - if verbosity > 0 and dtemp is not None: - print('Testing whether temperatures of both groups are within {:.1f}%'. - format(dtemp*100)) - - for key in dict_keys: - result.append(group1_temp[key]/group2_temp[key]) - if dtemp is not None: - if (1. - dtemp) <= group1_temp[key]/group2_temp[key] <= (1 + dtemp): - if verbosity > 1: - print('* {}: passed'.format(key)) - else: - failed += 1 - if verbosity > 1: - print('* {}: failed'.format(key)) - - if verbosity > 0 and dtemp is not None: - if failed == 0: - print('-> Passed') - else: - print('-> Failed') - - return result
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/util/plot.html b/docs/_modules/physical_validation/util/plot.html deleted file mode 100644 index cd1a24d..0000000 --- a/docs/_modules/physical_validation/util/plot.html +++ /dev/null @@ -1,364 +0,0 @@ - - - - - - - - - - - physical_validation.util.plot — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.util.plot
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.util.plot

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-
-import numpy as np
-import matplotlib as mpl
-import matplotlib.pyplot as plt
-from matplotlib.ticker import AutoMinorLocator
-
-
-
[docs]def plot(res, legend=None, title=None, - xlabel=None, ylabel=None, xlim=None, ylim=None, - inv_x=False, inv_y=False, sci_x=False, sci_y=False, - axtext=None, annotation_location=None, - filename=None, screen=True): - - font = {'family': 'serif', - 'weight': 'normal', - 'size': 16} - mpl.rc('font', **font) - - plt.ioff() - fig, ax = plt.subplots() - xmin = float('inf') - xmax = float('-inf') - for r in res: - x = r['x'] - y = r['y'] - if xlim is not None: - x = x[(r['x'] >= xlim[0]) & (r['x'] <= xlim[1])] - y = y[(r['x'] >= xlim[0]) & (r['x'] <= xlim[1])] - if 'y_err' in r: - dy = r['y_err'] - if xlim is not None: - dy = dy[(r['x'] >= xlim[0]) & (r['x'] <= xlim[1])] - ax.errorbar(x, y, label=r['name'], yerr=dy) - else: - ax.plot(x, y, label=r['name']) - if xlim is not None: - xmin = min(np.min(r['x']), xmin) - xmax = max(np.max(r['x']), xmax) - else: - xmin = min(np.min(r['x']), xmin) - xmax = max(np.max(r['x']), xmax) - - if legend is not None: - ax.legend(loc=legend) - box = ax.get_position() - if title is not None: - ax.set_title(title, y=1.05) - box = box.from_bounds(box.x0, box.y0, box.width, box.height * 0.95) - if xlabel is not None: - ax.set_xlabel(xlabel, labelpad=5) - box = box.from_bounds(box.x0, box.y0 + 0.05 * box.height, box.width, box.height * 0.95) - if ylabel is not None: - ax.set_ylabel(ylabel, labelpad=10) - box = box.from_bounds(box.x0 + 0.05 * box.width, box.y0, box.width * 0.95, box.height) - ax.set_position([box.x0, box.y0, box.width, box.height]) - ax.axis('auto') - if xlim is not None: - ax.set_xlim(xlim) - else: - ax.set_xlim([xmin, xmax]) - if ylim is not None: - ax.set_ylim(ylim) - ax.xaxis.set_minor_locator(AutoMinorLocator(2)) - - if inv_x: - ax.invert_xaxis() - if inv_y: - ax.invert_yaxis() - - if axtext is not None: - if isinstance(axtext, str): - axtext = [axtext] - if annotation_location is None: - annotation_location = [None for _ in axtext] - if isinstance(annotation_location, tuple): - annotation_location = [annotation_location] - for t, loc in zip(axtext, annotation_location): - bbox = dict(boxstyle="round", fc="w", ec="0.5", alpha=0.9) - if loc is None: - ax.text(0.95, 0.05, t, transform=ax.transAxes, - ha='right', va='bottom', - bbox=bbox) - else: - ax.text(loc[0], loc[1], t, - bbox=bbox) - - if sci_x: - ax.ticklabel_format(style='sci', axis='x', scilimits=(-3, 4)) - if sci_y: - ax.ticklabel_format(style='sci', axis='y', scilimits=(-3, 4)) - ax.xaxis.major.formatter._useMathText = True - - if filename is not None: - fig.savefig(filename + '.pdf', dpi=300) - if screen: - fig.show()
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/physical_validation/util/trajectory.html b/docs/_modules/physical_validation/util/trajectory.html deleted file mode 100644 index 52436f9..0000000 --- a/docs/_modules/physical_validation/util/trajectory.html +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - - - - - - physical_validation.util.trajectory — physical_validation 0.9b documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • physical_validation.util.trajectory
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- -

Source code for physical_validation.util.trajectory

-###########################################################################
-#                                                                         #
-#    physical_validation,                                                 #
-#    a python package to test the physical validity of MD results         #
-#                                                                         #
-#    Written by Michael R. Shirts <michael.shirts@colorado.edu>           #
-#               Pascal T. Merz <pascal.merz@colorado.edu>                 #
-#                                                                         #
-#    Copyright (C) 2012 University of Virginia                            #
-#              (C) 2017 University of Colorado Boulder                    #
-#                                                                         #
-#    This library is free software; you can redistribute it and/or        #
-#    modify it under the terms of the GNU Lesser General Public           #
-#    License as published by the Free Software Foundation; either         #
-#    version 2.1 of the License, or (at your option) any later version.   #
-#                                                                         #
-#    This library is distributed in the hope that it will be useful,      #
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of       #
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    #
-#    Lesser General Public License for more details.                      #
-#                                                                         #
-#    You should have received a copy of the GNU Lesser General Public     #
-#    License along with this library; if not, write to the                #
-#    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,     #
-#    Boston, MA 02110-1301 USA                                            #
-#                                                                         #
-###########################################################################
-
-from __future__ import division
-
-import numpy as np
-from scipy import stats
-
-from pymbar import timeseries
-
-from . import error as pv_error
-
-
-
[docs]def equilibrate(traj, verbose=False, name=None): - traj = np.array(traj) - if traj.ndim == 1: - t0, g, n_eff = timeseries.detectEquilibration(traj) - if t0 == 0 and traj.size > 10: - # See https://github.com/choderalab/pymbar/issues/277 - t0x, gx, n_effx = timeseries.detectEquilibration(traj[10:]) - if t0x != 0: - t0 = t0x + 10 - n = traj.size - res = traj[t0:] - - elif traj.ndim == 2 and traj.shape[0] == 2: - t01, g1, n_eff1 = timeseries.detectEquilibration(traj[0]) - t02, g2, n_eff2 = timeseries.detectEquilibration(traj[1]) - t0 = max(t01, t02) - if t0 == 0 and traj.shape[1] > 10: - # See https://github.com/choderalab/pymbar/issues/277 - t01x, g1x, n_eff1x = timeseries.detectEquilibration(traj[0, 10:]) - t02x, g2x, n_eff2x = timeseries.detectEquilibration(traj[1, 10:]) - t0x = max(t01x, t02x) - if t0x != 0: - t0 = t0x + 10 - n = traj.shape[1] - res = traj[:, t0:] - elif traj.ndim == 2: - raise NotImplementedError('trajectory.equilibrate() in 2 dimensions is only ' - 'implemented for exactly two timeseries.') - else: - raise NotImplementedError('trajectory.equilibrate() is not implemented for ' - 'trajectories with more than 2 dimensions.') - - if verbose: - if not name: - name = 'Trajectory' - if t0 == 0: - print('{:s} equilibration: No frames discarded for burn-in.'.format(name)) - elif t0 == 1: - print('{:s} equilibration: First frame ({:.1%} of ' - 'trajectory) discarded for burn-in.'.format(name, 1 / n)) - else: - print('{:s} equilibration: First {:d} frames ({:.1%} of ' - 'trajectory) discarded for burn-in.'.format(name, t0, t0 / n)) - - return res
- - -
[docs]def decorrelate(traj, facs=None, verbose=False, name=None): - traj = np.array(traj) - if traj.ndim == 1: - idx = timeseries.subsampleCorrelatedData(traj) - n0 = traj.size - n1 = len(idx) - res = traj[idx] - elif facs is not None: - # The cleanest way to decorrelate multi-dimensional trajectories would probably - # be a sort of "parallel-decorrelation", taking frames in a way that both trajectories - # are independently decorrelated. pymbar does not offer this functionality, so for - # now, here's a work-around: We'll decorrelate such that - # traj_sum = facs[0]*traj[0, :] + facs[1]*traj[1, :] + ... - # is decorrelated. - # Use case: - # traj_sum = 1.0 * U + P * V - traj_sum = np.zeros(traj.shape[1]) - for n, f in enumerate(facs): - traj_sum += f * traj[n] - idx = timeseries.subsampleCorrelatedData(traj_sum) - n0 = traj.shape[1] - n1 = len(idx) - res = traj[:, idx] - else: - raise NotImplementedError('trajectory.decorrelate() is not implemented for ' - 'trajectories with more than 1 dimension.') - if verbose: - n = n0 - n1 - if not name: - name = 'Trajectory' - if n == 0: - print('{:s} decorrelation: No frames discarded for decorrelation.'.format(name)) - elif n == 1: - print('{:s} decorrelation: 1 frame ({:.1%} of ' - 'trajectory) discarded for decorrelation.'.format(name, 1/n0)) - else: - print('{:s} decorrelation: {:d} frames ({:.1%} of ' - 'trajectory) discarded for decorrelation.'.format(name, n, n/n0)) - - return res
- - -
[docs]def cut_tails(traj, cut, verbose=False, name=None): - traj = np.array(traj) - dc = 100 * cut - if traj.ndim == 1: - tmax = stats.scoreatpercentile(traj, 100 - dc) - tmin = stats.scoreatpercentile(traj, dc) - t = traj[(tmin <= traj) * (traj <= tmax)] - n0 = traj.size - n = t.size - elif traj.ndim == 2: - tmax = stats.scoreatpercentile(traj, 100 - dc, axis=1) - tmin = stats.scoreatpercentile(traj, dc, axis=1) - t = traj[:, - (tmin[0] <= traj[0]) * (tmin[1] <= traj[1]) * - (tmax[0] >= traj[0]) * (tmax[1] >= traj[1])] - n0 = traj.shape[1] - n = t.shape[1] - else: - raise NotImplementedError('trajectory.cut_tails() is not implemented for ' - 'trajectories with more than 2 dimension.') - - if verbose: - if not name: - name = 'Trajectory' - print('{:s} tails (cut = {:.2%}): {:n} frames ({:.2%} of trajectory) were cut'.format( - name, cut, n0 - n, (n0-n)/n0)) - - return t
- - -
[docs]def overlap(traj1, traj2, cut=None, verbose=False, name=None): - traj1 = np.array(traj1) - traj2 = np.array(traj2) - if traj1.ndim == traj2.ndim and traj2.ndim == 1: - if cut: - dc = 100 * cut - max1 = stats.scoreatpercentile(traj1, 100 - dc) - min1 = stats.scoreatpercentile(traj1, dc) - max2 = stats.scoreatpercentile(traj2, 100 - dc) - min2 = stats.scoreatpercentile(traj2, dc) - else: - max1 = traj1.max() - min1 = traj1.min() - max2 = traj2.max() - min2 = traj2.min() - - tmin = max(min1, min2) - tmax = min(max1, max2) - - t1 = traj1[(tmin <= traj1) * (traj1 <= tmax)] - t2 = traj2[(tmin <= traj2) * (traj2 <= tmax)] - elif traj1.ndim == traj2.ndim and traj2.ndim == 2: - if traj1.shape[0] != 2 or traj2.shape[0] != 2: - raise NotImplementedError('trajectory.overlap() in 2 dimensions is only ' - 'implemented for exactly two timeseries per trajectory.') - if cut: - dc = 100 * cut - max1 = stats.scoreatpercentile(traj1, 100 - dc, axis=1) - min1 = stats.scoreatpercentile(traj1, dc, axis=1) - max2 = stats.scoreatpercentile(traj2, 100 - dc, axis=1) - min2 = stats.scoreatpercentile(traj2, dc, axis=1) - else: - max1 = traj1.max(axis=1) - min1 = traj1.min(axis=1) - max2 = traj2.max(axis=1) - min2 = traj2.min(axis=1) - - tmin = np.max([min1, min2], axis=0) - tmax = np.min([max1, max2], axis=0) - - t1 = traj1[:, - (tmin[0] <= traj1[0]) * (tmin[1] <= traj1[1]) * - (tmax[0] >= traj1[0]) * (tmax[1] >= traj1[1])] - t2 = traj2[:, - (tmin[0] <= traj2[0]) * (tmin[1] <= traj2[1]) * - (tmax[0] >= traj2[0]) * (tmax[1] >= traj2[1])] - elif traj1.ndim != traj2.ndim: - raise pv_error.InputError(['traj1', 'traj2'], - 'Trajectories don\'t have the same number of dimensions') - else: - raise NotImplementedError('trajectory.overlap() is not implemented for ' - 'trajectories with more than 2 dimensions.') - - if np.any(max1 < min2) or np.any(max2 < min1): - if verbose: - if not name: - name = 'Trajectory' - print('{:s} overlap: No overlap found between trajectories'.format(name)) - return np.array([]), np.array([]), None, None - - if verbose: - if not name: - name = 'Trajectory' - print('{:s} overlap: {:.1%} of trajectory 1, and {:.1%} of trajectory 2 ' - 'were found within overlap region.\n' - ' That corresponds to {:n} frames and {:n} frames, ' - 'respectively'.format(name, len(traj1)/len(t1), len(traj2)/len(t2), - len(t1), len(t2))) - - return t1, t2, tmin, tmax
-
- -
-
- -
-
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt deleted file mode 100644 index 1cb2149..0000000 --- a/docs/_sources/index.rst.txt +++ /dev/null @@ -1,38 +0,0 @@ -***************************** -Physical validation reference -***************************** - -`physical_validation` is a package aimed at testing results obtained -by molecular dynamics simulations for their physical validity. - -.. note:: We are always looking to enlarge our set of tests. If you are a - MD user or developer and have suggestions for physical validity tests - missing in this package, we would love to hear from you! Please - consider getting in touch with us via our `github page`_. - -.. toctree:: - userguide - :maxdepth: 2 - :caption: User guide: - -.. toctree:: - parsers - :maxdepth: 2 - :caption: Data format and parsers: - -.. toctree:: - physical_validation - physical_validation.data - physical_validation.util - :maxdepth: 2 - :caption: Package reference: - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - - -.. _`github page`: https://github.com/shirtsgroup/physical-validation diff --git a/docs/_sources/parsers.rst.txt b/docs/_sources/parsers.rst.txt deleted file mode 100644 index 92f7ef0..0000000 --- a/docs/_sources/parsers.rst.txt +++ /dev/null @@ -1,369 +0,0 @@ -.. _doc_parsers: - -:class:`.SimulationData` objects and parsers -============================================= - -The data of simulations to be validated are best represented by objects -of the :class:`.SimulationData` type. While lower-level functions accepting -bare arrays and numbers are available, the :class:`.SimulationData` objects -combine ease-of-use and higher stability in form of input testing. - -The :class:`.SimulationData` objects are consisting of information about the -simulation and the system. This information is collected in objects of different -classes, namely - -* :obj:`.SimulationData.units` of type :class:`.UnitData`: - Information on the units used by the simulation program. -* :obj:`.SimulationData.ensemble` of type :class:`.EnsembleData`: - Information on the sampled ensemble. -* :obj:`.SimulationData.system` of type :class:`.SystemData`: - Information on the system (atoms, molecules, constraints, etc.). -* :obj:`.SimulationData.observables` of type :class:`.ObservableData`: - Trajectories of observables along the simulation. -* :obj:`.SimulationData.trajectory` of type :class:`.TrajectoryData`: - Position / velocity / force trajectories along the simulation. -* :obj:`.SimulationData.dt` of type `float`: - The time step at which the simulation was performed. - -The :class:`.SimulationData` objects can either be constructed -directly from arrays and numbers, or (partially) automatically via parsers. - -Package-specific parsers ------------------------- - -Package-specific parsers return :class:`.SimulationData` objects via the -:func:`.Parser.get_simulation_data` function by reading the output files -of the corresponding MD program. - -GROMACS: :class:`.GromacsParser` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The :class:`.GromacsParser` takes the GROMACS input files `mdp` (run options) -and `top` (topology file) to read the details about the system, the ensemble -and the time step. The observable trajectory is extracted from an `edr` -(binary energy trajectory), while the position and velocity trajectory can -be read either from a `trr` (binary trajectory) or a `gro` (ascii trajectory) -file. The constructor optionally takes the path to a gromacs binary as well -as the path to the topology library as inputs. The first is necessary to -extract information from binary files (using `gmx energy` and `gmx dump`), -while becomes necessary if the `top` file contains `#include` statements -which usually rely on GROMACS environment variables. - -Example usage: -:: - - import physical_validation as pv - - parser = pv.data.GromacsParser(exe='~/bin/gromacs/bin/gmx', - includepath='~/bin/gromacs/share/gromacs/top') - - res = parser.get_simulation_data( - mdp='mdout.mdp', - top='system.top', - gro='system.gro', - edr='system.edr' - ) - -Flatfile parser ---------------- - -For MD packages not supported by the package-specific parsers, there is the -possibility to create the :class:`.SimulationData` objects via the -:class:`.FlatfileParser`. This parser fills the -:obj:`.SimulationData.trajectory` object via 3-dimensional ascii files -containing the position and velocity trajectories, and the -:obj:`.SimulationData.observables` via 1-dimensional ascii files containing -the trajectories for the observables of interest. As the details on the -units, the simulated system and the sampled ensemble can not easily be read -from such files, this information has to be provided by the user by passing -objects of the respective data structures. See -:func:`.FlatfileParser.get_simulation_data` for more details on the -:class:`.SimulationData` creation via the flat file parser, and -:ref:`simulationdata_details` for details on which test requires which -information. - - -Example usage, system of 900 water molecules in GROMACS units simulated in -NVT (note that this example leaves some fields in :class:`.SystemData` -empty, as well as the trajectory of some observables and the position and -velocities): -:: - - import physical_validation as pv - - parser = pv.data.FlatfileParser() - - system = pv.data.SystemData( - natoms=900*3, - nconstraints=900*3, - ndof_reduction_tra=3, - ndof_reduction_rot=0 - ) - - units = pv.data.UnitData( - kb=8.314462435405199e-3, - energy_str='kJ/mol', - energy_conversion=1.0, - length_str='nm', - length_conversion=1.0, - volume_str='nm^3', - volume_conversion=1.0, - temperature_str='K', - temperature_conversion=1.0, - pressure_str='bar', - pressure_conversion=1.0, - time_str='ps', - time_conversion=1.0 - ) - - ensemble = pv.data.EnsembleData( - ensemble='NVT', - natoms=900*3, - volume=3.01125**3, - temperature=298.15 - ) - - res = parser.get_simulation_data( - units=units, ensemble=ensemble, system=system, - kinetic_ene_file='kinetic.dat', - potential_ene_file='potential.dat', - total_ene_file='total.dat' - ) - - -Create :class:`.SimulationData` objects from python data --------------------------------------------------------- - -As an alternative to the different parsers described above, -:class:`.SimulationData` objects can of course also be created by calling -the constructor directly. The :class:`.SimulationData` constructor thereby -simply takes the objects listed at the beginning of this section. All these -objects can also be set later during the lifetime of the object - a -:class:`.SimulationData` object can hence be initialized empty and filled -at a later point. The objects contained in :class:`.SimulationData` objects -are explained in details in :ref:`simulationdata_details`. - -Example usage, system of 900 water molecules in GROMACS units simulated in -NVT (note that this example leaves some fields in :class:`.SystemData` -empty, as well as the trajectory of some observables and the position and -velocities): -:: - - import physical_validation as pv - - system = pv.data.SystemData( - natoms=900*3, - nconstraints=900*3, - ndof_reduction_tra=3, - ndof_reduction_rot=0 - ) - - units = pv.data.UnitData( - kb=8.314462435405199e-3, - energy_str='kJ/mol', - energy_conversion=1.0, - length_str='nm', - length_conversion=1.0, - volume_str='nm^3', - volume_conversion=1.0, - temperature_str='K', - temperature_conversion=1.0, - pressure_str='bar', - pressure_conversion=1.0, - time_str='ps', - time_conversion=1.0 - ) - - ensemble = pv.data.EnsembleData( - ensemble='NVT', - natoms=900*3, - volume=3.01125**3, - temperature=298.15 - ) - - # This snippet is assuming that kin_ene, pot_ene and tot_ene are lists - # or numpy arrays filled with the kinetic, potential and total energy - # of a simulation run. These might be obtained, e.g., from the python - # API of a simulation code, or from other python-based analysis tools. - - observables = pv.data.ObservableData( - kinetic_energy = kin_ene, - potential_energy = pot_ene, - total_energy = tot_ene - ) - - res = pv.data.SimulationData( - units=units, ensemble=ensemble, - system=system, observables=observables - ) - - -.. _simulationdata_details: - -Data contained in :class:`.SimulationData` objects -================================================== - -Units: :obj:`.SimulationData.units` of type :class:`.UnitData` --------------------------------------------------------------- -Attributes: - -* :attr:`.UnitData.kb`, `float` -* :attr:`.UnitData.energy_conversion`, `float` -* :attr:`.UnitData.length_conversion`, `float` -* :attr:`.UnitData.volume_conversion`, `float` -* :attr:`.UnitData.temperature_conversion`, `float` -* :attr:`.UnitData.pressure_conversion`, `float` -* :attr:`.UnitData.time_conversion`, `float` -* :attr:`.UnitData.energy_str`, `str` -* :attr:`.UnitData.length_str`, `str` -* :attr:`.UnitData.volume_str`, `str` -* :attr:`.UnitData.temperature_str`, `str` -* :attr:`.UnitData.pressure_str`, `str` -* :attr:`.UnitData.time_str`, `str` - -The information about units consists of different parts: -* The value of kB in the used energy units, -* the conversion factor to GROMACS units (kJ/mol, nm, nm^3, K, bar, ps), and -* the name of the units (energy_str, length_str, volume_str, temperature_str, pressure_str, time_str). -The names are only used for output (console printing and plotting), and are optional. -The conversion factors and kB are, on the other hand, used in computations and need -to be given. - -Needed by - - * :func:`physical_validation.ensemble.check` - * :func:`physical_validation.ensemble.estimate_interval` - * :func:`physical_validation.kinetic_energy.mb_ensemble`, only - - - :attr:`.UnitData.kb` - -Ensemble: :obj:`.SimulationData.ensemble` of type :class:`.EnsembleData` ------------------------------------------------------------------------- -Attributes: - -* :attr:`.EnsembleData.ensemble`, `str` -* :attr:`.EnsembleData.natoms`, `int` -* :attr:`.EnsembleData.mu`, `float` -* :attr:`.EnsembleData.volume`, `float` -* :attr:`.EnsembleData.pressure`, `float` -* :attr:`.EnsembleData.energy`, `float` -* :attr:`.EnsembleData.temperature`, `float` - -The ensemble is a string indicating the thermodynamical ensemble a simulation was -performed in, and is any of 'NVE', 'NVT', 'NPT', 'muVT'. - -Depending on the ensemble, EnsembleData then holds additional information defining -the ensemble, such as the number of particles N, the chemical potential mu, the -volume V, the pressure P, the constant energy E or the temperature T. While any -of these additional information are optional, most of them are needed by certain -tests, such that not fully defining the ensemble results in warnings. The notable -exception to this rule is the constant energy E for NVE, which is not needed -by any test and can hence be omitted without raising a warning. - -Needed by - * :func:`physical_validation.kinetic_energy.mb_ensemble` - * :func:`physical_validation.ensemble.check` - -System: :obj:`.SimulationData.system` of type :class:`.SystemData` ------------------------------------------------------------------- -Attributes: - - * :attr:`.SimulationData.natoms`, the total number of atoms in the system; - e.g. for a system containing 100 water molecules: `.SimulationData.natoms = 300` - * :attr:`.SimulationData.nconstraints`, the total number of constraints in the - system, not including the global translational and rotational constraints - (see next two attributes); e.g. for a system containing 100 *rigid* water molecules: - `.SimulationData.nconstraints = 300` - * :attr:`.SimulationData.ndof_reduction_tra`, global reduction of translational - degrees of freedom (e.g. due to constraining the center of mass of the system) - * :attr:`.SimulationData.ndof_reduction_rot`, global reduction of rotational - degrees of freedom (e.g. due to constraining the center of mass of the system) - * :attr:`.SimulationData.mass`, a list of the mass of every atom in the system; - e.g. for a single water molecule: `.SimulationData.mass = [15.9994, 1.008, 1.008]` - * :attr:`.SimulationData.molecule_idx`, a list with the indices first atoms of every - molecule (this assumes that the atoms are sorted by molecule); e.g. for a system - containing 3 water molecules: `.SimulationData.molecule_idx = [0, 3, 6]` - * :attr:`.SimulationData.nconstraints_per_molecule`, a list with the number of - constraints in every molecule; e.g. for a system containing 3 *rigid* water - molecules: `.SimulationData.nconstraints_per_molecule = [3, 3, 3]` - * :attr:`.SimulationData.bonds`, a list containing all bonds in the system; - e.g. for a system containing 3 water molecules: - `.SimulationData.bonds = [[0, 1], [0, 2], [3, 4], [3, 5], [6, 7], [6, 8]]` - * :attr:`.SimulationData.constrained_bonds`, a list containing only the constrained - bonds in the system, must be a subset of `.SimulationData.bonds` (and equal, if - all bonds are constrained). - -.. todo:: Currently, there is some redundancy in the attributes listed above. The - :attr:`.SimulationData.bonds` and :attr:`.SimulationData.constrained_bonds` are - reserved for future use - included already in the information about the system, - but not yet used by any tests included in the currently published package. In a - future version, the :class:`.SystemData` should be streamlined to make the object - initialization easier. - -Needed by - - * :func:`physical_validation.kinetic_energy.mb_ensemble`, partially: - - - :attr:`.SystemData.natoms`, - - :attr:`.SystemData.nconstraints`, - - :attr:`.SystemData.ndof_reduction_tra`, - - :attr:`.SystemData.ndof_reduction_rot` - - * :func:`physical_validation.kinetic_energy.equipartition`, all attributes except - :attr:`.SimulationData.bonds` and :attr:`.SimulationData.constrained_bonds`. - -Observables: :obj:`.SimulationData.observables` of type :class:`.ObservableData` --------------------------------------------------------------------------------- -Attributes: - - * :attr:`.ObservableData.kinetic_energy`, the kinetic energy trajectory (nframes x 1), - also accessible via `.ObservableData['kinetic_energy']` - * :attr:`.ObservableData.potential_energy`, the potential energy trajectory (nframes x 1), - also accessible via `.ObservableData['potential_energy']` - * :attr:`.ObservableData.total_energy`, the total energy trajectory (nframes x 1), - also accessible via `.ObservableData['total_energy']` - * :attr:`.ObservableData.volume`, the volume trajectory (nframes x 1), - also accessible via `.ObservableData['volume']` - * :attr:`.ObservableData.pressure` the pressure trajectory (nframes x 1), - also accessible via `.ObservableData['pressure']` - * :attr:`.ObservableData.temperature` the temperature trajectory (nframes x 1), - also accessible via `.ObservableData['temperature']` - * :attr:`.ObservableData.constant_of_motion` the constant of motion trajectory (nframes x 1), - also accessible via `.ObservableData['constant_of_motion']` - -Needed by - - * :func:`physical_validation.kinetic_energy.mb_ensemble` - - - :attr:`.ObservableData.kinetic_energy` - - * :func:`physical_validation.ensemble.check` - - - :attr:`.ObservableData.total_energy`, or - - :attr:`.ObservableData.potential_energy`, - - :attr:`.ObservableData.volume` (for NPT) - - * :func:`physical_validation.integrator.convergence` - - - :attr:`.ObservableData.constant_of_motion` - -Atom trajectories: :obj:`.SimulationData.trajectory` of type :class:`.TrajectoryData` -------------------------------------------------------------------------------------- -Attributes: - - * :attr:`.TrajectoryData.position`, the position trajectory (nframes x natoms x 3), - also accessible via `.TrajectoryData['position']` - * :attr:`.TrajectoryData.velocity`, the velocity trajectory (nframes x natoms x 3), - also accessible via `.TrajectoryData['velocity']` - -Needed by - - * :func:`physical_validation.kinetic_energy.equipartition` - - -Time step: :obj:`.SimulationData.dt` of type `float` ----------------------------------------------------- -The timestep used during the simulation run, a single `float` value. - -Needed by - - * :func:`physical_validation.integrator.convergence` diff --git a/docs/_sources/physical_validation.data.rst.txt b/docs/_sources/physical_validation.data.rst.txt deleted file mode 100644 index 60f8e94..0000000 --- a/docs/_sources/physical_validation.data.rst.txt +++ /dev/null @@ -1,62 +0,0 @@ -physical_validation\.data subpackage -==================================== - -physical_validation\.data\.simulation_data module -------------------------------------------------- -.. automodule:: physical_validation.data.simulation_data - :members: - :undoc-members: - -physical_validation\.data\.unit_data module -------------------------------------------- -.. automodule:: physical_validation.data.unit_data - :members: - :undoc-members: - -physical_validation\.data\.ensemble_data module ------------------------------------------------ -.. automodule:: physical_validation.data.ensemble_data - :members: - :undoc-members: - -physical_validation\.data\.trajectory_data module -------------------------------------------------- -.. automodule:: physical_validation.data.trajectory_data - :members: - :undoc-members: - -physical_validation\.data\.observable_data module -------------------------------------------------- -.. automodule:: physical_validation.data.observable_data - :members: - :undoc-members: - -physical_validation\.data\.system_data module ---------------------------------------------- -.. automodule:: physical_validation.data.system_data - :members: - :undoc-members: - -physical_validation\.data\.parser module ----------------------------------------- -.. automodule:: physical_validation.data.parser - -.. autoclass:: physical_validation.data.parser.Parser - :members: - :undoc-members: - -physical_validation\.data\.gromacs_parser module ------------------------------------------------- -.. automodule:: physical_validation.data.gromacs_parser - -.. autoclass:: physical_validation.data.gromacs_parser.GromacsParser - :members: - :undoc-members: - -physical_validation\.data\.flatfile_parser module -------------------------------------------------- -.. automodule:: physical_validation.data.flatfile_parser - -.. autoclass:: physical_validation.data.flatfile_parser.FlatfileParser - :members: - :undoc-members: diff --git a/docs/_sources/physical_validation.rst.txt b/docs/_sources/physical_validation.rst.txt deleted file mode 100644 index 6e9ea28..0000000 --- a/docs/_sources/physical_validation.rst.txt +++ /dev/null @@ -1,23 +0,0 @@ -physical_validation package -=========================== - -.. automodule:: physical_validation - :members: - -physical_validation\.kinetic_energy module ------------------------------------------- - -.. automodule:: physical_validation.kinetic_energy - :members: - -physical_validation\.ensemble module ------------------------------------- - -.. automodule:: physical_validation.ensemble - :members: - -physical_validation\.integratorconvergence module -------------------------------------------------- - -.. automodule:: physical_validation.integrator - :members: diff --git a/docs/_sources/physical_validation.util.rst.txt b/docs/_sources/physical_validation.util.rst.txt deleted file mode 100644 index 9073c32..0000000 --- a/docs/_sources/physical_validation.util.rst.txt +++ /dev/null @@ -1,47 +0,0 @@ -physical_validation\.util subpackage -==================================== - -.. warning:: This subpackage is intended for internal use. Documentation - and input validation is reduced. - -physical_validation\.util\.kinetic_energy module ------------------------------------------------- -.. automodule:: physical_validation.util.kinetic_energy - :members: - :undoc-members: - -physical_validation\.util\.ensemble module ------------------------------------------- -.. automodule:: physical_validation.util.ensemble - :members: - :undoc-members: - -physical_validation\.util\.integrator module --------------------------------------------- -.. automodule:: physical_validation.util.integrator - :members: - :undoc-members: - -physical_validation\.util\.trajectory module --------------------------------------------- -.. automodule:: physical_validation.util.trajectory - :members: - :undoc-members: - -physical_validation\.util\.plot module --------------------------------------- -.. automodule:: physical_validation.util.plot - :members: - :undoc-members: - -physical_validation\.util\.error module ---------------------------------------- -.. automodule:: physical_validation.util.error - :members: - :undoc-members: - -physical_validation\.util\.gromacs_interface module ---------------------------------------------------- -.. automodule:: physical_validation.util.gromacs_interface - :members: - :undoc-members: diff --git a/docs/_sources/userguide.rst.txt b/docs/_sources/userguide.rst.txt deleted file mode 100644 index ada06d7..0000000 --- a/docs/_sources/userguide.rst.txt +++ /dev/null @@ -1,522 +0,0 @@ -Introduction -============ - -Advances in recent years have made molecular dynamics (MD) simulations a -powerful tool in molecular-level research, allowing the prediction of -experimental observables in the study of systems such as proteins, drug -targets or membranes. The quality of any prediction based on MD results -targets or membranes. The quality of any prediction based on MD results -will, however, strongly depend on the validity of underlying physical -assumptions. - -This package is intended to help detecting (sometimes hard-to-spot) -unphysical behavior of simulations, which may have statistically important -influence on their results. It is part of a two-fold approach to -increase the robustness of molecular simulations. - -First, it empowers users of MD programs to test the physical validity on -their respective systems and setups. The tests range from simple -post-processing analysis to more involved tests requiring additional -simulations. These tests can significantly increase the -reliability of MD simulations by catching a number of common simulation -errors violating physical assumptions, such as non-conservative -integrators, deviations from the specified Boltzmann ensemble, or lack of ergodicity -between degrees of freedom. To make usage as easy as possible, -parsers for several popular MD program output formats are provided. - -Second, it can be integrated in MD code testing environments. While -unphysical behavior can be due to poor or incompatible choices of -parameters by the user, it can also originate in coding errors -within the program. Physical validation tests can be integrated in the -code-checking mechanism of MD software packages to facilitate the -detection of such bugs. The `physical-validation` package is currently -used in the automated code-testing facility of the GROMACS software -package, ensuring that every major releases passes a number of physical -sanity checks performed on selected representative systems before -shipping. - -.. note:: We are always looking to enlarge our set of tests. If you are a - MD user or developer and have suggestions for physical validity tests - missing in this package, we would love to hear from you! Please - consider getting in touch with us via our `github page`_. - - -Installation -============ - -The latest version is available at the `github page`_. Once you downloaded -or cloned the repository, simply type -:: - - python3 setup.py install - -while being in the root directory of the downloaded package. - - -`examples/` folder -================== - -The folder `examples/` contains examples (simulation results and analysis -scripts) which are used in the following to introduce the functionality of -the package. More specifically, the subfolders of `examples/` contain - -* Folder `water_ensemble/`: GROMACS result files of water systems simulated with - different thermostating and barostating algorithms. Specifically, the - subfolder `be/` contains NVT results obtained using a Berendsen thermostat, - the subfolder `vr/` contains NVT results obtained using the GROMACS v-rescale - thermostat, while the subfolders `be_pr/` and `vr_pr/` contain the corresponding - NPT results obtained by adding a Parinello-Rahman barostat to the systems. Each - system was simulated at two different state points (different temperatures, and - possibly pressures), stored in subfolders `base/` and `ensemble_1/` under the - respective system folders. Each of these folders then contain the following - files: - - - `start.gro`: the starting configuration, containing 900 three-site water molecules - - `system.top`: the topology of the system of water molecules - - `system.mdp`: the GROMACS input file - - `mdout.mdp`: the GROMACS input file obtained from `gmx grompp` - - `system.gro`: the end configuration - - `system.edr`: the resulting (binary) energy file - -* Folder `argon_integrator/`: GROMACS result files of argon systems simulated with - different van-der-Waals cutoff schemes. `none/` contains the results of - simulations performed with vdW interactions cut off at 1 nm without any - correction of the discontinuity at the cut-off distance. `shift/` contains - the results of simulations performed with vdW interactions cut off at 1 nm - and a potential shifted by a constant value such that it reaches zero at - the cut-off distance. `switch/` contains the results of simulations performed - with vdW interactions cut off at 1 nm where not only the potential, but also - the forces were altered in a way to have both the forces and the potential - smoothly reaching zero at the cut-off distance. For each choice of interaction - function, the same simulation was repeated five times, with each new simulation - halving the integration time step compared to the previous one. - - -Simulation data -=============== - -The data of simulations to be validated are best represented by objects -of the :class:`.SimulationData` type. While lower-level functions accepting -bare arrays and numbers are available, the :class:`.SimulationData` objects -combine ease-of-use and higher stability in form of input testing. - -The :class:`.SimulationData` objects are consisting of information about the -simulation and the system. This information is collected in objects of different -classes, namely - -* :obj:`.SimulationData.units` of type :class:`.UnitData`: - Information on the units used by the simulation program. -* :obj:`.SimulationData.ensemble` of type :class:`.EnsembleData`: - Information on the sampled ensemble. -* :obj:`.SimulationData.system` of type :class:`.SystemData`: - Information on the system (atoms, molecules, constraints, etc.). -* :obj:`.SimulationData.observables` of type :class:`.ObservableData`: - Trajectories of observables along the simulation. -* :obj:`.SimulationData.trajectory` of type :class:`.TrajectoryData`: - Position / velocity / force trajectories along the simulation. -* :obj:`.SimulationData.dt` of type `float`: - The time step at which the simulation was performed. - -The :class:`.SimulationData` objects can either be constructed -directly from arrays and numbers, or (partially) automatically via parsers. - -To facilitate the use of the physical validation suite, simulation results -generated by selected software packages can be automatically created by -:class:`.Parser` objects. The currently supported MD packages are: - -* GROMACS: :class:`.GromacsParser` - -Package-specific parsers are subclasses of :class:`.Parser`, and need to -redefine the :func:`.Parser.get_simulation_data` returning a -:class:`.SimulationData` object. - -For generic input, the flat file parser :class:`.FlatfileParser` allows to -create a :class:`.SimulationData` object from files containing trajectories -of observables and the positions and velocities of the atoms in the system. -It requires, however, to fill information on the units, the ensemble and the -system by hand. Furthermore, it is of course possible to fill all attributes -of :class:`.SimulationData` by hand, e.g. when starting from data stored -in python arrays rather than in files. - -Please see :ref:`doc_parsers` for more details on the :class:`.SimulationData` -type and the available parsers. - -.. note:: We are looking to enlarge the collection of parsers to make the - use of the package as convenient as possible for as many users as - possible. If your MD program of choice is not supported (yet), please - consider either writing your own parser and contribute it by creating - a pull request on the project's `github page`_, or contacting us to - let us know about your needs, and we can coordinate about introducing - the appropriate parser. - -.. _example_sec_1: - -Examples --------- -To illustrate the creation of SimulationData, we will look at the first part -of the analysis script `ana_water.py` located in the `examples/water_ensemble/` -folder. First, after some necessary import and definitions, the GROMACS -parser is created: -:: - - import physical_validation as pv - import os - - systems = ['vr', 'be', 'vr_pr', 'be_pr'] - - # change this to fit to your GROMACS installation - parser = pv.data.GromacsParser(exe='~/bin/gromacs/bin/gmx', - includepath='~/bin/gromacs/share/gromacs/top') - -Having the parser readily available, actually reading in the simulation data is a -one-line command that is easily included in a loop for the different systems -of interest: -:: - - for sys in systems: - print('### Analyzing system ' + sys) - print('## Reading lower temperature result') - dir_low = os.path.join(sys, 'base') - res_low = parser.get_simulation_data( - mdp=os.path.join(dir_low, 'mdout.mdp'), - top=os.path.join(dir_low, 'system.top'), - gro=os.path.join(dir_low, 'system.gro'), - edr=os.path.join(dir_low, 'system.edr') - ) - print('## Reading high temperature result') - dir_high = os.path.join(sys, 'ensemble_1') - res_high = parser.get_simulation_data( - mdp=os.path.join(dir_high, 'mdout.mdp'), - top=os.path.join(dir_high, 'system.top'), - gro=os.path.join(dir_high, 'system.gro'), - edr=os.path.join(dir_high, 'system.edr') - ) - - -Kinetic energy validation -========================= -Kinetic energy tests include testing the likelihood of a trajectory -originating from a Maxwell-Boltzmann distribution and validating the -temperature equipartition between groups of degrees of freedom. For -details on the employed algorithms, please check the respective -function documentations. - -Functions ---------- -*Maxwell-Boltzmann ensemble validation:* -:func:`physical_validation.kinetic_energy.mb_ensemble` - - -*Equipartition validation:* -:func:`physical_validation.kinetic_energy.equipartition` - -Examples --------- -With the data structures created in :ref:`example_sec_1` (`res_low` and -`res_high`), the kinetic energy ensemble of each simulated state point -can be validated as follows: -:: - - print('\n## Validating kinetic energy distribution (alpha = 0.05)') - alpha = 0.05 - print('# Low T:') - pv.kinetic_energy.mb_ensemble(res_low, alpha=alpha, verbose=True, - screen=False, filename=sysplot + '_low_mb') - print('# High T:') - pv.kinetic_energy.mb_ensemble(res_high, alpha=alpha, verbose=True, - screen=False, filename=sysplot + '_high_mb') - -This will plot the sampled distribution along with its analytical counterpart, -and print out the result of the analysis. For example for the NVT simulation -using the v-rescale algorithm (folder `vr/base`), the result will indicate -that under the chosen confidence (:math:`\alpha=0.05`), the null-hypothesis -that the energy is Maxwell-Boltzmann distributed stands: -:: - - Kolmogorov-Smirnov test result: p = 0.897073 - Null hypothesis: Kinetic energy is Maxwell-Boltzmann distributed - Confidence alpha = 0.050000 - Result: Hypothesis stands - -On the other hand, the NVT simulation using the Berendsen algorithm will show -a dramatically different picture: -:: - - Kolmogorov-Smirnov test result: p = 3.10225e-18 - Null hypothesis: Kinetic energy is Maxwell-Boltzmann distributed - Confidence alpha = 0.050000 - Result: Hypothesis rejected - -.. todo:: Equipartition example - -Ensemble validation -=================== -As the distribution of configurational quantities like the potential -energy :math:`U`, the volume :math:`V` or (for the grand and semigrand canonical ensembles) -the number of each species are in general not known analytically, testing the likelihood -of a trajectory sampling a given ensemble is less straightforward than -for the kinetic energy. However, generally, the ratio of the probability -distribution between samplings of the same ensemble at different state -points (e.g. at different temperatures, different pressures) is known -[Shirts2013]_. -Providing two simulations at different state points therefore allows a -validation of the sampled ensemble. - -Note that the ensemble validation function is automatically inferring the -correct test based on the simulation that are given as input. - -.. [Shirts2013] Shirts, M.R. - "Simple Quantitative Tests to Validate Sampling from Thermodynamic Ensembles", - J. Chem. Theory Comput., 2013, 9 (2), pp 909–926, - http://dx.doi.org/10.1021/ct300688p - -Functions ---------- -:func:`physical_validation.ensemble.check` - -Examples --------- -Still using the data structures created in :ref:`example_sec_1` (`res_low` and -`res_high`), the generated ensemble of the potential energy can now be validated, -to check whether a similar trend as for the kinetic energy can be observed. The -relevant line of code reads -:: - - print('\n## Validating ensemble') - quantiles = pv.ensemble.check(res_low, res_high, quiet=False, - screen=False, filename=sysplot + '_ensemble') - -The ensemble validation function used the two simulation results at lower and -higher state point to calculate the ratio of the energy distributions and -compare this ratio to the analytical expectation. As we have validated the -kinetic energy separately before, it makes sense to only use the potential -energy for this second validation (`total_energy=False`). The relevant result -from these calculations is the deviation from the analytical expectation, -reported in terms of the number of standard deviations (quantiles) the result -is off. The bootstrapped maximum-likelihood analysis of the NVT simulations -performed with the v-rescale thermostat reads -:: - - --------------------------------------------- - Maximum Likelihood Analysis (analytical error) - --------------------------------------------- - df = 467.57724 +/- 9.81112 - --------------------------------------------- - Estimated slope vs. True slope - --------------------------------------------- - 0.013141 +/- 0.000276 | 0.013091 - --------------------------------------------- - - (That's 0.18 quantiles from true slope=0.013091, FYI.) - - --------------------------------------------- - True dT = 10.000, Eff. dT = 10.039+/-0.211 - --------------------------------------------- - -This corresponds to a near-perfect agreement with the analytical expectation, -suggesting that the ensemble sampled by the potential energy is very close to -a canonical NVT ensemble. - -Performing the same analysis with the NVT simulations using the Berendsen -thermostat leads to a significantly different result: -:: - - --------------------------------------------- - Maximum Likelihood Analysis (analytical error) - --------------------------------------------- - df = 808.17863 +/- 19.48125 - --------------------------------------------- - Estimated slope vs. True slope - --------------------------------------------- - 0.022714 +/- 0.000548 | 0.013091 - --------------------------------------------- - - (That's 17.57 quantiles from true slope=0.013091, FYI.) - (Ouch!) - --------------------------------------------- - True dT = 10.000, Eff. dT = 17.351+/-0.418 - --------------------------------------------- - -This result indicates that using Berendsen thermostat does not only not -generate the proper distribution of the kinetic energy, but does also -effect the ratio of potential energy distribution at different -temperatures. - -There are three possible tests for NPT ensemble, each requiring -different simulations. If the two simulations were performed at -different temperatures, then the distribution of the instantaneous -enthalpy :math:`U + PV` is tested. If the two simulations were -performed at different pressures, then the distribution of :math:`V` -is tested. If simulations were performed at both different -temperatures and pressures, then test of the joint distribution of -:math:`U` and :math:`V` is performed. - -Note that for both the NVT and the NPT ensemble, the test involving -different temperatures can also be performed using the total energy -:math:`U + K` (NVT) or :math:`U + PV + K` (NPT). This option can be -enabled using the `total_energy = True` flag of the -:func:`physical_validation.ensemble.check` function, which is disabled -by default. As the kinetic energy can be checked separately (see above), -using the total energy will in general not give any additional insights -and might mask errors in the other energy terms. - -Support for grand and semigrand canonical ensembles, validating the -distribution of $N$ and $U$ or composition will be provided soon; in -the meantime, this functionality can still be found in the -checkensemble_ repository. - -Choice of the state points --------------------------- -As the ensemble tests presented above require two simulations at distinct -state points, the choice of interval between the two points becomes an -important question. Choosing two state points too far apart will result -in poor or zero overlap between the distributions, leading to very noisy -results (due to sample errors in the tails) or a breakdown of the method, -respectively. Choosing two state points very close to each others, on the -other hand, makes it difficult to distinguish the slope from statistical -error in the samples. - -A rule of thumb states [Shirts2013]_ that the maximal efficiency of the -method is reached when the distance between the peaks of the distributions -are roughly equal to the sum of their standard deviations. For most systems -with the exception of extremely small or very cold systems, it is reasonable -to assume that the difference in standard deviations between the state points -will be negligable. This leads to two ways of calculating the intervals: - -*Using calculated standard deviations*: Given a simulation at one state point, -the standard deviation of the distributions can be calculated numerically. The -suggested intervals are then given by - -* :math:`\Delta T = 2 k_B T^2 / \sigma_E`, where :math:`\sigma_E` is the standard - deviation of the energy distribution used in the test (potential energy, enthalpy, - or total energy). -* :math:`\Delta P = 2 k_B T / \sigma_V`, where :math:`\sigma_V` is the standard - deviation of the volume distribution. - -*Using physical observables*: The standard deviations can also be estimated using -physical observables such as the heat capacity and the compressibility. The -suggested intervals are then given by: - -* :math:`\Delta T = T (2 k_B / C_V)^{1/2}` (NVT), or - :math:`\Delta T = T (2 k_B / C_P)^{1/2}` (NPT), where :math:`C_V` and :math:`C_P` - denote the isochoric and the isobaric heat capacities, respectively. -* :math:`\Delta P = (2 k_B T / V \kappa_T)`, where :math:`\kappa_T` denotes the - isothermal compressibility. - -When setting `verbosity >= 1` in :func:`physical_validation.ensemble.check`, the -routine is printing an estimate for the optimal spacing based on the distributions -provided. Additionaly, :func:`physical_validation.ensemble.estimate_interval` -calculates the estimate given a single simulation result. This can be used to determine -at which state point a simulation should be repeated in order to efficiently check -its sampled ensemble. - -Integrator Validation -===================== -A symplectic integrator can be shown to conserve a constant of motion -(such as the energy in a microcanonical simulation) up to a fluctuation -that is quadratic in time step chosen. Comparing two or more -constant-of-motion trajectories realized using different time steps (but -otherwise unchanged simulation parameters) allows a check of the -symplecticity of the integration. Note that lack of symplecticity does not -necessarily imply an error in the integration algorithm, it can also hint -at physical violations in other parts of the model, such as non-continuous -potential functions, imprecise handling of constraints, etc. - -Functions ---------- -:func:`physical_validation.integrator.convergence` - -Examples --------- -To demonstrate the integration validation, we will use the results in -folder `argon_integrator`, and the corresponding analysis script -`ana_argon.py` located in that folder. As described above, this folder -contains the result of an argon system simulated with different cut-off -schemes of the van-der-Waals interactions, two of which include a -discontinuity of the forces (in subfolder `shift/`) or even -both the forces and the potential (in subfolder `none/`). These small -discontinuities are not unlike bugs that could be present in an interaction -calculation, and will therefore be used to demonstrate the use of the -integrator convergence validation to detect errors in MD codes. - -The first lines of the script `ana_argon.py` are very similar to the -previously discussed script `ana_water.py`, setting up the necessary -prerequisites and reading the results using the parser. The actual test -is then called as -:: - - pv.integrator.convergence(res, verbose=True, - filename=sysplot) - -where `res` is a list of :class:`.SimulationData` objects of identical -simulations performed at different integrator time steps. - -The final output of the script `ana_argon.py` reads -:: - - ### Analyzing system none - ## Reading results - ## Validating integrator convergence - ----------------------------------------------------------------- - dt avg rmsd slope ratio - dt^2 rmsd - ----------------------------------------------------------------- - 0.004 -4749.12 3.66e-01 2.86e-04 -- -- - 0.002 -4749.27 3.72e-01 2.77e-04 4.00 0.99 - 0.001 -4749.26 3.34e-01 3.47e-04 4.00 1.11 - 0.0005 -4749.23 3.37e-01 3.33e-04 4.00 0.99 - 0.00025 -4749.23 3.45e-01 2.54e-04 4.00 0.98 - ----------------------------------------------------------------- - - ### Analyzing system shift - ## Reading results - ## Validating integrator convergence - ----------------------------------------------------------------- - dt avg rmsd slope ratio - dt^2 rmsd - ----------------------------------------------------------------- - 0.004 -4491.08 1.63e-02 -1.76e-07 -- -- - 0.002 -4491.24 4.51e-03 -1.98e-06 4.00 3.62 - 0.001 -4491.24 1.36e-03 -2.55e-06 4.00 3.31 - 0.0005 -4491.21 2.83e-04 -2.46e-07 4.00 4.81 - 0.00025 -4491.19 1.20e-04 2.96e-07 4.00 2.35 - ----------------------------------------------------------------- - - ### Analyzing system switch - ## Reading results - ## Validating integrator convergence - ----------------------------------------------------------------- - dt avg rmsd slope ratio - dt^2 rmsd - ----------------------------------------------------------------- - 0.004 -4335.09 1.69e-02 5.54e-07 -- -- - 0.002 -4335.25 4.37e-03 -4.87e-07 4.00 3.87 - 0.001 -4335.24 1.09e-03 -3.81e-08 4.00 4.02 - 0.0005 -4335.22 2.77e-04 -2.67e-08 4.00 3.93 - 0.00025 -4335.20 6.90e-05 -9.41e-09 4.00 4.02 - ----------------------------------------------------------------- - -The outputs of the function are the time step, the average value of the -constant of motion, and its RMSD during the simulation. The fourth -column gives the measured slope of the constant of motion - a large -value here would indicate a strong drift and hence a problem in the -integrator. Even without strong drift, as in the current situation, a -large deviation in the ratio between the rmsd values compared to the -ratio between the time step will indicates some error in the integrator. -The reason for a failure of this test might not always be intuitively clear, -as many components play into the integrator convergence - the integrator -algorithm itself, but also the interaction function (e.g. non-continuous -cut-off) or the numerical precision of the floating point operations. - -In the examples presented here, the integrator convergence validation -shows a high sensibility towards the incontinuities describes above. In -the case with discontinuous potential and forces, the constant of motion -shows practically no dependence on the time step. But also with the -shifted (and hence continuous) potential, the large fluctuations around -the expected convergence indicate a problem in the calculation. Ensuring -continuity in the forces allows, on the other hand, to massively reduce -these fluctuations. - -.. _`github page`: https://github.com/shirtsgroup/physical-validation - -.. _checkensemble: https://github.com/shirtsgroup/checkensemble diff --git a/docs/_static/ajax-loader.gif b/docs/_static/ajax-loader.gif deleted file mode 100644 index 61faf8c..0000000 Binary files a/docs/_static/ajax-loader.gif and /dev/null differ diff --git a/docs/_static/basic.css b/docs/_static/basic.css deleted file mode 100644 index 3c7223b..0000000 --- a/docs/_static/basic.css +++ /dev/null @@ -1,643 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox input[type="text"] { - width: 170px; -} - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px 7px 0 7px; - background-color: #ffe; - width: 40%; - float: right; -} - -p.sidebar-title { - font-weight: bold; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px 7px 0 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -div.admonition dl { - margin-bottom: 0; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - border: 0; - border-collapse: collapse; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -dl { - margin-bottom: 15px; -} - -dd p { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -td.linenos pre { - padding: 5px 0px; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -div.code-block-caption { - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -div.code-block-caption + div > div.highlight > pre { - margin-top: 0; -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - padding: 1em 1em 0; -} - -div.literal-block-wrapper div.highlight { - margin: 0; -} - -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: relative; - left: 0px; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/_static/comment-bright.png b/docs/_static/comment-bright.png deleted file mode 100644 index 15e27ed..0000000 Binary files a/docs/_static/comment-bright.png and /dev/null differ diff --git a/docs/_static/comment-close.png b/docs/_static/comment-close.png deleted file mode 100644 index 4d91bcf..0000000 Binary files a/docs/_static/comment-close.png and /dev/null differ diff --git a/docs/_static/comment.png b/docs/_static/comment.png deleted file mode 100644 index dfbc0cb..0000000 Binary files a/docs/_static/comment.png and /dev/null differ diff --git a/docs/_static/css/badge_only.css b/docs/_static/css/badge_only.css deleted file mode 100644 index 6362912..0000000 --- a/docs/_static/css/badge_only.css +++ /dev/null @@ -1,2 +0,0 @@ -.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} -/*# sourceMappingURL=badge_only.css.map */ diff --git a/docs/_static/css/theme.css b/docs/_static/css/theme.css deleted file mode 100644 index c1631d8..0000000 --- a/docs/_static/css/theme.css +++ /dev/null @@ -1,5 +0,0 @@ -*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:0.2em 0;background:#ccc;color:#000;padding:0.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*! - * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.6.3");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.6.3") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.6.3") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.6.3") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:""}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-signing:before,.fa-sign-language:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:0.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:0.5;-webkit-transition:opacity 0.05s ease-in;-moz-transition:opacity 0.05s ease-in;transition:opacity 0.05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all 0.3s ease-in;-moz-transition:all 0.3s ease-in;transition:all 0.3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;transition:all 0.1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.35765%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:0.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}input[type="datetime-local"]{padding:.34375em .625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{width:36px;height:12px;margin:12px 0;position:relative;border-radius:4px;background:#ccc;cursor:pointer;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:before{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:after{content:"false";position:absolute;left:48px;display:block;font-size:12px;color:#ccc}.wy-switch.active{background:#1e8449}.wy-switch.active:before{left:24px;background:#27AE60}.wy-switch.active:after{content:"true"}.wy-switch.disabled,.wy-switch.active.disabled{cursor:not-allowed}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:0.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0.3em;display:block}.wy-form label{margin-bottom:0.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:0.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.codeblock-example{border:1px solid #e1e4e5;border-bottom:none;padding:24px;padding-top:48px;font-weight:500;background:#fff;position:relative}.codeblock-example:after{content:"Example";position:absolute;top:0px;left:0px;background:#9B59B6;color:#fff;padding:6px 12px}.codeblock-example.prettyprint-example-only{border:1px solid #e1e4e5;margin-bottom:24px}.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight']{border:1px solid #e1e4e5;padding:0px;overflow-x:auto;background:#fff;margin:1px 0 24px 0}.codeblock div[class^='highlight'],pre.literal-block div[class^='highlight'],.rst-content .literal-block div[class^='highlight'],div[class^='highlight'] div[class^='highlight']{border:none;background:none;margin:0}div[class^='highlight'] td.code{width:100%}.linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;color:#d9d9d9}div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;display:block;overflow:auto;color:#404040}@media print{.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight'],div[class^='highlight'] pre{white-space:pre-wrap}}.hll{background-color:#ffc;margin:0 -12px;padding:0 12px;display:block}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:bold}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:bold;font-style:italic}.gd{color:#000;background-color:#fdd}.gd .x{color:#000;background-color:#faa}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.gi .x{color:#000;background-color:#afa}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:purple;font-weight:bold}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#458;font-weight:bold}.m{color:#099}.s{color:#d14}.n{color:#333}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:bold}.no{color:teal}.ni{color:purple}.ne{color:#900;font-weight:bold}.nf{color:#900;font-weight:bold}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d14}.sc{color:#d14}.sd{color:#d14}.s2{color:#d14}.se{color:#d14}.sh{color:#d14}.si{color:#d14}.sx{color:#d14}.sr{color:#009926}.s1{color:#d14}.ss{color:#990073}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099}.gc{color:#999;background-color:#EAF2F5}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin-bottom:0;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;color:#555;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:0.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:0.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:0.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em;border-top:none;border-bottom:none}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:0.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical .local-toc li ul{display:block}.wy-menu-vertical li ul li a{margin-bottom:0;color:#b3b3b3;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#b3b3b3}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#b3b3b3}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980B9;text-align:center;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:0.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all 0.2s ease-in;-moz-transition:all 0.2s ease-in;transition:all 0.2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:left repeat-y #fcfcfc;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);background-size:300px 1px}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:#999}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:#999}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1400px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto !important}.rst-content .highlight>pre{line-height:normal}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .line-block{margin-left:24px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto;display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink{display:none;visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after{visibility:visible;content:"";font-family:FontAwesome;display:inline-block}.rst-content h1:hover .headerlink,.rst-content h2:hover .headerlink,.rst-content .toctree-wrapper p.caption:hover .headerlink,.rst-content h3:hover .headerlink,.rst-content h4:hover .headerlink,.rst-content h5:hover .headerlink,.rst-content h6:hover .headerlink,.rst-content dl dt:hover .headerlink,.rst-content p.caption:hover .headerlink{display:inline-block}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:super;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:#999}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none;padding-top:5px}.rst-content table.field-list td>strong{display:inline-block;margin-top:3px}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left;padding-left:0}.rst-content tt,.rst-content tt,.rst-content code{color:#000;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:inline-block;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:400;src:local("Inconsolata"),local("Inconsolata-Regular"),url(../fonts/Inconsolata-Regular.ttf) format("truetype")}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:700;src:local("Inconsolata Bold"),local("Inconsolata-Bold"),url(../fonts/Inconsolata-Bold.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:400;src:local("Lato Regular"),local("Lato-Regular"),url(../fonts/Lato-Regular.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:700;src:local("Lato Bold"),local("Lato-Bold"),url(../fonts/Lato-Bold.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:local("Roboto Slab Regular"),local("RobotoSlab-Regular"),url(../fonts/RobotoSlab-Regular.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:local("Roboto Slab Bold"),local("RobotoSlab-Bold"),url(../fonts/RobotoSlab-Bold.ttf) format("truetype")} -/*# sourceMappingURL=theme.css.map */ diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js deleted file mode 100644 index 24992e6..0000000 --- a/docs/_static/doctools.js +++ /dev/null @@ -1,311 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - */ -jQuery.urldecode = function(x) { - return decodeURIComponent(x).replace(/\+/g, ' '); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var bbox = span.getBBox(); - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - var parentOfText = node.parentNode.parentNode; - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated === 'undefined') - return string; - return (typeof translated === 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated === 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - }, - - initOnKeyListeners: function() { - $(document).keyup(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box or textarea - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); \ No newline at end of file diff --git a/docs/_static/down-pressed.png b/docs/_static/down-pressed.png deleted file mode 100644 index 5756c8c..0000000 Binary files a/docs/_static/down-pressed.png and /dev/null differ diff --git a/docs/_static/down.png b/docs/_static/down.png deleted file mode 100644 index 1b3bdad..0000000 Binary files a/docs/_static/down.png and /dev/null differ diff --git a/docs/_static/file.png b/docs/_static/file.png deleted file mode 100644 index a858a41..0000000 Binary files a/docs/_static/file.png and /dev/null differ diff --git a/docs/_static/fonts/Inconsolata-Bold.ttf b/docs/_static/fonts/Inconsolata-Bold.ttf deleted file mode 100644 index 809c1f5..0000000 Binary files a/docs/_static/fonts/Inconsolata-Bold.ttf and /dev/null differ diff --git a/docs/_static/fonts/Inconsolata-Regular.ttf b/docs/_static/fonts/Inconsolata-Regular.ttf deleted file mode 100644 index fc981ce..0000000 Binary files a/docs/_static/fonts/Inconsolata-Regular.ttf and /dev/null differ diff --git a/docs/_static/fonts/Lato-Bold.ttf b/docs/_static/fonts/Lato-Bold.ttf deleted file mode 100644 index 1d23c70..0000000 Binary files a/docs/_static/fonts/Lato-Bold.ttf and /dev/null differ diff --git a/docs/_static/fonts/Lato-Regular.ttf b/docs/_static/fonts/Lato-Regular.ttf deleted file mode 100644 index 0f3d0f8..0000000 Binary files a/docs/_static/fonts/Lato-Regular.ttf and /dev/null differ diff --git a/docs/_static/fonts/RobotoSlab-Bold.ttf b/docs/_static/fonts/RobotoSlab-Bold.ttf deleted file mode 100644 index df5d1df..0000000 Binary files a/docs/_static/fonts/RobotoSlab-Bold.ttf and /dev/null differ diff --git a/docs/_static/fonts/RobotoSlab-Regular.ttf b/docs/_static/fonts/RobotoSlab-Regular.ttf deleted file mode 100644 index eb52a79..0000000 Binary files a/docs/_static/fonts/RobotoSlab-Regular.ttf and /dev/null differ diff --git a/docs/_static/fonts/fontawesome-webfont.eot b/docs/_static/fonts/fontawesome-webfont.eot deleted file mode 100644 index c7b00d2..0000000 Binary files a/docs/_static/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/docs/_static/fonts/fontawesome-webfont.svg b/docs/_static/fonts/fontawesome-webfont.svg deleted file mode 100644 index 8b66187..0000000 --- a/docs/_static/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,685 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_static/fonts/fontawesome-webfont.ttf b/docs/_static/fonts/fontawesome-webfont.ttf deleted file mode 100644 index f221e50..0000000 Binary files a/docs/_static/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/docs/_static/fonts/fontawesome-webfont.woff b/docs/_static/fonts/fontawesome-webfont.woff deleted file mode 100644 index 6e7483c..0000000 Binary files a/docs/_static/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/docs/_static/jquery-3.1.0.js b/docs/_static/jquery-3.1.0.js deleted file mode 100644 index f2fc274..0000000 --- a/docs/_static/jquery-3.1.0.js +++ /dev/null @@ -1,10074 +0,0 @@ -/*eslint-disable no-unused-vars*/ -/*! - * jQuery JavaScript Library v3.1.0 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2016-07-07T21:44Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var document = window.document; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var concat = arr.concat; - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - - - - function DOMEval( code, doc ) { - doc = doc || document; - - var script = doc.createElement( "script" ); - - script.text = code; - doc.head.appendChild( script ).parentNode.removeChild( script ); - } -/* global Symbol */ -// Defining this global in .eslintrc would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.1.0", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num != null ? - - // Return just the one element from the set - ( num < 0 ? this[ num + this.length ] : this[ num ] ) : - - // Return all the elements in a clean array - slice.call( this ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = jQuery.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray( src ) ? src : []; - - } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isArray: Array.isArray, - - isWindow: function( obj ) { - return obj != null && obj === obj.window; - }, - - isNumeric: function( obj ) { - - // As of jQuery 3.0, isNumeric is limited to - // strings and numbers (primitives or objects) - // that can be coerced to finite numbers (gh-2662) - var type = jQuery.type( obj ); - return ( type === "number" || type === "string" ) && - - // parseFloat NaNs numeric-cast false positives ("") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - !isNaN( obj - parseFloat( obj ) ); - }, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); - }, - - // Convert dashed to camelCase; used by the css and data modules - // Support: IE <=9 - 11, Edge 12 - 13 - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: Date.now, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.0 - * https://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2016-01-04 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - disabledAncestor = addCombinator( - function( elem ) { - return elem.disabled === true; - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 - // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement("fieldset"); - - try { - return !!fn( el ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - // Known :disabled false positives: - // IE: *[disabled]:not(button, input, select, textarea, optgroup, option, menuitem, fieldset) - // not IE: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Check form elements and option elements for explicit disabling - return "label" in elem && elem.disabled === disabled || - "form" in elem && elem.disabled === disabled || - - // Check non-disabled form elements for fieldset[disabled] ancestors - "form" in elem && elem.disabled === false && ( - // Support: IE6-11+ - // Ancestry is covered for us - elem.isDisabled === disabled || - - // Otherwise, assume any non-