Beispiel #1
0
    def _init_derived_bonds(self):
        # 1-bond neighbors
        self.neighs1 = dict((i,set([])) for i in xrange(self.natom))
        for i0, i1 in self.bonds:
            self.neighs1[i0].add(i1)
            self.neighs1[i1].add(i0)
        # 2-bond neighbors
        self.neighs2 = dict((i,set([])) for i in xrange(self.natom))
        for i0, n0 in self.neighs1.iteritems():
            for i1 in n0:
                for i2 in self.neighs1[i1]:
                    # Require that there are no shorter paths than two bonds between
                    # i0 and i2. Also avoid duplicates.
                    if i2 > i0 and i2 not in self.neighs1[i0]:
                        self.neighs2[i0].add(i2)
                        self.neighs2[i2].add(i0)
        # 3-bond neighbors
        self.neighs3 = dict((i,set([])) for i in xrange(self.natom))
        for i0, n0 in self.neighs1.iteritems():
            for i1 in n0:
                for i3 in self.neighs2[i1]:
                    # Require that there are no shorter paths than three bonds
                    # between i0 and i3. Also avoid duplicates.
                    if i3 != i0 and i3 not in self.neighs1[i0] and i3 not in self.neighs2[i0]:
                        self.neighs3[i0].add(i3)
                        self.neighs3[i3].add(i0)
        # report some basic stuff on screen
        if log.do_medium:
            log('Analysis of the bonds:')
            bond_types = {}
            for i0, i1 in self.bonds:
                key = tuple(sorted([self.numbers[i0], self.numbers[i1]]))
                bond_types[key] = bond_types.get(key, 0) + 1
            log.hline()
            log(' First   Second   Count')
            for (num0, num1), count in sorted(bond_types.iteritems()):
                log('%6i   %6i   %5i' % (num0, num1, count))
            log.hline()
            log.blank()

            log('Analysis of the neighbors:')
            log.hline()
            log('Number of first neighbors:  %6i' % (sum(len(n) for n in self.neighs1.itervalues())/2))
            log('Number of second neighbors: %6i' % (sum(len(n) for n in self.neighs2.itervalues())/2))
            log('Number of third neighbors:  %6i' % (sum(len(n) for n in self.neighs3.itervalues())/2))
            # Collect all types of 'environments' for each element. This is
            # useful to double check the bonds
            envs = {}
            for i0 in xrange(self.natom):
                num0 = self.numbers[i0]
                nnums = tuple(sorted(self.numbers[i1] for i1 in self.neighs1[i0]))
                key = (num0, nnums)
                envs[key] = envs.get(key, 0)+1
            # Print the environments on screen
            log.hline()
            log('Element   Neighboring elements   Count')
            for (num0, nnums), count in sorted(envs.iteritems()):
                log('%7i   %20s   %5i' % (num0, ','.join(str(num1) for num1 in nnums), count))
            log.hline()
            log.blank()
Beispiel #2
0
 def _init_derived_scopes(self):
     if self.scope_ids is None:
         if len(self.scopes) != self.natom:
             raise TypeError('When the scope_ids are derived automatically, the length of the scopes list must match the number of atoms.')
         lookup = {}
         scopes = []
         self.scope_ids = np.zeros(self.natom, int)
         for i in xrange(self.natom):
             scope = self.scopes[i]
             scope_id = lookup.get(scope)
             if scope_id is None:
                 scope_id = len(scopes)
                 scopes.append(scope)
                 lookup[scope] = scope_id
             self.scope_ids[i] = scope_id
         self.scopes = scopes
     for scope in self.scopes:
         check_name(scope)
     # check the range of the ids
     if self.scope_ids.min() != 0 or self.scope_ids.max() != len(self.scopes)-1:
         raise ValueError('The ffatype_ids have incorrect bounds.')
     if log.do_medium:
         log('The following scopes are present in the system:')
         log.hline()
         log('                 Scope   ID   Number of atoms')
         log.hline()
         for scope_id, scope in enumerate(self.scopes):
             log('%22s  %3i       %3i' % (scope, scope_id, (self.scope_ids==scope_id).sum()))
         log.hline()
         log.blank()
