Example #1
0
def add_path(targets,dpath,dctc,dtesLL,lts,mod=False):
    set_completer(2)
    # defaults
    if "*" in targets or targets == []:
        if mod: targets = dpath.keys()
        else  : targets = lts
    targets = [target for target in targets if target in lts]
    # no targets? Finish
    if len(targets) == 0: return dpath, dtesLL
    # Generate PathVars object for all of them
    for target in targets:
        ctc, itc = PN.name2data(target)
        if ctc not in dctc.keys(): return dpath, dtesLL
        if mod and (ctc in dpath.keys()): continue
        if ctc in dpath.keys(): continue
        dpath[ctc] = PathVars("mep")
        # get fwdir (this may take some time...)
        gtsfile = dctc[ctc].gtsfiles()[0]
        try   : fwdir = calc_fwdir(gtsfile)
        except: continue
        dpath[ctc]._fwdir = fwdir
    # print path(s)
    ls_path(dpath,targets)
    # modify them
    while True:
          try:
            line = input(ILINE2).strip()
            if line.split()[0] in END: break
            if "=" not in line:
                line = line.split()
            else:
                line = [ string.strip() for string in line.split("=")]
            if len(line) != 2: raise Exception
            var, val = line
            var = var.lower()
            if var not in ["sbw","sfw","ds","hsteps","paral","scterr","sctmns"]: raise Exception
            for target in targets:
                dpath[target].setvar(var,val)
          except KeyboardInterrupt:
            print("")
            break
          except:
            print(IBLANK2+"invalid line...")
            print("")
            ls_path(dpath,targets)
            continue
          # print 
          ls_path(dpath,targets)
    # update dtesLL
    for ctc in dpath.keys():
        try   : ch,mtp = dctc[ctc]._ch, dctc[ctc]._mtp
        except: ch,mtp = 0, 1
        # templates by default
        default_templates = get_templates(ch,mtp,"LL")
        # add default?
        for software,string in default_templates.items():
            dtesLL[software] = dtesLL.get(software,{})
            if ctc in dtesLL[software].keys(): continue
            dtesLL[software][ctc] = string
    return dpath, dtesLL
Example #2
0
def get_itargets(targets, dpath, dctc):
    '''
    get individual targets
    '''
    # Targets?
    if (len(targets) == 0) or ("*" in targets): targets = dpath.keys()

    # generate list of individual targets
    itargets = []
    for target in targets:
        ctc, itc = PN.name2data(target)
        # check ctc
        if ctc not in dctc.keys():
            fncs.print_string("* '%s' not in '%s'" % (target, PN.IFILE1), 3)
            print("")
            continue
        if ctc not in dpath.keys():
            fncs.print_string("* '%s' not in '%s'" % (target, PN.IFILE3), 3)
            print("")
            continue
        # list of itcs for the ctc
        itclist = [itc_i for itc_i, weight_i in dctc[ctc]._itcs]
        # add itc
        if itc is None:
            itargets += [
                PN.struckey(ctc, itc) for itc, weight in dctc[ctc]._itcs
            ]
        elif itc in itclist:
            itargets += [PN.struckey(ctc, itc)]
    return sorted(itargets)
