From 6b65702832902d359a35a79e7b558d4a2f171e48 Mon Sep 17 00:00:00 2001 From: Norwid Behrnd Date: Sun, 12 Feb 2023 17:40:48 +0100 Subject: [PATCH 1/6] add color of nitrogen Test-wise addition for / about nitrogen. Tested on the example of pyridine by openbabel from the SMILES string (`c1ccncc1`), and diethylamine (`CCNCC`). --- xyz2povray.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xyz2povray.py b/xyz2povray.py index a313bc7..779db35 100755 --- a/xyz2povray.py +++ b/xyz2povray.py @@ -18,6 +18,10 @@ def __init__(self, species, tag, position=[0, 0, 0]): self.mass = 12 self.rad = 0.25 self.rgb = [0.4, 0.4, 0.4] + elif self.species == "N": + self.mass = 14 + self.rad = 0.25 + self.rgb = [0.19, 0.31, 0.97] # Jmol / 255] else: self.mass = 1 self.rad = 0.25 From 63e398d55467943f8f1db7f0d5597b9d03e05f4c Mon Sep 17 00:00:00 2001 From: Norwid Behrnd Date: Sun, 12 Feb 2023 17:47:55 +0100 Subject: [PATCH 2/6] add the color for oxygen Tested for the examples of diethylether (`CCOCC`), THF (`C1COCC1`), and propan-2-ol (`C(C)(O)(C)`) in .xyz files generated by obabel. --- xyz2povray.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xyz2povray.py b/xyz2povray.py index 779db35..9444426 100755 --- a/xyz2povray.py +++ b/xyz2povray.py @@ -22,6 +22,10 @@ def __init__(self, species, tag, position=[0, 0, 0]): self.mass = 14 self.rad = 0.25 self.rgb = [0.19, 0.31, 0.97] # Jmol / 255] + elif self.species == "O": + self.mass = 16 + self.rad = 0.25 + self.rgb = [1.00, 0.05, 0.05] else: self.mass = 1 self.rad = 0.25 From 3fc7f6a4843516cb58f2ce80a61455a4e7cca70d Mon Sep 17 00:00:00 2001 From: Norwid Behrnd Date: Sun, 12 Feb 2023 18:21:36 +0100 Subject: [PATCH 3/6] add color about sulfur Tested with openbabel generated .xyz about diethyl thioether (`CCSCC`) and furfural (`O=Cc1cccs1`). However, contrasting to e.g., the depiction with openbabel generated .pov, the C-S bonds no longer are visible. --- xyz2povray.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xyz2povray.py b/xyz2povray.py index 9444426..19e1754 100755 --- a/xyz2povray.py +++ b/xyz2povray.py @@ -26,6 +26,10 @@ def __init__(self, species, tag, position=[0, 0, 0]): self.mass = 16 self.rad = 0.25 self.rgb = [1.00, 0.05, 0.05] + elif self.species == "S": + self.mass = 32 + self.rad = 0.25 + self.rgb = [1.00, 1.00, 0.19] else: self.mass = 1 self.rad = 0.25 From 4e95454ee6deea9892bbde4cb02e5b9915e57e30 Mon Sep 17 00:00:00 2001 From: Norwid Behrnd Date: Sun, 12 Feb 2023 18:28:58 +0100 Subject: [PATCH 4/6] add color of fluorine Tested with openbabel SMILES string of fluoroethane (`CCF`). The .pov/.ini and subsequent generation of .png seem fine. --- xyz2povray.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xyz2povray.py b/xyz2povray.py index 19e1754..9a72746 100755 --- a/xyz2povray.py +++ b/xyz2povray.py @@ -30,6 +30,10 @@ def __init__(self, species, tag, position=[0, 0, 0]): self.mass = 32 self.rad = 0.25 self.rgb = [1.00, 1.00, 0.19] + elif self.species == "F": + self.mass = 19 + self.rad = 0.25 + self.rgb = [0.0, 1.0, 0.0] # only for testing purpose else: self.mass = 1 self.rad = 0.25 From a457a40f8ac3ba2f9a3c33eac6cb22cc955f42aa Mon Sep 17 00:00:00 2001 From: Norwid Behrnd Date: Sun, 12 Feb 2023 18:32:17 +0100 Subject: [PATCH 5/6] tentative addition for/about Cl Introduction of chlorine. Tested with an .xyz about chloroethane (`CCCl`) generated by openbabel, the chlorine atom is depicted as sphere, separated from the backbone of the molecule. Because of a similar observation for compounds with C-S bonds, and because the analogue CCF was rendered well, perhaps the assignment where to draw a bond faces an obstacle here. --- xyz2povray.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xyz2povray.py b/xyz2povray.py index 9a72746..f4f2118 100755 --- a/xyz2povray.py +++ b/xyz2povray.py @@ -34,6 +34,11 @@ def __init__(self, species, tag, position=[0, 0, 0]): self.mass = 19 self.rad = 0.25 self.rgb = [0.0, 1.0, 0.0] # only for testing purpose + elif self.species == "Cl": + self.mass = 35 + self.rad = 0.25 + self.rgb = [0.0, 1.0, 0.0] # only for testing purpose + else: self.mass = 1 self.rad = 0.25 From 6831cb00af47962d524521f7ebb47cf3d8d53a0d Mon Sep 17 00:00:00 2001 From: Norwid Behrnd Date: Mon, 24 Apr 2023 18:35:31 +0200 Subject: [PATCH 6/6] organize atom definition more like a dictionary The previous approach requires four lines each for every atom type as an instance of class Atom. I think an approach which uses the element symbol as key to a the corresponding values of mass, radiosity, and rgb coordinates in a dictionary is - in comparison to this one - easier to read, and to maintain. Lacking any better inspiration, atoms with atom types not yet explicitly defined in said dictionary default to hydrogen. In such an instance, the conversion will not stop for good, however is going to issue one warning for each atom not fully defined (yet). --- xyz2povray.py | 161 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 31 deletions(-) diff --git a/xyz2povray.py b/xyz2povray.py index f4f2118..2061518 100755 --- a/xyz2povray.py +++ b/xyz2povray.py @@ -9,40 +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] - elif self.species == "N": - self.mass = 14 - self.rad = 0.25 - self.rgb = [0.19, 0.31, 0.97] # Jmol / 255] - elif self.species == "O": - self.mass = 16 - self.rad = 0.25 - self.rgb = [1.00, 0.05, 0.05] - elif self.species == "S": - self.mass = 32 - self.rad = 0.25 - self.rgb = [1.00, 1.00, 0.19] - elif self.species == "F": - self.mass = 19 - self.rad = 0.25 - self.rgb = [0.0, 1.0, 0.0] # only for testing purpose - elif self.species == "Cl": - self.mass = 35 - self.rad = 0.25 - self.rgb = [0.0, 1.0, 0.0] # only for testing purpose - - 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" % ( @@ -85,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): @@ -99,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 @@ -107,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 @@ -115,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) @@ -207,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