diff --git a/xyz2povray.py b/xyz2povray.py index a313bc7..2061518 100755 --- a/xyz2povray.py +++ b/xyz2povray.py @@ -9,19 +9,138 @@ class Atom: """define appearance of atoms as colored spheres""" + # define the properties for different species + # RGB values of the Jmol scheme + # reference: https://jmol.sourceforge.net/jscolors/ + properties = { + 'H': {'mass': 1, 'rad': 0.25, 'rgb': [1.00, 1.00, 1.00]}, + 'He': {'mass': 4, 'rad': 0.25, 'rgb': [0.85, 1.00, 1.00]}, + 'Li': {'mass': 6, 'rad': 0.25, 'rgb': [0.80, 0.51, 1.00]}, + 'Be': {'mass': 9, 'rad': 0.25, 'rgb': [0.76, 1.00, 0.00]}, + 'B': {'mass': 11, 'rad': 0.25, 'rgb': [1.00, 0.71, 0.71]}, + 'C': {'mass': 12, 'rad': 0.25, 'rgb': [0.56, 0.56, 0.56]}, + 'N': {'mass': 14, 'rad': 0.25, 'rgb': [0.19, 0.31, 0.97]}, + 'O': {'mass': 16, 'rad': 0.25, 'rgb': [1.00, 0.05, 0.05]}, + 'F': {'mass': 19, 'rad': 0.25, 'rgb': [0.56, 0.88, 0.31]}, + 'Ne': {'mass': 20, 'rad': 0.25, 'rgb': [0.70, 0.89, 0.96]}, + 'Na': {'mass': 22, 'rad': 0.25, 'rgb': [0.67, 0.36, 0.95]}, + 'Mg': {'mass': 24, 'rad': 0.25, 'rgb': [0.54, 1.00, 0.00]}, + 'Al': {'mass': 27, 'rad': 0.25, 'rgb': [0.75, 0.65, 0.65]}, + 'Si': {'mass': 29, 'rad': 0.25, 'rgb': [0.94, 0.78, 0.63]}, + 'P': {'mass': 31, 'rad': 0.25, 'rgb': [1.00, 0.50, 0.00]}, + 'S': {'mass': 32, 'rad': 0.25, 'rgb': [1.00, 1.00, 0.19]}, + 'Cl': {'mass': 35, 'rad': 0.25, 'rgb': [0.12, 0.94, 0.12]}, + 'Ar': {'mass': 40, 'rad': 0.25, 'rgb': [0.50, 0.82, 0.89]}, + 'K': {'mass': 39, 'rad': 0.25, 'rgb': [0.56, 0.25, 0.83]}, + 'Ca': {'mass': 40, 'rad': 0.25, 'rgb': [0.24, 1.00, 0.00]}, + 'Sc': {'mass': 45, 'rad': 0.25, 'rgb': [0.90, 0.90, 0.90]}, + 'Ti': {'mass': 48, 'rad': 0.25, 'rgb': [0.75, 0.76, 0.78]}, + 'V': {'mass': 51, 'rad': 0.25, 'rgb': [0.65, 0.65, 0.78]}, + 'Cr': {'mass': 52, 'rad': 0.25, 'rgb': [0.54, 0.60, 0.78]}, + 'Mn': {'mass': 55, 'rad': 0.25, 'rgb': [0.61, 0.48, 0.78]}, + 'Fe': {'mass': 56, 'rad': 0.25, 'rgb': [0.88, 0.40, 0.20]}, + 'Co': {'mass': 59, 'rad': 0.25, 'rgb': [0.94, 0.56, 0.62]}, + 'Ni': {'mass': 59, 'rad': 0.25, 'rgb': [0.31, 0.82, 0.31]}, + 'Cu': {'mass': 63, 'rad': 0.25, 'rgb': [0.78, 0.50, 0.20]}, + 'Zn': {'mass': 65, 'rad': 0.25, 'rgb': [0.49, 0.50, 0.69]}, + 'Ga': {'mass': 70, 'rad': 0.25, 'rgb': [0.76, 0.56, 0.56]}, + 'Ge': {'mass': 73, 'rad': 0.25, 'rgb': [0.40, 0.56, 0.56]}, + 'As': {'mass': 75, 'rad': 0.25, 'rgb': [0.74, 0.50, 0.89]}, + 'Se': {'mass': 79, 'rad': 0.25, 'rgb': [1.00, 0.63, 0.00]}, + 'Br': {'mass': 80, 'rad': 0.25, 'rgb': [0.65, 0.16, 0.16]}, + 'Kr': {'mass': 84, 'rad': 0.25, 'rgb': [0.36, 0.72, 0.82]}, + 'Rb': {'mass': 86, 'rad': 0.25, 'rgb': [0.43, 0.18, 0.69]}, + 'Sr': {'mass': 88, 'rad': 0.25, 'rgb': [0.00, 1.00, 0.00]}, + 'Y': {'mass': 89, 'rad': 0.25, 'rgb': [0.58, 1.00, 1.00]}, + 'Zr': {'mass': 91, 'rad': 0.25, 'rgb': [0.58, 0.88, 0.88]}, + 'Nb': {'mass': 93, 'rad': 0.25, 'rgb': [0.45, 0.76, 0.79]}, + 'Mo': {'mass': 96, 'rad': 0.25, 'rgb': [0.32, 0.71, 0.71]}, + 'Tc': {'mass': 97, 'rad': 0.25, 'rgb': [0.23, 0.62, 0.62]}, + 'Ru': {'mass': 101, 'rad': 0.25, 'rgb': [0.14, 0.56, 0.56]}, + 'Rh': {'mass': 103, 'rad': 0.25, 'rgb': [0.04, 0.49, 0.55]}, + 'Pd': {'mass': 106, 'rad': 0.25, 'rgb': [0.00, 0.41, 0.52]}, + 'Ag': {'mass': 108, 'rad': 0.25, 'rgb': [0.75, 0.75, 0.75]}, + 'Cd': {'mass': 112, 'rad': 0.25, 'rgb': [1.00, 0.85, 0.56]}, + 'In': {'mass': 115, 'rad': 0.25, 'rgb': [0.65, 0.46, 0.45]}, + 'Sn': {'mass': 117, 'rad': 0.25, 'rgb': [0.40, 0.50, 0.50]}, + 'Sb': {'mass': 122, 'rad': 0.25, 'rgb': [0.62, 0.39, 0.71]}, + 'Te': {'mass': 128, 'rad': 0.25, 'rgb': [0.83, 0.48, 0.00]}, + 'I': {'mass': 127, 'rad': 0.25, 'rgb': [0.58, 0.00, 0.58]}, + 'Xe': {'mass': 131, 'rad': 0.25, 'rgb': [0.26, 0.62, 0.69]}, + 'Cs': {'mass': 133, 'rad': 0.25, 'rgb': [0.34, 0.09, 0.56]}, + 'Ba': {'mass': 137, 'rad': 0.25, 'rgb': [0.00, 0.79, 0.00]}, + 'La': {'mass': 139, 'rad': 0.25, 'rgb': [0.44, 0.83, 1.00]}, + 'Ce': {'mass': 140, 'rad': 0.25, 'rgb': [1.00, 1.00, 0.78]}, + 'Pr': {'mass': 141, 'rad': 0.25, 'rgb': [0.85, 1.00, 0.78]}, + 'Nd': {'mass': 144, 'rad': 0.25, 'rgb': [0.78, 1.00, 0.78]}, + 'Pm': {'mass': 145, 'rad': 0.25, 'rgb': [0.64, 1.00, 0.78]}, + 'Sm': {'mass': 150, 'rad': 0.25, 'rgb': [0.56, 1.00, 0.78]}, + 'Eu': {'mass': 152, 'rad': 0.25, 'rgb': [0.38, 1.00, 0.78]}, + 'Gd': {'mass': 157, 'rad': 0.25, 'rgb': [0.27, 1.00, 0.78]}, + 'Tb': {'mass': 159, 'rad': 0.25, 'rgb': [0.19, 1.00, 0.78]}, + 'Dy': {'mass': 163, 'rad': 0.25, 'rgb': [0.12, 1.00, 0.78]}, + 'Ho': {'mass': 165, 'rad': 0.25, 'rgb': [0.00, 1.00, 0.61]}, + 'Er': {'mass': 167, 'rad': 0.25, 'rgb': [0.00, 0.90, 0.46]}, + 'Tm': {'mass': 169, 'rad': 0.25, 'rgb': [0.00, 0.83, 0.32]}, + 'Yb': {'mass': 173, 'rad': 0.25, 'rgb': [0.00, 0.75, 0.22]}, + 'Lu': {'mass': 175, 'rad': 0.25, 'rgb': [0.00, 0.67, 0.14]}, + 'Hf': {'mass': 179, 'rad': 0.25, 'rgb': [0.30, 0.76, 1.00]}, + 'Ta': {'mass': 181, 'rad': 0.25, 'rgb': [0.30, 0.65, 1.00]}, + 'W': {'mass': 184, 'rad': 0.25, 'rgb': [0.13, 0.58, 0.84]}, + 'Re': {'mass': 186, 'rad': 0.25, 'rgb': [0.15, 0.49, 0.67]}, + 'Os': {'mass': 190, 'rad': 0.25, 'rgb': [0.15, 0.40, 0.59]}, + 'Ir': {'mass': 192, 'rad': 0.25, 'rgb': [0.09, 0.33, 0.53]}, + 'Pt': {'mass': 195, 'rad': 0.25, 'rgb': [0.82, 0.82, 0.88]}, + 'Au': {'mass': 197, 'rad': 0.25, 'rgb': [1.00, 0.82, 0.14]}, + 'Hg': {'mass': 201, 'rad': 0.25, 'rgb': [0.72, 0.72, 0.82]}, + 'Tl': {'mass': 204, 'rad': 0.25, 'rgb': [0.65, 0.33, 0.30]}, + 'Pb': {'mass': 207, 'rad': 0.25, 'rgb': [0.34, 0.35, 0.38]}, + 'Bi': {'mass': 209, 'rad': 0.25, 'rgb': [0.62, 0.31, 0.71]}, + 'Po': {'mass': 209, 'rad': 0.25, 'rgb': [0.67, 0.36, 0.00]}, + 'At': {'mass': 210, 'rad': 0.25, 'rgb': [0.46, 0.31, 0.27]}, + 'Rn': {'mass': 222, 'rad': 0.25, 'rgb': [0.26, 0.51, 0.59]}, + 'Fr': {'mass': 223, 'rad': 0.25, 'rgb': [0.26, 0.00, 0.40]}, + 'Ra': {'mass': 226, 'rad': 0.25, 'rgb': [0.00, 0.49, 0.00]}, + 'Ac': {'mass': 227, 'rad': 0.25, 'rgb': [0.44, 0.67, 1.00]}, + 'Th': {'mass': 232, 'rad': 0.25, 'rgb': [0.00, 0.73, 1.00]}, + 'Pa': {'mass': 231, 'rad': 0.25, 'rgb': [0.00, 0.63, 1.00]}, + 'U': {'mass': 238, 'rad': 0.25, 'rgb': [0.00, 0.56, 1.00]}, + 'Np': {'mass': 237, 'rad': 0.25, 'rgb': [0.00, 0.50, 1.00]}, + 'Pu': {'mass': 244, 'rad': 0.25, 'rgb': [0.00, 0.42, 1.00]}, + 'Am': {'mass': 243, 'rad': 0.25, 'rgb': [0.33, 0.36, 0.95]}, + 'Cm': {'mass': 247, 'rad': 0.25, 'rgb': [0.47, 0.36, 0.89]}, + 'Bk': {'mass': 247, 'rad': 0.25, 'rgb': [0.54, 0.31, 0.89]}, + 'Cf': {'mass': 251, 'rad': 0.25, 'rgb': [0.63, 0.21, 0.83]}, + 'Es': {'mass': 252, 'rad': 0.25, 'rgb': [0.70, 0.12, 0.83]}, + 'Fm': {'mass': 257, 'rad': 0.25, 'rgb': [0.70, 0.12, 0.73]}, + 'Md': {'mass': 258, 'rad': 0.25, 'rgb': [0.70, 0.05, 0.65]}, + 'No': {'mass': 259, 'rad': 0.25, 'rgb': [0.74, 0.05, 0.53]}, + 'Lr': {'mass': 260, 'rad': 0.25, 'rgb': [0.78, 0.00, 0.40]}, + 'Rf': {'mass': 261, 'rad': 0.25, 'rgb': [0.80, 0.00, 0.35]}, + 'Db': {'mass': 262, 'rad': 0.25, 'rgb': [0.82, 0.00, 0.31]}, + 'Sg': {'mass': 269, 'rad': 0.25, 'rgb': [0.85, 0.00, 0.27]}, + 'Bh': {'mass': 270, 'rad': 0.25, 'rgb': [0.88, 0.00, 0.22]}, + 'Hs': {'mass': 269, 'rad': 0.25, 'rgb': [0.90, 0.00, 0.18]}, + 'Mt': {'mass': 278, 'rad': 0.25, 'rgb': [0.92, 0.00, 0.15]}, + } + def __init__(self, species, tag, position=[0, 0, 0]): self.species = species self.tag = tag self.position = np.array(position) - if self.species == 'C': - self.mass = 12 - self.rad = 0.25 - self.rgb = [0.4, 0.4, 0.4] - else: + # set the properties based on the species + if self.species in Atom.properties: + prop = Atom.properties[self.species] + self.mass = prop['mass'] + self.rad = prop['rad'] + self.rgb = prop['rgb'] + else: # default to hydrogen self.mass = 1 self.rad = 0.25 self.rgb = [0.75, 0.75, 0.75] + print(f"WARNING: structure contains {self.species}, an atom unknown to the program.") + def __repr__(self): return "%r %r tag: %r pos: %r, %r, %r" % ( @@ -64,6 +183,7 @@ def toPOV(self): def get_structure(data): + """access atomic coordinates""" atoms = np.array([]) with open(data) as xyz: for ii, line in enumerate(xyz): @@ -78,7 +198,7 @@ def get_structure(data): return atoms -def get_center_of_mass(Molecule): +def get_center_of_mass(molecule): """determine the molecule's center of gravity Note: this is literally by the atoms' masses, and not only by mere dimension @@ -86,7 +206,7 @@ def get_center_of_mass(Molecule): center_of_mass = np.array([0.0, 0.0, 0.0]) total_mass = 0.0 - for atom in Molecule: + for atom in molecule: center_of_mass += atom.mass * atom.position total_mass += atom.mass center_of_mass /= total_mass @@ -94,9 +214,9 @@ def get_center_of_mass(Molecule): return np.around(center_of_mass, decimals=2) -def move2origin(Molecule, center_of_mass): +def move2origin(molecule, center_of_mass): """align molecule's centre of gravity and origin of the coordinate system""" - for atom in Molecule: + for atom in molecule: atom.translate(center_of_mass) @@ -186,7 +306,7 @@ def get_args(): global_settings {ambient_light rgb <0.200, 0.200, 0.200> max_trace_level 15} - background {color rgb <1,1,1>} + background {color rgb <0.8,0.8,0.8>} camera { orthographic