Example #3
0
      def prepare_qrc(self,dchem,dctc,dimasses):
          '''
          also modifies self._qrccase:
              self._qrccase == 0: everything is ok / qrc is not activated
              self._qrccase == 1: no reaction is associated to the TS
              self._qrccase == 2: reaction is not unimolecular
              self._qrccase == 3: ctc for reactant not defined
              self._qrccase == 4: gts file for reactant not found
              self._qrccase == 5: unable to get energy of products
          '''

          # Will qrc be used?
          if self._qrc      is None: return
          if self._reaction is None: self._qrccase = 1; return
          # assert unimolecular
          reactants = dchem[self._reaction][0]
          products  = dchem[self._reaction][2]
          if self._exorgic:
             if len(reactants) != 1: self._qrccase = 2; return
             self._qrcname = reactants[0]
          else:
             if len(products ) != 1: self._qrccase = 2; return
             self._qrcname = products[0]
          if self._V1P is None: self._qrccase = 5; return
          #---------------------------------#
          # Now, generate Molecule instance #
          #---------------------------------#
          ctc, itc = PN.name2data(self._qrcname)
          if ctc not in dctc.keys(): self._qrccase = 3; return
          cluster = dctc[ctc]
          if itc is None: itc = cluster._itcs[0][0]
          if   itc in cluster._diso.keys(): imods = cluster._diso[itc]
          elif "*" in cluster._diso.keys(): imods = cluster._diso["*"]
          else                            : imods = None
          gtsfile = dctc[ctc].gtsfile(itc)
          if not os.path.exists(gtsfile): self._qrccase = 4; return
          # Generate Molecule instance
          molecule = Molecule()
          molecule.set_from_gts(gtsfile)
          # apply fscal
          molecule.setvar(fscal=cluster._fscal)
          # apply isotopic masses
          if imods is not None:
             molecule.apply_imods(imods,dimasses)
          # calculate frequencies
          molecule.setup()
          #------------------------------#
          # Prepare list of QRC energies #
          #------------------------------#
          mode , nE      = self._qrc
          self._qrcafreq = molecule._ccfreqs[mode]
          self._qrclE    = [n*HBAR*self._qrcafreq for n in range(nE)]
Example #4
0
def get_masses(target, dctc, dimasses):
    ctc, itc = PN.name2data(target)
    diso = dctc[ctc]._diso
    if itc in diso.keys(): imod = diso[itc]
    elif "*" in diso.keys(): imod = diso["*"]
    else: imod = None
    if imod is None: return None
    gtsTS = dctc[ctc].gtsfile(itc)
    TS = Molecule()
    TS.set_from_gts(gtsTS)
    TS.apply_imods(imod, dimasses)
    masses = list(TS._masses)
    return masses
Example #5
0
def get_itcs(target,dctc):
    if target is None: return None
    # ctc and itc name
    ctc, itc = PN.name2data(target)
    # multi-structural? (True even with one conformer if itc is not defined)
    if itc is None: ms = True
    else          : ms = False
    # list of itcs
    if   itc is not None   : itcs = [(itc,1)]
    elif ctc in dctc.keys(): itcs = list(dctc[ctc]._itcs)
    else                   : itcs = None
    # save data?
    return ctc,itcs,ms
Example #6
0
def execute_pfn(itargets, dchem, idata, status, case):
    reactions = set([])
    for target in itargets:
        ctc1, itc1 = PN.name2data(target)
        the_reaction = None
        for reaction, (Rs, TS, Ps) in dchem.items():
            try:
                ctc2, itc2 = PN.name2data(TS)
            except:
                continue
            if ctc1 == ctc2:
                the_reaction = reaction
                if itc1 == itc2: break
        if the_reaction is not None: reactions.add(the_reaction)
    if len(reactions) == 0: return
    reactions = sorted(list(reactions))

    fncs.print_string(
        "The selected transitions states are involved in defined reactions!",
        3)
    pfn_targets = set([])
    for reaction in reactions:
        fncs.print_string("* %s" % reaction, 6)
        Rs, TS, Ps = dchem[reaction]
        for xx in Rs + [TS] + Ps:
            pfn_targets.add(PN.name2data(xx)[0])
    if len(pfn_targets) == 0: return
    pfn_targets = sorted(list(pfn_targets))
    print("")

    import opt_pfn as pfn
    fncs.print_string("Calculating partition functions for the next targets:",
                      3)
    for target in pfn_targets:
        fncs.print_string("* %s" % target, 6)
    print("")
    pfn.main(idata, status, case, targets=pfn_targets)
