示例#1
0
    def get_constraints(self,step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i+1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i+1,j+1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance, step, 12)
            for dih in range(len(self.instance)-4): #do not include hydrogen atom
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step < 22:
            for dih in range(len(self.instance)-3):  
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                release.append(constraint)

            fvals = [2.0,1.4,1.3,1.8,1.3]
            val1 = geometry.new_bond_length(self.species,self.instance[0],self.instance[-2],step-11,10,fvals[0],geom)
            constraint1 = [self.instance[0] + 1,self.instance[-2] + 1,val1]
            change.append(constraint1)
            val2 = geometry.new_bond_length(self.species,self.instance[0],self.instance[1],step-11,10,fvals[1],geom)
            constraint2 = [self.instance[0] + 1,self.instance[1] + 1,val2]
            change.append(constraint2)
            val3 = geometry.new_bond_length(self.species,self.instance[1],self.instance[-1],step-11,10,fvals[2],geom)
            constraint3 = [self.instance[1] + 1,self.instance[-1] + 1,val3]
            change.append(constraint3)
            val4 = geometry.new_bond_length(self.species,self.instance[0],self.instance[-1],step-11,10,fvals[3],geom)
            constraint4 = [self.instance[0] + 1,self.instance[-1] + 1,val4]
            change.append(constraint4)
            val5 = geometry.new_bond_length(self.species,self.instance[-1],self.instance[-2],step-11,10,fvals[4],geom)
            constraint5 = [self.instance[-1] + 1,self.instance[-2] + 1,val5]
            change.append(constraint5)
        
        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i,fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]

        return step, fix, change, release
示例#2
0
 def testNewRingDihedrals(self):
     """
     Test the calculation of new dihedrals necessary for the update
     """
     smi = 'CCCC'
     mol = StationaryPoint(smi, 0, 1, smiles=smi)
     mol.characterize()
     ins = [0, 1, 2, 3]  # change the C-C-C-C dihedral
     step_nr = 0  # This corresponds to the first dihedral update
     # there are 12 steps done in total, this means that the dihedral
     # angle should be changed by 1/10 of the total change
     total_nr_of_steps = 10
     # final dihedral value we are shooting for after 10 updates
     # this is a default value for a instance of 5 or less atoms
     final_val = 15.
     # initial dihedral
     ini = geometry.calc_dihedral(mol.geom[ins[0]],
                                  mol.geom[ins[1]],
                                  mol.geom[ins[2]],
                                  mol.geom[ins[3]])[0]
     # this is the new dihedral angle after one step
     update = geometry.new_ring_dihedrals(mol, ins, step_nr,
                                          total_nr_of_steps)
     exp = ini - (ini - final_val) / 10
     cal = update[0]
     warn = 'Dihedral update is not correct: '
     warn += 'expected {}, calculated {}'.format(exp, cal)
     self.assertEqual(exp, cal, msg=warn)
示例#3
0
 def set_dihedrals(self, change, step, cut=0):
     new_dihs = geometry.new_ring_dihedrals(self.species, self.instance,
                                            step, self.dihstep)
     for dih in range(len(self.instance) - 3 - cut):
         constraint = []
         for i in range(4):
             constraint.append(self.instance[dih + i] + 1)
         constraint.append(new_dihs[dih])
         change.append(constraint)
