def __init__(self, items, key=None, num=None, step=None): if num is None and step is None: raise ValueError("Either num or step must be specified") from collections import defaultdict, OrderedDict values = [key(item) for item in items] if key is not None else items start, stop = min(values), max(values) if num is None: num = int((stop - start) / step) if num == 0: num = 1 mesh = np.linspace(start, stop, num, endpoint=False) from monty.bisect import find_le hist = defaultdict(list) for item, value in zip(items, values): # Find rightmost value less than or equal to x. # hence each bin contains all items whose value is >= value pos = find_le(mesh, value) hist[mesh[pos]].append(item) #new = OrderedDict([(pos, hist[pos]) for pos in sorted(hist.keys(), reverse=reverse)]) self.binvals = sorted(hist.keys()) self.values = [hist[pos] for pos in self.binvals] self.start, self.stop, self.num = start, stop, num
def test_funcs(self): l = [0, 1, 2, 3, 4] self.assertEqual(index(l, 1), 1) self.assertEqual(find_lt(l, 1), 0) self.assertEqual(find_gt(l, 1), 2) self.assertEqual(find_le(l, 1), 1) self.assertEqual(find_ge(l, 2), 2)
def build_scissors(self, domains, bounds=None, k=3, **kwargs): """ Construct a scissors operator by interpolating the QPState corrections as function of the initial energies E0. Args: domains: list in the form [ [start1, stop1], [start2, stop2] Domains should not overlap, cover e0mesh, and given in increasing order. Holes are permitted but the interpolation will raise an exception if the point is not in domains. bounds: Specify how to handle out-of-boundary conditions, i.e. how to treat energies that do not fall inside one of the domains (not used at present) ============== ============================================================== kwargs Meaning ============== ============================================================== plot If true, use `matplolib` to compare input data and fit. ============== ============================================================== Return: instance of :class:`Scissors`operator Usage example: .. code-block:: python # Build the scissors operator. scissors = qplist_spin[0].build_scissors(domains) # Compute list of interpolated QP energies. qp_enes = [scissors.apply(e0) for e0 in ks_energies] """ # Sort QP corrections according to the initial KS energy. qps = self.sort_by_e0() e0mesh, qpcorrs = qps.get_e0mesh(), qps.get_qpeme0() # Check domains. domains = np.atleast_2d(domains) dsize, dflat = domains.size, domains.ravel() for idx, v in enumerate(dflat): if idx == 0 and v > e0mesh[0]: raise ValueError("min(e0mesh) %s is not included in domains" % e0mesh[0]) if idx == dsize-1 and v < e0mesh[-1]: raise ValueError("max(e0mesh) %s is not included in domains" % e0mesh[-1]) if idx != dsize-1 and dflat[idx] > dflat[idx+1]: raise ValueError("domain boundaries should be given in increasing order.") if idx == dsize-1 and dflat[idx] < dflat[idx-1]: raise ValueError("domain boundaries should be given in increasing order.") # Create the sub_domains and the spline functions in each subdomain. func_list = [] residues = [] if len(domains) == 2: #print('forcing extrmal point on the scissor') ndom = 0 else: ndom = 99 for dom in domains[:]: ndom += 1 low, high = dom[0], dom[1] start, stop = find_ge(e0mesh, low), find_le(e0mesh, high) dom_e0 = e0mesh[start:stop+1] dom_corr = qpcorrs[start:stop+1] # todo check if the number of non degenerate data points > k from scipy.interpolate import UnivariateSpline w = len(dom_e0)*[1] if ndom == 1: w[-1] = 1000 elif ndom == 2: w[0] = 1000 else: w = None f = UnivariateSpline(dom_e0, dom_corr, w=w, bbox=[None, None], k=k, s=None) func_list.append(f) residues.append(f.get_residual()) # Build the scissors operator. sciss = Scissors(func_list, domains, residues, bounds) # Compare fit with input data. if kwargs.pop("plot", False): title = kwargs.pop("title", None) import matplotlib.pyplot as plt plt.plot(e0mesh, qpcorrs, 'o', label="input data") if title: plt.suptitle(title) for dom in domains[:]: plt.plot(2*[dom[0]], [min(qpcorrs), max(qpcorrs)]) plt.plot(2*[dom[1]], [min(qpcorrs), max(qpcorrs)]) intp_qpc = [sciss.apply(e0) for e0 in e0mesh] plt.plot(e0mesh, intp_qpc, label="scissor") plt.legend(bbox_to_anchor=(0.9, 0.2)) plt.show() # Return the object. return sciss
def build_scissors(self, domains, bounds=None, k=3, **kwargs): """ Construct a scissors operator by interpolating the QPState corrections as function of the initial energies E0. Args: domains: list in the form [ [start1, stop1], [start2, stop2] Domains should not overlap, cover e0mesh, and given in increasing order. Holes are permitted but the interpolation will raise an exception if the point is not in domains. bounds: Specify how to handle out-of-boundary conditions, i.e. how to treat energies that do not fall inside one of the domains (not used at present) ============== ============================================================== kwargs Meaning ============== ============================================================== plot If true, use `matplolib` to compare input data and fit. ============== ============================================================== Return: instance of :class:`Scissors`operator Usage example: .. code-block:: python # Build the scissors operator. scissors = qplist_spin[0].build_scissors(domains) # Compute list of interpolated QP energies. qp_enes = [scissors.apply(e0) for e0 in ks_energies] """ # Sort QP corrections according to the initial KS energy. qps = self.sort_by_e0() e0mesh, qpcorrs = qps.get_e0mesh(), qps.get_qpeme0() # Check domains. domains = np.atleast_2d(domains) dsize, dflat = domains.size, domains.ravel() for idx, v in enumerate(dflat): if idx == 0 and v > e0mesh[0]: raise ValueError("min(e0mesh) %s is not included in domains" % e0mesh[0]) if idx == dsize-1 and v < e0mesh[-1]: raise ValueError("max(e0mesh) %s is not included in domains" % e0mesh[-1]) if idx != dsize-1 and dflat[idx] > dflat[idx+1]: raise ValueError("domain boundaries should be given in increasing order.") if idx == dsize-1 and dflat[idx] < dflat[idx-1]: raise ValueError("domain boundaries should be given in increasing order.") # Create the sub_domains and the spline functions in each subdomain. func_list = [] residues = [] for dom in domains[:]: low, high = dom[0], dom[1] start, stop = find_ge(e0mesh, low), find_le(e0mesh, high) dom_e0 = e0mesh[start:stop+1] dom_corr = qpcorrs[start:stop+1].real # todo check if the number of non degenerate data points > k from scipy.interpolate import UnivariateSpline f = UnivariateSpline(dom_e0, dom_corr, w=None, bbox=[None, None], k=k, s=None) func_list.append(f) residues.append(f.get_residual()) # Build the scissors operator. sciss = Scissors(func_list, domains, residues, bounds) # Compare fit with input data. if kwargs.pop("plot", False): title = kwargs.pop("title", None) import matplotlib.pyplot as plt plt.plot(e0mesh, qpcorrs, 'o', label="input data") if title: plt.suptitle(title) for dom in domains[:]: plt.plot(2*[dom[0]], [min(qpcorrs), max(qpcorrs)]) plt.plot(2*[dom[1]], [min(qpcorrs), max(qpcorrs)]) intp_qpc = [sciss.apply(e0) for e0 in e0mesh] plt.plot(e0mesh, intp_qpc, label="scissor") plt.legend(bbox_to_anchor=(0.9, 0.2)) plt.show() # Return the object. return sciss