Example #7
0
def calc_mep(itarget, gtsTS, pathvars, tsoftware, TMP):
    # data in name
    ctc, itc = PN.name2data(itarget)
    # Low-Level
    if pathvars._dlevel is None:
        tcommon, drst, pathvars = obtain_mep(itarget, gtsTS, pathvars,
                                             tsoftware, TMP)
        fncs.print_string(PS.smep_table(drst, pathvars._eref), 4)
    # Dual-Level
    else:
        rstfile = PN.get_rst(ctc, itc)
        xyzfile = PN.get_rstxyz(ctc, itc)
        software, tes = tsoftware
        fncs.print_string(PS.smep_init(itarget,software,pathvars._paral,pathvars.tuple_first(),\
                     pathvars.tuple_sdbw(),pathvars.tuple_sdfw()),4)
        fncs.print_string(PS.smep_ff(TMP, PN.DIR4, PN.DIR5, rstfile, xyzfile),
                          4)

        # read rst
        tpath, tcommon, drst = ff.read_rst(rstfile)
        fncs.print_string(PS.smep_rst(rstfile, drst), 4)

        fncs.print_string("Applying Dual-Level...", 4)
        print("")
        dlevel_xy = [(find_label_in_rst(x, drst)[0], y)
                     for x, y in pathvars._dlevel.items()]
        dlevel_xy = [(x, y) for x, y in dlevel_xy if x is not None]
        # Print points (sorted by s value)
        dummy = [(drst[xx][0], idx) for idx, (xx, yy) in enumerate(dlevel_xy)]
        dummy.sort()
        for s_i, idx_i in dummy:
            xx_i, yy_i = dlevel_xy[idx_i]
            fncs.print_string(
                "%+8.4f bohr (%-6s) --> %.7f hartree" % (s_i, xx_i, yy_i), 13)
        print("")
        # interpolation
        drst, points, xx, yyll, yyhl = ispe.ispe(tcommon,
                                                 drst,
                                                 dlevel_xy,
                                                 tension=0.0)
        tdleveldata = (points, xx, yyll, yyhl)
        # table new values
        fncs.print_string(
            PS.smep_tableDLEVEL(drst, tdleveldata, pathvars._eref), 4)
    return tcommon, drst, pathvars
Example #8
0
 def set_eref_from_reaction(self,tsname,dchem,dof):
     thebool = self._eref in [None,"auto","default"]
     ctc, itc = PN.name2data(tsname)
     # Get data from reactions
     rname, V0R, V0P, V1R, V1P, GibbsR = get_reaction_energies(tsname,dchem,dof)
     self._V1R = V1R
     self._V1P = V1P
     if None not in (self._V1R,self._V1P) and self._V1P > self._V1R: self._exorgic = False
     # save GibbsR for CVT gibbs
     self._GibbsR = GibbsR
     # go case by case
     if thebool and V0R is not None: self._eref = V0R
     # save reaction name and check if beyond mep
     self._reaction = rname
     if self._eref in [None,"auto","default"]: self._beyondmep = False
     try:
         Rs,TS,Ps = dchem[self._reaction]
         self._reactioneq = '%s --> %s --> %s'%("+".join(Rs),TS,"+".join(Ps))
     except: self._reactioneq = None
