Source code for basis.potential
"""Defines a class and methods for evaluating 1D quantum potentials.
"""
import numpy as np
from basis import msg
[docs]class Potential(object):
"""Represnts a 1D quantum potential.
Args:
potcfg (str): path to the potential configuration file.
Attributes:
filepath (str): absolute path to the file that this potential
represents.
params (dict): keys are parameter names; values are
python-evaluated objects.
regions (dict): keys are a tuple ('float', 'float') that specify the
start and end the region; values are either functions or variables
to define the potential's value in that region.
parser (ConfigParser): parses the potential configuration
file.
Examples:
>>> from basis.potential import Potential
>>> import numpy as np
>>> x = np.linspace(-2,2,100)
>>> pot = Potential("sho.cfg")
>>> V = pot(x)
"""
def __init__(self, potcfg):
from os import path
self.filepath = path.abspath(path.expanduser(potcfg))
self.params = {}
self.regions = {}
self.parser = None
self._parse_config()
def __getattr__(self,attr):
if attr in self.params:
return self.params[attr]
else:
emsg = "{} is not an attribute of Potential objects."
raise AttributeError(emsg.format(attr))
def __call__(self, value):
"""Evaluates te potential for the given value(s).
Args:
value (numpy.ndarray or float): where to evaluate.
Returns:
numpy.ndarray or float: potential evaluated at `value`.
Raises:
ValueError: if the argument is not an `int` of `float`.
"""
if isinstance(value, list) or isinstance(value, np.ndarray):
return np.array(list(map(self, value)))
if not isinstance(value, (int,float)):
raise ValueError("Only `int` and `float` values con be "
"evaluated by the potential.")
for xi, xf in self.regions:
if value >= xi and value < xf:
function = self.regions[(xi, xf)]
if hasattr(function, "__call__"):
return function(value)
else:
return function
else:
return 0.
def _parse_params(self):
"""Extracts the potential parameters from the specified config
parser.
"""
if self.parser.has_section("parameters"):
for param, sval in self.parser.items("parameters"):
self.params[param] = eval(sval)
def _parse_regions(self):
"""Parses the potential configuration file to initialize the
parameters and function call.
"""
if not self.parser.has_section("regions"):
raise ValueError("[regions] is required to define a "
"potential.")
self.regions = {}
for i, spec in self.parser.items("regions"):
domain, sfunc = spec.split('|')
if "numpy" in sfunc:
import numpy as np
self.params["numpy"] = np
if "operator" in sfunc:
import operator
self.params["operator"] = operator
xi, xf = eval(domain, self.params)
function = eval(sfunc, self.params)
self.regions[(xi, xf)] = function
def _parse_config(self):
"""Parses the potential configuration file to initialize the
parameters and function call.
"""
try: # pragma: no cover
from ConfigParser import ConfigParser
except ImportError: # pragma: no cover
from configparser import ConfigParser
self.parser = ConfigParser()
with open(self.filepath) as f:
self.parser.readfp(f)
self._parse_params()
self._parse_regions()
[docs] def adjust_potential(self, **kwargs):
"""Adjusts the parameters of the potential.
Args:
kwargs (dict): parameters and values to overwrite.
"""
for k, v in kwargs.items():
if k in self.params:
self.params[k] = v
else:
wmsg = "'{}' is nat a valid parameter for '{}',"
msg.warn(wmsg.format(k,self.filepath))
self._parse_regions()