def atom_surface(self, atom: Atom, ref: Surface, prad: float) -> Surface: """Create a new surface from the points that do fall on the reference surface. :param atom: Atom from which surface will be constructed. :return: Returns surface generated from the atom. .. note:: Although this seems like a candidate for a static method, the `accessable_outside_inflated_venderwalls_rad` method of this class *is* called from this function, and therefore must be a regular method. """ arad = atom.radius apos = atom.position atomID = atom.id surf: Surface if arad < Constants.very_small_eps: return Surface(prad, 0) rad = arad + prad # Possibly merge these two loops? npoints = 0 pos = Coordinate() for i in range(ref.npoints): pos.x = rad(ref.xs[i]) + apos.x pos.y = rad(ref.ys[i]) + apos.y pos.z = rad(ref.zs[i]) + apos.z # need to implement if self.accessable_outside_inflated_venderwalls_rad( pos, prad, atomID ): npoints += 1 ref.is_on_surf[i] = True else: ref.is_on_surf[i] = False surf = Surface(prad, npoints) for i in range(ref.npoints): if ref.coords[i].is_on_surf: surf.coords.append((rad * ref.coords[i] + apos)) surf.coords[-1].is_on_surf = True surf.area = ( 4.0 * math.pi * rad * rad * float(surf.npoints) / float(ref.npoints) ) return surf
def test_property_set(self): sut = Coordinate(0, 0, 0) assert sut.x == 0 assert sut.y == 0 assert sut.z == 0 sut.x = 1 sut.y = 2 sut.z = 3 assert sut.x == 1 assert sut.y == 2 assert sut.z == 3
def __init__(self, filename: str = None, atoms=None): self._atoms: Tuple[Atom] = atoms if atoms is not None else [] self.charge: float = None self.maxrad: float = None self._center = Coordinate() self._mincrd = Coordinate() self._maxcrd = Coordinate() self._dp = dict() if filename is not None: self.read_pdb(filename)
def __init__(self, *vals: List[float]): if len(vals) > 0: self.position = Coordinate(*vals) else: self.position = Coordinate() self.radius: float = 0.0 self.charge: float = 0.0 self.partID: float = 0.0 self.epsilon: float = 0.0 self.id: int = 0 self.res_name: str = "" self.name: str = ""
def __init__(self, atoms: List = None): """ Construct a list of Atoms. :param List atoms: A list of Atoms """ self._atoms: Tuple[Atom] = atoms if atoms is not None else [] self.charge: float = None self.maxrad: float = None self._center = Coordinate() self._min_coord = Coordinate() self._max_coord = Coordinate() self._dp = dict()
def test_any(self): c = Coordinate(3, 2, 2) assert c.any(lambda x: x > 2) c = Coordinate(-1, 2, 2) assert c.any(lambda x: x < 0) assert c.any(lambda x: x == -1)
def test_get_idx(self): sut = Coordinate(0, 0, 0) sut[0] = 1 sut[1] = 2 sut[2] = 3 assert sut.x == 1 assert sut.y == 2 assert sut.z == 3 with pytest.raises(IndexError): sut[3] = 5
def mincrd(self) -> Coordinate: """Minimum coordinates """ if "min" not in self._dp.keys(): x, y, z = inf, inf, inf for a in self._atoms: x = min(x, a.x) y = min(y, a.y) z = min(z, a.z) self._dp["min"] = Coordinate(x, y, z) return self._dp["min"]
def maxcrd(self) -> Coordinate: """Maximum coordinates """ if "max" not in self._dp.keys(): x, y, z = 0.0, 0.0, 0.0 for a in self._atoms: x = max(x, a.x) y = max(y, a.y) z = max(z, a.z) self._dp["max"] = Coordinate(x, y, z) return self._dp["max"]
def min_coord(self) -> Coordinate: """Minimum coordinates :return: The minimum Coordinate :rtype: Coordinate """ if "min" not in self._dp.keys(): x, y, z = np.inf, np.inf, np.inf for a in self._atoms: x = min(x, a.x) y = min(y, a.y) z = min(z, a.z) self._dp["min"] = Coordinate(x, y, z) return self._dp["min"]
def center(self) -> Coordinate: """Molecule center note: not the median molecule, but the average of the max values int the x, y, and z coordinates """ if "center" not in self._dp.keys(): ma = self.maxcrd() mi = self.mincrd() self._dp["center"] = Coordinate( (ma.x + mi.x) * 0.5, (ma.y + mi.y) * 0.5, (ma.z + mi.z) * 0.5, ) return self._dp["center"]
def max_coord(self) -> Coordinate: """Maximum coordinates :return: The maximum Coordinate :rtype: Coordinate """ if "max" not in self._dp.keys(): x, y, z = 0.0, 0.0, 0.0 for atom in self._atoms: x = max(x, atom.x) y = max(y, atom.y) z = max(z, atom.z) self._dp["max"] = Coordinate(x, y, z) return self._dp["max"]
def test_exceptions(self, args): with pytest.raises(RuntimeError): sut = Coordinate(*args)
def test_property_get(self): sut = Coordinate(1, 2, 3) assert sut.x == 1 assert sut.y == 2 assert sut.z == 3
def test_operators(self): lo = Coordinate(0, 0, 0) hi = Coordinate(1, 1, 1) assert hi > lo same1 = Coordinate(0, 0, 0) same2 = Coordinate(0, 0, 0) assert same1 == same2 lo = Coordinate(0, 0, 0) hi = Coordinate(1, 1, 1) assert hi != lo same1 = Coordinate(0, 0, 0) same2 = Coordinate(0, 0, 0) assert same1 <= same2 lo = Coordinate(0, 0, 0) hi = Coordinate(1, 1, 1) assert lo <= hi same1 = Coordinate(0, 0, 0) same2 = Coordinate(0, 0, 0) assert same1 >= same2 lo = Coordinate(0, 0, 0) hi = Coordinate(1, 1, 1) assert lo <= hi c = Coordinate(0, 0, 0) assert c + 1 == Coordinate(1, 1, 1) c = Coordinate(1, 1, 1) assert c - 1 == Coordinate(0, 0, 0) c = Coordinate(1, 1, 1) assert c * 2 == Coordinate(2, 2, 2) c = Coordinate(2, 2, 2) assert c / 2 == Coordinate(1, 1, 1)
def test_euclidian_distance_array2(self, params1, params2): expect = np.sum((np.array(params1) - np.array(params2))**2) a = Atom(id=1, *params1) b = Coordinate(*params2) assert a.euclidian_dist2(b) == expect
def test_ctor(self, args, expect): sut = Coordinate(*args) assert (sut._data == expect).all()
def value(self, pt: Coordinate[float]) -> float: """Get potential value (from mesh or approximation) at a point :note: Previously returned by pointer, using return code as an error code. This has been replaced by returning the value and raising an exception on error. :param x : Coordinate at which to evaluate potential :returns : value of grid """ if self.data is None: raise RuntimeError("No data available.") ret_value = float(0) tmp = Coordinate( (pt.x - self.mins.x) / self.spaces.x, (pt.y - self.mins.y) / self.spaces.y, (pt.z - self.mins.z) / self.spaces.z, ) hi = Coordinate(int(math.ceil(tmp.x)), int(math.ceil(tmp.y)), int(math.ceil(tmp.z))) lo = Coordinate( int(math.floor(tmp.x)), int(math.floor(tmp.y)), int(math.floor(tmp.z)), ) hi.x = (self.dims.x - 1 if abs(pt.x - self.maxs.x) < Constants.epsilon else hi.x) hi.y = (self.dims.y - 1 if abs(pt.y - self.maxs.y) < Constants.epsilon else hi.y) hi.z = (self.dims.z - 1 if abs(pt.z - self.maxs.z) < Constants.epsilon else hi.z) lo.x = 0 if abs(pt.x - self.mins.x) < Constants.eps else lo.x lo.y = 0 if abs(pt.y - self.mins.y) < Constants.eps else lo.y lo.z = 0 if abs(pt.z - self.mins.z) < Constants.eps else lo.z if hi < self.dims: dx, dy, dz = tmp.x - lo.x, tmp.y - lo.y, tmp.z - lo.z ret_value = list() ret_value.append(float(dx * dy * dz * self.data[hi.x, hi.y, hi.z])) ret_value.append( float(dx * (1.0 - dy) * dz * self.data[hi.x, lo.y, hi.z])) ret_value.append( float(dx * dy * (1.0 - dz) * self.data[hi.x, hi.y, lo.z])) ret_value.append( float(dx * (1.0 - dy) * (1.0 - dz) * self.data[hi.x, lo.y, lo.z])) ret_value.append( float((1.0 - dx) * dy * dz * self.data[lo.x, hi.y, hi.z])) ret_value.append( float((1.0 - dx) * (1.0 - dy) * dz * self.data[lo.x, lo.y, hi.z])) ret_value.append( float((1.0 - dx) * dy * (1.0 - dz) * self.data[lo.x, hi.y, lo.z])) ret_value.append( float((1.0 - dx) * (1.0 - dy) * (1.0 - dz) * self.data[lo.x, lo.y, lo.z])) ret_value = sum(ret_value) if ret_value == math.nan: # TODO: Add a more descriptive error raise RuntimeError( "Value routine failed to converge with the following " "coordinates:\n" f"\tLow: {lo}\n" f"\tHigh: {hi}\n" f"\tCoordinate: {pt}\n") return ret_value
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.lower_bound = Coordinate() self.upper_bound = Coordinate() self.stride = Stride(0.0, 0.0, 0.0)
def __init__(self, *args, **kwargs): """ Arguments: :param int id: A unique identifier for this Atom :param str field_name: Specifies the type of PQR entry and should either be ATOM or HETATM in order to be parsed by APBS. :param int atom_number: The atom index. :param str atom_name: The atom name. :param str residue_name: The residue name. :param str chain_id: An optional value which provides the chain ID of the atom. NOTE: that chain ID support is a new feature of APBS 0.5.0 and later versions. :param int residue_number: The residue index. :param str ins_code: An optional value which provides the PDB insertion code. :param float x: The X atomic coordinate in angstroms :param float y: The Y atomic coordinate in angstroms :param float z: The Z atomic coordinate in angstroms :param float charge: The atomic charge (in electrons). :param float radius: The atomic radius (in angstroms). :Example: atom = Atom( id=42, field_name=ATOM, atom_number=39, atom_name=O3PB, residue_name=ADP, chain_id=None, residue_number=1, ins_code=None, x=-16.362, y=-6.763, z=26.980, charge=-0.900, radius=1.700 ) """ if len(args) > 0: self.position = Coordinate(args[0], args[1], args[2]) self.field_name: str = kwargs.get("field_name", None) self.atom_number: int = int(kwargs.get("atom_number", 0)) self.atom_name: str = kwargs.get("atom_name", None) self.residue_name: str = kwargs.get("residue_name", None) self.chain_id: str = kwargs.get("chain_id", None) self.residue_number: int = int(kwargs.get("residue_number", 0)) self.ins_code: str = kwargs.get("ins_code", None) if "x" in kwargs and "y" in kwargs and "z" in kwargs: self.position = Coordinate( float(kwargs.get("x")), float(kwargs.get("y")), float(kwargs.get("z")), ) self.charge: float = float(kwargs.get("charge", 0.0)) self.radius: float = float(kwargs.get("radius", 0.0)) self.epsilon: float = float(kwargs.get("epsilon", 0.0)) self.id: int = int(kwargs.get("id", 0)) if "id" not in kwargs: raise ValueError("The Atom id must be set to non-zero value")
def test_all(self): c = Coordinate(2, 2, 2) assert c.all(lambda x: x == 2) c = Coordinate(-1, 2, 2) assert c.all(lambda x: x < 3)