Beispiel #3
0
 def _init_derived_scopes(self):
     if self.scope_ids is None:
         if len(self.scopes) != self.natom:
             raise TypeError(
                 'When the scope_ids are derived automatically, the length of the scopes list must match the number of atoms.'
             )
         lookup = {}
         scopes = []
         self.scope_ids = np.zeros(self.natom, int)
         for i in range(self.natom):
             scope = self.scopes[i]
             scope_id = lookup.get(scope)
             if scope_id is None:
                 scope_id = len(scopes)
                 scopes.append(scope)
                 lookup[scope] = scope_id
             self.scope_ids[i] = scope_id
         self.scopes = scopes
     for scope in self.scopes:
         check_name(scope)
     # check the range of the ids
     if self.scope_ids.min() != 0 or self.scope_ids.max() != len(
             self.scopes) - 1:
         raise ValueError('The ffatype_ids have incorrect bounds.')
     if log.do_medium:
         log('The following scopes are present in the system:')
         log.hline()
         log('                 Scope   ID   Number of atoms')
         log.hline()
         for scope_id, scope in enumerate(self.scopes):
             log('%22s  %3i       %3i' %
                 (scope, scope_id, (self.scope_ids == scope_id).sum()))
         log.hline()
         log.blank()
Beispiel #4
0
 def _init_log(self):
     if log.do_medium:
         log('Unit cell')
         log.hline()
         log('Number of periodic dimensions: %i' % self.cell.nvec)
         lengths, angles = self.cell.parameters
         names = 'abc'
         for i in xrange(len(lengths)):
             log('Cell parameter %5s: %10s' % (names[i], log.length(lengths[i])))
         names = 'alpha', 'beta', 'gamma'
         for i in xrange(len(angles)):
             log('Cell parameter %5s: %10s' % (names[i], log.angle(angles[i])))
         log.hline()
         log.blank()
Beispiel #5
0
 def _init_log(self):
     if log.do_medium:
         log('Unit cell')
         log.hline()
         log('Number of periodic dimensions: %i' % self.cell.nvec)
         lengths, angles = self.cell.parameters
         names = 'abc'
         for i in range(len(lengths)):
             log('Cell parameter %5s: %10s' % (names[i], log.length(lengths[i])))
         names = 'alpha', 'beta', 'gamma'
         for i in range(len(angles)):
             log('Cell parameter %5s: %10s' % (names[i], log.angle(angles[i])))
         log.hline()
         log.blank()
Beispiel #6
0
 def _init_derived_ffatypes(self):
     if self.ffatype_ids is None:
         if len(self.ffatypes) != self.natom:
             raise TypeError('When the ffatype_ids are derived automatically, the length of the ffatypes list must match the number of atoms.')
         lookup = {}
         ffatypes = []
         self.ffatype_ids = np.zeros(self.natom, int)
         for i in xrange(self.natom):
             if self.scope_ids is None:
                 ffatype = self.ffatypes[i]
                 key = ffatype, None
             else:
                 scope_id = self.scope_ids[i]
                 ffatype = self.ffatypes[i]
                 key = ffatype, scope_id
             ffatype_id = lookup.get(key)
             if ffatype_id is None:
                 ffatype_id = len(ffatypes)
                 ffatypes.append(ffatype)
                 lookup[key] = ffatype_id
             self.ffatype_ids[i] = ffatype_id
         self.ffatypes = ffatypes
     for ffatype in self.ffatypes:
         check_name(ffatype)
     # check the range of the ids
     if self.ffatype_ids.min() != 0 or self.ffatype_ids.max() != len(self.ffatypes)-1:
         raise ValueError('The ffatype_ids have incorrect bounds.')
     # differentiate ffatype_ids if the same ffatype_id is used in different
     # scopes
     if self.scopes is not None:
         self.ffatype_id_to_scope_id = {}
         fixed_fids = {}
         for i in xrange(self.natom):
             fid = self.ffatype_ids[i]
             sid = self.ffatype_id_to_scope_id.get(fid)
             if sid is None:
                 self.ffatype_id_to_scope_id[fid] = self.scope_ids[i]
             elif sid != self.scope_ids[i]:
                 # We found the same ffatype_id in a different scope_id. This
                 # must be fixed. First check if we have already a new
                 # scope_id ready
                 sid = self.scope_ids[i]
                 new_fid = fixed_fids.get((sid, fid))
                 if new_fid is None:
                     # No previous new fid create, do it now.
                     new_fid = len(self.ffatypes)
                     # Copy the ffatype label
                     self.ffatypes.append(self.ffatypes[fid])
                     # Keep track of the new fid
                     fixed_fids[(sid, fid)] = new_fid
                     if log.do_warning:
                         log.warn('Atoms with type ID %i in scope %s were changed to type ID %i.' % (fid, self.scopes[sid], new_fid))
                 # Apply the new fid
                 self.ffatype_ids[i] = new_fid
                 self.ffatype_id_to_scope_id[new_fid] = sid
     # Turn the ffatypes in the scopes into array
     if self.ffatypes is not None:
         self.ffatypes = np.array(self.ffatypes, copy=False)
     if self.scopes is not None:
         self.scopes = np.array(self.scopes, copy=False)
     # check the range of the ids
     if self.ffatype_ids.min() != 0 or self.ffatype_ids.max() != len(self.ffatypes)-1:
         raise ValueError('The ffatype_ids have incorrect bounds.')
     if log.do_medium:
         log('The following atom types are present in the system:')
         log.hline()
         if self.scopes is None:
             log('             Atom type   ID   Number of atoms')
             log.hline()
             for ffatype_id, ffatype in enumerate(self.ffatypes):
                 log('%22s  %3i       %3i' % (ffatype, ffatype_id, (self.ffatype_ids==ffatype_id).sum()))
         else:
             log('                 Scope              Atom type   ID   Number of atoms')
             log.hline()
             for ffatype_id, ffatype in enumerate(self.ffatypes):
                 scope = self.scopes[self.ffatype_id_to_scope_id[ffatype_id]]
                 log('%22s %22s  %3i       %3i' % (scope, ffatype, ffatype_id, (self.ffatype_ids==ffatype_id).sum()))
         log.hline()
         log.blank()
