예제 #1
0
def gamess_quantum_pipeline(request, molinfo):
    """

    Assumed that rdkit understands the molecule

    """

    # TODO Read gamess settings from ini

    # Read input
    molobj = molinfo["molobj"]
    sdfstr = molinfo["sdfstr"]

    if "name " in request.POST:
        name = request.POST["name"].encode('utf-8')
    else:
        name = None

    # Get that smile on your face
    smiles = cheminfo.molobj_to_smiles(molobj, remove_hs=True)

    # hash on sdf (conformer)
    hshobj = hashlib.md5(sdfstr.encode())
    hashkey = hshobj.hexdigest()

    # Start respond message
    msg = {"smiles": smiles, "hashkey": hashkey}

    # Check if calculation already exists
    if False:
        calculation = request.dbsession.query(models.GamessCalculation) \
            .filter_by(hashkey=hashkey).first()

        if calculation is not None:
            calculation.created = datetime.datetime.now()
            return msg

    # Create new calculation
    calculation = models.GamessCalculation()

    # check if folder exists
    here = os.path.abspath(os.path.dirname(__file__)) + "/"
    datahere = here + "data/"

    if not os.path.isdir(datahere + hashkey):
        os.mkdir(datahere + hashkey)

    os.chdir(datahere + hashkey)

    # GAMESS DEBUG

    # TODO Add error messages when gamess fails
    # TODO add timeouts for all gamess calls

    # Optimize molecule

    gmsargs = {
        "scr": datahere + hashkey,
        "autoclean": True,
        "debug": False,
    }
    properties = gamess.calculate_optimize(molobj, **gmsargs)

    if properties is None:
        return {
            'error': 'Error g-80 - gamess optimization error',
            'message': "Error. Server was unable to optimize molecule"
        }

    print(smiles, list(properties.keys()))

    # Save and set coordinates
    coord = properties["coord"]
    calculation.coordinates = save_array(coord)
    calculation.enthalpy = properties["h"]
    cheminfo.molobj_set_coordinates(molobj, coord)

    # Optimization is finished, do other calculation async-like

    # Vibrate molecule
    vibheader = """
 $basis
     gbasis=PM3
 $end

 $contrl
    scftyp=RHF
    runtyp=hessian
    icharg={:}
    maxit=60
 $end
"""

    orbheader = """
 $contrl
 coord=cart
 units=angs
 scftyp=rhf
 icharg={:}
 maxit=60
 $end
 $basis gbasis=sto ngauss=3 $end
"""

    solheader = """
 $system
    mwords=125
 $end
 $basis
    gbasis=PM3
 $end
 $contrl
    scftyp=RHF
    runtyp=energy
    icharg={:}
 $end
 $pcm
    solvnt=water
    mxts=15000
    icav=1
    idisp=1
 $end
 $tescav
    mthall=4
    ntsall=60
 $end

"""

    headers = [vibheader, orbheader, solheader]
    readers = [
        gamess.read_properties_vibration, gamess.read_properties_orbitals,
        gamess.read_properties_solvation
    ]

    def procfunc(conn, reader, *args, **kwargs):
        stdout, status = gamess.calculate(*args, **kwargs)
        try:
            properties = reader(stdout)
        except:
            # TODO Error reading properties
            properties = None
        conn.send(properties)
        conn.close()

    procs = []
    conns = []

    for header, reader in zip(headers, readers):

        parent_conn, child_conn = Pipe()
        p = Process(target=procfunc,
                    args=(child_conn, reader, molobj, header),
                    kwargs=gmsargs)
        p.start()

        procs.append(p)
        conns.append(parent_conn)

    for proc in procs:
        proc.join()

    properties_vib = conns[0].recv()
    properties_orb = conns[1].recv()
    properties_sol = conns[2].recv()

    if properties_vib is None:
        return {
            'error': 'Error g-104 - gamess vibration error',
            'message': "Error. Server was unable to vibrate molecule"
        }

    print(smiles, list(properties_vib.keys()))

    calculation.islinear = properties_vib["linear"]
    calculation.vibjsmol = properties_vib["jsmol"]
    calculation.vibfreq = save_array(properties_vib["freq"])
    calculation.vibintens = save_array(properties_vib["intens"])
    calculation.thermo = save_array(properties_vib["thermo"])

    if properties_orb is None:
        return {
            'error': 'Error g-128 - gamess orbital error',
            'message': "Error. Server was unable to orbital the molecule"
        }

    print(smiles, list(properties_orb.keys()))
    calculation.orbitals = save_array(properties_orb["orbitals"])
    calculation.orbitalstxt = properties_orb["stdout"]

    if properties_sol is None:
        return {
            'error': 'Error g-159 - gamess solvation error',
            'message': "Error. Server was unable to run solvation calculation"
        }

    # 'charges', 'solvation_total', 'solvation_polar', 'solvation_nonpolar',
    # 'surface', 'total_charge', 'dipole', 'dipole_total'
    print(smiles, list(properties_sol.keys()))

    charges = properties_sol["charges"]
    calculation.charges = save_array(charges)
    calculation.soltotal = properties_sol["solvation_total"]
    calculation.solpolar = properties_sol["solvation_polar"]
    calculation.solnonpolar = properties_sol["solvation_nonpolar"]
    calculation.solsurface = properties_sol["surface"]
    calculation.soldipole = save_array(properties_sol["dipole"])
    calculation.soldipoletotal = properties_sol["dipole_total"]

    # GAMESS DEBUG

    os.chdir(here)

    # Saveable sdf and reset title
    sdfstr = cheminfo.molobj_to_sdfstr(molobj)
    sdfstr = str(sdfstr)
    for _ in range(2):
        i = sdfstr.index('\n')
        sdfstr = sdfstr[i + 1:]
    sdfstr = "\n\n" + sdfstr

    # Save mol2 fmt

    mol2 = cheminfo.molobj_to_mol2(molobj, charges=charges)
    calculation.mol2 = mol2

    # Get a 2D Picture
    # TODO Compute 2D coordinates
    svgstr = cheminfo.molobj_to_svgstr(molobj, removeHs=True)

    # Success, setup database
    # calculation = models.GamessCalculation()
    calculation.smiles = smiles
    calculation.hashkey = hashkey
    calculation.sdf = sdfstr
    calculation.svg = svgstr
    calculation.created = datetime.datetime.now()

    # Add calculation to the database
    request.dbsession.add(calculation)

    # Add smiles to counter
    countobj = request.dbsession.query(models.Counter) \
        .filter_by(smiles=smiles).first()

    if countobj is None:
        counter = models.Counter()
        counter.smiles = smiles
        counter.count = 1
        request.dbsession.add(counter)
    else:
        countobj.count += 1

    return msg