示例#4
0
 def set_dihedrals(self, change, step, cut=0):
     for lin in self.linear:
         for i in range(len(self.instance)):
             if all(np.roll(self.instance, i)[0:3] == lin):
                 self.set_angle_single(lin[0], lin[1], lin[2], 170., change)
     new_dihs = geometry.new_ring_dihedrals(self.species, self.instance,
                                            step, self.dihstep)
     for dih in range(len(self.instance) - 3 - cut):
         constraint = []
         for i in range(4):
             constraint.append(self.instance[dih + i] + 1)
         constraint.append(new_dihs[dih])
         change.append(constraint)
    def get_constraints(self, step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i + 1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i + 1, j + 1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance,
                                                   step, 12)
            for dih in range(len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step == 12:
            if len(self.instance) > 3:
                for dih in range(len(self.instance) - 3):
                    f = []
                    for i in range(4):
                        f.append(self.instance[dih + i] + 1)
                    fix.append(f)
                for angle in range(len(self.instance) - 2):
                    constraint = []
                    for i in range(3):
                        constraint.append(self.instance[angle + i] + 1)
                    constraint.append(180. * (len(self.instance) - 2.) /
                                      len(self.instance))
                    change.append(constraint)
        elif step == 13:
            for angle in range(len(self.instance) - 2):
                constraint = []
                for i in range(3):
                    constraint.append(self.instance[angle + i] + 1)
                release.append(constraint)
            for dih in range(len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                release.append(constraint)

            if len(self.instance) > 4:
                fval = 2.2
            else:
                fval = 2.0
            constraint = [self.instance[0] + 1, self.instance[-1] + 1, fval]
            change.append(constraint)

        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i, fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]

        return step, fix, change, release
示例#6
0
    def get_constraints(self, step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i + 1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i + 1, j + 1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance,
                                                   step, 12, geom)
            for dih in range(len(self.instance) -
                             4):  # do not include last atom
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
            ldih = [
            ]  # constraint for the last dihedral, which needs to be 180 degrees
            for i in range(4):
                ldih.append(self.instance[len(self.instance) - 4 + i] + 1)
            dih = geometry.calc_dihedral(geom[ldih[0] - 1], geom[ldih[1] - 1],
                                         geom[ldih[2] - 1],
                                         geom[ldih[3] - 1])[0]
            frac = 1. / (12. - step)
            if dih < 0:
                new_dih = dih - frac * (180. + dih)
                ldih.append(new_dih)
            else:
                new_dih = dih + frac * (180. - dih)
                ldih.append(new_dih)
            change.append(ldih)
        elif step < 22:
            for dih in range(len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                release.append(constraint)

            fdist1 = constants.st_bond[''.join(
                sorted(self.species.atom[self.instance[0]] +
                       self.species.atom[self.instance[-2]]))] * 1.0
            if ''.join(
                    sorted(self.species.atom[self.instance[0]] +
                           self.species.atom[self.instance[-2]])) == 'CO':
                fdist1 = 1.68
            ndist1 = geometry.new_bond_length(self.species, self.instance[0],
                                              self.instance[-2], step - 11, 10,
                                              fdist1, geom)
            constraint = [self.instance[0] + 1, self.instance[-2] + 1, ndist1]
            change.append(constraint)

            fdist2 = constants.st_bond[''.join(
                sorted(self.species.atom[self.instance[-1]] +
                       self.species.atom[self.instance[-2]]))] * 1.0
            if ''.join(
                    sorted(self.species.atom[self.instance[-1]] +
                           self.species.atom[self.instance[-2]])) == 'CO':
                fdist2 = 1.68
            ndist2 = geometry.new_bond_length(self.species, self.instance[-1],
                                              self.instance[-2], step - 11, 10,
                                              fdist2, geom)
            constraint = [self.instance[-1] + 1, self.instance[-2] + 1, ndist2]
            change.append(constraint)

        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i, fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]

        return step, fix, change, release
示例#7
0
    def get_constraints(self,step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i+1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i+1,j+1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance, step, 12)
            for dih in range(len(self.instance)-3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step < 22:
            for dih in range(len(self.instance)-3):  
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                release.append(constraint)
                
            fval = [2.0,1.3,2.0,2.0]
            
            if self.species.atom[self.instance[-1]] == 'H':
                fval[2] = 1.35
                fval[3] = 1.35
            
            val = geometry.new_bond_length(self.species,self.instance[0],self.instance[1],step - 11,10,fval[0],geom)
            constraint = [self.instance[0] + 1,self.instance[1] + 1,val]
            change.append(constraint)
            
            val = geometry.new_bond_length(self.species,self.instance[1],self.instance[2],step - 11,10,fval[1],geom)
            constraint = [self.instance[1] + 1,self.instance[2] + 1,val]
            change.append(constraint)
            
            val = geometry.new_bond_length(self.species,self.instance[2],self.instance[3],step - 11,10,fval[2],geom)
            constraint = [self.instance[2] + 1,self.instance[3] + 1,val]
            change.append(constraint)
            
            val = geometry.new_bond_length(self.species,self.instance[3],self.instance[0],step - 11,10,fval[3],geom)
            constraint = [self.instance[3] + 1,self.instance[0] + 1,val]
            change.append(constraint)

        
        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i,fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]
        
        return step, fix, change, release
示例#8
0
    def get_constraints(self, step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i + 1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i + 1, j + 1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance,
                                                   step, 12)
            for dih in range(len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step < 22:
            for dih in range(len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                release.append(constraint)

            fval = [2.0, 1.45, 2.0, 2.0]
            if self.species.atom[self.instance[0]] == 'H':
                fval[0] = 1.3
                fval[3] = 1.3

            val = geometry.new_bond_length(self.species, self.instance[0],
                                           self.instance[1], step - 11, 10,
                                           fval[0], geom)
            constraint = [self.instance[0] + 1, self.instance[1] + 1, val]
            change.append(constraint)

            val = geometry.new_bond_length(self.species, self.instance[1],
                                           self.instance[2], step - 11, 10,
                                           fval[1], geom)
            constraint = [self.instance[1] + 1, self.instance[2] + 1, val]
            change.append(constraint)

            val = geometry.new_bond_length(self.species, self.instance[2],
                                           self.instance[3], step - 11, 10,
                                           fval[2], geom)
            constraint = [self.instance[2] + 1, self.instance[3] + 1, val]
            change.append(constraint)

            val = geometry.new_bond_length(self.species, self.instance[3],
                                           self.instance[0], step - 11, 10,
                                           fval[3], geom)
            constraint = [self.instance[3] + 1, self.instance[0] + 1, val]
            change.append(constraint)

        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i, fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]

        return step, fix, change, release
    def get_constraints(self,step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i+1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i+1,j+1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance, step, 12)
            for dih in range(len(self.instance)-3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step == 12:
            if len(self.instance) > 3:
                for dih in range(len(self.instance)-3):
                    f = []
                    for i in range(4):
                        f.append(self.instance[dih+i] + 1)
                    fix.append(f)
                for angle in range(len(self.instance)-2):
                    constraint = []
                    for i in range(3):
                        constraint.append(self.instance[angle+i] + 1)
                    constraint.append(180. * (len(self.instance)-2.) / len(self.instance))
                    change.append(constraint)
        elif step == 13:
            for angle in range(len(self.instance)-2):
                constraint = []
                for i in range(3):
                    constraint.append(self.instance[angle+i] + 1)
                release.append(constraint)
            for dih in range(len(self.instance)-3):  
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                release.append(constraint)
            
            
            if len(self.instance) > 3:
                fval = 1.8
            else:
                fval = 1.5

            constraint = [self.instance[0] + 1,self.instance[-1] + 1,fval]
            change.append(constraint)

        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i,fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]
        
        return step, fix, change, release
示例#10
0
    def get_constraints(self, step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i + 1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i + 1, j + 1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance,
                                                   step, 12)
            for dih in range(len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step < 22:
            for dih in range(1, len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                release.append(constraint)
            first_dih = [self.instance[i] + 1 for i in range(4)]
            if step < 18:  # make sure that the forming double bond stays in trans instead of moving to cis
                fix.append(first_dih)
            else:
                release.append(first_dih)

            fval = 2.2
            val = geometry.new_bond_length(self.species, self.instance[0],
                                           self.instance[-1], step - 11, 10,
                                           fval, geom)
            constraint = [self.instance[0] + 1, self.instance[-1] + 1, val]
            change.append(constraint)

            fval = 1.8
            val = geometry.new_bond_length(self.species, self.instance[-2],
                                           self.instance[3], step - 11, 10,
                                           fval, geom)
            constraint = [self.instance[-2] + 1, self.instance[3] + 1, val]
            change.append(constraint)

        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i, fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]

        return step, fix, change, release

        step += submit_qc(self.instance_name, 0)

        return step
示例#11
0
    def get_constraints(self,step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i+1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i+1,j+1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance, step, 12)
            for dih in range(len(self.instance)-3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step < 22:
            for dih in range(1,len(self.instance)-3):  
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                release.append(constraint)
            first_dih = [ self.instance[i]+1 for i in range(4)]
            if step < 18: # make sure that the forming double bond stays in trans instead of moving to cis
                fix.append(first_dih)
            else:
                release.append(first_dih)

            fval = 2.2
            val = geometry.new_bond_length(self.species,self.instance[0],self.instance[-1],step-11,10,fval,geom)
            constraint = [self.instance[0] + 1,self.instance[-1] + 1,val]
            change.append(constraint)
            
            fval = 1.8
            val = geometry.new_bond_length(self.species,self.instance[-2],self.instance[3],step-11,10,fval,geom)
            constraint = [self.instance[-2] + 1,self.instance[3] + 1,val]
            change.append(constraint)

        
        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i,fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]
        
        return step, fix, change, release

       
        step += submit_qc(self.instance_name, 0)
        
        return step
    def __init__(self,species,qc,par,instance,instance_name):
        #st_pt of the reactant
        self.species = species
        #st_pt of the ts
        self.ts = None
        #st_pt of the product(s)
        self.products = []
        #bond matrix of the products
        self.product_bonds = [] 
        
        #optimization objects
        self.ts_opt = None
        self.prod_opt = []
        
        self.qc = qc
        self.par = par
        
        #indices of the reactive atoms
        self.instance = instance
        #name of the reaction
        self.instance_name = instance_name
        
        #maximum number of steps for this reaction family
        self.max_step = 22
        #do a scan?
        self.scan = 0
        #skip the first 12 steps in case the instance has a length of 3?
        self.skip = 0

        def get_constraints(self,step, geom):
            """
            There are three types of constraints:
            1. fix a coordinate to the current value
            2. change a coordinate and fix is to the new value
            3. release a coordinate (only for gaussian)
            """
            fix = []
            change = []
            release = []
            if step < self.max_step:
                #fix all the bond lengths
                for i in range(self.species.natom - 1):
                    for j in range(i+1, self.species.natom):
                        if self.species.bond[i][j] > 0:
                            fix.append([i+1,j+1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance, step, 12)
            for dih in range(len(self.instance)-3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step < 22:
            for dih in range(len(self.instance)-3):  
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                release.append(constraint)
                
            fval = 1.35

            val = geometry.new_bond_length(self.species,self.instance[0],self.instance[-1],step-11,10,fval,geom)
            constraint = [self.instance[0] + 1,self.instance[-1] + 1,val]
            change.append(constraint)
            
            val = geometry.new_bond_length(self.species,self.instance[-2],self.instance[-1],step-11,10,fval,geom)
            constraint = [self.instance[-2] + 1,self.instance[-1] + 1,val]
            change.append(constraint)

        
        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i,fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]
        
        return step, fix, change, release
    def __init__(self, species, qc, par, instance, instance_name):
        #st_pt of the reactant
        self.species = species
        #st_pt of the ts
        self.ts = None
        #st_pt of the product(s)
        self.products = []
        #bond matrix of the products
        self.product_bonds = []

        #optimization objects
        self.ts_opt = None
        self.prod_opt = []

        self.qc = qc
        self.par = par

        #indices of the reactive atoms
        self.instance = instance
        #name of the reaction
        self.instance_name = instance_name

        #maximum number of steps for this reaction family
        self.max_step = 22
        #do a scan?
        self.scan = 0
        #skip the first 12 steps in case the instance has a length of 3?
        self.skip = 0

        def get_constraints(self, step, geom):
            """
            There are three types of constraints:
            1. fix a coordinate to the current value
            2. change a coordinate and fix is to the new value
            3. release a coordinate (only for gaussian)
            """
            fix = []
            change = []
            release = []
            if step < self.max_step:
                #fix all the bond lengths
                for i in range(self.species.natom - 1):
                    for j in range(i + 1, self.species.natom):
                        if self.species.bond[i][j] > 0:
                            fix.append([i + 1, j + 1])

        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance,
                                                   step, 12)
            for dih in range(len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
        elif step < 22:
            for dih in range(len(self.instance) - 3):
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih + i] + 1)
                release.append(constraint)

            fval = 1.35

            val = geometry.new_bond_length(self.species, self.instance[0],
                                           self.instance[-1], step - 11, 10,
                                           fval, geom)
            constraint = [self.instance[0] + 1, self.instance[-1] + 1, val]
            change.append(constraint)

            val = geometry.new_bond_length(self.species, self.instance[-2],
                                           self.instance[-1], step - 11, 10,
                                           fval, geom)
            constraint = [self.instance[-2] + 1, self.instance[-1] + 1, val]
            change.append(constraint)

        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i, fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]

        return step, fix, change, release
    def get_constraints(self,step, geom):
        """
        There are three types of constraints:
        1. fix a coordinate to the current value
        2. change a coordinate and fix is to the new value
        3. release a coordinate (only for gaussian)
        """
        fix = []
        change = []
        release = []
        if step < self.max_step:
            #fix all the bond lengths
            for i in range(self.species.natom - 1):
                for j in range(i+1, self.species.natom):
                    if self.species.bond[i][j] > 0:
                        fix.append([i+1,j+1])
        if step < 12:
            new_dihs = geometry.new_ring_dihedrals(self.species, self.instance, step, 12,geom)
            for dih in range(len(self.instance)-4): # do not include last atom
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                constraint.append(new_dihs[dih])
                change.append(constraint)
            ldih = [] # constraint for the last dihedral, which needs to be 180 degrees    
            for i in range(4):
                ldih.append(self.instance[len(self.instance)-4+i] + 1)
            dih = geometry.calc_dihedral(geom[ldih[0] - 1], geom[ldih[1] - 1], geom[ldih[2] - 1], geom[ldih[3] - 1])[0]
            frac = 1./(12. - step)
            if dih < 0:
                new_dih = dih - frac * (180. + dih) 
                ldih.append(new_dih)
            else:
                new_dih = dih + frac * (180. - dih) 
                ldih.append(new_dih)
            change.append(ldih)
        elif step < 22:
            for dih in range(len(self.instance)-3):  
                constraint = []
                for i in range(4):
                    constraint.append(self.instance[dih+i] + 1)
                release.append(constraint)

            fdist1 = constants.st_bond[''.join(sorted(self.species.atom[self.instance[0]]+self.species.atom[self.instance[-2]]))]*1.0
            if ''.join(sorted(self.species.atom[self.instance[0]]+self.species.atom[self.instance[-2]])) == 'CO':
                fdist1 = 1.68
            ndist1 = geometry.new_bond_length(self.species,self.instance[0],self.instance[-2],step - 11 ,10,fdist1,geom)
            constraint = [self.instance[0] + 1,self.instance[-2] + 1,ndist1]
            change.append(constraint)
            
            fdist2 = constants.st_bond[''.join(sorted(self.species.atom[self.instance[-1]]+self.species.atom[self.instance[-2]]))]*1.0
            if ''.join(sorted(self.species.atom[self.instance[-1]]+self.species.atom[self.instance[-2]])) == 'CO':
                fdist2 = 1.68
            ndist2 = geometry.new_bond_length(self.species,self.instance[-1],self.instance[-2],step - 11 ,10,fdist2,geom)
            constraint = [self.instance[-1] + 1,self.instance[-2] + 1,ndist2]
            change.append(constraint)

        #remove the bonds from the fix if they are in another constaint
        for c in change:
            if len(c) == 3:
                index = -1
                for i,fi in enumerate(fix):
                    if len(fi) == 2:
                        if sorted(fi) == sorted(c[:2]):
                            index = i
                if index > -1:
                    del fix[index]
        
        return step, fix, change, release