Beispiel #7
0
    def check_mic(self, system):
        '''Check if each scale2 and scale3 are uniquely defined.

           **Arguments:**

           system
                An instance of the system class, i.e. the one that is used to
                create this scaling object.

           This check is done by constructing for each scaled pair, all possible
           bond paths between the two atoms. For each path, the bond vectors
           (after applying the minimum image convention) are added. If for a
           given pair, these sums of bond vectors differ between all possible
           paths, the differences are expanded in cell vectors which can be used
           to construct a proper supercell in which scale2 and scale3 pairs are
           all uniquely defined.
        '''
        if system.cell.nvec == 0:
            return
        troubles = False
        with log.section('SCALING'):
            for i0, i1, scale, nbond in self.stab:
                if nbond == 1:
                    continue
                all_deltas = []
                paths = []
                for path in iter_paths(system, i0, i1, nbond):
                    delta_total = 0
                    for j0 in range(nbond):
                        j1 = j0 + 1
                        delta = system.pos[path[j0]] - system.pos[path[j1]]
                        system.cell.mic(delta)
                        delta_total += delta
                    all_deltas.append(delta_total)
                    paths.append(path)
                all_deltas = np.array(all_deltas)
                if abs(all_deltas.mean(axis=0) - all_deltas).max() > 1e-10:
                    troubles = True
                    if log.do_warning:
                        log.warn('Troublesome pair scaling detected.')
                    log('The following bond paths connect the same pair of '
                        'atoms, yet the relative vectors are different.')
                    for ipath in range(len(paths)):
                        log('%2i %27s %10s %10s %10s' % (
                            ipath,
                            ','.join(str(index) for index in paths[ipath]),
                            log.length(all_deltas[ipath, 0]),
                            log.length(all_deltas[ipath, 1]),
                            log.length(all_deltas[ipath, 2]),
                        ))
                    log('Differences between relative vectors in fractional '
                        'coordinates:')
                    for ipath0 in range(1, len(paths)):
                        for ipath1 in range(ipath0):
                            diff = all_deltas[ipath0] - all_deltas[ipath1]
                            diff_frac = np.dot(system.cell.gvecs, diff)
                            log('%2i %2i %10.4f %10.4f %10.4f' %
                                (ipath0, ipath1, diff_frac[0], diff_frac[1],
                                 diff_frac[2]))
                    log.blank()
        if troubles:
            raise AssertionError(
                'Due to the small spacing between some crystal planes, the scaling of non-bonding interactions will not work properly. Use a supercell to avoid this problem.'
            )
