Example #1
0
def find_closest_o_to_ostar(water_oxys, o_star, hydronium, box, h30_atom_type):
    """
    Calculate the minimum distance between a water oxygen and the protonatable oxygen atom closest to the excess proton
    @param water_oxys:
    @param o_star: the protonatable oxygen atom closest to the excess proton
    @param hydronium: the list of atoms in the hydronium, if there is a hydronium
    @param box: the dimensions of the periodic box (assumed 90 degree angles)
    @param h30_atom_type: (int) lammps type for h30 oxygen atom
    @return: the water oxygen (or hydronium oxygen) closest to the o_star, and the distance between them
    """
    # initialize smallest distance to the maximum distance in a periodic box
    min_dist = np.linalg.norm(np.divide(box, 2))
    closest_o = None
    if not hydronium:
        # initialize minimum distance to maximum distance allowed in the PBC
        for wat_o in water_oxys:
            dist = pbc_dist(np.asarray(wat_o[XYZ_COORDS]), np.asarray(o_star[XYZ_COORDS]), box)
            if dist < min_dist:
                min_dist = dist
                closest_o = wat_o
    else:
        for atom in hydronium:
            if atom[ATOM_TYPE] == h30_atom_type:
                min_dist = pbc_dist(np.asarray(atom[XYZ_COORDS]), np.asarray(o_star[XYZ_COORDS]), box)
                closest_o = atom

    return closest_o, min_dist
Example #2
0
def find_closest_o_to_ostar(water_oxys, o_star, hydronium, box,
                            h3o_oxy_atom_type):
    """
    Calculate the minimum distance between a water oxygen and the protonatable oxygen atom closest to the excess proton
    @param water_oxys: list of atom dicts
    @param o_star: the protonatable oxygen atom closest to the excess proton
    @param hydronium: the list of atoms in the hydronium, if there is a hydronium
    @param box: the dimensions of the periodic box (assumed 90 degree angles)
    @param h3o_oxy_atom_type: (int) lammps type for h30 oxygen atom
    @return: the water oxygen (or hydronium oxygen) closest to the o_star, and the distance between them
    """
    # initialize smallest distance to the maximum distance in a periodic box
    min_dist = np.linalg.norm(np.divide(box, 2))
    closest_o = None
    o_star_coord = np.asarray(o_star[XYZ_COORDS])
    if not hydronium:
        # initialize minimum distance to maximum distance allowed in the PBC
        for wat_o in water_oxys:
            dist = pbc_dist(np.asarray(wat_o[XYZ_COORDS]), o_star_coord, box)
            if dist < min_dist:
                min_dist = dist
                closest_o = wat_o
    else:
        for atom in hydronium:
            if atom[ATOM_TYPE] == h3o_oxy_atom_type:
                min_dist = pbc_dist(np.asarray(atom[XYZ_COORDS]), o_star_coord,
                                    box)
                closest_o = atom

    return closest_o, min_dist
Example #3
0
def find_closest_excess_proton(carboxyl_oxys, prot_h, hydronium, box, cfg):
    # initialize minimum distance to maximum distance possible in the periodic box (assume 90 degree corners)
    min_dist = np.full(len(carboxyl_oxys), np.linalg.norm(np.divide(box, 2)))
    closest_h = {}
    alt_dist = np.nan
    for index, oxy in enumerate(carboxyl_oxys):
        if prot_h is None:
            for atom in hydronium:
                if atom[ATOM_TYPE] == cfg[H3O_H_TYPE]:
                    dist = pbc_dist(np.asarray(atom[XYZ_COORDS]), np.asarray(oxy[XYZ_COORDS]), box)
                    if dist < min_dist[index]:
                        min_dist[index] = dist
                        closest_h[index] = atom
        else:
            min_dist[index] = pbc_dist(np.asarray(prot_h[XYZ_COORDS]), np.asarray(oxy[XYZ_COORDS]), box)
            closest_h[index] = prot_h
    index_min = np.argmin(min_dist)
    min_min = min_dist[index_min]
    o_star = carboxyl_oxys[index_min]
    excess_proton = closest_h[index_min]
    # The distance calculated again below because this will ensure that the 2nd return distance uses the same excess
    # proton
    for index, oxy in enumerate(carboxyl_oxys):
        if index != index_min:
            alt_dist = pbc_dist(np.asarray(excess_proton[XYZ_COORDS]), np.asarray(oxy[XYZ_COORDS]), box)
    alt_min = np.amin(alt_dist)
    return excess_proton, o_star, {OH_MIN: min_min, OH_MAX: alt_min, OH_DIFF: alt_min - min_min}