예제 #2
0
파일: views.py 프로젝트: Q20110911/molcalc
def ajax_submitquantum(request):
    """

    Setup quantum calculation

    """

    if not request.POST:
        return {
            'error': 'Error 128 - empty post',
            'message': "Error. Empty post."
        }

    if not request.POST["sdf"]:
        return {
            'error': 'Error 132 - sdf key error',
            'message': "Error. Missing information."
        }

    # Get coordinates from request
    sdfstr = request.POST["sdf"].encode('utf-8')

    # Get rdkit
    molobj, status = cheminfo.sdfstr_to_molobj(sdfstr)

    if molobj is None:
        status = status.split("]")
        status = status[-1]
        return {'error': 'Error 141 - rdkit error', 'message': status}

    try:
        conf = molobj.GetConformer()
    except ValueError:
        # Error
        return {
            'error':
            'Error 141 - rdkit error',
            'message':
            "Error. Server was unable to generate conformations for this molecule"
        }

    # If hydrogens not added, assume graph and optimize with forcefield
    atoms = cheminfo.molobj_to_atoms(molobj)
    if 1 not in atoms:
        molobj = cheminfo.molobj_add_hydrogens(molobj)
        cheminfo.molobj_optimize(molobj)

    # TODO Check lengths of atoms
    # TODO Define max in settings

    # Fix sdfstr
    sdfstr = sdfstr.decode('utf8')
    for _ in range(3):
        i = sdfstr.index('\n')
        sdfstr = sdfstr[i + 1:]
    sdfstr = "\n" * 3 + sdfstr

    # hash on sdf (conformer)
    hshobj = hashlib.md5(sdfstr.encode())
    hashkey = hshobj.hexdigest()

    calculation = request.dbsession.query(models.GamessCalculation) \
        .filter_by(hashkey=hashkey).first()

    if calculation is not None:

        msg = {'hashkey': hashkey}

        calculation.created = datetime.datetime.now()
        return msg

    print("new:", hashkey)

    molecule_info = {"sdfstr": sdfstr, "molobj": molobj, "hashkey": hashkey}

    msg = pipelines.gamess_quantum_pipeline(request, molecule_info)

    return msg

    #
    #
    #

    calculation = request.dbsession.query(models.GamessCalculation) \
        .filter_by(hashkey=hashkey).first()

    if calculation is not None:
        calculation.created = datetime.datetime.now()
        return msg
    else:
        pass

    # check if folder exists
    here = os.path.abspath(os.path.dirname(__file__)) + "/"
    datahere = here + "data/"

    if os.path.isdir(datahere + hashkey):
        # return msg
        pass

    else:
        os.mkdir(datahere + hashkey)

    os.chdir(datahere + hashkey)

    # Minimize with forcefield first
    molobj = cheminfo.molobj_add_hydrogens(molobj)

    cheminfo.molobj_optimize(molobj)

    header = """ $basis gbasis=pm3 $end
 $contrl runtyp=optimize icharg=0 $end
 $statpt opttol=0.0005 nstep=200 projct=.F. $end
"""

    # Prepare gamess input
    # inpstr = gamess.molobj_to_gmsinp(molobj, header)

    # Save and run file
    # with open("optimize.inp", "w") as f:
    #     f.write(inpstr)
    #
    # stdout, stderr = gamess.calculate(hashkey+".inp", store_output=False)

    # with open("start.sdf", 'w') as f:
    #     f.write(cheminfo.molobj_to_sdfstr(molobj))

    # Check output
    # status, message = gamess.check_output(stdout)

    os.chdir(here)

    # if not status:
    #     msg["error"] = "error 192: QM Calculation fail"
    #     msg["message"] = message
    #     return msg

    # Saveable sdf and reset title
    sdfstr = cheminfo.molobj_to_sdfstr(molobj)
    sdfstr = str(sdfstr)
    for _ in range(2):
        i = sdfstr.index('\n')
        sdfstr = sdfstr[i + 1:]
    sdfstr = "\n\n" + sdfstr

    # Get a 2D Picture
    # TODO Compute 2D coordinates
    svgstr = cheminfo.molobj_to_svgstr(molobj, removeHs=True)

    # Success, setup database
    calculation = models.GamessCalculation()
    calculation.smiles = smiles
    calculation.hashkey = hashkey
    calculation.sdf = sdfstr
    calculation.svg = svgstr
    calculation.created = datetime.datetime.now()

    # Add calculation to the database
    request.dbsession.add(calculation)

    # Add smiles to counter
    countobj = request.dbsession.query(models.Counter) \
        .filter_by(smiles=smiles).first()

    if countobj is None:
        counter = models.Counter()
        counter.smiles = smiles
        counter.count = 1
        request.dbsession.add(counter)
        print(counter)
    else:
        countobj.count += 1

    return msg
