Source code for schrodinger.application.jaguar.scan

"""
Support functions and classes for Jaguar scans.

Copyright Schrodinger, LLC. All rights reserved.

"""

import math
import re
from past.utils import old_div

__cvs_version__ = "$Revision: 1.2 $"
_version = __cvs_version__


[docs]class Scan(object): """ A class for storing information about geometry scan variables. """ precision = 1.0e-3
[docs] def __init__(self, var_name, initial=None, final=None, steps=None, step_size=None, at_values=None): """ This constructor can be used for two different types of scans - regular and irregular. For regular scans, the 'initial' argument must be specified along with two out of the three arguments 'final,' 'steps,' or 'step_size.' For irregular scans, the only argument that should be specified is 'at_values.' Attributes var_name (str) The name of the variable the scan is based on. initial (float) The starting point for a scan. final (float) The final point for a scan. steps (float) The number of steps in the scan step_size (float) The step size of a regular scan. at_values (sequence of floats) Specific values at which a """ self.var_name = var_name self._initial = initial self._final = final self._steps = steps self._step_size = step_size self._at_values = at_values
def _getFinal(self): if self._final is not None: return self._final elif self._at_values: return self._at_values[-1] else: return self._initial + (self._steps - 1) * self._step_size final = property(_getFinal, doc="final scan value") def _getInitial(self): if self._initial is not None: return self._initial else: return self._at_values[0] initial = property(_getInitial, doc="initial scan value") def _getSteps(self): if self._steps is not None: return self._steps elif self._at_values: return len(self._at_values) else: return 1 + int( math.floor( old_div((self._final - self._initial), self._step_size))) steps = property(_getSteps, doc="number of steps in the scan") def _getStepSize(self): if self._step_size is not None: return self._step_size elif self._at_values: return None else: return old_div((self._final - self._initial), (self._steps - 1)) step_size = property(_getStepSize, doc="step size (None for 'at values' scans)") def _getAtValues(self): if self._at_values: return self._at_values else: return [] at_values = property( _getAtValues, doc="an array of the scan values for 'at values' scans") def __eq__(self, other): """ Equality comparison only looks at numeric quantities, not the variable name. """ if self.steps != other.steps: return False if abs(self.initial - other.initial) > self.precision: return False if abs(self.final - other.final) > self.precision: return False if abs(self.step_size - other.step_size) > self.precision: return False return True def __ne__(self, other): return not self.__eq__(other)
[docs] @staticmethod def parse(zvarstring): """ Parse a scan definition string and return a Scan object. """ # This is defined as a static method (as opposed to a module level # function) to allow it to be used when 'from scan import Scan' is # the import method. zvarsplit = zvarstring.split("=") if len(zvarsplit) == 2: zvarname, assignment = zvarsplit else: # The output files print 'ohlen at 1.11 1.12' without the equals # sign, so assume that a missing '=' is for this type of scan. zvarname, assignment = zvarstring.split(" ", 1) zvarname = zvarname.strip() scan = None # FROM ... TO ... BY match = re.match(r"\s*(from\s+)?(\S+)\s+to\s+(\S+)\s+by\s+(\S+)\s*", assignment, re.IGNORECASE) if match: scan = Scan(zvarname, initial=float(match.group(2)), final=float(match.group(3)), step_size=float(match.group(4))) # FROM ... TO ... IN if not scan: match = re.match(r"\s*(from\s+)?(\S+)\s+to\s+(\S+)\s+in\s+(\S+)\s*", assignment, re.IGNORECASE) if match: scan = Scan(zvarname, initial=float(match.group(2)), final=float(match.group(3)), steps=int(match.group(4))) # FROM ... BY ... IN if not scan: match = re.match(r"\s*(from\s+)?(\S+)\s+by\s+(\S+)\s+in\s+(\S+)\s*", assignment, re.IGNORECASE) if match: scan = Scan(zvarname, initial=float(match.group(2)), step_size=float(match.group(3)), steps=int(match.group(4))) # AT ... if not scan: match = re.match(r"\s*at\s+", assignment, re.IGNORECASE) if match: items = assignment.split() at_values = [float(item) for item in items[1:]] scan = Scan(zvarname, at_values=at_values) return scan