Example #9
0
    def __init__(self, rcname, reacts, ts, prods, ltemp, dctc):

        # save input data
        self._rcname = rcname
        self._ltemp = ltemp
        self._beta = 1.0 / (np.array(ltemp) * KB)
        self._reacts = reacts
        self._ts = ts
        self._prods = prods

        #---------------------------------------#
        # Some basic operations with input data #
        #---------------------------------------#

        remove = []
        self._itcs = {}
        self._gtsfile = {}  # name of gts files
        self._anhfile = {}  # name of anh files
        self._disos = {}  # isotopic modifications
        self._weight = {}
        for target in self._reacts + [self._ts] + self._prods:
            ctc, itcs, ms = None, None, None
            # get itcs
            if target is not None:
                ctc, itc = PN.name2data(target)
                # list of itcs
                if itc is not None: itcs = [(itc, 1)]
                elif ctc in dctc.keys(): itcs = list(dctc[ctc]._itcs)
                else: itcs = None
                # multi-structural?
                ms = itc is None  # (True also with 1 conformer if itc is None)
            # itcs NOT found
            if itcs is None:
                remove.append(target)
                continue
            # save data
            self._anhfile[ctc] = dctc[ctc]._anh
            self._disos[ctc] = dctc[ctc]._diso
            self._itcs[target] = (ctc, itcs, ms)
            for itc, weight in itcs:
                self._weight[(ctc, itc)] = weight
                self._gtsfile[(ctc, itc)] = dctc[ctc].gtsfile(itc)

        # clean up
        self._reacts = [
            target for target in self._reacts if target not in remove
        ]
        self._prods = [
            target for target in self._prods if target not in remove
        ]
        if self._ts in remove: self._ts = None

        # number of reactants/product and correction weight
        self._nR, self._wfw = len(self._reacts), 1
        self._nP, self._wbw = len(self._prods), 1
        if self._nR == 2 and self._reacts[0] == self._reacts[1]: self._wfw = 2
        if self._nP == 2 and self._prods[0] == self._prods[1]: self._wbw = 2

        #------------------------------#
        # initialize rest of variables #
        #------------------------------#
        self._dall = {}
        self._massch = {}

        self._massR = 0.0
        self._massTS = 0.0
        self._massP = 0.0
        self._chR = 0
        self._chTS = 0
        self._chP = 0

        self._V0R = 0.0
        self._V1R = 0.0
        self._V0P = 0.0
        self._V1P = 0.0
        self._V0TS = 0.0
        self._V1TS = 0.0

        self._QtR = np.array([1.0 for t in self._ltemp])
        self._QtP = np.array([1.0 for t in self._ltemp])
        self._QtTS = np.array([1.0 for t in self._ltemp])
        self._chi0 = {
        }  # contribution of most stable conformer [considering V0]

        self._tsitc0 = None  # for ctc of ts [considering V0]
        self._tschi = {
            X: {}
            for X in "tst,tstzct,tstsct,cvt,cvtzct,cvtsct".split(",")
        }
        self._dtcoef = {
            X: {}
            for X in "tstzct,tstsct,cvt,cvtzct,cvtsct".split(",")
        }

        self._anhctcs = set([])
        self._FMSQH = np.array([1.0 for t in self._ltemp])  # SS considering V0
        self._ANHR = np.array([1.0 for t in self._ltemp])
        self._ANHP = np.array([1.0 for t in self._ltemp])
        self._ANHTS = np.array([1.0 for t in self._ltemp])
        self._ANHKeq = np.array([1.0 for t in self._ltemp])
        self._ANHkfw = np.array([1.0 for t in self._ltemp])
        self._ANHkbw = np.array([1.0 for t in self._ltemp])

        self._Keq = np.array([1.0 for t in self._ltemp])

        self._kfw = {X: None for X in RCONS}
        self._kbw = {X: None for X in RCONS}

        self._problem = False
Example #10
0
def get_reaction_energies(TS,dchem,dof):
    '''
    * checks the reactions which involved the target transition
      state (TS) in order to extract V0 and V1 for reactants
      and products 
    '''
    # initialize variables
    reaction = None
    Eref     = None
    V0R      = None
    V0P      = None
    V1R      = None
    V1P      = None
    GibbsR   = None
    # select reaction
    ctc, itc = PN.name2data(TS)
    for rname in dchem.keys():
        Rs, ts, Ps = dchem[rname]
        ctc2, itc2 = PN.name2data(ts)
        if ctc == ctc2:
           reaction = rname
           if itc == itc2: break
    # no reaction?
    if reaction is None: return reaction, V0R, V0P, V1R, V1P, GibbsR
    # read dof
    dall = RW.read_alldata(dof)[0]
    # get energy from reaction
    Rs = dchem[reaction][0]
    Ps = dchem[reaction][2]
    # reactants
    if len(Rs) != 0:
        V0R, V1R = 0.0, 0.0
        for R in Rs:
            ctc, itc = PN.name2data(R)
            if itc is None: key = PN.struckey(ctc,"msho")
            else          : key = R
            data = dall["pfn"].get(key,None)
            if data is None:
               V0R, V1R = None, None
               break
            V0, V1, pfns = data
            V0R += V0
            V1R += V1
            # Gibbs energy
            if key in dall["gibbs1cm3"].keys():
               gibbs = dall["gibbs1cm3"][key]
               if GibbsR is None: GibbsR = gibbs
               else             : GibbsR = [ gi+gj for gi,gj in zip(GibbsR,gibbs)]
    # products
    if len(Ps) != 0:
        V0P, V1P = 0.0, 0.0
        for P in Ps:
            ctc, itc = PN.name2data(P)
            if itc is None: key = PN.struckey(ctc,"msho")
            else          : key = P
            data = dall["pfn"].get(key,None)
            if data is None:
               V0P, V1P = None, None
               break
            V0, V1, pfns = data
            V0P += V0
            V1P += V1
    # Output
    return reaction, V0R, V0P, V1R, V1P, GibbsR
