Ejemplo n.º 1
0
 def append_to_swap_list(self, subList):
     """
     append a sub list to swap list
     
     :Parameters: 
         #. subList (List): The sub-list of atom indexes to append to swapList.
     """
     assert isinstance(subList, (list,tuple)), LOGGER.error("subList must be a list")
     subSL = []
     for num in subList:
         assert is_integer(num), LOGGER.error("subList items must be integers")
         num = INT_TYPE(num)
         assert num>=0, LOGGER.error("subList items must be positive")
         subSL.append(num)
     assert len(set(subSL))==len(subSL), LOGGER.error("swapList items must not have any redundancy")
     assert len(subSL) == self.__swapLength, LOGGER.error("swapList item length must be equal to swapLength")
     # append
     self.__swapList = list(self.__swapList)
     subSL = np.array(subSL, dtype=INT_TYPE)
     self.__swapList.append(subSL)
     self.__swapList = tuple(self.__swapList)
     # set uncollected atoms swapList
     self._remainingAtomsSwapList  = self.__swapList
     # reset collector state
     self._collectorState = None  
Ejemplo n.º 2
0
 def set_adjust_scale_factor(self, adjustScaleFactor):
     """
     Sets adjust scale factor.
     
     :Parameters:
         #. adjustScaleFactor (list, tuple): Used to adjust fit or guess the best scale factor during EMC runtime. 
            It must be a list of exactly three entries.\n
            1. The frequency in number of accepted moves of finding the best scale factor. 
               If 0 frequency is given, it means that the scale factor is fixed.
            2. The minimum allowed scale factor value.
            3. The maximum allowed scale factor value.
     """
     assert isinstance(adjustScaleFactor, (list, tuple)), LOGGER.error('adjustScaleFactor must be a list.')
     assert len(adjustScaleFactor) == 3, LOGGER.error('adjustScaleFactor must be a list of exactly three items.')
     freq  = adjustScaleFactor[0]
     minSF = adjustScaleFactor[1]
     maxSF = adjustScaleFactor[2]
     assert is_integer(freq), LOGGER.error("adjustScaleFactor first item (frequency) must be an integer.")
     freq = INT_TYPE(freq)
     assert freq>=0, LOGGER.error("adjustScaleFactor first (frequency) item must be bigger or equal to 0.")
     assert is_number(minSF), LOGGER.error("adjustScaleFactor second item (minimum) must be a number.")
     minSF = FLOAT_TYPE(minSF)
     assert is_number(maxSF), LOGGER.error("adjustScaleFactor third item (maximum) must be a number.")
     maxSF = FLOAT_TYPE(maxSF)
     assert minSF<=maxSF, LOGGER.error("adjustScaleFactor second item (minimum) must be smaller or equal to third second item (maximum).")
     # set values
     self.__adjustScaleFactorFrequency = freq
     self.__adjustScaleFactorMinimum   = minSF
     self.__adjustScaleFactorMaximum   = maxSF
     # dump to repository
     self._dump_to_repository({'_ExperimentalConstraint__adjustScaleFactorFrequency': self.__adjustScaleFactorFrequency,
                               '_ExperimentalConstraint__adjustScaleFactorMinimum'  : self.__adjustScaleFactorMinimum,
                               '_ExperimentalConstraint__adjustScaleFactorMaximum'  : self.__adjustScaleFactorMaximum})
     # reset constraint
     self.reset_constraint()
Ejemplo n.º 3
0
 def select_index(self):
     """
     Select index.
     
     :Returns:
         #. index (integer): the selected group index in engine groups list
     """
     return INT_TYPE(generate_random_integer(0,
                                             len(self.engine.groups) - 1))
Ejemplo n.º 4
0
 def select_index(self):
     """
     Select index.
     
     :Returns:
         #. index (integer): the selected group index in engine groups list
     """
     return INT_TYPE(
         np.searchsorted(self._selectionScheme, generate_random_float()))
Ejemplo n.º 5
0
    def compute_after_move(self, realIndexes, relativeIndexes,
                           movedBoxCoordinates):
        """
        Compute constraint after move is executed

        :Parameters:
            #. realIndexes (numpy.ndarray): Not used here.
            #. relativeIndexes (numpy.ndarray): Group atoms relative index
               the move will be applied to.
            #. movedBoxCoordinates (numpy.ndarray): The moved atoms new
               coordinates.
        """
        bondsIndexes = self.activeAtomsDataBeforeMove["bondsIndexes"]
        # change coordinates temporarily
        boxData = np.array(self.engine.boxCoordinates[relativeIndexes],
                           dtype=FLOAT_TYPE)
        self.engine.boxCoordinates[relativeIndexes] = movedBoxCoordinates
        # compute data after move
        if len(bondsIndexes):
            bonds, reduced = full_bonds_coords(
                idx1=self._atomsCollector.get_relative_indexes(
                    self.__bondsList[0]
                    [bondsIndexes]),  #self.__bondsList[0][bondsIndexes],
                idx2=self._atomsCollector.get_relative_indexes(
                    self.__bondsList[1]
                    [bondsIndexes]),  #self.__bondsList[1][bondsIndexes],
                lowerLimit=self.__bondsList[2][bondsIndexes],
                upperLimit=self.__bondsList[3][bondsIndexes],
                boxCoords=self.engine.boxCoordinates,
                basis=self.engine.basisVectors,
                isPBC=self.engine.isPBC,
                reduceDistanceToUpper=False,
                reduceDistanceToLower=False,
                ncores=INT_TYPE(1))
        else:
            bonds = None
            reduced = None
        # set active data after move
        self.set_active_atoms_data_after_move({
            "bondsLength": bonds,
            "reducedLengths": reduced
        })
        # reset coordinates
        self.engine.boxCoordinates[relativeIndexes] = boxData
        # compute standardError after move
        if bonds is None:
            self.set_after_move_standard_error(self.standardError)
        else:
            # bondsIndexes is a fancy slicing, RL is a copy not a view.
            RL = self.data["reducedLengths"][bondsIndexes]
            self.data["reducedLengths"][
                bondsIndexes] += reduced - self.activeAtomsDataBeforeMove[
                    "reducedLengths"]
            self.set_after_move_standard_error(
                self.compute_standard_error(data=self.data))
            self.data["reducedLengths"][bondsIndexes] = RL