Example #4
0
def atom_distances(rst, atom_pairs):
    """Finds the distance between the each of the atom pairs in the
    given LAMMPS dump file.

    :param rst: A file in the LAMMPS dump format.
    :param atom_pairs: Zero or more pairs of atom IDs to compare.
    :returns: Nested dicts keyed by time step, then pair, with the distance as the value.
    """
    results = OrderedDict()
    flat_ids = set(itertools.chain.from_iterable(atom_pairs))
    tstep_atoms, tstep_box = find_atom_data(rst, flat_ids)

    for tstep, atoms in tstep_atoms.items():
        pair_dist = OrderedDict({FILENAME: os.path.basename(rst)})
        for pair in atom_pairs:
            try:
                row1 = atoms[pair[0]]
                row2 = atoms[pair[1]]
                pair_dist[pair] = pbc_dist(row1[-3:], row2[-3:],
                                           tstep_box[tstep])
            except KeyError as e:
                warning(MISSING_TSTEP_ATOM_MSG.format(rst, tstep, e))
                return
        results[tstep] = pair_dist
    return results
Example #5
0
def calc_pair_dists(atom_a_list, atom_b_list, box):
    dist = np.zeros(len(atom_a_list) * len(atom_b_list))
    dist_index = 0
    for atom_a in atom_a_list:
        for atom_b in atom_b_list:
            dist[dist_index] = pbc_dist(np.asarray(atom_a[XYZ_COORDS]), np.asarray(atom_b[XYZ_COORDS]), box)
            dist_index += 1
    return dist
Example #6
0
def calc_pair_dists(atom_a_list, atom_b_list, box):
    dist = np.zeros(len(atom_a_list) * len(atom_b_list))
    dist_index = 0
    for atom_a in atom_a_list:
        for atom_b in atom_b_list:
            dist[dist_index] = pbc_dist(np.asarray(atom_a[XYZ_COORDS]),
                                        np.asarray(atom_b[XYZ_COORDS]), box)
            dist_index += 1
    return dist
Example #7
0
def find_closest_wat_o_to_hyd_o(water_oxys, hydronium, box, h3o_oxy_atom_type):
    """
    Calculate the minimum distance between a water oxygen a hydronium oxygen
    @param water_oxys: list of atom dicts
    @param hydronium: the list of atoms in the hydronium, if there is a hydronium
    @param box: the dimensions of the periodic box (assumed 90 degree angles)
    @param h3o_oxy_atom_type: (int) lammps type for h30 oxygen atom
    @return: the water oxygen closest to the hydronium oxygen and the distance between them; the hydronium oxygen;
       the hydronium hydrogen closes to the water oxygen and the distance between it and the hydronium oxygen
    """
    min_oo_dist = np.linalg.norm(np.divide(box, 2))
    min_oh_dist = copy.copy(min_oo_dist)
    wat_o_hstar_dist = copy.copy(min_oo_dist)
    close_wat_o_to_hyd = None
    hyd_o = None
    hyd_h = []
    close_hyd_h_to_wat = None
    for atom in hydronium:
        if atom[ATOM_TYPE] == h3o_oxy_atom_type:
            hyd_o = atom
        else:
            hyd_h.append(atom)
    hyd_o_coords = np.asarray(hyd_o[XYZ_COORDS])
    for wat_o in water_oxys:
        dist = pbc_dist(np.asarray(wat_o[XYZ_COORDS]), hyd_o_coords, box)
        if dist < min_oo_dist:
            min_oo_dist = dist
            close_wat_o_to_hyd = wat_o
    close_wat_o_coords = np.asarray(close_wat_o_to_hyd[XYZ_COORDS])
    for h_atom in hyd_h:
        # noinspection PyTypeChecker
        h_atom_coords = np.asarray(h_atom[XYZ_COORDS])
        dist = pbc_dist(h_atom_coords, close_wat_o_coords, box)
        if dist < wat_o_hstar_dist:
            wat_o_hstar_dist = dist
            min_oh_dist = pbc_dist(h_atom_coords, hyd_o_coords, box)
            close_hyd_h_to_wat = h_atom

    hyd_wat_dict = {
        R_OO_HYD_WAT: min_oo_dist,
        R_OH_HYD: min_oh_dist,
        R_OH_WAT_HYD: wat_o_hstar_dist
    }
    return hyd_wat_dict, hyd_o, close_hyd_h_to_wat, close_wat_o_to_hyd
