Ejemplo n.º 1
0
    def estimate(self, ic, trajectory, pot_kind='harmonic'): 
    #original
    # def estimate(self, ic, trajectory):
    #SHLL end
        '''
            Method to estimate the FF parameters for the given ic from the given
            perturbation trajectory by fitting a harmonic potential to the
            covalent energy along the trajectory.

            **Arguments**

            ic
                an instance of the class :class:`quickff.ic.IC` defining for
                which ic the FF parameters will be estimated

            trajectory
                a (F,N,3) numpy array defining the perturbation trajectory
                associated to the given ic. It contains F frames of
                (N,3)-dimensional geometry arrays.
        '''
        evaluators = [eval_ic(ic), eval_energy('ai'), eval_energy('ei'), eval_energy('vdw')]
        qs, tot, ei, vdw = self.analyze(trajectory, evaluators)
        #SHLL 1508
        #-- fitting params for spf or harmcos potentials
        pars = fitpar(qs, tot-ei-vdw, rcond=1e-6, pot_kind=pot_kind)
        if pot_kind.lower()=='spf':
            #0.5*k*(1-q0/q)**2+c = 0.5*k+c -k*q0/q +k/2*q0**2/q**2 = c0+c1/q+c2/q**2
            #k=-c1/q0=c1**2/2/c2, q0=-2*c2/c1
            #return pars[1]**2/2/pars[2]/1.889716165**2, -2*pars[2]/pars[1]
            return 2*pars[0], pars[1]
        if pot_kind.lower()=='harmcos':
            return 2*pars[0], pars[1]
        else:
            return 2*pars[0], -pars[1]/(2*pars[0])
Ejemplo n.º 2
0
 def add_plot(xs, ys, prefix, kwargs):
     pars = fitpar(xs, ys, rcond=1e-6)
     k = 2*pars[0]
     if k==0: q0 = np.nan
     else: q0 = -pars[1]/k
     label = '%s (K=%.0f q0=%.3f)' %(prefix, k/parse_unit(self.kunit), q0/parse_unit(self.qunit))
     kwargs['label'] = label
     ax.plot(xs/parse_unit(self.qunit), ys/parse_unit(eunit), **kwargs)
Ejemplo n.º 3
0
 def add_plot(xs, ys, prefix, kwargs):
     pars = fitpar(xs, ys, rcond=1e-6)
     k = 2*pars[0]
     if k==0: q0 = np.nan
     else: q0 = -pars[1]/k
     label = '%s (K=%.0f q0=%.3f)' %(prefix, k/parse_unit(self.kunit), q0/parse_unit(self.qunit))
     kwargs['label'] = label
     ax.plot(xs/parse_unit(self.qunit), ys/parse_unit(eunit), **kwargs)