Ejemplo n.º 6
0
    def compute_after_move(self, realIndexes, relativeIndexes,
                           movedBoxCoordinates):
        """
        Compute constraint after move is executed.

        :Parameters:
            #. realIndexes (numpy.ndarray): Not used here.
            #. relativeIndexes (numpy.ndarray): Group atoms relative index
               the move will be applied to.
            #. movedBoxCoordinates (numpy.ndarray): The moved atoms new coordinates.
        """
        # get angles indexes
        anglesIndex = self.activeAtomsDataBeforeMove["anglesIndex"]
        # change coordinates temporarily
        boxData = np.array(self.engine.boxCoordinates[relativeIndexes],
                           dtype=FLOAT_TYPE)
        self.engine.boxCoordinates[relativeIndexes] = movedBoxCoordinates
        # compute data before move
        if len(anglesIndex):
            angles, reduced = full_angles_coords(
                central=self._atomsCollector.get_relative_indexes(
                    self.__anglesList[0][anglesIndex]),
                left=self._atomsCollector.get_relative_indexes(
                    self.__anglesList[1][anglesIndex]),
                right=self._atomsCollector.get_relative_indexes(
                    self.__anglesList[2][anglesIndex]),
                lowerLimit=self.__anglesList[3][anglesIndex],
                upperLimit=self.__anglesList[4][anglesIndex],
                boxCoords=self.engine.boxCoordinates,
                basis=self.engine.basisVectors,
                isPBC=self.engine.isPBC,
                reduceAngleToUpper=False,
                reduceAngleToLower=False,
                ncores=INT_TYPE(1))
        else:
            angles = None
            reduced = None
        # set active data after move
        self.set_active_atoms_data_after_move({
            "angles": angles,
            "reducedAngles": reduced
        })
        # reset coordinates
        self.engine.boxCoordinates[relativeIndexes] = boxData
        # compute standardError after move
        if angles is None:
            self.set_after_move_standard_error(self.standardError)
        else:
            # anglesIndex is a fancy slicing, RL is a copy not a view.
            RL = self.data["reducedAngles"][anglesIndex]
            self.data["reducedAngles"][
                anglesIndex] += reduced - self.activeAtomsDataBeforeMove[
                    "reducedAngles"]
            self.set_after_move_standard_error(
                self.compute_standard_error(data=self.data))
            self.data["reducedAngles"][anglesIndex] = RL
Ejemplo n.º 7
0
 def compute_data(self):
     """ Compute data and update engine constraintsData dictionary. """
     if len(self._atomsCollector):
         anglesData = np.zeros(self.__anglesList[0].shape[0],
                               dtype=FLOAT_TYPE)
         reducedData = np.zeros(self.__anglesList[0].shape[0],
                                dtype=FLOAT_TYPE)
         anglesIndexes = set(set(range(self.__anglesList[0].shape[0])))
         anglesIndexes = list(anglesIndexes -
                              self._atomsCollector._randomData)
         central = self._atomsCollector.get_relative_indexes(
             self.__anglesList[0][anglesIndexes])
         left = self._atomsCollector.get_relative_indexes(
             self.__anglesList[1][anglesIndexes])
         right = self._atomsCollector.get_relative_indexes(
             self.__anglesList[2][anglesIndexes])
         lowerLimit = self.__anglesList[3][anglesIndexes]
         upperLimit = self.__anglesList[4][anglesIndexes]
     else:
         central = self._atomsCollector.get_relative_indexes(
             self.__anglesList[0])
         left = self._atomsCollector.get_relative_indexes(
             self.__anglesList[1])
         right = self._atomsCollector.get_relative_indexes(
             self.__anglesList[2])
         lowerLimit = self.__anglesList[3]
         upperLimit = self.__anglesList[4]
     # compute data
     angles, reduced = full_angles_coords(
         central=central,
         left=left,
         right=right,
         lowerLimit=lowerLimit,
         upperLimit=upperLimit,
         boxCoords=self.engine.boxCoordinates,
         basis=self.engine.basisVectors,
         isPBC=self.engine.isPBC,
         reduceAngleToUpper=False,
         reduceAngleToLower=False,
         ncores=INT_TYPE(1))
     # create full length data
     if len(self._atomsCollector):
         anglesData[anglesIndexes] = angles
         reducedData[anglesIndexes] = reduced
         angles = anglesData
         reduced = reducedData
     # set data
     self.set_data({"angles": angles, "reducedAngles": reduced})
     self.set_active_atoms_data_before_move(None)
     self.set_active_atoms_data_after_move(None)
     # set standardError
     self.set_standard_error(self.compute_standard_error(data=self.data))
     # set original data
     if self.originalData is None:
         self._set_original_data(self.data)
Ejemplo n.º 8
0
    def set_swap_list(self, swapList):
        """
        Set the swap-list to exchange atoms position from.

        :Parameters:
            #. swapList (None, List): The list of atoms.\n
               If None is given, no swapping or exchanging will be performed.\n
               If List is given, it must contain lists of atom indexes where
               every sub-list length must be equal to swapLength.
        """
        C = _Container()
        # add container
        if not C.is_container('swapList'):
            C.add_container('swapList')
        # check if swapList already defined
        loc = C.get_location_by_hint(swapList)
        if loc is not None:
            self.__swapList = C.get_value(loc)
        elif swapList is None:
            self.__swapList = ()
        else:
            SL = []
            assert isinstance(
                swapList,
                (list, tuple)), LOGGER.error("swapList must be a list")
            for sl in swapList:
                assert isinstance(
                    sl, (list,
                         tuple)), LOGGER.error("swapList items must be a list")
                subSL = []
                for num in sl:
                    assert is_integer(num), LOGGER.error(
                        "swapList sub-list items must be integers")
                    num = INT_TYPE(num)
                    assert num >= 0, LOGGER.error(
                        "swapList sub-list items must be positive")
                    subSL.append(num)
                assert len(set(subSL)) == len(subSL), LOGGER.error(
                    "swapList items must not have any redundancy")
                if self.swapLength is not None:
                    assert len(subSL) == self.swapLength, LOGGER.error(
                        "swapList item length must be equal to swapLength")
                SL.append(np.array(subSL, dtype=INT_TYPE))
            self.__swapList = tuple(SL)
            # add swapList to container
            C.set_value(container='swapList',
                        value=self.__swapList,
                        hint=swapList)
        # set uncollected atoms swapList
        self._remainingAtomsSwapList = self.__swapList
        # reset collector state
        self._collectorState = None
Ejemplo n.º 9
0
 def set_recur(self, recur):
     """
     Sets the recur value.
     
     :Parameters:
         #. recur (integer): Set the recur value.
            It must be a positive integer.
     """
     assert is_integer(recur), LOGGER.error("recur must be an integer")
     recur = INT_TYPE(recur)
     assert recur >= 0, LOGGER.error("recur must be positive")
     self.__recur = recur
     self.__recurAsSet = recur
Ejemplo n.º 10
0
    def set_group_axis(self, groupAxis):
        """
        Sets group axis value.

        :Parameters:
           #. groupAxis (dict): The group axis. Only one key is allowed.
              If key is fixed, value must be a list, tuple or a numpy.array
              of a vector such as [X,Y,Z]. If key is symmetry, in this case
              the group axis is computed as one of the three symmetry axis of
              the group atoms. the value must be even 0, 1 or 2 for
              respectively the first, second and tertiary symmetry axis.
        """
        assert isinstance(groupAxis,
                          dict), LOGGER.error("groupAxis must be a dictionary")
        assert len(groupAxis) == 1, LOGGER.error(
            "groupAxis must have a single key")
        key = groupAxis.keys()[0]
        val = groupAxis[key]
        if key == "fixed":
            self.__mustComputeGroupAxis = False
            assert isinstance(
                val,
                (list, set, tuple,
                 np.ndarray)), LOGGER.error("groupAxis value must be a list")
            if isinstance(val, np.ndarray):
                assert len(val.shape) == 1, LOGGER.error(
                    "groupAxis value must have a single dimension")
            val = list(val)
            assert len(val) == 3, LOGGER.error(
                "groupAxis fixed value must be a vector")
            for v in val:
                assert is_number(v), LOGGER.error(
                    "groupAxis value item must be numbers")
            val = np.array([FLOAT_TYPE(v) for v in val], dtype=FLOAT_TYPE)
            norm = FLOAT_TYPE(np.sqrt(np.sum(val**2)))
            val /= norm
        elif key == "symmetry":
            self.__mustComputeGroupAxis = True
            assert is_integer(val), LOGGER.error(
                "groupAxis symmetry value must be an integer")
            val = INT_TYPE(val)
            assert val >= 0 and val < 3, LOGGER.error(
                "groupAxis symmetry value must be positive smaller than 3")
        else:
            self.__mustComputeGroupAxis = None
            raise Exception(
                LOGGER.error(
                    "groupAxis key must be either 'fixed' or 'symmetry'"))
        # set groupAxis
        self.__groupAxis = {key: val}