Example #11
0
    if fstatus == -1: exit()
    # expand case
    (dof,hlf,plotfile),dlevel,software = case
    #-------------------------------------------------------#


    print("   Selected software: %s"%software)
    print("")

    targets = get_targets(targets,dctc)
    # Print targets
    if len(targets) != 0:
       print("   High-level (HL) calculations will be carried out for:")
       ml = max([len(target) for target in targets]+[1])
       for target in targets:
           ctc,itc = PN.name2data(target)
           TMP     = PN.TMPHLi%PN.struckey(ctc,itc)
           print("       %s (TMP folder: %s)"%("%%-%is"%ml%target,TMP))
       print("")
    else:
       print("   No valid target(s) for High-level (HL) calculations")
       print("")
       return

    # read high-level output file
    dhighlvl = RW.read_highlevelfile(hlf)

    # loop over each target
    print("   Carrying out HL-calculations:")
    print("")
    ml   = max([len(target) for target in targets])
Example #12
0
def deal_with_path(target, dlevel, software, ltemp, dctc, pathvars, dtes,
                   dchem, dhighlvl, dimasses):
    dof = PN.get_dof(dlevel)
    plotfile = PN.get_plf(dlevel)
    # gts file for this TS
    ctc, itc = PN.name2data(target)
    gtsTS = dctc[ctc].gtsfile(itc)
    # rotational symmetry
    moleculeTS = Molecule()
    moleculeTS.set_from_gts(gtsTS)
    symmetry = str(moleculeTS._pgroup), int(moleculeTS._rotsigma)
    # temporal folder
    TMP = PN.TMPi % (target)
    # if exists,remove content (unless keeptmp is activated)
    # (to avoid reading old files from different levels of calculation)
    if os.path.exists(TMP) and not pathvars._keeptmp:
        shutil.rmtree(TMP, ignore_errors=True)
    # split target
    ctc, itc = PN.name2data(target)
    # name of rst file
    rstfile = PN.get_rst(ctc, itc)
    # tuple software
    tes = dtes.get(software, {}).get(ctc, None)
    tsoftw = (software, tes)
    # internal coordinates
    if itc in dctc[ctc]._dics.keys(): ics = dctc[ctc]._dics[itc]
    elif "*" in dctc[ctc]._dics.keys(): ics = dctc[ctc]._dics["*"]
    else: ics = None
    if itc in dctc[ctc]._dicsbw.keys(): icsbw = dctc[ctc]._dicsbw[itc]
    elif "*" in dctc[ctc]._dicsbw.keys(): icsbw = dctc[ctc]._dicsbw["*"]
    else: icsbw = None
    if itc in dctc[ctc]._dicsfw.keys(): icsfw = dctc[ctc]._dicsfw[itc]
    elif "*" in dctc[ctc]._dicsfw.keys(): icsfw = dctc[ctc]._dicsfw["*"]
    else: icsfw = None
    # path variables
    pathvars.set_ics(ics, icsbw, icsfw)  # before setup3!!
    pathvars.apply_specific(itc)
    pathvars.setup1()
    pathvars.setup2()
    pathvars.setup3()
    # Set Eref (from reaction)
    pathvars.set_eref_from_reaction(target, dchem, dof)
    # Quantum reaction coordinate qrc
    pathvars.prepare_qrc(dchem, dctc, dimasses)
    # frequency scaling factor
    pathvars._freqscal = float(dctc[ctc]._fscal)
    # if dlevel --> no convergence and dlevel data
    if dlevel:
        exception = Exc.NoDLEVELdata(Exception)
        pathvars._scterr = None
        keydhl = "%s.%s.path" % (ctc, itc)
        if keydhl not in dhighlvl.keys():
            # maybe only TS
            keydhl = "%s.%s" % (dctc[ctc]._root, itc)
            if keydhl in dhighlvl.keys():
                dictE = {0.0: dhighlvl[keydhl]}
            else:
                global WARNINGS
                WARNINGS.append("No high-level data for %s" % target)
                raise exception
        else:
            dictE = dhighlvl[keydhl]
        pathvars._dlevel = dictE
    # LOGGER
    pof = PN.get_pof(dlevel, "path", target)
    sys.stdout = Logger(pof, "w", True)
    sys.stdout.writeinfile(PS.init_txt())
    #string
    fncs.print_string(PS.smep_title(target, pathvars, pof), 2)
    # Was previously converged???
    ffloat = "%.3f"
    drstconv = RW.read_rstconv()
    if target in drstconv.keys() and not dlevel and os.path.exists(rstfile):
        lowtemp, useics, scterr, converged = drstconv[target]
        b0 = (converged == "yes")
        b1 = (pathvars._useics == useics)
        b2 = (ffloat % pathvars._scterr == ffloat % scterr)
        b3 = (ffloat % min(ltemp) == ffloat % lowtemp)
        if b0 and b1 and b2 and b3:
            pathvars._scterr = None
            fncs.print_string("THIS PATH IS STORED AS CONVERGED!\n", 4)
            tpath, tcommon, drst = ff.read_rst(rstfile)
            lbw, lfw, sbw, sfw, V0bw, V0fw = sd.rstlimits(drst)
            pathvars._sbw = sbw
            pathvars._sfw = sfw
            del drst
    #----------------#
    # calculate path #
    #----------------#

    # 1. Only MEP
    if not pathvars._beyondmep:
        common, drst, pathvars = calc_mep(target, gtsTS, pathvars, tsoftw, TMP)
        dcoefs = {}
        del drst
        # raise error
        raise Exc.OnlyMEP(Exception)

    # 2. MEP expanded till SCT convergence
    elif pathvars.sct_convergence():
        dcoefs, converged = get_path_sctconv(target, gtsTS, pathvars, tsoftw,
                                             ltemp, TMP, symmetry, plotfile)
        # save convergence in file!
        drstconv = RW.read_rstconv()
        if converged:
            drstconv[target] = (min(ltemp), pathvars._useics, pathvars._scterr,
                                "yes")
        else:
            drstconv[target] = (min(ltemp), pathvars._useics, pathvars._scterr,
                                "no")
        RW.write_rstconv(drstconv)

    # 3. Coefs with the current MEP extension
    else:
        tcommon, drst, pathvars = calc_mep(target, gtsTS, pathvars, tsoftw,
                                           TMP)
        dcoefs, pathvars, palpha, pomega = calc_coefs(target, tcommon, drst,
                                                      pathvars, ltemp,
                                                      symmetry, plotfile)
        del drst

    # print summary with the coefficients
    fncs.print_string(PS.spath_allcoefs(ltemp, dcoefs), 3)
    # return data
    return dcoefs, pathvars