Ejemplo n.º 4
0
    def estimate(self, trajectory, ai, ffrefs=[], do_valence=False):
        '''
            Method to estimate the FF parameters for the relevant ic from the
            given perturbation trajectory by fitting a harmonic potential to the
            covalent energy along the trajectory.

            **Arguments**

            trajectory
                a Trajectory instance representing the perturbation trajectory

            ai
                an instance of the Reference representing the ab initio input

            **Optional Arguments**

            ffrefs
                a list of Reference instances representing possible a priori
                determined contributions to the force field (such as eg.
                electrostatics and van der Waals)

            do_valence
                If set to True, the current valence force field (stored in
                self.valence) will be used to compute the valence contribution
        '''
        with log.section('PTEST', 3, timer='PT Estimate'):
            term = trajectory.term
            index = term.index
            basename = term.basename
            if 'active' in trajectory.__dict__.keys(
            ) and not trajectory.active:
                log.dump('Trajectory of %s was deactivated: skipping' %
                         (basename))
                return
            qs = trajectory.values.copy()
            AIs = np.zeros(len(trajectory.coords))
            FFs = np.zeros(len(trajectory.coords))
            RESs = np.zeros(len(trajectory.coords))
            for istep, pos in enumerate(trajectory.coords):
                AIs[istep] = ai.energy(pos)
                for ref in ffrefs:
                    FFs[istep] += ref.energy(pos)
            if do_valence:
                fc = self.valence.get_params(index, only='fc')
                rv = self.valence.get_params(index, only='rv')
                self.valence.set_params(index, fc=0.0)
                self.valence.set_params(index, rv0=0.0)
                for istep, pos in enumerate(trajectory.coords):
                    RESs[istep] += self.valence.calc_energy(
                        pos)  #- 0.5*fc*(qs[istep]-rv)**2
                self.valence.set_params(index, fc=fc)
                self.valence.set_params(index, rv0=rv)
            pars = fitpar(qs,
                          AIs - FFs - RESs - min(AIs - FFs - RESs),
                          rcond=-1)
            if pars[0] != 0.0:
                trajectory.fc = 2.0 * pars[0]
                trajectory.rv = -pars[1] / (2.0 * pars[0])
            else:
                trajectory.fc = 0.0
                trajectory.rv = qs[len(qs) / 2]
                log.dump(
                    'force constant of %s is zero: rest value set to middle value'
                    % basename)
            #no negative rest values for all ics except dihedrals and bendcos
            if term.ics[0].kind not in [1, 3, 4, 11]:
                if trajectory.rv < 0:
                    trajectory.rv = 0.0
                    log.dump('rest value of %s was negative: set to zero' %
                             basename)