Ejemplo n.º 11
0
    def set_axis(self, axis):
        """
        Set the symmetry axis index to translate along.

        :Parameters:
            #. axis (integer): Must be 0,1 or 2 for respectively the main,
               secondary or tertiary symmetry axis
        """
        assert is_integer(axis), LOGGER.error("rotation symmetry axis must be an integer.")
        axis = INT_TYPE(axis)
        assert axis>=0, LOGGER.error("rotation symmetry axis must be positive.")
        assert axis<=2, LOGGER.error("rotation symmetry axis must be smaller or equal to 2.")
        # convert to radian and store amplitude
        self.__axis = axis
Ejemplo n.º 12
0
 def compute_data(self):
     """ Compute constraint's data."""
     if len(self._atomsCollector):
         bondsData = np.zeros(self.__bondsList[0].shape[0],
                              dtype=FLOAT_TYPE)
         reducedData = np.zeros(self.__bondsList[0].shape[0],
                                dtype=FLOAT_TYPE)
         bondsIndexes = set(set(range(self.__bondsList[0].shape[0])))
         bondsIndexes = list(bondsIndexes -
                             self._atomsCollector._randomData)
         idx1 = self._atomsCollector.get_relative_indexes(
             self.__bondsList[0][bondsIndexes])
         idx2 = self._atomsCollector.get_relative_indexes(
             self.__bondsList[1][bondsIndexes])
         lowerLimit = self.__bondsList[2][bondsIndexes]
         upperLimit = self.__bondsList[3][bondsIndexes]
     else:
         idx1 = self._atomsCollector.get_relative_indexes(
             self.__bondsList[0])
         idx2 = self._atomsCollector.get_relative_indexes(
             self.__bondsList[1])
         lowerLimit = self.__bondsList[2]
         upperLimit = self.__bondsList[3]
     # compute
     bonds, reduced = full_bonds_coords(
         idx1=idx1,
         idx2=idx2,
         lowerLimit=lowerLimit,
         upperLimit=upperLimit,
         boxCoords=self.engine.boxCoordinates,
         basis=self.engine.basisVectors,
         isPBC=self.engine.isPBC,
         reduceDistanceToUpper=False,
         reduceDistanceToLower=False,
         ncores=INT_TYPE(1))
     # create full length data
     if len(self._atomsCollector):
         bondsData[bondsIndexes] = bonds
         reducedData[bondsIndexes] = reduced
         bonds = bondsData
         reduced = reducedData
     self.set_data({"bondsLength": bonds, "reducedLengths": reduced})
     self.set_active_atoms_data_before_move(None)
     self.set_active_atoms_data_after_move(None)
     # set standardError
     self.set_standard_error(self.compute_standard_error(data=self.data))
     # set original data
     if self.originalData is None:
         self._set_original_data(self.data)
Ejemplo n.º 13
0
 def __check_single_weight(self, w):
     """Checks a single group weight tuple format"""
     assert isinstance(w, (list,set,tuple)),LOGGER.error("weights list items must be tuples")
     assert len(w)==2, LOGGER.error("weights list tuples must have exactly 2 items")
     idx  = w[0]
     wgt = w[1]
     assert is_integer(idx), LOGGER.error("weights list tuples first item must be an integer")
     idx = INT_TYPE(idx)
     assert idx>=0, LOGGER.error("weights list tuples first item must be positive")
     assert idx<len(self.__collection), LOGGER.error("weights list tuples first item must be smaller than the number of generators in collection")
     assert is_number(wgt), LOGGER.error("weights list tuples second item must be an integer")
     wgt = FLOAT_TYPE(wgt)
     assert wgt>0, LOGGER.error("weights list tuples first item must be bigger than 0")
     # all True return idx and weight
     return idx, wgt  
Ejemplo n.º 14
0
 def set_maximum_collected(self, maximumCollected):
     """
     Set maximum collected number of atoms allowed.
     
     :Parameters:
         #. maximumCollected (None, Integer): The maximum number allowed of atoms to be 
            removed and collected from the engine. This property is general to the 
            system and checks engine's collected atoms not the number of removed atoms 
            via this generator. If None is given, the remover will not check for the
            number of already removed atoms before attempting a remove.
     """
     if maximumCollected is not None:
         assert is_integer(maximumCollected), LOGGER.error("maximumCollected must be an integer")
         maximumCollected = INT_TYPE(maximumCollected)
         assert maximumCollected>0, LOGGER.error("maximumCollected must be bigger than 0")
     self.__maximumCollected = maximumCollected
Ejemplo n.º 15
0
 def set_center(self, center):
     """
     Sets center value.
     
     :Parameters:
         #. center (dict): The center value dictionary. Must have a single key and this can only be 'fixed' or 'indexes'.
            If key is fixed, value must be a list or a numpy.array of a point coordinates such as [X,Y,Z]
            If key is indexes, value must be a list or a numpy array of indexes.
     """
     assert isinstance(center,
                       dict), LOGGER.error("center must be a dictionary")
     assert len(center) == 1, LOGGER.error("center must have a single key")
     key = center.keys()[0]
     val = center[key]
     assert isinstance(
         val, (list, set, tuple,
               np.ndarray)), LOGGER.error("center value must be a list")
     if isinstance(val, np.ndarray):
         assert len(val.shape) == 1, LOGGER.error(
             "center value must have a single dimension")
     assert len(val) > 0, LOGGER.error(
         "center value must be a non-zero list.")
     for v in val:
         assert is_number(v), LOGGER.error(
             "center value item must be numbers")
     if key == "fixed":
         self.__mustCompute = False
         assert len(val) == 3, LOGGER.error(
             "fixed center must have exactly 3 elements corresponding to X,Y and Z coordinates of the center point."
         )
         val = np.array([FLOAT_TYPE(v) for v in val], dtype=FLOAT_TYPE)
     elif key == "indexes":
         self.__mustCompute = True
         for v in val:
             assert is_integer(v), LOGGER.error(
                 "indexes center items be integers")
         val = np.array([INT_TYPE(v) for v in val], dtype=INT_TYPE)
         for v in val:
             assert v >= 0, LOGGER.error(
                 "indexes center items be positive integers")
     else:
         self.__mustCompute = None
         raise Exception(
             LOGGER.error("center key must be either 'fixed' or 'indexes'"))
     # set center
     self.__center = {key: val}
Ejemplo n.º 16
0
 def set_swap_length(self, swapLength):
     """
     Set swap length. it will reset swaplist automatically.
 
     :Parameters:
         #. swapLength (Integer): The swap length that defines the length of the group 
            and the length of the every swap sub-list in swapList.
     """   
     assert is_integer(swapLength), LOGGER.error("swapLength must be an integer")
     swapLength = INT_TYPE(swapLength)
     assert swapLength>0, LOGGER.error("swapLength must be bigger than 0")
     self.__swapLength = swapLength
     self.__swapList   = ()
     # set uncollected atoms swapList
     self._remainingAtomsSwapList  = self.__swapList
     # reset collector state
     self._collectorState = None    