Example #13
0
def obtain_mep(target, gtsTS, pathvars, tsoftware, TMP):
    ctc, itc = PN.name2data(target)

    # create folder now and not in the parallel process
    if not os.path.exists(TMP):
        try:
            os.mkdir(TMP)
        except:
            pass

    # Files
    rstfile = PN.get_rst(ctc, itc)
    xyzfile = PN.get_rstxyz(ctc, itc)

    # print
    software, tes = tsoftware
    fncs.print_string(PS.smep_init(target,software,pathvars._paral,pathvars.tuple_first(),\
                 pathvars.tuple_sdbw(),pathvars.tuple_sdfw()),4)
    fncs.print_string(PS.smep_ff(TMP, PN.DIR4, PN.DIR5, rstfile, xyzfile), 4)

    # read rst
    try:
        tpath2, tcommon2, drst = ff.read_rst(rstfile)
    except:
        exception = Exc.RstReadProblem(Exception)
        exception._var = rstfile
        raise exception
    fncs.print_string(PS.smep_rst(rstfile, drst), 4)

    # correct MEP direction?
    if TSLABEL in drst.keys():
        ii_s, ii_V, ii_x, ii_g, ii_F, ii_v0, ii_v1, ii_t = drst[TSLABEL]
        ii_ic, ii_sign = pathvars._fwdir
        if not intl.ics_correctdir(ii_x, ii_v0, ii_ic, ii_sign, tcommon2[3],
                                   tcommon2[4]):
            fncs.print_string(
                "'fwdir' variable differs from MEP direction in rst file!", 4)
            fncs.print_string("* modifying rst internal dictionary...", 8)
            new_drst = {}
            for key in drst.keys():
                ii_s, ii_V, ii_x, ii_g, ii_F, ii_v0, ii_v1, ii_t = drst[key]
                ii_s = -ii_s
                if ii_v0 is not None: ii_v0 = [-ii for ii in ii_v0]
                if ii_v1 is not None: ii_v1 = [-ii for ii in ii_v1]
                if "bw" in key: newkey = key.replace("bw", "fw")
                else: newkey = key.replace("fw", "bw")
                new_drst[newkey] = (ii_s, ii_V, ii_x, ii_g, ii_F, ii_v0, ii_v1,
                                    ii_t)
            drst = new_drst
            del new_drst
            fncs.print_string("* rewriting rst file...", 8)
            ff.write_rst(rstfile, tpath2, tcommon2, drst)

    # Extension of MEP in rst is bigger
    if drst != {}:
        lbw, lfw, sbw, sfw, V0bw, V0fw = sd.rstlimits(drst)
        pathvars._sbw = min(pathvars._sbw, sbw)
        pathvars._sfw = max(pathvars._sfw, sfw)

    # Read gts
    ts = Molecule()
    ts.set_from_gts(gtsTS)
    # scaling of frequencies
    ts.setvar(fscal=pathvars._freqscal)
    # apply iso mod
    if pathvars._masses is not None: ts.mod_masses(pathvars._masses)
    # setup
    ts.setup(mu=pathvars._mu)
    ts.ana_freqs(case="cc")

    fncs.print_string(PS.smep_ts(ts), 4)

    tcommon = (ts._ch, ts._mtp, ts._atnums, ts._masses, ts._mu)
    compare_tpath(pathvars.tuple_rst(), tpath2, rstfile)
    compare_tcommon(tcommon, tcommon2, rstfile)

    # data for single-point calculation
    frozen = RW.read_frozen(gtsTS + ".frozen")
    oniom_layers = (list(pathvars._oniomh), list(pathvars._oniomm),
                    list(pathvars._onioml))
    spc_args = (tes, TMP, False, frozen, oniom_layers)
    spc_fnc = get_spc_fnc(software)

    #------------#
    # First step #
    #------------#
    print("")
    fncs.print_string("Performing first step of MEP...", 4)
    print("")
    inputvars = (ts._xcc,ts._gcc,ts._Fcc,ts._symbols,ts._masses,pathvars.tuple_first(),\
                 spc_fnc,spc_args,drst,pathvars._paral)
    (xms, gms, Fms), (v0, v1), (xms_bw, xms_fw) = sd.mep_first(*inputvars)
    s1bw = -float(pathvars._ds)
    s1fw = +float(pathvars._ds)

    # oniom layers?
    oniom_ok = pathvars.isONIOMok(ts._natoms, software)
    layers = pathvars.get_layers()
    fncs.print_string(PS.smep_oniom(layers, ts._natoms, software), 8)
    if not oniom_ok: raise Exc.WrongONIOMlayers(Exception)

    # Print MEP info
    fncs.print_string(PS.smep_first(ts._symbols, ts._xms, v0, v1, layers), 8)

    # write rst file
    if TSLABEL not in drst.keys():
        drst[TSLABEL] = (0.0, ts._V0, xms, gms, Fms, v0, v1, None)
        ff.write_rst_head(rstfile, pathvars.tuple_rst(), tcommon)
        ff.write_rst_add(rstfile, TSLABEL, drst[TSLABEL])

    #------------#
    # The MEP    #
    #------------#
    print("")
    fncs.print_string("Calculating MEP...", 4)
    print("")
    fncs.print_string(
        "* REMEMBER: data of each step will be saved at %s" % rstfile, 7)
    fncs.print_string("            a summary will be printed when finished", 7)
    # preparation
    xcc_bw = fncs.ms2cc_x(xms_bw, ts._masses, pathvars._mu)
    xcc_fw = fncs.ms2cc_x(xms_fw, ts._masses, pathvars._mu)
    args_bw = ((xcc_bw,s1bw,ts._symbols,ts._masses,pathvars.tuple_sdbw(),\
                spc_fnc,spc_args,drst,ts._Fms,"bw%i") , rstfile,drst)
    args_fw = ((xcc_fw,s1fw,ts._symbols,ts._masses,pathvars.tuple_sdfw(),\
                spc_fnc,spc_args,drst,ts._Fms,"fw%i") , rstfile,drst)
    # execution
    if pathvars._paral:
        import multiprocessing
        pool = multiprocessing.Pool()
        out = [
            pool.apply_async(onesidemep, args=args)
            for args in [args_bw, args_fw]
        ]
        drstbw, pointsbw, convbw = out[0].get()
        drstfw, pointsfw, convfw = out[1].get()
        del out
        # clean up pool
        pool.close()
        pool.join()
    else:
        drstbw, pointsbw, convbw = onesidemep(*args_bw)
        drstfw, pointsfw, convfw = onesidemep(*args_fw)
    # update drst
    fncs.print_string("* FINISHED!", 7)
    print("")
    drst.update(drstbw)
    drst.update(drstfw)
    points = [TSLABEL] + pointsbw + pointsfw
    # empty variables
    del drstbw, pointsbw
    del drstfw, pointsfw
    # Rewrite rst
    fncs.print_string("* (re)writing file: %s (sorted version)" % rstfile, 7)
    ff.write_rst(rstfile, pathvars.tuple_rst(), tcommon, drst)
    print("")
    ## restrict drst to points
    #if restrict: drst = {point:drst[point] for point in points}
    # Get limits of rst
    lbw, lfw, sbw, sfw, V0bw, V0fw = sd.rstlimits(drst)
    convbw, l1bw, l2bw = convbw
    convfw, l1fw, l2fw = convfw
    if l1bw + l1fw != "":
        fncs.print_string("* MEP convergence criteria (epse and epsg):", 7)
        print("")
        if l1bw != "": fncs.print_string("%s" % l1bw, 9)
        if l2bw != "": fncs.print_string("%s" % l2bw, 9)
        if l1fw != "": fncs.print_string("%s" % l1fw, 9)
        if l2fw != "": fncs.print_string("%s" % l2fw, 9)
        print("")
        if convbw:
            pathvars.converged_in_bw(sbw)
            fncs.print_string("CRITERIA FULFILLED in backward dir.!", 9)
            fncs.print_string("path stopped at sbw = %+8.4f bohr" % sbw, 9)
            print("")
        if convfw:
            pathvars.converged_in_fw(sfw)
            fncs.print_string("CRITERIA FULFILLED in forward dir.!", 9)
            fncs.print_string("path stopped at sfw = %+8.4f bohr" % sfw, 9)
            print("")
    # write molden file
    fncs.print_string("* writing file: %s" % xyzfile, 7)
    ff.rst2xyz(rstfile, xyzfile, onlyhess=True)
    print("")
    # reference energy
    if pathvars._eref is None: pathvars._eref = V0bw
    # return data
    return tcommon, drst, pathvars