Example #8
0
def calc_q_arq(r_ao, r_do, r_h, box, r0_sc, r0_da_q, lambda_q):
    """
    Calculates the 3-body term, keeping the pbc in mind, per Maupin et al. 2006,
    http://pubs.acs.org/doi/pdf/10.1021/jp053596r, equations 7-8
    @param r_ao: x,y,z position of the acceptor oxygen (closest water O)
    @param r_do: x,y,z position of the donor oxygen (always using the glu oxygen, for now)
    @param r_h: x,y,z position of the reactive H
    @param box: the dimensions of the periodic box (assumed 90 degree angles)
    @param r0_sc: parameter for calc
    @param r0_da_q: parameter for calc
    @param lambda_q: parameters for calc
    @return: the dot-product of the vector q (not the norm, as we need it squared for the next step)
    """
    da_dist = pbc_dist(r_do, r_ao, box)
    r_sc = r0_sc - lambda_q * (da_dist - r0_da_q)
    r_dh = pbc_calc_vector(r_h, r_do, box)
    r_da = pbc_calc_vector(r_ao, r_do, box)
    q_vec = np.subtract(r_dh, r_sc * r_da / 2.0)
    return da_dist, np.dot(q_vec, q_vec)
Example #9
0
def deprotonate(cfg, protonatable_res, excess_proton, dump_h3o_mol,
                water_mol_dict, box, tpl_data):
    """
    Deprotonate a the residue and assign the proton to the closest water
    so that the output data matches with the template.
    """
    # Convert excess proton to a hydronium proton
    excess_proton[1] = tpl_data[H3O_MOL][0][1]  # molecule number
    excess_proton[2] = cfg[H3O_H_TYPE]  # type
    excess_proton[3] = tpl_data[H3O_H_CHARGE]  # charge
    dump_h3o_mol.append(excess_proton)
    min_dist_id = None
    min_dist = np.linalg.norm(box)
    for mol_id, molecule in water_mol_dict.items():
        for atom in molecule:
            if atom[2] == cfg[WAT_O_TYPE]:
                dist = pbc_dist(np.asarray(excess_proton[4:7]),
                                np.asarray(atom[4:7]), box)
        if dist < min_dist:
            min_dist_id = mol_id
            min_dist = dist
    logger.debug('Deprotonated residue: the molecule ID of the closest water '
                 '(to become a hydronium) is {}.'.format(min_dist_id))
    # Now that have the closest water, add its atoms to the hydronium list
    for atom in water_mol_dict[min_dist_id]:
        dump_h3o_mol.append(atom)
        # Remove the closest water from the dictionary of water molecules, and convert it to a hydronium
    del water_mol_dict[min_dist_id]
    for atom in dump_h3o_mol:
        if atom[2] == cfg[WAT_O_TYPE]:
            atom[2] = cfg[H3O_O_TYPE]
            atom[3] = tpl_data[H3O_O_CHARGE]
        elif atom[2] == cfg[WAT_H_TYPE]:
            atom[2] = cfg[H3O_H_TYPE]
            atom[3] = tpl_data[H3O_H_CHARGE]
    # Make the atom type and charge of the protonatable residue the same as for the template file (switching
    # from protonated to deprotonated residue)
    if len(tpl_data[PROT_RES_MOL]) != len(protonatable_res):
        raise InvalidDataError(
            'Encountered dump file in which the number of atoms in the '
            'protonatable residue does not equal the number of atoms in the template data file.'
        )