Beispiel #8
0
    def check_mic(self, system):
        '''Check if each scale2 and scale3 are uniquely defined.

           **Arguments:**

           system
                An instance of the system class, i.e. the one that is used to
                create this scaling object.

           This check is done by constructing for each scaled pair, all possible
           bond paths between the two atoms. For each path, the bond vectors
           (after applying the minimum image convention) are added. If for a
           given pair, these sums of bond vectors differ between all possible
           paths, the differences are expanded in cell vectors which can be used
           to construct a proper supercell in which scale2 and scale3 pairs are
           all uniquely defined.
        '''
        if system.cell.nvec == 0:
            return
        troubles = False
        with log.section('SCALING'):
            for i0, i1, scale, nbond in self.stab:
                if nbond == 1:
                    continue
                all_deltas = []
                paths = []
                for path in iter_paths(system, i0, i1, nbond):
                    delta_total = 0
                    for j0 in xrange(nbond):
                        j1 = j0 + 1
                        delta = system.pos[path[j0]] - system.pos[path[j1]]
                        system.cell.mic(delta)
                        delta_total += delta
                    all_deltas.append(delta_total)
                    paths.append(path)
                all_deltas = np.array(all_deltas)
                if abs(all_deltas.mean(axis=0) - all_deltas).max() > 1e-10:
                    troubles = True
                    if log.do_warning:
                        log.warn('Troublesome pair scaling detected.')
                    log('The following bond paths connect the same pair of '
                        'atoms, yet the relative vectors are different.')
                    for ipath in xrange(len(paths)):
                        log('%2i %27s %10s %10s %10s' % (
                            ipath,
                            ','.join(str(index) for index in paths[ipath]),
                            log.length(all_deltas[ipath,0]),
                            log.length(all_deltas[ipath,1]),
                            log.length(all_deltas[ipath,2]),
                        ))
                    log('Differences between relative vectors in fractional '
                        'coordinates:')
                    for ipath0 in xrange(1, len(paths)):
                        for ipath1 in xrange(ipath0):
                            diff = all_deltas[ipath0] - all_deltas[ipath1]
                            diff_frac = np.dot(system.cell.gvecs, diff)
                            log('%2i %2i %10.4f %10.4f %10.4f' % (
                                ipath0, ipath1,
                                diff_frac[0], diff_frac[1], diff_frac[2]
                            ))
                    log.blank()
        if troubles:
            raise AssertionError('Due to the small spacing between some crystal planes, the scaling of non-bonding interactions will not work properly. Use a supercell to avoid this problem.')
Beispiel #9
0
 def _init_derived_ffatypes(self):
     if self.ffatype_ids is None:
         if len(self.ffatypes) != self.natom:
             raise TypeError(
                 'When the ffatype_ids are derived automatically, the length of the ffatypes list must match the number of atoms.'
             )
         lookup = {}
         ffatypes = []
         self.ffatype_ids = np.zeros(self.natom, int)
         for i in range(self.natom):
             if self.scope_ids is None:
                 ffatype = self.ffatypes[i]
                 key = ffatype, None
             else:
                 scope_id = self.scope_ids[i]
                 ffatype = self.ffatypes[i]
                 key = ffatype, scope_id
             ffatype_id = lookup.get(key)
             if ffatype_id is None:
                 ffatype_id = len(ffatypes)
                 ffatypes.append(ffatype)
                 lookup[key] = ffatype_id
             self.ffatype_ids[i] = ffatype_id
         self.ffatypes = ffatypes
     for ffatype in self.ffatypes:
         check_name(ffatype)
     # check the range of the ids
     if self.ffatype_ids.min() != 0 or self.ffatype_ids.max() != len(
             self.ffatypes) - 1:
         raise ValueError('The ffatype_ids have incorrect bounds.')
     # differentiate ffatype_ids if the same ffatype_id is used in different
     # scopes
     if self.scopes is not None:
         self.ffatype_id_to_scope_id = {}
         fixed_fids = {}
         for i in range(self.natom):
             fid = self.ffatype_ids[i]
             sid = self.ffatype_id_to_scope_id.get(fid)
             if sid is None:
                 self.ffatype_id_to_scope_id[fid] = self.scope_ids[i]
             elif sid != self.scope_ids[i]:
                 # We found the same ffatype_id in a different scope_id. This
                 # must be fixed. First check if we have already a new
                 # scope_id ready
                 sid = self.scope_ids[i]
                 new_fid = fixed_fids.get((sid, fid))
                 if new_fid is None:
                     # No previous new fid create, do it now.
                     new_fid = len(self.ffatypes)
                     # Copy the ffatype label
                     self.ffatypes.append(self.ffatypes[fid])
                     # Keep track of the new fid
                     fixed_fids[(sid, fid)] = new_fid
                     if log.do_warning:
                         log.warn(
                             'Atoms with type ID %i in scope %s were changed to type ID %i.'
                             % (fid, self.scopes[sid], new_fid))
                 # Apply the new fid
                 self.ffatype_ids[i] = new_fid
                 self.ffatype_id_to_scope_id[new_fid] = sid
     # Turn the ffatypes in the scopes into array
     if self.ffatypes is not None:
         self.ffatypes = np.array(self.ffatypes, copy=False)
     if self.scopes is not None:
         self.scopes = np.array(self.scopes, copy=False)
     # check the range of the ids
     if self.ffatype_ids.min() != 0 or self.ffatype_ids.max() != len(
             self.ffatypes) - 1:
         raise ValueError('The ffatype_ids have incorrect bounds.')
     if log.do_medium:
         log('The following atom types are present in the system:')
         log.hline()
         if self.scopes is None:
             log('             Atom type   ID   Number of atoms')
             log.hline()
             for ffatype_id, ffatype in enumerate(self.ffatypes):
                 log('%22s  %3i       %3i' %
                     (ffatype, ffatype_id,
                      (self.ffatype_ids == ffatype_id).sum()))
         else:
             log('                 Scope              Atom type   ID   Number of atoms'
                 )
             log.hline()
             for ffatype_id, ffatype in enumerate(self.ffatypes):
                 scope = self.scopes[
                     self.ffatype_id_to_scope_id[ffatype_id]]
                 log('%22s %22s  %3i       %3i' %
                     (scope, ffatype, ffatype_id,
                      (self.ffatype_ids == ffatype_id).sum()))
         log.hline()
         log.blank()
