Beispiel #1
0
    def rotate(self, a, b, angle):
        """
        Unitary transformation of the discrete field.

        .. code-block:: Python

            newfield = uni.field.rotate(0, 1, np.pi / 2)  # returns an :class:`~exatomic.core.field.AtomicField`
            uni.add_field(newfield)                       # appends new fields to :class:`~exatomic.core.universe.Universe`

        Args:
            a (int): Index of first field
            b (int): Index of second field
            angle (float or list of floats): angle(s) of rotation (in radians)

        Return:
            rotated (:class:`~exatomic.field.AtomicField`): positive then negative linear combinations
        """
        field_params = self.loc[[a]]
        f0 = self.field_values[a]
        f1 = self.field_values[b]
        posvals, negvals = [], []
        try:
            angle = [float(angle)]
        except TypeError:
            pass
        for ang in angle:
            t1 = np.cos(ang) * f0
            t2 = np.sin(ang) * f1
            posvals.append(Series(t1 + t2))
            negvals.append(Series(t1 - t2))
        num = len(posvals) + len(negvals)
        field_params = pd.concat([field_params] * num)
        field_params.reset_index(drop=True, inplace=True)
        return AtomicField(field_params, field_values=posvals + negvals)
Beispiel #2
0
    def get_atom_labels(self):
        """
        Compute and return enumerated atoms.

        Returns:
            labels (:class:`~exa.core.numerical.Series`): Enumerated atom labels (of type int)
        """
        nats = self.cardinal_groupby().size().values
        labels = Series([i for nat in nats for i in range(nat)], dtype='category')
        labels.index = self.index
        return labels
Beispiel #3
0
    def get_atom_labels(self):
        """
        Compute and return enumerated atoms.

        Returns:
            labels (:class:`~exa.core.numerical.Series`): Enumerated atom labels (of type int)
        """
        nats = self.cardinal_groupby().size().values
        labels = Series([i for nat in nats for i in range(nat)],
                        dtype='category')
        labels.index = self.index
        return labels
Beispiel #4
0
 def _evaluate_sto(self, xs, ys, zs, irrep=None):
     """Evaluates a STO basis set and returns a numpy array."""
     cnt = 0
     if xs is not None: flds = np.empty((len(self), len(xs)))
     else: flds = Series([None for _ in range(len(self))])
     sphr = self._meta['spherical']
     for _, ax, ay, az, ishl in _iter_atom_shells(self._ptrs, self._xyzs,
                                                  *self._shells):
         norm = ishl.norm_contract()
         ang = ishl.enum_spherical() if sphr else ishl.enum_cartesian()
         for mag in ang:
             a = self._angular(ishl, ax, ay, az, *mag)
             if xs is not None: a = evaluate_expr(a, xs, ys, zs)
             for c in range(ishl.ncont):
                 pre = 1 if self._meta['spherical'] else self._pre[cnt]
                 r = self._radial(ax,
                                  ay,
                                  az,
                                  ishl.alphas,
                                  norm[:, c],
                                  rs=ishl.rs,
                                  pre=pre)
                 if xs is None: flds[cnt] = a * r
                 else: flds[cnt] = evaluate_expr(r, xs, ys, zs, arr=a)
                 cnt += 1
     return flds
Beispiel #5
0
 def _evaluate_gau_bso(self, xs, ys, zs, irrep=None):
     """Evaluates a Gaussian basis set according to the order specified
     by the :class:`~exatomic.core.basis.BasisSetOrder` and returns a
     numpy array of numerical basis function values."""
     cnt = 0
     if xs is not None: flds = np.empty((len(self), len(xs)))
     else: flds = Series([None for _ in range(len(self))])
     # cache remembers how many contracted functions are used
     # in each instance of Shell so we can access them out of order
     cache = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
     p = pd.DataFrame(self._ptrs, columns=('center', 'shelldx'))
     p['L'] = [self._shells[i].L for i in p['shelldx']]
     grps = p.groupby(['center', 'L'])
     # Just normalize each Shell once instead of on each access
     norms = [shl.norm_contract() for shl in self._shells]
     for cen, L, ml in zip(self._bso['center'], self._bso['L'],
                           self._bso['ml']):
         ax, ay, az = self._xyzs[cen]
         shldx = grps.get_group((cen, L))['shelldx'].values[0]
         ishl = self._shells[shldx]
         norm = norms[shldx]
         a = self._angular(ishl, ax, ay, az, L, ml)
         r = self._radial(ax, ay, az, ishl.alphas, norm[:,
                                                        cache[cen][L][ml]])
         if xs is None: flds[cnt] = a * r
         else: flds[cnt] = evaluate_expr(a * r, xs, ys, zs)
         cache[cen][L][ml] += 1
         cnt += 1
     return flds