Example #10
0
def deprotonate(cfg, protonatable_res, excess_proton, dump_h3o_mol, water_mol_dict, box, tpl_data):
    """
    Deprotonate a the residue and assign the proton to the closest water
    so that the output data matches with the template.
    """
    # Convert excess proton to a hydronium proton
    excess_proton[1] = tpl_data[H3O_MOL][0][1]   # molecule number
    excess_proton[2] = cfg[H3O_H_TYPE]           # type
    excess_proton[3] = tpl_data[H3O_H_CHARGE]    # charge
    dump_h3o_mol.append(excess_proton)
    min_dist_id = None
    min_dist = np.linalg.norm(box)
    for mol_id, molecule in water_mol_dict.items():
        for atom in molecule:
            if atom[2] == cfg[WAT_O_TYPE]:
                dist = pbc_dist(np.asarray(excess_proton[4:7]), np.asarray(atom[4:7]), box)
        if dist < min_dist:
            min_dist_id = mol_id
            min_dist = dist
    logger.debug('Deprotonated residue: the molecule ID of the closest water '
                 '(to become a hydronium) is {}.'.format(min_dist_id))
    # Now that have the closest water, add its atoms to the hydronium list
    for atom in water_mol_dict[min_dist_id]:
        dump_h3o_mol.append(atom)
        # Remove the closest water from the dictionary of water molecules, and convert it to a hydronium
    del water_mol_dict[min_dist_id]
    for atom in dump_h3o_mol:
        if atom[2] == cfg[WAT_O_TYPE]:
            atom[2] = cfg[H3O_O_TYPE]
            atom[3] = tpl_data[H3O_O_CHARGE]
        elif atom[2] == cfg[WAT_H_TYPE]:
            atom[2] = cfg[H3O_H_TYPE]
            atom[3] = tpl_data[H3O_H_CHARGE]
    # Make the atom type and charge of the protonatable residue the same as for the template file (switching
    # from protonated to deprotonated residue)
    if len(tpl_data[PROT_RES_MOL]) != len(protonatable_res):
        raise InvalidDataError('Encountered dump file in which the number of atoms in the '
                               'protonatable residue does not equal the number of atoms in the template data file.')
Example #11
0
def calc_more_ocoh_props(box, carboxyl_c_xyz, o_star_xyz, alt_o_xyz,
                         excess_h_xyz):
    """
    If requested and there are xyz coords,
    @param box: xyz box size
    @param carboxyl_c_xyz:
    @param o_star_xyz:
    @param alt_o_xyz:
    @param excess_h_xyz:
    @return: a dict of additional calculated properties
    """
    if carboxyl_c_xyz is not None:
        # TODO: test that accounts for the case when carboxyl group is broken over the PBC
        # does not have be be shown: move c_carbon to the origin; we know the results of moving it and multiplying
        #   the resulting xyz coords (0, 0, 0) by the COM_WEIGHT_C
        c_o_star_vec = pbc_calc_vector(o_star_xyz, carboxyl_c_xyz, box)
        c_alt_o_vec = pbc_calc_vector(alt_o_xyz, carboxyl_c_xyz, box)
        c_h_star_vec = pbc_calc_vector(excess_h_xyz, carboxyl_c_xyz, box)
        o_star_h_vec = pbc_calc_vector(excess_h_xyz, o_star_xyz, box)

        com_xyz = COM_WEIGHT_PER_O * c_o_star_vec
        com_xyz += COM_WEIGHT_PER_O * c_alt_o_vec

        oh_prop_dict = {
            COM_H_DIST: pbc_dist(com_xyz, c_h_star_vec, box),
            OCO_ANGLE: vec_angle(c_o_star_vec, c_alt_o_vec),
            OCOH_DIH: vec_dihedral(c_alt_o_vec, c_o_star_vec, o_star_h_vec),
            COM_XYZ: carboxyl_c_xyz + com_xyz
        }
    else:
        oh_prop_dict = {
            COM_H_DIST: np.nan,
            OCO_ANGLE: np.nan,
            OCOH_DIH: np.nan,
            COM_XYZ: np.nan
        }
    return oh_prop_dict
