Matter and Coordinates
Atoms and Charges are the building blocks of Crystals and Molecules in PorousMaterials.jl. Each have coordinates in both Cartesian and Fractional space (associated with unit cell information, i.e., a Box).
Coordinates
we store coordinates as an abstract Coords type that has two subtypes: Cart and Frac for Cartesian and Fractional, respectively. see the Wikipedia page on fractional coordinates, which are defined in the context of a periodic system, e.g. within a crystal.
construct coordinates of n particles by passing a n by 3 array
coord = Cart([1.0, 2.0, 5.0]) # construct cartesian coordinate of a particle
coord.x # 3 x 1 array, [1, 2, 3]
coord = Frac([0.1, 0.2, 0.5]) # construct fractional coordinate of a particle
coord.xf # 3 x 1 array, [0.1, 0.2, 0.3]the coordinates of multiple particles are stored column-wise:
coords = Cart([
0.651027 0.274176 0.386178 0.371651 0.619131;
0.0681196 0.0267313 0.836004 0.819681 0.585807;
0.667704 0.825569 0.780142 0.606194 0.572355
]) # five particles at uniform random coordinatesmany Array operations work on Coords, such as:
coords[2] # coordinate of 2nd particle
coords[2:3] # (slicing by index) coords of particles 2 and 3
coords[[1, 2, 5]] # (slicing by index) coords of particles 1, 2, and 5
coords[rand(Bool, 5)] # (boolean slicing) coords, selected at random
length(coords) # number of particles, (5)manipulating coordinates
Coords are immutable:
coords.x = rand(3, 5)
# output
ERROR: setfield! immutable struct of type Cart cannot be changedbut we can manipulate the values of Array{Float64, 2} where coordinates (through coords.x or coords.xf) are stored:
coords.x[2, 3] = 100.0
coords.x[:] = [ # need the [:] to say "overwrite all of the elements"
0.496997 0.560528 0.496615 0.213062 0.21751;
0.772372 0.697443 0.133055 0.211073 0.02676;
0.230555 0.0988727 0.592699 0.193649 0.16536
]fractional coordinates can be wrapped to be inside the unit cell box:
coords = Frac([1.2, -0.3, 0.9])
wrap!(coords)
# output
3×1 Matrix{Float64}:
0.19999999999999996
0.7
0.9we can translate coordinates by a vector dx:
dx = Cart([1.0, 2.0, 3.0])
coords = Cart([1.0, 0.0, 0.0])
translate_by!(coords, dx)
# output
3×1 Matrix{Float64}:
2.0
2.0
3.0if dx::Frac and coords::Cart, translate_by! requires a Box to convert between fractional and cartesian, as the last argument:
dx = Frac([0.1, 0.2, 0.3])
box = unit_cube()
coords = Cart([1.0, 0.0, 0.0])
translate_by!(coords, dx, box)
# output
3×1 Matrix{Float64}:
1.1
0.20000000000000004
0.3Atoms
an atom is specified by its coordinates and atomic species. we can construct a set of atoms (perhaps, comprising a molecule or crystal) as follows.
species = [:O, :H, :H] # atomic species are represnted with Symbols
coords = Cart([0.0 0.757 -0.757; # coordinates of each
0.0 0.586 0.586;
0.0 0.0 0.0 ]
)
atoms = Atoms(species, coords) # 3 atoms comprising water
atoms.n # number of atoms, 3
atoms.coords # coordinates; atoms.coords.x gives the array of coords
atoms.species # array of species
atoms::Atoms{Cart} # successful type assertion, as opposed to atoms::Atoms{Frac}
# output
Atoms{Cart}(3, [:O, :H, :H], Cart([0.0 0.757 -0.757; 0.0 0.586 0.586; 0.0 0.0 0.0]))the last line illustrates the two subtypes of Atoms, depending on whether the Coords are stored as Fractional or Cartesian.
we can slice atoms, such as:
atoms[2:3]
# output
Atoms{Cart}(2, [:H, :H], Cart([0.757 -0.757; 0.586 0.586; 0.0 0.0]))and combine them:
atoms_combined = atoms[1] + atoms[2:3]
isapprox(atoms, atoms_combined)
# output
trueCharges
Charges, well, point charges, work analogously to atoms, except instead of species, the values of the point charges are stored in an array, q.
q = [-1.0, 0.5, 0.5] # values of point charges, units: electrons
coords = Cart([0.0 0.757 -0.757; # coordinates of the point charges
0.0 0.586 0.586;
0.0 0.0 0.0 ]
)
charges = Charges(q, coords) # 3 point charges
charges.n # number of charges, 3
charges.coords # retreive coords
charges.q # retreive q
charges::Charges{Cart} # successful type assertion, as opposed to charges::Charges{Frac}
# output
Charges{Cart}(3, [-1.0, 0.5, 0.5], Cart([0.0 0.757 -0.757; 0.0 0.586 0.586; 0.0 0.0 0.0]))we can determine if the set of point charges comprise a charge-neutral system by:
net_charge(charges) # 0.0
neutral(charges) # truedetailed docs
Missing docstring for Coords. Check Documenter's build log for details.
Missing docstring for Frac. Check Documenter's build log for details.
Missing docstring for Cart. Check Documenter's build log for details.
Missing docstring for Atoms. Check Documenter's build log for details.
Missing docstring for Charges. Check Documenter's build log for details.
Missing docstring for net_charge. Check Documenter's build log for details.
Missing docstring for neutral. Check Documenter's build log for details.
Missing docstring for translate_by!. Check Documenter's build log for details.