Ejemplo n.º 17
0
    def compute_before_move(self, realIndexes, relativeIndexes):
        """
        Compute constraint's data before move is executed.

        :Parameters:
            #. realIndexes (numpy.ndarray): Group atoms index the move will
               be applied to.
            #. relativeIndexes (numpy.ndarray): Not used here.
        """
        # get bonds indexes
        bondsIndexes = []
        #for idx in relativeIndexes:
        for idx in realIndexes:
            bondsIndexes.extend(self.__bonds[idx]['map'])
        #bondsIndexes = list(set(bondsIndexes))
        # remove collected bonds
        bondsIndexes = list(
            set(bondsIndexes) - set(self._atomsCollector._randomData))
        # compute data before move
        if len(bondsIndexes):
            bonds, reduced = full_bonds_coords(
                idx1=self._atomsCollector.get_relative_indexes(
                    self.__bondsList[0][bondsIndexes]),
                idx2=self._atomsCollector.get_relative_indexes(
                    self.__bondsList[1][bondsIndexes]),
                lowerLimit=self.__bondsList[2][bondsIndexes],
                upperLimit=self.__bondsList[3][bondsIndexes],
                boxCoords=self.engine.boxCoordinates,
                basis=self.engine.basisVectors,
                isPBC=self.engine.isPBC,
                reduceDistanceToUpper=False,
                reduceDistanceToLower=False,
                ncores=INT_TYPE(1))
        else:
            bonds = None
            reduced = None
        # set data before move
        self.set_active_atoms_data_before_move({
            "bondsIndexes": bondsIndexes,
            "bondsLength": bonds,
            "reducedLengths": reduced
        })
        self.set_active_atoms_data_after_move(None)
Ejemplo n.º 18
0
    def compute_before_move(self, realIndexes, relativeIndexes):
        """
        Compute constraint before move is executed.

        :Parameters:
            #. realIndexes (numpy.ndarray): Group atoms index the move will
               be applied to.
            #. relativeIndexes (numpy.ndarray): Not used here.
        """
        # get angles indexes
        anglesIndex = []
        #for idx in relativeIndexes:
        for idx in realIndexes:
            anglesIndex.extend(self.__angles[idx]['centralMap'])
            anglesIndex.extend(self.__angles[idx]['otherMap'])
        anglesIndex = list(set(anglesIndex) - self._atomsCollector._randomData)
        # compute data before move
        if len(anglesIndex):
            angles, reduced = full_angles_coords(
                central=self._atomsCollector.get_relative_indexes(
                    self.__anglesList[0][anglesIndex]),
                left=self._atomsCollector.get_relative_indexes(
                    self.__anglesList[1][anglesIndex]),
                right=self._atomsCollector.get_relative_indexes(
                    self.__anglesList[2][anglesIndex]),
                lowerLimit=self.__anglesList[3][anglesIndex],
                upperLimit=self.__anglesList[4][anglesIndex],
                boxCoords=self.engine.boxCoordinates,
                basis=self.engine.basisVectors,
                isPBC=self.engine.isPBC,
                reduceAngleToUpper=False,
                reduceAngleToLower=False,
                ncores=INT_TYPE(1))
        else:
            angles = None
            reduced = None
        # set data before move
        self.set_active_atoms_data_before_move({
            "anglesIndex": anglesIndex,
            "angles": angles,
            "reducedAngles": reduced
        })
        self.set_active_atoms_data_after_move(None)
Ejemplo n.º 19
0
    def set_atoms_list(self, atomsList):
        """
        Set atoms index list from which atoms will be picked to attempt removal.
        This method must be overloaded and not be called from this class but
        from its children. Otherwise a usage error will be raised.

        :Parameters:
            #. atomsList (None, list,set,tuple,np.ndarray): The list of atoms
               index to chose and remove from.
        """
        if atomsList is not None:
            C = _Container()
            # add container
            if not C.is_container('removeAtomsList'):
                C.add_container('removeAtomsList')
            # check if atomsList already defined
            loc = C.get_location_by_hint(atomsList)
            if loc is not None:
                atomsList = C.get_value(loc)
            else:
                assert isinstance(
                    atomsList, (list, tuple, np.ndarray)), LOGGER.error(
                        "atomsList must be either a list or a numpy.array")
                CL = []
                for idx in atomsList:
                    assert is_integer(idx), LOGGER.error(
                        "atomsList items must be integers")
                    assert idx >= 0, LOGGER.error(
                        "atomsList item must equal or bigger than 0")
                    CL.append(INT_TYPE(idx))
                setCL = set(CL)
                assert len(setCL) == len(CL), LOGGER.error(
                    "atomsList redundancy is not allowed")
                AL = np.array(CL, dtype=INT_TYPE)
                # add swapList to container
                C.set_value(container='removeAtomsList',
                            value=AL,
                            hint=atomsList)
                atomsList = AL
        # set atomsList attribute
        self.__atomsList = atomsList
        # reset collector state
        self._collectorState = None
Ejemplo n.º 20
0
 def move(self, coordinates):
     """
     Moves coordinates.
     
     :Parameters:
         #. coordinates (np.ndarray): The coordinates on which to apply the transformation
         
     :Returns:
         #. coordinates (np.ndarray): The new coordinates after applying the transformation
     """
     if self.__randomize:
         index = INT_TYPE( np.searchsorted(self.__selectionScheme, generate_random_float()) )
         moveGenerator = self.__collection[ index ]
     else:
         moveGenerator = self.__collection[self.__step]
         self.__step   = (self.__step+1)%len(self.__collection)
     # perform the move
     return moveGenerator.move(coordinates) 
     
             
     
     
Ejemplo n.º 21
0
    def set_bonds(self, bondsList, tform=True):
        """
        Sets bonds dictionary by parsing bondsList list.

        :Parameters:
            #. bondsList (None, list): Bonds definition list. If None is given
               no bonds are defined. Otherwise it can be of any of the
               following two forms:

                   tuples format: every item must be a list or tuple of four
                   items.\n
                   #. First atom index forming the bond.
                   #. Second atom index forming the bond.
                   #. Lower limit or the minimum bond length
                      allowed.
                   #. Upper limit or the maximum bond length
                      allowed.

                   four vectors format: List of exaclty four lists or
                   numpy.arrays of the same length.\n
                   #. List contains the first atoms index
                      forming the bond.
                   #. List contains the second atoms index
                      forming the bond.
                   #. List containing the lower limit or
                      the minimum bond length allowed.
                   #. List containing the upper limit or
                      the maximum bond length allowed.

            #. tform (boolean): set whether given bondsList follows tuples
               format, If not then it must follow the four vectors one.
        """
        # check if bondsList is given
        if bondsList is None:
            bondsList = [[], [], [], []]
            tform = False
        elif len(bondsList) == 4 and len(bondsList[0]) == 0:
            tform = False
        if self.engine is None:
            self.__bondsList = bondsList
            self.__bonds = {}
        else:
            NUMBER_OF_ATOMS = self.engine.get_original_data("numberOfAtoms")
            # set bonds and bondsList definition
            oldBondsList = self.__bondsList
            oldBonds = self.__bonds
            self.__bondsList = [
                np.array([], dtype=INT_TYPE),
                np.array([], dtype=INT_TYPE),
                np.array([], dtype=FLOAT_TYPE),
                np.array([], dtype=FLOAT_TYPE)
            ]
            self.__bonds = {}
            self.__dumpBonds = False
            # build bonds
            try:
                if tform:
                    for bond in bondsList:
                        self.add_bond(bond)
                else:
                    for idx in xrange(len(bondsList[0])):
                        bond = [
                            bondsList[0][idx], bondsList[1][idx],
                            bondsList[2][idx], bondsList[3][idx]
                        ]
                        self.add_bond(bond)
            except Exception as e:
                self.__dumpBonds = True
                self.__bondsList = oldBondsList
                self.__bonds = oldBonds
                LOGGER.error(e)
                import traceback
                raise Exception(traceback.format_exc())
            self.__dumpBonds = True
            # finalize bonds
            for idx in xrange(NUMBER_OF_ATOMS):
                self.__bonds[INT_TYPE(idx)] = self.__bonds.get(
                    INT_TYPE(idx), {
                        "indexes": [],
                        "map": []
                    })
        # dump to repository
        self._dump_to_repository({
            '_BondConstraint__bondsList': self.__bondsList,
            '_BondConstraint__bonds': self.__bonds
        })
        # reset constraint
        self.reset_constraint()