Beispiel #6
0
 def _evaluate_gau_bso_sym(self, xs, ys, zs, irrep=None):
     """Evaluates a symmetrized Gaussian basis set and returns a numpy array.
     Currently the implementation only relies on the format most easily
     obtained from the Molcas basis set order format. It is possible that
     for other codes a different method would be preferred."""
     print("Warning: symmetrized basis set evaluation is pre-alpha.")
     cnt = 0
     # Slice the basis set order if irrep is provided
     bso = self._bso if irrep is None else \
         self._bso.groupby('irrep').get_group(irrep)
     nbf = len(bso.index)
     if xs is not None: flds = np.empty((nbf, len(xs)))
     else: flds = Series([None for _ in range(nbf)])
     # cache remembers how many contracted functions are used
     # in each instance of Shell so we can access them out of order
     # but since basis functions can span multiple irreps, must
     # outer index by irrep.
     cache = defaultdict(
         lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(int))))
     p = pd.DataFrame(self._ptrs, columns=('center', 'shldx'))
     p['L'] = [self._shells[i].L for i in p['shldx']]
     shls = p.groupby(['center', 'L'])
     norms = [shl.norm_contract() for shl in self._shells]
     ocens = [
         c for col in bso.columns if col.startswith('ocen')
         for c in (col, col.replace('ocen', 'sign'))
     ]
     for i, (cen, L, ml, irrep) in enumerate(
             zip(bso['center'], bso['L'], bso['ml'], bso['irrep'])):
         ax, ay, az = self._xyzs[cen]
         shldx = shls.get_group((cen, L)).shldx.values[0]
         ishl = self._shells[shldx]
         norm = norms[shldx]
         a = self._angular(ishl, ax, ay, az, L, ml)
         r = self._radial(ax, ay, az, ishl.alphas,
                          norm[:, cache[irrep][cen][L][ml]])
         oterm = None
         for oc, si in zip(ocens[::2], ocens[1::2]):
             ocen = bso[oc].iloc[i]
             sign = bso[si].iloc[i]
             if ocen >= 0:
                 ox, oy, oz = self._xyzs[ocen]
                 ao = self._angular(ishl, ox, oy, oz, L, ml)
                 ro = self._radial(ox, oy, oz, ishl.alphas,
                                   norm[:, cache[irrep][cen][L][ml]])
                 if oterm is None: oterm = sign * (ao * ro)
                 else: oterm += sign * (ao * ro)
         if oterm is not None:
             if xs is None: flds[cnt] = (a * r) + oterm
             else: flds[cnt] = evaluate_expr(a * r + oterm, xs, ys, zs)
         else:
             if xs is None: flds[cnt] = a * r
             else: flds[cnt] = evaluate_expr(a * r, xs, ys, zs)
         cache[irrep][cen][L][ml] += 1
         cnt += 1
     return flds
Beispiel #7
0
    def parse_field(self):
        """
        Parse the scalar field into an :class:`~exatomic.core.field.AtomicField`.

        Note:
            The :class:`~exatomic.core.field.AtomicField` tracks both the
            field parameters (i.e. information about the discretization and shape of
            the field's spatial points) as well as the field values (at each of
            those points in space). See :meth:`~exatomic.algorithms.orbital_util.make_fps`
            for more details.
        """
        self.meta = {'comments': self[:2]}
        typs = [int, float, float, float]
        nat, ox, oy, oz = [typ(i) for typ, i in zip(typs, self[2].split())]
        nx, dxi, dxj, dxk = [typ(i) for typ, i in zip(typs, self[3].split())]
        ny, dyi, dyj, dyk = [typ(i) for typ, i in zip(typs, self[4].split())]
        nz, dzi, dzj, dzk = [typ(i) for typ, i in zip(typs, self[5].split())]
        nat, nx, ny, nz = abs(nat), abs(nx), abs(ny), abs(nz)
        volstart = nat + 6
        if len(self[volstart].split()) < 5:
            if not len(self[volstart + 1].split()) < 5:
                volstart += 1
        ncol = len(self[volstart].split())
        data = self.pandas_dataframe(volstart, len(self), ncol).values.ravel()
        df = pd.Series({
            'ox': ox,
            'oy': oy,
            'oz': oz,
            'nx': nx,
            'ny': ny,
            'nz': nz,
            'dxi': dxi,
            'dxj': dxj,
            'dxk': dxk,
            'dyi': dyi,
            'dyj': dyj,
            'dyk': dyk,
            'dzi': dzi,
            'dzj': dzj,
            'dzk': dzk,
            'frame': 0,
            'label': self.label,
            'field_type': self.field_type
        }).to_frame().T
        for col in ['nx', 'ny', 'nz']:
            df[col] = df[col].astype(np.int64)
        for col in [
                'ox', 'oy', 'oz', 'dxi', 'dxj', 'dxk', 'dyi', 'dyj', 'dyk',
                'dzi', 'dzj', 'dzk'
        ]:
            df[col] = df[col].astype(np.float64)
        fields = [Series(data[~np.isnan(data)])]
        self.field = AtomicField(df, field_values=fields)
Beispiel #8
0
 def _evaluate_gau_mag(self, xs, ys, zs, irrep=None):
     """Evaluates a Gaussian basis set according to (apparently) only
     Molcas ordering and returns a numpy array."""
     cnt = 0
     if xs is not None: flds = np.empty((len(self), len(xs)))
     else: flds = Series([None for _ in range(len(self))])
     for _, ax, ay, az, ishl in _iter_atom_shells(self._ptrs, self._xyzs,
                                                  *self._shells):
         norm = ishl.norm_contract()
         for mag in self.enum_shell(ishl):
             a = self._angular(ishl, ax, ay, az, *mag)
             if xs is not None: a = evaluate_expr(a, xs, ys, zs)
             for c in range(ishl.ncont):
                 r = self._radial(ax, ay, az, ishl.alphas, norm[:, c])
                 if xs is None: flds[cnt] = a * r
                 else: flds[cnt] = evaluate_expr(r, xs, ys, zs, arr=a)
                 cnt += 1
     return flds