Beispiel #10
0
    def _init_derived_bonds(self):
        # 1-bond neighbors
        self.neighs1 = dict((i, set([])) for i in range(self.natom))
        for i0, i1 in self.bonds:
            self.neighs1[i0].add(i1)
            self.neighs1[i1].add(i0)
        # 2-bond neighbors
        self.neighs2 = dict((i, set([])) for i in range(self.natom))
        for i0, n0 in self.neighs1.items():
            for i1 in n0:
                for i2 in self.neighs1[i1]:
                    # Require that there are no shorter paths than two bonds between
                    # i0 and i2. Also avoid duplicates.
                    if i2 > i0 and i2 not in self.neighs1[i0]:
                        self.neighs2[i0].add(i2)
                        self.neighs2[i2].add(i0)
        # 3-bond neighbors
        self.neighs3 = dict((i, set([])) for i in range(self.natom))
        for i0, n0 in self.neighs1.items():
            for i1 in n0:
                for i3 in self.neighs2[i1]:
                    # Require that there are no shorter paths than three bonds
                    # between i0 and i3. Also avoid duplicates.
                    if i3 != i0 and i3 not in self.neighs1[
                            i0] and i3 not in self.neighs2[i0]:
                        self.neighs3[i0].add(i3)
                        self.neighs3[i3].add(i0)
        # 4-bond neighbors
        self.neighs4 = dict((i, set([])) for i in range(self.natom))
        for i0, n0 in self.neighs1.items():
            for i1 in n0:
                for i4 in self.neighs3[i1]:
                    # Require that there are no shorter paths than three bonds
                    # between i0 and i4. Also avoid duplicates.
                    if i4 != i0 and i4 not in self.neighs1[
                            i0] and i4 not in self.neighs2[
                                i0] and i4 not in self.neighs3[i0]:
                        self.neighs4[i0].add(i4)
                        self.neighs4[i4].add(i0)
        # report some basic stuff on screen
        if log.do_medium:
            log('Analysis of the bonds:')
            bond_types = {}
            for i0, i1 in self.bonds:
                key = tuple(sorted([self.numbers[i0], self.numbers[i1]]))
                bond_types[key] = bond_types.get(key, 0) + 1
            log.hline()
            log(' First   Second   Count')
            for (num0, num1), count in sorted(bond_types.items()):
                log('%6i   %6i   %5i' % (num0, num1, count))
            log.hline()
            log.blank()

            log('Analysis of the neighbors:')
            log.hline()
            log('Number of first neighbors:  %6i' %
                (sum(len(n) for n in self.neighs1.values()) // 2))
            log('Number of second neighbors: %6i' %
                (sum(len(n) for n in self.neighs2.values()) // 2))
            log('Number of third neighbors:  %6i' %
                (sum(len(n) for n in self.neighs3.values()) // 2))
            # Collect all types of 'environments' for each element. This is
            # useful to double check the bonds
            envs = {}
            for i0 in range(self.natom):
                num0 = self.numbers[i0]
                nnums = tuple(
                    sorted(self.numbers[i1] for i1 in self.neighs1[i0]))
                key = (num0, nnums)
                envs[key] = envs.get(key, 0) + 1
            # Print the environments on screen
            log.hline()
            log('Element   Neighboring elements   Count')
            for (num0, nnums), count in sorted(envs.items()):
                log('%7i   %20s   %5i' %
                    (num0, ','.join(str(num1) for num1 in nnums), count))
            log.hline()
            log.blank()