Ejemplo n.º 22
0
    def set_orientation_axis(self, orientationAxis):
        """
        Set orientation axis value.

        :Parameters:
            #. orientationAxis (dict): The axis to align the group axis with.
               If key is fixed, value must be a list, tuple or a numpy.array
               of a vector such as [X,Y,Z]. If Key is symmetry, in this case
               the value must be a list of two items, the first one is a list
               of atoms indexes to compute symmetry axis and the second item
               must be even 0, 1 or 2 for respectively the first, second and
               tertiary symmetry axis.
        """
        assert isinstance(
            orientationAxis,
            dict), LOGGER.error("orientationAxis must be a dictionary")
        assert len(orientationAxis) == 1, LOGGER.error(
            "orientationAxis must have a single key")
        key = orientationAxis.keys()[0]
        val = orientationAxis[key]
        if key == "fixed":
            self.__mustComputeOrientationAxis = False
            assert isinstance(val,
                              (list, set, tuple, np.ndarray)), LOGGER.error(
                                  "orientationAxis value must be a list")
            if isinstance(val, np.ndarray):
                assert len(val.shape) == 1, LOGGER.error(
                    "orientationAxis value must have a single dimension")
            val = list(val)
            assert len(val) == 3, LOGGER.error(
                "orientationAxis fixed value must be a vector")
            for v in val:
                assert is_number(v), LOGGER.error(
                    "orientationAxis value item must be numbers")
            val = np.array([FLOAT_TYPE(v) for v in val], dtype=FLOAT_TYPE)
            norm = FLOAT_TYPE(np.sqrt(np.sum(val**2)))
            val /= norm
        elif key == "symmetry":
            self.__mustComputeOrientationAxis = True
            assert isintance(val, (list, tuple)), LOGGER.error(
                "orientationAxis symmetry value must be a list")
            assert len(val) == 2, LOGGER.error(
                "orientationAxis symmetry value must be a list of two items")
            val0 = []
            for v in val[0]:
                assert is_integer(v), LOGGER.error(
                    "orientationAxis symmetry value list items must be integers"
                )
                v0 = INT_TYPE(v)
                assert v0 >= 0, LOGGER.error(
                    "orientationAxis symmetry value list items must be positive"
                )
                val0.append(v0)
            assert len(set(val0)) == len(val[0]), LOGGER.error(
                "orientationAxis symmetry value list redundant items indexes found"
            )
            val0 = np.array(val0, dtype=INT_TYPE)
            val1 = val[1]
            assert is_integer(val1), LOGGER.error(
                "orientationAxis symmetry value second item must be an integer"
            )
            val1 = INT_TYPE(val1)
            assert val1 >= 0 and val1 < 3, LOGGER.error(
                "orientationAxis symmetry value second item must be positive smaller than 3"
            )
            val = (val0, val1)
        else:
            self.__mustComputeOrientationAxis = None
            raise Exception(
                LOGGER.error(
                    "orientationAxis key must be either 'fixed' or 'symmetry'")
            )
        # set orientationAxis
        self.__orientationAxis = {key: val}
Ejemplo n.º 23
0
    def set_angles(self, anglesList, tform=True):
        """
        Sets the angles dictionary by parsing the anglesList. All angles are in
        degrees.

        :Parameters:
            #. anglesList (list): The angles list definition that can be
               given in two different formats.

               tuples format:  every item must be a list of five items.\n
               #. Central atom index.
               #. Index of the left atom forming the angle
                  (interchangeable with the right atom).
               #. Index of the right atom forming the angle
                  (interchangeable with the left atom).
               #. Minimum lower limit or the minimum angle
                  allowed in degrees which later will be converted to rad.
               #. Maximum upper limit or the maximum angle
                  allowed in degrees which later will be converted to rad.

               five vectors format:  List of exaclty five lists or
               numpy.arrays or vectors of the same length.\n
               #. List containing central atom indexes.
               #. List containing the index of the left atom
                  forming the angle (interchangeable with the right atom).
               #. List containing the index of the right atom
                  forming the angle (interchangeable with the left atom).
               #. List containing the minimum lower limit or the
                  minimum angle allowed in degrees which later will be
                  converted to rad.
               #. List containing the maximum upper limit or the
                  maximum angle allowed in degrees which later will be
                  converted to rad.

           #. tform (boolean): set whether given anglesList follows tuples
              format, If False, then it must follow the five vectors one.
        """
        # check if anglesList is given
        if anglesList is None:
            bondsList = [[], [], [], [], []]
            tform = False
        elif len(anglesList) == 5 and len(anglesList[0]) == 0:
            tform = False
        if self.engine is None:
            self.__anglesList = anglesList
            self.__angles = {}
        else:
            NUMBER_OF_ATOMS = self.engine.get_original_data("numberOfAtoms")
            oldAnglesList = self.__anglesList
            oldAngles = self.__angles
            self.__anglesList = [
                np.array([], dtype=INT_TYPE),
                np.array([], dtype=INT_TYPE),
                np.array([], dtype=INT_TYPE),
                np.array([], dtype=FLOAT_TYPE),
                np.array([], dtype=FLOAT_TYPE)
            ]
            self.__angles = {}
            self.__dumpAngles = False
            # build angles
            try:
                if tform:
                    for angle in anglesList:
                        self.add_angle(angle)
                else:
                    for idx in xrange(len(anglesList[0])):
                        angle = [
                            anglesList[0][idx], anglesList[1][idx],
                            anglesList[2][idx], anglesList[3][idx],
                            anglesList[4][idx]
                        ]
                        self.add_angle(angle)
            except Exception as e:
                self.__dumpAngles = True
                self.__anglesList = oldAnglesList
                self.__angles = oldAngles
                LOGGER.error(e)
                import traceback
                raise Exception(traceback.format_exc())
            self.__dumpAngles = True
            # finalize angles
            for idx in xrange(NUMBER_OF_ATOMS):
                self.__angles[INT_TYPE(idx)] = self.__angles.get(
                    INT_TYPE(idx), {
                        "left": [],
                        "right": [],
                        "centralMap": [],
                        "otherMap": []
                    })
        # dump to repository
        self._dump_to_repository({
            '_BondsAngleConstraint__anglesList': self.__anglesList,
            '_BondsAngleConstraint__angles': self.__angles
        })
        # reset constraint
        self.reset_constraint()