Ejemplo n.º 5
0
    def estimate(self, trajectory, ai, ffrefs=[], do_valence=False, energy_noise=None, Nerrorsteps=100):
        '''
            Method to estimate the FF parameters for the relevant ic from the
            given perturbation trajectory by fitting a harmonic potential to the
            covalent energy along the trajectory.

            **Arguments**

            trajectory
                a Trajectory instance representing the perturbation trajectory

            ai
                an instance of the Reference representing the ab initio input

            **Optional Arguments**

            ffrefs
                a list of Reference instances representing possible a priori
                determined contributions to the force field (such as eg.
                electrostatics and van der Waals)

            do_valence
                If set to True, the current valence force field (stored in
                self.valence) will be used to compute the valence contribution

            energy_noise
                If set to a float, the parabolic fitting will be repeated
                Nerrorsteps times including normal noise on top of the reference
                value. The mean of the noise is 0, while the std equals the
                number given by energy_noise. The resulting fits give a
                distribution of force  constants and rest values instead of
                single value, the std is used to identify bad estimates, the
                mean is used for the actual FF parametrs. If set to nan, the
                parabolic fit is performed only once without any noise.
        '''
        with log.section('PTEST', 3, timer='PT Estimate'):
            term = trajectory.term
            index = term.index
            basename = term.basename
            if 'active' in list(trajectory.__dict__.keys()) and not trajectory.active:
                log.dump('Trajectory of %s was deactivated: skipping' %(basename))
                return
            qs = trajectory.values.copy()
            AIs = np.zeros(len(trajectory.coords))
            FFs = np.zeros(len(trajectory.coords))
            RESs = np.zeros(len(trajectory.coords))
            for istep, pos in enumerate(trajectory.coords):
                AIs[istep] = ai.energy(pos)
                for ref in ffrefs:
                    FFs[istep] += ref.energy(pos)
            if do_valence:
                fc = self.valence.get_params(index, only='fc')
                rv = self.valence.get_params(index, only='rv')
                self.valence.set_params(index, fc=0.0)
                self.valence.set_params(index, rv0=0.0)
                for istep, pos in enumerate(trajectory.coords):
                    RESs[istep] += self.valence.calc_energy(pos) #- 0.5*fc*(qs[istep]-rv)**2
                self.valence.set_params(index, fc=fc)
                self.valence.set_params(index, rv0=rv)
            pars = fitpar(qs, AIs-FFs-RESs-min(AIs-FFs-RESs), rcond=-1)
            if energy_noise is None:
                if pars[0]>0.0: #!=0.0:
                    trajectory.fc = 2.0*pars[0]
                    trajectory.rv = -pars[1]/(2.0*pars[0])
                else:
                    trajectory.fc = 0.0
                    trajectory.rv = qs[len(qs)//2]
                    log.dump('force constant of %s is not positive: force constant set to zero and rest value set to ab initio equilibrium' %basename)
            else:
                with log.section('PTEST', 4, timer='PT Estimate'):
                    log.dump('Performing noise analysis for trajectory of %s' %basename)
                    As = [pars[0]]
                    Bs = [pars[1]]
                    for i in range(Nerrorsteps):
                        pars = fitpar(qs, AIs-FFs-RESs-min(AIs-FFs-RESs)+np.random.normal(0.0, energy_noise, size=AIs.shape), rcond=-1)
                        As.append(pars[0])
                        Bs.append(pars[1])
                    if 0.0 in As:
                        log.dump('  force constant of zero detected, removing the relevant runs from analysis')
                    Bs = np.array([b for a,b in zip(As,Bs) if a!=0.0])
                    As = np.array([a for a in As if a!=0.0])
                    ks = As*2.0
                    q0s = -Bs/(2.0*As)
                    kunit = trajectory.term.units[0]
                    qunit = trajectory.term.units[1]
                    log.dump('    k  = %8.3f +- %6.3f (noisefree: %8.3f) %s' %(ks.mean()/parse_unit(kunit), ks.std()/parse_unit(kunit), ks[0]/parse_unit(kunit), kunit))
                    log.dump('    q0 = %8.3f +- %6.3f (noisefree: %8.3f) %s' %(q0s.mean()/parse_unit(qunit), q0s.std()/parse_unit(qunit), q0s[0]/parse_unit(qunit), qunit))
                    if q0s.std()/q0s.mean()>0.01:
                        with log.section('PTEST', 3, timer='PT Estimate'):
                            fc, rv = self.valence.get_params(trajectory.term.index)
                            if rv is None:
                                log.dump('Noise on rest value of %s to high, using ab initio rest value' %basename)
                                pars = fitpar(qs, AIs-FFs-RESs-min(AIs-FFs-RESs)+np.random.normal(0.0, energy_noise, size=AIs.shape), rcond=-1)
                                if pars[0]!=0.0:
                                    trajectory.fc = 2.0*pars[0]
                                    trajectory.rv = -pars[1]/(2.0*pars[0])
                                else:
                                    trajectory.fc = 0.0
                                    trajectory.rv = qs[len(qs)//2]
                                    log.dump('AI force constant of %s is zero: rest value set to middle value' %basename)
                            else:
                                log.dump('Noise on rest value of %s to high, using previous value' %basename)
                                trajectory.fc = fc
                                trajectory.rv = rv
                    else:
                        trajectory.fc = ks.mean()
                        trajectory.rv = q0s.mean()
            #no negative rest values for all ics except dihedrals and bendcos
            if term.ics[0].kind not in [1,3,4,11]:
                if trajectory.rv<0:
                    trajectory.rv = 0.0
                    log.dump('rest value of %s was negative: set to zero' %basename)
Ejemplo n.º 6
0
    def estimate(self, trajectory, ai, ffrefs=[], do_valence=False, energy_noise=None, Nerrorsteps=100):
        '''
            Method to estimate the FF parameters for the relevant ic from the
            given perturbation trajectory by fitting a harmonic potential to the
            covalent energy along the trajectory.

            **Arguments**

            trajectory
                a Trajectory instance representing the perturbation trajectory

            ai
                an instance of the Reference representing the ab initio input

            **Optional Arguments**

            ffrefs
                a list of Reference instances representing possible a priori
                determined contributions to the force field (such as eg.
                electrostatics and van der Waals)

            do_valence
                If set to True, the current valence force field (stored in
                self.valence) will be used to compute the valence contribution

            energy_noise
                If set to a float, the parabolic fitting will be repeated
                Nerrorsteps times including normal noise on top of the reference
                value. The mean of the noise is 0, while the std equals the
                number given by energy_noise. The resulting fits give a
                distribution of force  constants and rest values instead of
                single value, the std is used to identify bad estimates, the
                mean is used for the actual FF parametrs. If set to nan, the
                parabolic fit is performed only once without any noise.
        '''
        with log.section('PTEST', 3, timer='PT Estimate'):
            term = trajectory.term
            index = term.index
            basename = term.basename
            if 'active' in list(trajectory.__dict__.keys()) and not trajectory.active:
                log.dump('Trajectory of %s was deactivated: skipping' %(basename))
                return
            qs = trajectory.values.copy()
            AIs = np.zeros(len(trajectory.coords))
            FFs = np.zeros(len(trajectory.coords))
            RESs = np.zeros(len(trajectory.coords))
            for istep, pos in enumerate(trajectory.coords):
                AIs[istep] = ai.energy(pos)
                for ref in ffrefs:
                    FFs[istep] += ref.energy(pos)
            if do_valence:
                fc = self.valence.get_params(index, only='fc')
                rv = self.valence.get_params(index, only='rv')
                self.valence.set_params(index, fc=0.0)
                self.valence.set_params(index, rv0=0.0)
                for istep, pos in enumerate(trajectory.coords):
                    RESs[istep] += self.valence.calc_energy(pos) #- 0.5*fc*(qs[istep]-rv)**2
                self.valence.set_params(index, fc=fc)
                self.valence.set_params(index, rv0=rv)
            pars = fitpar(qs, AIs-FFs-RESs-min(AIs-FFs-RESs), rcond=-1)
            if energy_noise is None:
                if pars[0]!=0.0:
                    trajectory.fc = 2.0*pars[0]
                    trajectory.rv = -pars[1]/(2.0*pars[0])
                else:
                    trajectory.fc = 0.0
                    trajectory.rv = qs[len(qs)//2]
                    log.dump('force constant of %s is zero: rest value set to middle value' %basename)
            else:
                with log.section('PTEST', 4, timer='PT Estimate'):
                    log.dump('Performing noise analysis for trajectory of %s' %basename)
                    As = [pars[0]]
                    Bs = [pars[1]]
                    for i in range(Nerrorsteps):
                        pars = fitpar(qs, AIs-FFs-RESs-min(AIs-FFs-RESs)+np.random.normal(0.0, energy_noise, size=AIs.shape), rcond=-1)
                        As.append(pars[0])
                        Bs.append(pars[1])
                    if 0.0 in As:
                        log.dump('  force constant of zero detected, removing the relevant runs from analysis')
                    Bs = np.array([b for a,b in zip(As,Bs) if a!=0.0])
                    As = np.array([a for a in As if a!=0.0])
                    ks = As*2.0
                    q0s = -Bs/(2.0*As)
                    kunit = trajectory.term.units[0]
                    qunit = trajectory.term.units[1]
                    log.dump('    k  = %8.3f +- %6.3f (noisefree: %8.3f) %s' %(ks.mean()/parse_unit(kunit), ks.std()/parse_unit(kunit), ks[0]/parse_unit(kunit), kunit))
                    log.dump('    q0 = %8.3f +- %6.3f (noisefree: %8.3f) %s' %(q0s.mean()/parse_unit(qunit), q0s.std()/parse_unit(qunit), q0s[0]/parse_unit(qunit), qunit))
                    if q0s.std()/q0s.mean()>0.01:
                        with log.section('PTEST', 3, timer='PT Estimate'):
                            fc, rv = self.valence.get_params(trajectory.term.index)
                            if rv is None:
                                log.dump('Noise on rest value of %s to high, using ab initio rest value' %basename)
                                pars = fitpar(qs, AIs-FFs-RESs-min(AIs-FFs-RESs)+np.random.normal(0.0, energy_noise, size=AIs.shape), rcond=-1)
                                if pars[0]!=0.0:
                                    trajectory.fc = 2.0*pars[0]
                                    trajectory.rv = -pars[1]/(2.0*pars[0])
                                else:
                                    trajectory.fc = 0.0
                                    trajectory.rv = qs[len(qs)//2]
                                    log.dump('AI force constant of %s is zero: rest value set to middle value' %basename)
                            else:
                                log.dump('Noise on rest value of %s to high, using previous value' %basename)
                                trajectory.fc = fc
                                trajectory.rv = rv
                    else:
                        trajectory.fc = ks.mean()
                        trajectory.rv = q0s.mean()
            #no negative rest values for all ics except dihedrals and bendcos
            if term.ics[0].kind not in [1,3,4,11]:
                if trajectory.rv<0:
                    trajectory.rv = 0.0
                    log.dump('rest value of %s was negative: set to zero' %basename)
Ejemplo n.º 7
0
    def plot(self, ic, trajectory, filename, eunit='kjmol'):
        '''
            Method to plot the energy contributions along a perturbation
            trajectory associated to a given ic.

            **Arguments**

            ic
                an instance of the class :class:`quickff.ic.IC` defining for
                which ic the plot will be made.

            trajectory
                a (F,N,3) numpy array defining the perturbation trajectory
                associated to the given ic. It contains F frames of
                (N,3)-dimensional geometry arrays.

            filename
                a string defining the name of the figure

            **Optional Arguments**

            eunit
                a string describing the conversion of the unit of energy. More
                info regarding possible strings can be found in the
                `MolMod documentation <http://molmod.github.io/molmod/reference/const.html#module-molmod.units>`_.
        '''
        import matplotlib.pyplot as pp
        evaluators = [eval_ic(ic), eval_energy('ai'), eval_energy('ei'), eval_energy('vdw')]
        qs, tot, ei, vdw = self.analyze(trajectory, evaluators)
        label = {}
        for (name, obs) in zip(['ai', 'ei', 'vdw', 'cov'], [tot, ei, vdw, tot-ei-vdw]):
            pars = fitpar(qs, obs, rcond=1e-6)
            k = 2*pars[0]
            if k != 0.0:
                q0 = -0.5*pars[1]/pars[0]
                label[name] = '(K=%.0f q0=%.3f)' %(
                    k/parse_unit(ic.kunit),
                    q0/parse_unit(ic.qunit)
                )
            else:
                label[name] = '(K=0.0 q0=None)'
            if name=='cov':
                cov = (pars[0]*qs**2+pars[1]*qs+pars[2])
        fig, ax = pp.subplots()
        ax.plot(
            qs/parse_unit(ic.qunit), tot/parse_unit(eunit),
            'k--', linewidth=4, label='AI total %s' %label['ai']
        )
        ax.plot(
            qs/parse_unit(ic.qunit), ei/parse_unit(eunit),
            'b--', linewidth=2, label='FF elec  %s' %label['ei']
        )
        ax.plot(
            qs/parse_unit(ic.qunit), vdw/parse_unit(eunit),
            'g--', linewidth=2, label='FF vdW   %s' %label['vdw']
        )
        ax.plot(
            qs/parse_unit(ic.qunit), cov/parse_unit(eunit),
            'r-', linewidth=2, label='FF cov   %s' %label['cov']
        )
        ax.set_title(ic.name)
        ax.set_xlabel('%s [%s]' % (ic.name.split('/')[0], ic.qunit), fontsize=16)
        ax.set_ylabel('Energy [%s]' %eunit, fontsize=16)
        ax.grid()
        ax.legend(loc='best', fontsize=16)
        fig.set_size_inches([8, 8])
        fig.savefig(filename)