Example #1
0
if __name__ == '__main__':
    from .qchem import QChem
    from .pes import PES
    from .dlc_new import DelocalizedInternalCoordinates
    from .eigenvector_follow import eigenvector_follow
    from ._linesearch import backtrack, NoLineSearch
    from .molecule import Molecule

    basis = '6-31G'
    nproc = 8
    functional = 'B3LYP'
    filepath1 = "examples/tests/butadiene_ethene.xyz"
    lot1 = QChem.from_options(states=[(1, 0)],
                              charge=0,
                              basis=basis,
                              functional=functional,
                              nproc=nproc,
                              fnm=filepath1)
    pes1 = PES.from_options(lot=lot1, ad_idx=0, multiplicity=1)
    M1 = Molecule.from_options(fnm=filepath1, PES=pes1, coordinate_type="DLC")
    optimizer = eigenvector_follow.from_options(
        print_level=1
    )  #default parameters fine here/opt_type will get set by GSM

    gsm = SE_GSM.from_options(reactant=M1,
                              nnodes=20,
                              driving_coords=[("ADD", 6, 4), ("ADD", 5, 1)],
                              optimizer=optimizer,
                              print_level=1)
    gsm.go_gsm()
Example #2
0
def main():
    parser = argparse.ArgumentParser(
        description="Reaction path transition state and photochemistry tool",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=textwrap.dedent('''\
                Example of use:
                --------------------------------
                gsm -mode DE_GSM -xyzfile yourfile.xyz -package QChem -lot_inp_file qstart -ID 1
                ''')
        )
    parser.add_argument('-xyzfile', help='XYZ file containing reactant and, if DE-GSM, product.',  required=True)
    parser.add_argument('-isomers', help='driving coordinate file', type=str, required=False)
    parser.add_argument('-mode', default="DE_GSM",help='GSM Type (default: %(default)s)',choices=["DE_GSM","SE_GSM","SE_Cross"], type=str, required=True)
    parser.add_argument('-only_drive',action='store_true',help='')
    parser.add_argument('-package',default="QChem",type=str,help="Electronic structure theory package (default: %(default)s)",choices=["QChem","Orca","Molpro","PyTC","TeraChemCloud","OpenMM","DFTB","TeraChem","BAGEL","xTB_lot"])
    parser.add_argument('-lot_inp_file',type=str,default=None, help='external file to specify calculation e.g. qstart,gstart,etc. Highly package specific.',required=False)
    parser.add_argument('-ID',default=0, type=int,help='string identification number (default: %(default)s)',required=False)
    parser.add_argument('-num_nodes',type=int,default=11,help='number of nodes for string (defaults: 9 DE-GSM, 20 SE-GSM)',required=False)
    parser.add_argument('-pes_type',type=str,default='PES',help='Potential energy surface (default: %(default)s)',choices=['PES','Avg_PES','Penalty_PES'])
    parser.add_argument('-adiabatic_index',nargs="*",type=int,default=[0],help='Adiabatic index (default: %(default)s)',required=False)
    parser.add_argument('-multiplicity',nargs="*",type=int,default=[1],help='Multiplicity (default: %(default)s)')
    parser.add_argument('-FORCE_FILE',type=str,default=None,help='Constant force between atoms in AU,e.g. [(1,2,0.1214)]. Negative is tensile, positive is compresive')
    parser.add_argument('-RESTRAINT_FILE',type=str,default=None,help='Harmonic translational restraints')
    parser.add_argument('-optimizer',type=str,default='eigenvector_follow',help='The optimizer object. (default: %(default)s Recommend LBFGS for large molecules >1000 atoms)',required=False)
    parser.add_argument('-opt_print_level',type=int,default=1,help='Printout for optimization. 2 prints everything in opt.',required=False)
    parser.add_argument('-gsm_print_level',type=int,default=1,help='Printout for gsm. 1 prints ?',required=False)
    parser.add_argument('-linesearch',type=str,default='NoLineSearch',help='default: %(default)s',choices=['NoLineSearch','backtrack'])
    parser.add_argument('-coordinate_type',type=str,default='TRIC',help='Coordinate system (default %(default)s)',choices=['TRIC','DLC','HDLC'])
    parser.add_argument('-ADD_NODE_TOL',type=float,default=0.01,help='Convergence tolerance for adding new node (default: %(default)s)',required=False)
    parser.add_argument('-DQMAG_MAX',type=float,default=0.8,help='Maximum step size in single-ended mode (default: %(default)s)',required=False)
    parser.add_argument('-BDIST_RATIO',type=float,default=0.5,help='Reaction completion convergence in SE modes (default: %(default)s)')
    parser.add_argument('-CONV_TOL',type=float,default=0.0005,help='Convergence tolerance for optimizing nodes (default: %(default)s)',required=False)
    parser.add_argument('-growth_direction',type=int,default=0,help='Direction adding new nodes (default: %(default)s)',choices=[0,1,2])
    parser.add_argument('-reactant_geom_fixed',action='store_true',help='Fix reactant geometry i.e. do not pre-optimize')
    parser.add_argument('-product_geom_fixed',action='store_true',help='Fix product geometry i.e. do not pre-optimize')
    parser.add_argument('-nproc',type=int,default=1,help='Processors for calculation. Python will detect OMP_NUM_THREADS, only use this if you want to force the number of processors')
    parser.add_argument('-charge',type=int,default=0,help='Total system charge (default: %(default)s)')
    parser.add_argument('-max_gsm_iters',type=int,default=100,help='The maximum number of GSM cycles (default: %(default)s)')
    parser.add_argument('-max_opt_steps',type=int,help='The maximum number of node optimizations per GSM cycle (defaults: 3 DE-GSM, 20 SE-GSM)')
    parser.add_argument('-only_climb',action='store_true',help="Only use climbing image to optimize TS")
    parser.add_argument('-no_climb',action='store_true',help="Don't climb to the TS")
    parser.add_argument('-optimize_mesx',action='store_true',help='optimize to the MESX')
    parser.add_argument('-optimize_meci',action='store_true',help='optimize to the MECI')
    parser.add_argument('-restart_file',help='restart file',type=str)
    parser.add_argument('-mp_cores',type=int,default=1,help="Use python multiprocessing to parallelize jobs on a single compute node. Set OMP_NUM_THREADS, ncpus accordingly.")
    parser.add_argument('-dont_analyze_ICs',action='store_false',help="Don't post-print the internal coordinates primitives and values") #defaults to true
    parser.add_argument('-hybrid_coord_idx_file',type=str,default=None,help="A filename containing a list of  indices to use in hybrid coordinates. 0-Based indexed")
    parser.add_argument('-frozen_coord_idx_file',type=str,default=None,help="A filename containing a list of  indices to be frozen. 0-Based indexed")
    parser.add_argument('-conv_Ediff',default=100.,type=float,help='Energy difference convergence of optimization.')
    parser.add_argument('-conv_dE',default=1.,type=float,help='State difference energy convergence')
    parser.add_argument('-conv_gmax',default=100.,type=float,help='Max grad rms threshold')
    parser.add_argument('-DMAX',default=.1,type=float,help='')
    parser.add_argument('-sigma',default=1.,type=float,help='The strength of the difference energy penalty in Penalty_PES')
    parser.add_argument('-prim_idx_file',type=str,help="A filename containing a list of indices to define fragments. 0-Based indexed")
    parser.add_argument('-reparametrize',action='store_true',help='Reparametrize restart string equally along path')
    parser.add_argument('-interp_method',default='DLC',type=str,help='')
    parser.add_argument('-bonds_file',type=str,help="A file which contains the bond indices (0-based)")


    args = parser.parse_args()

    print_msg()

    if args.nproc>1:
        force_num_procs=True
        print("forcing number of processors to be {}!!!".format(args.nproc))
    else:
        force_num_procs=False
    if force_num_procs:
        nproc = args.nproc
    else:
        #nproc = get_nproc()
        try:
            nproc = int(os.environ['OMP_NUM_THREADS'])
        except: 
            nproc = 1
        print(" Using {} processors".format(nproc))

    inpfileq = {
               # LOT
              'lot_inp_file': args.lot_inp_file,
              'xyzfile' : args.xyzfile,
              'EST_Package': args.package,
              'reactant_geom_fixed' : args.reactant_geom_fixed,
              'nproc': args.nproc,
              'states': None,
              
              #PES
              'PES_type': args.pes_type,
              'adiabatic_index': args.adiabatic_index,
              'multiplicity': args.multiplicity,
              'FORCE_FILE': args.FORCE_FILE,
              'RESTRAINT_FILE': args.RESTRAINT_FILE,
              'FORCE': None,
              'RESTRAINTS': None,

              #optimizer
              'optimizer' : args.optimizer,
              'opt_print_level' : args.opt_print_level,
              'linesearch' : args.linesearch,
              'DMAX'    :   args.DMAX,

              #molecule
              'coordinate_type' : args.coordinate_type,
              'hybrid_coord_idx_file' : args.hybrid_coord_idx_file,
              'frozen_coord_idx_file' : args.frozen_coord_idx_file,
              'prim_idx_file' : args.prim_idx_file,

              # GSM
              'gsm_type': args.mode, # SE_GSM, SE_Cross
              'num_nodes' : args.num_nodes,
              'isomers_file': args.isomers,
              'ADD_NODE_TOL': args.ADD_NODE_TOL,
              'CONV_TOL': args.CONV_TOL,
              'conv_Ediff': args.conv_Ediff,
              'conv_dE': args.conv_dE,
              'conv_gmax': args.conv_gmax,
              'BDIST_RATIO':args.BDIST_RATIO,
              'DQMAG_MAX': args.DQMAG_MAX,
              'growth_direction': args.growth_direction,
              'ID':args.ID,
              'product_geom_fixed' : args.product_geom_fixed,
              'gsm_print_level' : args.gsm_print_level,
              'max_gsm_iters' : args.max_gsm_iters,
              'max_opt_steps' : args.max_opt_steps,
              #'use_multiprocessing': args.use_multiprocessing,
              'sigma'   :   args.sigma,
              }

    nifty.printcool_dictionary(inpfileq,title='Parsed GSM Keys : Values')


    #LOT
    nifty.printcool("Build the {} level of theory (LOT) object".format(inpfileq['EST_Package']))
    est_package=importlib.import_module("level_of_theories."+inpfileq['EST_Package'].lower())
    lot_class = getattr(est_package,inpfileq['EST_Package'])

    geoms = manage_xyz.read_xyzs(inpfileq['xyzfile'])
    if args.restart_file:
        geoms = manage_xyz.read_molden_geoms(args.restart_file)

    inpfileq['states'] = [ (int(m),int(s)) for m,s in zip(args.multiplicity,args.adiabatic_index)]
    if inpfileq['PES_type']!="PES":
        assert len(args.adiabatic_index)>1, "need more states"
        assert len(args.multiplicity)>1, "need more spins"
    if args.charge != 0:
        print("Warning: charge is not implemented for all level of theories. Make sure this is correct for your package.")
    if inpfileq['num_nodes'] is None:
        if inpfileq['gsm_type']=="DE_GSM":
            inpfileq['num_nodes']=9
        else:
            inpfileq['num_nodes']=20
    do_coupling = True if inpfileq['PES_type']=="Avg_PES" else False
    coupling_states = [ (int(m),int(s)) for m,s in zip(args.multiplicity,args.adiabatic_index)] if inpfileq['PES_type']=="Avg_PES" else []
    
    lot = lot_class.from_options(
            ID = inpfileq['ID'],
            lot_inp_file=inpfileq['lot_inp_file'],
            states=inpfileq['states'],
            gradient_states=inpfileq['states'],
            coupling_states=coupling_states,
            geom=geoms[0],
            nproc=nproc,
            charge=args.charge,
            do_coupling=do_coupling,
            )

    #PES
    if inpfileq['gsm_type'] == "SE_Cross":
        if inpfileq['PES_type']!="Penalty_PES":
            print(" setting PES type to Penalty")
            inpfileq['PES_type']="Penalty_PES"
    if args.optimize_mesx or args.optimize_meci  or inpfileq['gsm_type']=="SE_Cross":
        assert inpfileq['PES_type'] == "Penalty_PES", "Need penalty pes for optimizing MESX/MECI"
    if inpfileq['FORCE_FILE']:
        inpfileq['FORCE']=[]
        with open(inpfileq['FORCE_FILE'],'r') as f:
            tmp = filter(None, (line.rstrip() for line in f))
            lines=[]
            for line in tmp:
                lines.append(line)
        for line in lines:
            force=[]
            for i,elem in enumerate(line.split()):
                if i==0 or i==1:
                    force.append(int(elem))
                else:
                    force.append(float(elem))
            inpfileq['FORCE'].append(tuple(force))
        print(inpfileq['FORCE'])
    if inpfileq['RESTRAINT_FILE']:
        inpfileq['RESTRAINTS']=[]
        with open(inpfileq['RESTRAINT_FILE'],'r') as f:
            tmp = filter(None, (line.rstrip() for line in f))
            lines=[]
            for line in tmp:
                lines.append(line)
        for line in lines:
            restraint=[]
            for i,elem in enumerate(line.split()):
                if i==0:
                    restraint.append(int(elem))
                else:
                    restraint.append(float(elem))
            inpfileq['RESTRAINTS'].append(tuple(restraint))
        print(inpfileq['RESTRAINTS'])

    nifty.printcool("Building the {} objects".format(inpfileq['PES_type']))
    pes_class = getattr(sys.modules[__name__], inpfileq['PES_type'])
    if inpfileq['PES_type']=='PES':
        pes = pes_class.from_options(
                lot=lot,
                ad_idx=inpfileq['adiabatic_index'][0],
                multiplicity=inpfileq['multiplicity'][0],
                FORCE=inpfileq['FORCE'],
                RESTRAINTS=inpfileq['RESTRAINTS'],
                )
    else:
        pes1 = PES.from_options(
                lot=lot,multiplicity=inpfileq['states'][0][0],
                ad_idx=inpfileq['states'][0][1],
                FORCE=inpfileq['FORCE'],
                RESTRAINTS=inpfileq['RESTRAINTS'],
                )
        pes2 = PES.from_options(
                lot=lot,
                multiplicity=inpfileq['states'][1][0],
                ad_idx=inpfileq['states'][1][1],
                FORCE=inpfileq['FORCE'],
                RESTRAINTS=inpfileq['RESTRAINTS'],
                )
        if inpfileq['PES_type']=="Avg_PES":
            pes = pes_class(PES1=pes1,PES2=pes2,lot=lot)
        elif inpfileq['PES_type']=="Penalty_PES": 
            pes = pes_class(PES1=pes1,PES2=pes2,lot=lot,sigma=inpfileq['sigma'])
        else:
            raise NotImplementedError

    # Molecule
    nifty.printcool("Building the reactant object with {}".format(inpfileq['coordinate_type']))
    Form_Hessian = True if inpfileq['optimizer']=='eigenvector_follow' else False
    #form_primitives = True if inpfileq['gsm_type']!='DE_GSM' else False

    # hybrid coordinates
    if inpfileq['hybrid_coord_idx_file'] is not None:
        nifty.printcool(" Using Hybrid COORDINATES :)")
        assert inpfileq['coordinate_type']=="TRIC", "hybrid indices won't work (currently) with other coordinate systems"
        with open(inpfileq['hybrid_coord_idx_file']) as f:
            hybrid_indices = f.read().splitlines()
        hybrid_indices = [int(x) for x in hybrid_indices]
    else:
        hybrid_indices = None
    if inpfileq['frozen_coord_idx_file'] is not None:
        with open(inpfileq['frozen_coord_idx_file']) as f:
            frozen_indices = f.read().splitlines()
        frozen_indices = [int(x) for x in frozen_indices]
    else:
        frozen_indices = None


    # prim internal coordinates
    # The start and stop indexes of the primitive internal region, this defines the "fragments" so no large molecule is built        
    if inpfileq['prim_idx_file'] is not None:
        nifty.printcool(" Defining primitive internal region :)")
        assert inpfileq['coordinate_type']=="TRIC", "won't work (currently) with other coordinate systems"
        prim_indices = np.loadtxt(inpfileq['prim_idx_file'])
        if prim_indices.ndim==2:
            prim_indices = [ (int(prim_indices[i,0]), int(prim_indices[i,1])-1) for i in range(len(prim_indices))]
        elif prim_indices.ndim==1:
            prim_indices = [ (int(prim_indices[0]), int(prim_indices[1])-1) ]

        print(prim_indices)
        #with open(inpfileq['prim_idx_file']) as f:
        #    prim_indices = f.read().splitlines()
        #prim_indices = [int(x) for x in prim_indices]
    else:
        prim_indices = None



    # Build the topology
    nifty.printcool("Building the topology")
    atom_symbols  = manage_xyz.get_atoms(geoms[0])
    ELEMENT_TABLE = elements.ElementData()
    atoms = [ELEMENT_TABLE.from_symbol(atom) for atom in atom_symbols]
    xyz1 = manage_xyz.xyz_to_np(geoms[0])
    top1 = Topology.build_topology(
            xyz1,
            atoms,
            hybrid_indices=hybrid_indices,
            prim_idx_start_stop=prim_indices,
            bondlistfile=args.bonds_file,
            )

    if inpfileq['gsm_type'] == 'DE_GSM':
        # find union bonds
        xyz2 = manage_xyz.xyz_to_np(geoms[-1])
        top2 = Topology.build_topology(
                xyz2,
                atoms,
                hybrid_indices=hybrid_indices,
                prim_idx_start_stop=prim_indices,
                )

        # Add bonds to top1 that are present in top2
        # It's not clear if we should form the topology so the bonds
        # are the same since this might affect the Primitives of the xyz1 (slightly)
        # Later we stil need to form the union of bonds, angles and torsions
        # However, I think this is important, the way its formulated, for identifiyin 
        # the number of fragments and blocks, which is used in hybrid TRIC. 
        for bond in top2.edges():
            if bond in top1.edges:
                pass
            elif (bond[1],bond[0]) in top1.edges():
                pass
            else:
                print(" Adding bond {} to top1".format(bond))
                if bond[0]>bond[1]:
                    top1.add_edge(bond[0],bond[1])
                else:
                    top1.add_edge(bond[1],bond[0])
    elif inpfileq['gsm_type'] == 'SE_GSM' or inpfileq['gsm_type']=='SE_Cross':
        driving_coordinates = read_isomers_file(inpfileq['isomers_file'])

        driving_coord_prims=[]
        for dc in driving_coordinates:
            prim = get_driving_coord_prim(dc)
            if prim is not None:
                driving_coord_prims.append(prim)

        for prim in driving_coord_prims:
            if type(prim)==Distance:
                bond = (prim.atoms[0],prim.atoms[1])
                if bond in top1.edges:
                    pass
                elif (bond[1],bond[0]) in top1.edges():
                    pass
                else:
                    print(" Adding bond {} to top1".format(bond))
                    top1.add_edge(bond[0],bond[1])

    nifty.printcool("Building Primitive Internal Coordinates")
    connect=False
    addtr = False
    addcart=False
    if inpfileq['coordinate_type']=="DLC":
        connect=True
    elif inpfileq['coordinate_type']=="TRIC":
        addtr=True
    elif inpfileq['coordinate_type']=="HDLC":
        addcart=True
    p1 = PrimitiveInternalCoordinates.from_options(
            xyz=xyz1,
            atoms=atoms,
            connect=connect,
            addtr=addtr,
            addcart=addcart,
            topology=top1,
            )

    if inpfileq['gsm_type'] == 'DE_GSM':
        nifty.printcool("Building Primitive Internal Coordinates 2")
        p2 = PrimitiveInternalCoordinates.from_options(
                xyz=xyz2,
                atoms=atoms,
                addtr = addtr,
                addcart=addcart,
                connect=connect,
                topology=top1,  # Use the topology of 1 because we fixed it above
                ) 
        nifty.printcool("Forming Union of Primitives")
        # Form the union of primitives
        p1.add_union_primitives(p2)

        print("check {}".format(len(p1.Internals)))
    elif inpfileq['gsm_type'] == 'SE_GSM' or inpfileq['gsm_type']=='SE_Cross':
        for dc in driving_coord_prims:
            if type(dc)!=Distance: # Already handled in topology
                if dc not in p1.Internals:
                    print("Adding driving coord prim {} to Internals".format(dc))
                    p1.append_prim_to_block(dc)

    nifty.printcool("Building Delocalized Internal Coordinates")
    coord_obj1 = DelocalizedInternalCoordinates.from_options(
            xyz=xyz1,
            atoms=atoms,
            addtr = addtr,
            addcart=addcart,
            connect=connect,
            primitives=p1,
            ) 
    if inpfileq['gsm_type'] == 'DE_GSM':
        # TMP 
        pass


    nifty.printcool("Building the reactant")
    reactant = Molecule.from_options(
            geom=geoms[0],
            PES=pes,
            coord_obj = coord_obj1,
            Form_Hessian=Form_Hessian,
            frozen_atoms=frozen_indices,
            )

    if inpfileq['gsm_type']=='DE_GSM':
        nifty.printcool("Building the product object")
        xyz2 = manage_xyz.xyz_to_np(geoms[-1])
        product = Molecule.copy_from_options(
                reactant,
                xyz=xyz2,
                new_node_id = inpfileq['num_nodes']-1,
                copy_wavefunction=False,
                )
   
    # optimizer
    nifty.printcool("Building the Optimizer object")
    update_hess_in_bg = True
    if args.only_climb or inpfileq['optimizer']=="lbfgs":
        update_hess_in_bg = False
    opt_class = getattr(sys.modules[__name__], inpfileq['optimizer'])
    optimizer = opt_class.from_options(
            print_level=inpfileq['opt_print_level'],
            Linesearch=inpfileq['linesearch'],
            update_hess_in_bg = update_hess_in_bg,
            conv_Ediff = inpfileq['conv_Ediff'],
            conv_dE = inpfileq['conv_dE'],
            conv_gmax = inpfileq['conv_gmax'],
            DMAX = inpfileq['DMAX'],
            opt_climb = True if args.only_climb else False,
            )

    # GSM
    nifty.printcool("Building the GSM object")
    gsm_class = getattr(sys.modules[__name__], inpfileq['gsm_type'])
    if inpfileq['gsm_type']=="DE_GSM":
        gsm = gsm_class.from_options(
                reactant=reactant,
                product=product,
                nnodes=inpfileq['num_nodes'],
                CONV_TOL=inpfileq['CONV_TOL'],
                CONV_gmax=inpfileq['conv_gmax'],
                CONV_Ediff=inpfileq['conv_Ediff'],
                CONV_dE=inpfileq['conv_dE'],
                ADD_NODE_TOL=inpfileq['ADD_NODE_TOL'],
                growth_direction=inpfileq['growth_direction'],
                optimizer=optimizer,
                ID=inpfileq['ID'],
                print_level=inpfileq['gsm_print_level'],
                mp_cores=args.mp_cores,
                interp_method = args.interp_method,
                )
    else:
        gsm = gsm_class.from_options(
                reactant=reactant,
                nnodes=inpfileq['num_nodes'],
                DQMAG_MAX=inpfileq['DQMAG_MAX'],
                BDIST_RATIO=inpfileq['BDIST_RATIO'],
                CONV_TOL=inpfileq['CONV_TOL'],
                ADD_NODE_TOL=inpfileq['ADD_NODE_TOL'],
                optimizer=optimizer,
                print_level=inpfileq['gsm_print_level'],
                driving_coords=driving_coordinates,
                ID=inpfileq['ID'],
                mp_cores=args.mp_cores,
                interp_method = args.interp_method,
                )



    if args.only_drive:
        for i in range(gsm.nnodes-1):
            try:
                gsm.add_GSM_nodeR()
            except:
                break
        geoms=[]
        for node in gsm.nodes:
            if node is not None:
                geoms.append(node.geometry)
            else:
                break
        manage_xyz.write_xyzs('interpolated.xyz',geoms)
        return


    # For seam calculation
    if inpfileq['gsm_type']!='SE_Cross' and (inpfileq['PES_type'] =="Avg_PES" or inpfileq['PES_type']=="Penalty_PES"):
        optimizer.opt_cross = True

    if not inpfileq['reactant_geom_fixed'] and inpfileq['gsm_type']!='SE_Cross':
        path=os.path.join(os.getcwd(),'scratch/{:03}/{}/'.format(args.ID,0))
        nifty.printcool("REACTANT GEOMETRY NOT FIXED!!! OPTIMIZING")
        optimizer.optimize(
           molecule = reactant,
           refE = reactant.energy,
           opt_steps=100,
           path=path
           )

    if not inpfileq['product_geom_fixed'] and inpfileq['gsm_type']=='DE_GSM':
        path=os.path.join(os.getcwd(),'scratch/{:03}/{}/'.format(args.ID,args.num_nodes-1))
        nifty.printcool("PRODUCT GEOMETRY NOT FIXED!!! OPTIMIZING")
        optimizer.optimize(
           molecule = product,
           refE = reactant.energy,
           opt_steps=100,
           path=path
           )

    rtype=2
    if args.only_climb:
        rtype=1
    elif args.no_climb:
        rtype=0
    elif args.optimize_meci:
        rtype=0
    elif args.optimize_mesx:
        rtype=1
    elif inpfileq['gsm_type']=="SE_Cross":
        rtype=1

    if inpfileq['max_opt_steps'] is None:
        if inpfileq['gsm_type']=="DE_GSM":
            inpfileq['max_opt_steps']=3
        else:
            inpfileq['max_opt_steps']=20
   
    if args.restart_file is not None:
        gsm.setup_from_geometries(geoms,reparametrize=args.reparametrize)
    gsm.go_gsm(inpfileq['max_gsm_iters'],inpfileq['max_opt_steps'],rtype)
    if inpfileq['gsm_type']=='SE_Cross':
        post_processing(
                gsm,
                analyze_ICs=args.dont_analyze_ICs,
                have_TS=False,
                )
        manage_xyz.write_xyz(f'meci_{gsm.ID}.xyz',gsm.nodes[gsm.nR].geometry)

        if not gsm.end_early:
            manage_xyz.write_xyz(f'TSnode_{gsm.ID}.xyz',gsm.nodes[gsm.TSnode].geometry)
    else:
        post_processing(
                gsm,
                analyze_ICs=args.dont_analyze_ICs,
                have_TS=True,
                )
        manage_xyz.write_xyz(f'TSnode_{gsm.ID}.xyz',gsm.nodes[gsm.TSnode].geometry)

    cleanup_scratch(gsm.ID)

    return
Example #3
0
    p1.add_union_primitives(p2)

    coord_obj1 = DelocalizedInternalCoordinates.from_options(
        xyz=xyz1,
        atoms=atoms,
        addtr=addtr,
        addcart=addcart,
        connect=connect,
        primitives=p1,
    )

    optimizer = eigenvector_follow.from_options()

    reactant = Molecule.from_options(
        geom=geoms[0],
        PES=pes,
        coord_obj=coord_obj1,
        Form_Hessian=True,
    )
    product = Molecule.copy_from_options(
        reactant,
        xyz=xyz2,
        new_node_id=len(geoms) - 1,
        copy_wavefunction=False,
    )

    gsm = DE_GSM.from_options(
        reactant=reactant,
        product=product,
        nnodes=len(geoms),
        optimizer=optimizer,
    )