Ejemplo n.º 24
0
    def set_coordination_number_definition(self, coordNumDef):
        """
        Set the coordination number definition.

        :Parameters:
            #. coordNumDef (None, list, tuple): Coordination number definition.
               It must be None, list or tuple where every element is a list or
               a tuple of exactly 6 items and an optional 7th item for weight.

               #. core atoms: Can be any of the following:

                  * string: indicating atomic element.
                  * dictionary: Key as atomic attribute among (element, name)
                    and value is the attribute value.
                  * list, tuple, set, numpy.ndarray: core atoms index.

               #. in shell atoms: Can be any of the following:

                  * string: indicating atomic element.
                  * dictionary: Key as atomic attribute among (element, name)
                    and value is the attribute value.
                  * list, tuple, set, numpy.ndarray: in shell atoms index

               #. Lower distance limit of the coordination shell.
               #. Upper distance limit of the coordination shell.
               #. :math:`N_{min}` : minimum number of neighbours in the
                  shell.
               #. :math:`N_{max}` : maximum number of neighbours in the
                  shell.
               #. :math:`W_{i}` : weight contribution to the standard error,
                  this is optional, if not given it is set automatically to 1.0.

               ::

                   e.g. [ ('Ti','Ti', 2.5, 3.5, 5, 7.1, 1), ('Ni','Ti', 2.2, 3.1, 7.2, 9.7, 100), ...]
                        [ ({'element':'Ti'},'Ti', 2.5, 3.5, 5, 7.1, 0.1), ...]
                        [ ({'name':'au'},'Au', 2.5, 3.5, 4.1, 6.3), ...]
                        [ ({'name':'Ni'},{'element':'Ti'}, 2.2, 3.1, 7, 9), ...]
                        [ ('Ti',range(100,500), 2.2, 3.1, 7, 9), ...]
                        [ ([0,10,11,15,1000],{'name':'Ti'}, 2.2, 3.1, 7, 9, 5), ...]

        """
        if self.engine is None:
            self.__coordNumDef = coordNumDef
            return
        elif coordNumDef is None:
            coordNumDef = []
        ########## check definitions, create coordination number data ##########
        self.__initialize_constraint_data()
        ALL_NAMES = self.engine.get_original_data("allNames")
        NAMES = self.engine.get_original_data("names")
        ALL_ELEMENTS = self.engine.get_original_data("allElements")
        ELEMENTS = self.engine.get_original_data("elements")
        NUMBER_OF_ATOMS = self.engine.get_original_data("numberOfAtoms")
        for CNDef in coordNumDef:
            assert isinstance(CNDef, (list, tuple)), LOGGER.error(
                "coordNumDef item must be a list or a tuple")
            if len(CNDef) == 6:
                coreDef, shellDef, lowerShell, upperShell, minCN, maxCN = CNDef
                weight = 1.0
            elif len(CNDef) == 7:
                coreDef, shellDef, lowerShell, upperShell, minCN, maxCN, weight = CNDef
            else:
                raise LOGGER.error("coordNumDef item must have 6 or 7 items")
            # core definition
            if isinstance(coreDef, basestring):
                coreDef = str(coreDef)
                assert coreDef in ELEMENTS, LOGGER.error(
                    "core atom definition '%s' is not a valid element" %
                    coreDef)
                coreIndexes = [
                    idx for idx, el in enumerate(ALL_ELEMENTS) if el == coreDef
                ]
            elif isinstance(coreDef, dict):
                assert len(coreDef) == 1, LOGGER.error(
                    "core atom definition dictionary must be of length 1")
                key, value = coreDef.keys()[0], coreDef.values()[0]
                if key is "name":
                    assert value in NAMES, LOGGER.error(
                        "core atom definition '%s' is not a valid name" %
                        coreDef)
                    coreIndexes = [
                        idx for idx, el in enumerate(ALL_NAMES)
                        if el == coreDef
                    ]
                elif key is "element":
                    assert value in ELEMENTS, LOGGER.error(
                        "core atom definition '%s' is not a valid element" %
                        coreDef)
                    coreIndexes = [
                        idx for idx, el in enumerate(ALL_ELEMENTS)
                        if el == coreDef
                    ]
                else:
                    raise LOGGER.error(
                        "core atom definition dictionary key must be either 'name' or 'element'"
                    )
            elif isinstance(coreDef, (list, tuple, set, np.ndarray)):
                coreIndexes = []
                if isinstance(coreDef, np.ndarray):
                    assert len(coreDef.shape) == 1, LOGGER.error(
                        "core atom definition numpy.ndarray must be 1D")
                for c in coreDef:
                    assert is_integer(c), LOGGER.error(
                        "core atom definition index must be integer")
                    c = INT_TYPE(c)
                    assert c >= 0, LOGGER.error(
                        "core atom definition index must be >=0")
                    assert c < NUMBER_OF_ATOMS, LOGGER.error(
                        "core atom definition index must be smaler than number of atoms in system"
                    )
                    coreIndexes.append(c)
            # shell definition
            if isinstance(shellDef, basestring):
                shellDef = str(shellDef)
                assert shellDef in ELEMENTS, LOGGER.error(
                    "core atom definition '%s' is not a valid element" %
                    shellDef)
                shellIndexes = [
                    idx for idx, el in enumerate(ALL_ELEMENTS)
                    if el == shellDef
                ]
            elif isinstance(shellDef, dict):
                assert len(shellDef) == 1, LOGGER.error(
                    "core atom definition dictionary must be of length 1")
                key, value = shellDef.keys()[0], shellDef.values()[0]
                if key is "name":
                    assert value in NAMES, LOGGER.error(
                        "core atom definition '%s' is not a valid name" %
                        shellDef)
                    shellIndexes = [
                        idx for idx, el in enumerate(ALL_NAMES)
                        if el == shellDef
                    ]
                elif key is "element":
                    assert value in ELEMENTS, LOGGER.error(
                        "core atom definition '%s' is not a valid element" %
                        shellDef)
                    shellIndexes = [
                        idx for idx, el in enumerate(ALL_ELEMENTS)
                        if el == shellDef
                    ]
                else:
                    raise LOGGER.error(
                        "core atom definition dictionary key must be either 'name' or 'element'"
                    )
            elif isinstance(shellDef, (list, tuple, set, np.ndarray)):
                shellIndexes = []
                if isinstance(shellDef, np.ndarray):
                    assert len(shellDef.shape) == 1, LOGGER.error(
                        "core atom definition numpy.ndarray must be 1D")
                for c in shellDef:
                    assert is_integer(c), LOGGER.error(
                        "core atom definition index must be integer")
                    c = INT_TYPE(c)
                    assert c >= 0, LOGGER.error(
                        "core atom definition index must be >=0")
                    assert c < NUMBER_OF_ATOMS, LOGGER.error(
                        "core atom definition index must be smaler than number of atoms in system"
                    )
                    shellIndexes.append(c)
            # lower and upper shells definition
            assert is_number(lowerShell), LOGGER.error(
                "Coordination number lower shell '%s' must be a number." %
                lowerShell)
            lowerShell = FLOAT_TYPE(lowerShell)
            assert lowerShell >= 0, LOGGER.error(
                "Coordination number lower shell '%s' must be a positive." %
                lowerShell)
            assert is_number(upperShell), LOGGER.error(
                "Coordination number upper shell '%s' must be a number." % key)
            upperShell = FLOAT_TYPE(upperShell)
            assert upperShell > lowerShell, LOGGER.error(
                "Coordination number lower shell '%s' must be smaller than upper shell %s"
                % (lowerShell, upperShell))
            # minimum and maximum number of atoms definitions
            assert is_number(minCN), LOGGER.error(
                "Coordination number minimum atoms '%s' must be a number." %
                minCN)
            minCN = FLOAT_TYPE(minCN)
            assert minCN >= 0, LOGGER.error(
                "Coordination number minimim atoms '%s' must be >=0." % minCN)
            assert is_number(maxCN), LOGGER.error(
                "Coordination number maximum atoms '%s' must be a number." %
                key)
            maxCN = FLOAT_TYPE(maxCN)
            assert maxCN >= minCN, LOGGER.error(
                "Coordination number minimum atoms '%s' must be smaller than maximum atoms %s"
                % (minCN, maxCN))
            # check weight
            assert is_number(weight), LOGGER.error(
                "Coordination number weight '%s' must be a number." % weight)
            weight = FLOAT_TYPE(weight)
            assert weight > 0, LOGGER.error(
                "Coordination number weight '%s' must be >0." % weight)
            # append coordination number data
            self.__coresIndexes.append(sorted(set(coreIndexes)))
            self.__shellsIndexes.append(sorted(set(shellIndexes)))
            self.__lowerShells.append(lowerShell)
            self.__upperShells.append(upperShell)
            self.__minAtoms.append(minCN)
            self.__maxAtoms.append(maxCN)
            #self.__coordNumData.append( FLOAT_TYPE(0) )
            self.__coordNumData.append(None)
            self.__weights.append(weight)
        ########## set asCoreDefIdxs and inShellDefIdxs points ##########
        for _ in xrange(NUMBER_OF_ATOMS):
            self.__asCoreDefIdxs.append([])
            self.__inShellDefIdxs.append([])
        for defIdx, indexes in enumerate(self.__coresIndexes):
            self.__coresIndexes[defIdx] = np.array(indexes, dtype=INT_TYPE)
            for atIdx in indexes:
                self.__asCoreDefIdxs[atIdx].append(defIdx)
        for defIdx, indexes in enumerate(self.__shellsIndexes):
            self.__shellsIndexes[defIdx] = np.array(indexes, dtype=INT_TYPE)
            for atIdx in indexes:
                self.__inShellDefIdxs[atIdx].append(defIdx)
        for atIdx in xrange(NUMBER_OF_ATOMS):
            self.__asCoreDefIdxs[atIdx] = np.array(self.__asCoreDefIdxs[atIdx],
                                                   dtype=INT_TYPE)
            self.__inShellDefIdxs[atIdx] = np.array(
                self.__inShellDefIdxs[atIdx], dtype=INT_TYPE)
        # set all to arrays
        #self.__coordNumData  = np.array( self.__coordNumData, dtype=FLOAT_TYPE )
        self.__weights = np.array(self.__weights, dtype=FLOAT_TYPE)
        self.__numberOfCores = np.array(
            [len(idxs) for idxs in self.__coresIndexes], dtype=FLOAT_TYPE)
        # set definition
        self.__coordNumDef = coordNumDef
        # dump to repository
        self._dump_to_repository({
            '_AtomicCoordinationNumberConstraint__coordNumDef':
            self.__coordNumDef,
            '_AtomicCoordinationNumberConstraint__coordNumData':
            self.__coordNumData,
            '_AtomicCoordinationNumberConstraint__weights':
            self.__weights,
            '_AtomicCoordinationNumberConstraint__numberOfCores':
            self.__numberOfCores,
            '_AtomicCoordinationNumberConstraint__coresIndexes':
            self.__coresIndexes,
            '_AtomicCoordinationNumberConstraint__shellsIndexes':
            self.__shellsIndexes,
            '_AtomicCoordinationNumberConstraint__lowerShells':
            self.__lowerShells,
            '_AtomicCoordinationNumberConstraint__upperShells':
            self.__upperShells,
            '_AtomicCoordinationNumberConstraint__minAtoms':
            self.__minAtoms,
            '_AtomicCoordinationNumberConstraint__maxAtoms':
            self.__maxAtoms
        })
        # reset constraint
        self.reset_constraint()  # ADDED 2017-JAN-08