Example #12
0
def find_closest_excess_proton(carboxyl_oxys, prot_h, hydronium, box, cfg,
                               carboxyl_carbon, cec_xyz):
    # initialize minimum distance to maximum distance possible in the periodic box (assume 90 degree corners)
    oxy_h_min_dists = np.full(len(carboxyl_oxys),
                              np.linalg.norm(np.divide(box, 2)))
    # excess proton will become None if prot_h is none, then calculated
    excess_proton = prot_h
    for index, oxy in enumerate(carboxyl_oxys):
        if prot_h is None:
            for atom in hydronium:
                if atom[ATOM_TYPE] == cfg[H3O_H_TYPE]:
                    dist = pbc_dist(np.asarray(atom[XYZ_COORDS]),
                                    np.asarray(oxy[XYZ_COORDS]), box)
                    if dist < oxy_h_min_dists[index]:
                        oxy_h_min_dists[index] = dist
                        excess_proton = atom
        else:
            oxy_h_min_dists[index] = pbc_dist(np.asarray(prot_h[XYZ_COORDS]),
                                              np.asarray(oxy[XYZ_COORDS]), box)
    index_min = np.argmin(oxy_h_min_dists)
    o_star = carboxyl_oxys[index_min]
    min_oh_dist = oxy_h_min_dists[index_min]
    oh_prop_dict = {OH_MIN: min_oh_dist}
    if cfg[CALC_OCOH_PROPS] or cfg[CALC_CEC_DIST]:
        # the following depends on there being exactly 2 carboxylic oxygen atoms
        index_max = abs(index_min - 1)

        o_star_xyz = np.asarray(o_star[XYZ_COORDS])
        excess_proton_xyz = np.asarray(excess_proton[XYZ_COORDS])
        alt_o_xyz = np.asarray(carboxyl_oxys[index_max][XYZ_COORDS])
        # distance calculated again to ensure that the 2nd return distance uses the same excess proton
        alt_oh_dist = pbc_dist(excess_proton_xyz, alt_o_xyz, box)
        oh_prop_dict.update({
            OH_MAX: alt_oh_dist,
            OH_DIFF: alt_oh_dist - min_oh_dist,
        })
        if carboxyl_carbon is not None:
            carboxyl_c_xyz = np.asarray(carboxyl_carbon[XYZ_COORDS])
            oh_prop_dict.update(
                calc_more_ocoh_props(box, carboxyl_c_xyz, o_star_xyz,
                                     alt_o_xyz, excess_proton_xyz))
        if cfg[CALC_CEC_DIST] and cec_xyz is not None:
            cec_o_dists = np.array([
                pbc_dist(cec_xyz, o_star_xyz, box),
                pbc_dist(cec_xyz, alt_o_xyz, box)
            ])
            oh_prop_dict[CEC_O_MIN] = cec_o_dists.min()
            oh_prop_dict[CEC_O_MAX] = cec_o_dists.max()
            oh_prop_dict[
                CEC_O_DIFF] = oh_prop_dict[CEC_O_MAX] - oh_prop_dict[CEC_O_MIN]
            oh_prop_dict[CEC_H_DIST] = pbc_dist(cec_xyz, excess_proton_xyz,
                                                box)
            oh_prop_dict[CEC_O_MIN_DIST] = calc_min_dist(
                np.array([oh_prop_dict[CEC_O_MIN], oh_prop_dict[CEC_O_MAX]]),
                cfg[MIN_DIST_BETA])
            if carboxyl_carbon is not None:
                oh_prop_dict[CEC_COM_DIST] = pbc_dist(cec_xyz,
                                                      oh_prop_dict[COM_XYZ],
                                                      box)

    return excess_proton, o_star, oh_prop_dict