예제 #3
0
def calculation_pipeline(molinfo, settings):
    """

    Assumed that rdkit understands the molecule

    args:
        molinfo - dict
        settings -

    """

    # Read input
    molobj = molinfo["molobj"]
    sdfstr = molinfo["sdfstr"]
    hashkey = molinfo["hashkey"]

    scratch_dir = settings["scr.scr"]
    scratch_dir = pathlib.Path(scratch_dir)

    # TODO Get molecule names

    # Get that smile on your face
    try:
        smiles = chembridge.molobj_to_smiles(molobj, remove_hs=True)
    except Exception:
        smiles = chembridge.molobj_to_smiles(molobj)

    # Start respond message
    msg = {"smiles": smiles, "hashkey": hashkey}

    atoms = chembridge.molobj_to_atoms(molobj)
    _logger.info(f"{hashkey} '{smiles}' {atoms}")

    # Create new calculation
    calculation = models.GamessCalculation()

    # Switch to scrdir / hashkey
    hashdir = scratch_dir / hashkey
    hashdir.mkdir(parents=True, exist_ok=True)

    gamess_options = {
        "cmd": settings["gamess.rungms"],
        "gamess_scr": settings["gamess.scr"],
        "gamess_userscr": settings["gamess.userscr"],
        "scr": hashdir,
        "filename": hashkey,
    }

    # TODO Add error messages when gamess fails
    # TODO add timeouts for all gamess calls

    # Optimize molecule
    try:
        properties = gamess_calculations.optimize_coordinates(
            molobj, gamess_options)

    except Exception:
        # TODO Logger + rich should store these exceptions somewhere. One file
        # per exception for easy debugging.
        # TODO Should store SDF of the molecule if exception
        sdfstr = chembridge.molobj_to_sdfstr(molobj)
        _logger.error(f"{hashkey} OptimizationError", exc_info=True)
        _logger.error(sdfstr)
        properties = None

    if properties is None:
        return {
            "error": "Error g-80 - gamess optimization error",
            "message": "Error. Unable to optimize molecule",
        }, None

    if "error" in properties:
        return {
            "error": "Error g-93 - gamess optimization error known",
            "message": properties["error"],
        }, None

    if (COLUMN_COORDINATES not in properties
            or properties[COLUMN_COORDINATES] is None):
        return {
            "error": "Error g-104 - gamess optimization error",
            "message": "Error. Unable to optimize molecule",
        }, None

    _logger.info(f"{hashkey} OptimizationSucces")

    # Save and set coordinates
    coord = properties[ppqm.constants.COLUMN_COORDINATES]
    calculation.coordinates = misc.save_array(coord)
    calculation.enthalpy = properties[ppqm.constants.COLUMN_ENERGY]
    chembridge.molobj_set_coordinates(molobj, coord)

    # Optimization is finished, do other calculation async-like

    (
        properties_vib,
        properties_orb,
        properties_sol,
    ) = gamess_calculations.calculate_all_properties(molobj, gamess_options)

    # Check results

    if properties_vib is None or "error" in properties_vib:
        return {
            "error": "Error g-104 - gamess vibration error",
            "message": "Error. Unable to vibrate molecule",
        }, None

    _logger.info(f"{hashkey} VibrationSuccess")

    # TODO Make a custom reader and move this out of ppqm
    calculation.islinear = properties_vib["linear"]
    calculation.vibjsmol = properties_vib["jsmol"]
    calculation.vibfreq = misc.save_array(properties_vib["freq"])
    calculation.vibintens = misc.save_array(properties_vib["intens"])
    calculation.thermo = misc.save_array(properties_vib["thermo"])

    if properties_orb is None or "error" in properties_orb:
        return {
            "error": "Error g-128 - gamess orbital error",
            "message": "Error. Unable to calculate molecular orbitals",
        }, None

    _logger.info(f"{hashkey} OrbitalsSuccess")
    calculation.orbitals = misc.save_array(properties_orb["orbitals"])
    calculation.orbitalstxt = properties_orb["stdout"]

    if properties_sol is None or "error" in properties_sol:

        # Is okay solvation didn't converge, just warn.
        _logger.warning(f"{hashkey} SolvationError")

    else:
        # 'charges', 'solvation_total', 'solvation_polar',
        # 'solvation_nonpolar', 'surface', 'total_charge', 'dipole',
        # 'dipole_total'
        _logger.info(f"{hashkey} SolvationSuccess")

        charges = properties_sol["charges"]
        calculation.charges = misc.save_array(charges)
        calculation.soltotal = properties_sol["solvation_total"]
        calculation.solpolar = properties_sol["solvation_polar"]
        calculation.solnonpolar = properties_sol["solvation_nonpolar"]
        calculation.solsurface = properties_sol["surface"]
        calculation.soldipole = misc.save_array(properties_sol["dipole"])
        calculation.soldipoletotal = properties_sol["dipole_total"]

        # Save mol2 fmt
        mol2 = chembridge.molobj_to_mol2(molobj, charges=charges)
        calculation.mol2 = mol2

    # Saveable sdf and reset title
    sdfstr = chembridge.molobj_to_sdfstr(molobj)
    sdfstr = chembridge.clean_sdf_header(sdfstr)

    # Get a 2D Picture
    svgstr = chembridge.molobj_to_svgstr(molobj, removeHs=True, use_2d=True)

    # Success, store results database
    calculation.smiles = smiles
    calculation.hashkey = hashkey
    calculation.sdf = sdfstr
    calculation.svg = svgstr
    calculation.created = datetime.datetime.now()

    return msg, calculation