Ejemplo n.º 25
0
    def add_angle(self, angle):
        """
        Add a single angle to the list of constraint angles.
        All angles are in degrees.

        :Parameters:
            #. angle (list): The angle list of five items.\n
               #. Central atom index.
               #. Index of the left atom forming the angle
                  (interchangeable with the right atom).
               #. Index of the right atom forming the angle
                  (interchangeable with the left atom).
               #. Minimum lower limit or the minimum angle
                  allowed in degrees which later will be converted to rad.
               #. Maximum upper limit or the maximum angle
                  allowed in degrees which later will be converted to rad.
        """
        assert self.engine is not None, LOGGER.error(
            "setting an angle is not allowed unless engine is defined.")
        NUMBER_OF_ATOMS = self.engine.get_original_data("numberOfAtoms")
        assert isinstance(
            angle,
            (list, set, tuple)), LOGGER.error("angle items must be lists")
        assert len(angle) == 5, LOGGER.error(
            "angle items must be lists of 5 items each")
        centralIdx, leftIdx, rightIdx, lower, upper = angle
        assert centralIdx < NUMBER_OF_ATOMS, LOGGER.error(
            "angle atom index must be smaller than maximum number of atoms")
        assert leftIdx < NUMBER_OF_ATOMS, LOGGER.error(
            "angle atom index must be smaller than maximum number of atoms")
        assert rightIdx < NUMBER_OF_ATOMS, LOGGER.error(
            "angle atom index must be smaller than maximum number of atoms")
        centralIdx = INT_TYPE(centralIdx)
        leftIdx = INT_TYPE(leftIdx)
        rightIdx = INT_TYPE(rightIdx)
        assert is_number(lower)
        lower = FLOAT_TYPE(lower)
        assert is_number(upper)
        upper = FLOAT_TYPE(upper)
        assert lower >= 0, LOGGER.error(
            "angle items lists fourth item must be positive")
        assert upper > lower, LOGGER.error(
            "angle items lists fourth item must be smaller than the fifth item"
        )
        assert upper <= 180, LOGGER.error(
            "angle items lists fifth item must be smaller or equal to 180")
        lower *= FLOAT_TYPE(PI / FLOAT_TYPE(180.))
        upper *= FLOAT_TYPE(PI / FLOAT_TYPE(180.))
        # create central angle
        if not self.__angles.has_key(centralIdx):
            anglesCentral = {
                "left": [],
                "right": [],
                "centralMap": [],
                "otherMap": []
            }
        else:
            anglesCentral = {
                "left": self.__angles[centralIdx]["left"],
                "right": self.__angles[centralIdx]["right"],
                "centralMap": self.__angles[centralIdx]["centralMap"],
                "otherMap": self.__angles[centralIdx]["otherMap"]
            }
        # create left angle
        if not self.__angles.has_key(leftIdx):
            anglesLeft = {
                "left": [],
                "right": [],
                "centralMap": [],
                "otherMap": []
            }
        else:
            anglesLeft = {
                "left": self.__angles[leftIdx]["left"],
                "right": self.__angles[leftIdx]["right"],
                "centralMap": self.__angles[leftIdx]["centralMap"],
                "otherMap": self.__angles[leftIdx]["otherMap"]
            }
        # create right angle
        if not self.__angles.has_key(rightIdx):
            anglesRight = {
                "left": [],
                "right": [],
                "centralMap": [],
                "otherMap": []
            }
        else:
            anglesRight = {
                "left": self.__angles[rightIdx]["left"],
                "right": self.__angles[rightIdx]["right"],
                "centralMap": self.__angles[rightIdx]["centralMap"],
                "otherMap": self.__angles[rightIdx]["otherMap"]
            }

        # check for re-defining
        setPos = ileft = iright = None
        if leftIdx in anglesCentral["left"] and rightIdx in anglesCentral[
                "right"]:
            ileft = anglesCentral["left"].index(leftIdx)
            iright = anglesCentral["right"].index(rightIdx)
        elif leftIdx in anglesCentral["right"] and rightIdx in anglesCentral[
                "left"]:
            ileft = anglesCentral["right"].index(leftIdx)
            iright = anglesCentral["left"].index(rightIdx)
        if (ileft is not None) and (ileft == iright):
            LOGGER.warn(
                "Angle definition for central atom index '%i' and interchangeable left '%i' atom and right '%i' atom is  already defined. New angle limits [%.3f,%.3f] are set."
                % (centralIdx, leftIdx, rightIdx, lower, upper))
            setPos = anglesCentral["centralMap"][ileft]
        # set angle
        if setPos is None:
            anglesCentral['left'].append(leftIdx)
            anglesCentral['right'].append(rightIdx)
            anglesCentral['centralMap'].append(len(self.__anglesList[0]))
            anglesLeft['otherMap'].append(len(self.__anglesList[0]))
            anglesRight['otherMap'].append(len(self.__anglesList[0]))
            self.__anglesList[0] = np.append(self.__anglesList[0], centralIdx)
            self.__anglesList[1] = np.append(self.__anglesList[1], leftIdx)
            self.__anglesList[2] = np.append(self.__anglesList[2], rightIdx)
            self.__anglesList[3] = np.append(self.__anglesList[3], lower)
            self.__anglesList[4] = np.append(self.__anglesList[4], upper)
        else:
            assert self.__anglesList[0][setPos] == centralIdx, LOOGER.error(
                "mismatched angles central atom '%s' and '%s'" %
                (elf.__anglesList[0][setPos], centralIdx))
            assert sorted([leftIdx, rightIdx]) == sorted([
                self.__anglesList[1][setPos], self.__anglesList[2][setPos]
            ]), LOOGER.error(
                "mismatched angles left and right at central atom '%s' and '%s'"
                % (elf.__anglesList[0][setPos], centralIdx))
            self.__anglesList[3][setPos] = lower
            self.__anglesList[4][setPos] = upper
        self.__angles[centralIdx] = anglesCentral
        self.__angles[leftIdx] = anglesLeft
        self.__angles[rightIdx] = anglesRight
        # dump to repository
        if self.__dumpAngles:
            self._dump_to_repository({
                '_BondsAngleConstraint__anglesList':
                self.__anglesList,
                '_BondsAngleConstraint__angles':
                self.__angles
            })
            # reset constraint
            self.reset_constraint()
Ejemplo n.º 26
0
    def add_bond(self, bond):
        """
        Add a single bond to constraint's list of bonds.

        :Parameters:
            #. bond (list): The bond list of four items.\n
               #. First atom index forming the bond.
               #. Second atom index forming the bond.
               #. Lower limit or the minimum bond length allowed.
               #. Upper limit or the maximum bond length allowed.
        """
        assert self.engine is not None, LOGGER.error(
            "setting a bond is not allowed unless engine is defined.")
        NUMBER_OF_ATOMS = self.engine.get_original_data("numberOfAtoms")
        assert isinstance(
            bond, (list, set, tuple)), LOGGER.error("bond items must be lists")
        assert len(bond) == 4, LOGGER.error(
            "bond items must be lists of 4 items each")
        idx1, idx2, lower, upper = bond
        assert is_integer(idx1), LOGGER.error(
            "bondsList items lists first item must be an integer")
        idx1 = INT_TYPE(idx1)
        assert is_integer(idx2), LOGGER.error(
            "bondsList items lists second item must be an integer")
        idx2 = INT_TYPE(idx2)
        assert idx1 < NUMBER_OF_ATOMS, LOGGER.error(
            "bond atom index must be smaller than maximum number of atoms")
        assert idx2 < NUMBER_OF_ATOMS, LOGGER.error(
            "bond atom index must be smaller than maximum number of atoms")
        assert idx1 >= 0, LOGGER.error("bond first item must be positive")
        assert idx2 >= 0, LOGGER.error("bond second item must be positive")
        assert idx1 != idx2, LOGGER.error(
            "bond first and second items can't be the same")
        assert is_number(lower), LOGGER.error(
            "bond third item must be a number")
        lower = FLOAT_TYPE(lower)
        assert is_number(upper), LOGGER.error(
            "bond fourth item must be a number")
        upper = FLOAT_TYPE(upper)
        assert lower >= 0, LOGGER.error("bond third item must be positive")
        assert upper > lower, LOGGER.error(
            "bond third item must be smaller than the fourth item")
        # create bonds
        if not self.__bonds.has_key(idx1):
            bondsIdx1 = {"indexes": [], "map": []}
        else:
            bondsIdx1 = {
                "indexes": self.__bonds[idx1]["indexes"],
                "map": self.__bonds[idx1]["map"]
            }
        if not self.__bonds.has_key(INT_TYPE(idx2)):
            bondsIdx2 = {"indexes": [], "map": []}
        else:
            bondsIdx2 = {
                "indexes": self.__bonds[idx2]["indexes"],
                "map": self.__bonds[idx2]["map"]
            }
        # set bond
        if idx2 in bondsIdx1["indexes"]:
            assert idx1 in bondsIdx2["indexes"], LOOGER.error(
                "mismatched bonds between atom '%s' and '%s'" % (idx1, idx2))
            at2InAt1 = bondsIdx1["indexes"].index(idx2)
            at1InAt2 = bondsIdx2["indexes"].index(idx1)
            assert bondsIdx1["map"][at2InAt1] == bondsIdx2["map"][
                at1InAt2], LOOGER.error(
                    "bonded atoms '%s' and '%s' point to different defintions"
                    % (idx1, idx2))
            setPos = bondsIdx1["map"][at2InAt1]
            LOGGER.warn(
                "Bond between atom index '%i' and '%i' is already defined. New bond limits [%.3f,%.3f] will replace old bond limits [%.3f,%.3f]. "
                % (idx2, idx1, lower, upper, self.__bondsList[2][setPos],
                   self.__bondsList[3][setPos]))
            self.__bondsList[0][setPos] = idx1
            self.__bondsList[1][setPos] = idx2
            self.__bondsList[2][setPos] = lower
            self.__bondsList[3][setPos] = upper
        else:
            bondsIdx1["map"].append(len(self.__bondsList[0]))
            bondsIdx2["map"].append(len(self.__bondsList[0]))
            bondsIdx1["indexes"].append(idx2)
            bondsIdx2["indexes"].append(idx1)
            self.__bondsList[0] = np.append(self.__bondsList[0], idx1)
            self.__bondsList[1] = np.append(self.__bondsList[1], idx2)
            self.__bondsList[2] = np.append(self.__bondsList[2], lower)
            self.__bondsList[3] = np.append(self.__bondsList[3], upper)
        self.__bonds[idx1] = bondsIdx1
        self.__bonds[idx2] = bondsIdx2
        # dump to repository
        if self.__dumpBonds:
            self._dump_to_repository({
                '_BondConstraint__bondsList': self.__bondsList,
                '_BondConstraint__bonds': self.__bonds
            })
            # reset constraint
            self.reset_constraint()