1 // ATOM.CPP
2
3 // Copyright (C) 1998 Tommi Hassinen.
4
5 // This package is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9
10 // This package is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14
15 // You should have received a copy of the GNU General Public License
16 // along with this package; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 /*################################################################################################*/
20
21 #include "libghemicalconfig2.h"
22 #include "atom.h"
23
24 #include "bond.h"
25 #include "local_i18n.h"
26 #include "notice.h"
27
28 #include <cstring>
29 using namespace std;
30
31 /*################################################################################################*/
32
33 element element::current_element = element("C");
34
35 const char element::string[ELEMENT_SYMBOLS][32] =
36 {
37 "hydrogen", "helium", "lithium", "beryllium", "boron",
38 "carbon", "nitrogen", "oxygen", "fluorine", "neon", // 10
39 "sodium", "magnesium", "aluminium", "silicon", "phosphorus",
40 "sulphur", "chlorine", "argon", "potassium", "calcium", // 20
41 "scandium", "titanium", "vanadium", "chromium", "manganese",
42 "iron", "cobalt", "nickel", "copper", "zinc", // 30
43 "gallium", "germanium", "arsenic", "selenium", "bromine",
44 "krypton", "rubidium", "strontium", "yttrium", "zirconium", // 40
45 "niobium", "molybdenum", "technetium", "ruthenium", "rhodium",
46 "palladium", "silver", "cadmium", "indium", "tin", // 50
47 "antimony", "tellurium", "iodine", "xenon", "cesium",
48 "barium", "lanthanum", "cerium", "praseodymium", "neodymium", // 60
49 "promethium", "samarium", "europium", "gadolinium", "terbium",
50 "dysprosium", "holmium", "erbium", "thulium", "ytterbium", // 70
51 "lutetium", "hafnium", "tantalum", "tungsten", "rhenium",
52 "osmium", "iridium", "platinum", "gold", "mercury", // 80
53 "thallium", "lead", "bismuth", "polonium", "astatine",
54 "radon", "francium", " radium", "actinium", "thorium", // 90
55 "protactinium", "uranium", "neptunium", "plutionium", "americium",
56 "curium", "berkelium", "californium", "einsteinium", "fermium", // 100
57 "mendelevium", "nobelium", "lawrencium", "rutherfordium", "dubnium",
58 "seaborgium", "bohrium", "hassium", "meitnerium", "ununnilium" // 110
59 };
60
61 const char element::symbol[ELEMENT_SYMBOLS][4] =
62 {
63 "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne",
64 "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", // 20
65 "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn",
66 "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", // 40
67 "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn",
68 "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", // 60
69 "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb",
70 "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", // 80
71 "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
72 "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", // 100
73 "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Uun"
74 };
75
76 // These are the defaults--modified via the prefs class.
77 // REMOVE CONST AND MODIFY THESE DIRECTLY?!?!?!?!
78
79 const fGL element::color[ELEMENT_SYMBOLS][3] =
80 {
81 { 1.00, 1.00, 1.00 }, { 0.85, 1.00, 1.00 }, { 0.80, 0.50, 1.00 },
82 { 0.76, 1.00, 0.00 }, { 1.00, 0.71, 0.71 }, { 0.56, 0.56, 0.56 }, // 6
83 { 0.18, 0.31, 0.97 }, { 1.00, 0.05, 0.05 }, { 0.56, 0.87, 0.31 },
84 { 0.70, 0.89, 0.96 }, { 0.67, 0.36, 0.95 }, { 0.54, 1.00, 0.00 }, // 12
85 { 0.75, 0.65, 0.65 }, { 0.94, 0.78, 0.62 }, { 1.00, 0.50, 0.00 },
86 { 1.00, 1.00, 0.19 }, { 0.12, 0.94, 0.12 }, { 0.50, 0.82, 0.89 }, // 18
87 { 0.56, 0.25, 0.83 }, { 0.24, 1.00, 0.00 }, { 0.90, 0.90, 0.90 },
88 { 0.75, 0.76, 0.78 }, { 0.65, 0.65, 0.67 }, { 0.54, 0.60, 0.78 }, // 24
89 { 0.61, 0.48, 0.78 }, { 0.87, 0.40, 0.20 }, { 0.94, 0.56, 0.62 },
90 { 0.31, 0.81, 0.31 }, { 0.78, 0.50, 0.20 }, { 0.49, 0.50, 0.69 }, // 30
91 { 0.76, 0.56, 0.56 }, { 0.40, 0.56, 0.56 }, { 0.74, 0.50, 0.89 },
92 { 1.00, 0.63, 0.00 }, { 0.65, 0.16, 0.16 }, { 0.36, 0.72, 0.82 }, // 36
93 { 0.44, 0.18, 0.69 }, { 0.00, 1.00, 0.00 }, { 0.58, 1.00, 1.00 },
94 { 0.58, 0.88, 0.88 }, { 0.45, 0.76, 0.79 }, { 0.33, 0.71, 0.71 }, // 42
95 { 0.23, 0.62, 0.62 }, { 0.14, 0.56, 0.56 }, { 0.04, 0.49, 0.55 },
96 { 0.00, 0.41, 0.52 }, { 0.75, 0.75, 0.75 }, { 1.00, 0.85, 0.56 }, // 48
97 { 0.65, 0.46, 0.45 }, { 0.40, 0.50, 0.50 }, { 0.62, 0.39, 0.71 },
98 { 0.83, 0.48, 0.00 }, { 0.58, 0.00, 0.58 }, { 0.26, 0.62, 0.69 }, // 54
99 { 0.34, 0.09, 0.56 }, { 0.00, 0.79, 0.00 }, { 0.44, 0.83, 1.00 },
100 { 1.00, 1.00, 0.78 }, { 0.85, 1.00, 0.78 }, { 0.78, 1.00, 0.78 }, // 60
101 { 0.64, 1.00, 0.78 }, { 0.56, 1.00, 0.78 }, { 0.38, 1.00, 0.78 },
102 { 0.27, 1.00, 0.78 }, { 0.19, 1.00, 0.78 }, { 0.12, 1.00, 0.78 }, // 66
103 { 0.00, 1.00, 0.61 }, { 0.00, 0.90, 0.46 }, { 0.00, 0.83, 0.32 },
104 { 0.00, 0.75, 0.22 }, { 0.00, 0.67, 0.14 }, { 0.30, 0.76, 1.00 }, // 72
105 { 0.30, 0.65, 1.00 }, { 0.13, 0.58, 0.84 }, { 0.15, 0.49, 0.67 },
106 { 0.15, 0.40, 0.59 }, { 0.09, 0.33, 0.53 }, { 0.81, 0.81, 0.87 }, // 78
107 { 1.00, 0.81, 0.13 }, { 0.72, 0.72, 0.81 }, { 0.65, 0.33, 0.30 },
108 { 0.34, 0.35, 0.38 }, { 0.62, 0.31, 0.71 }, { 0.67, 0.36, 0.00 }, // 84
109 { 0.46, 0.31, 0.27 }, { 0.26, 0.51, 0.59 }, { 0.26, 0.00, 0.40 },
110 { 0.00, 0.49, 0.00 }, { 0.44, 0.67, 0.98 }, { 0.00, 0.73, 1.00 }, // 90
111 { 0.00, 0.63, 1.00 }, { 0.00, 0.56, 1.00 }, { 0.00, 0.50, 1.00 },
112 { 0.00, 0.42, 1.00 }, { 0.33, 0.36, 0.95 }, { 0.47, 0.36, 0.89 }, // 96
113 { 0.54, 0.31, 0.89 }, { 0.63, 0.21, 0.83 }, { 0.70, 0.12, 0.83 },
114 { 0.70, 0.12, 0.73 }, { 0.70, 0.05, 0.65 }, { 0.74, 0.05, 0.53 }, // 102
115 { 0.78, 0.00, 0.40 }, { 0.80, 0.00, 0.35 }, { 0.82, 0.00, 0.31 },
116 { 0.85, 0.00, 0.27 }, { 0.88, 0.00, 0.22 }, { 0.90, 0.00, 0.18 }, // 108
117 { 0.92, 0.00, 0.15 }, { 0.95, 0.00, 0.11 }
118 };
119
120 // IUPAC recognized masses rounded to 0.001 where appropriate
121 // From _Pure Appl. Chem., 71 (1999) 1593-1607.
122 // these are in normal atomic mass units... TH
123
124 const fGL element::mass[ELEMENT_SYMBOLS] =
125 {
126 1.008, 4.003, 6.941, 9.012, 10.812,
127 12.011, 14.007, 15.999, 18.998, 20.180, // 10
128 22.990, 24.305, 26.982, 28.086, 30.974,
129 32.067, 35.453, 39.948, 39.098, 40.078, // 20
130 44.956, 47.867, 50.942, 51.996, 54.938,
131 55.845, 58.933, 58.693, 63.546, 65.39, // 30
132 69.723, 72.61, 74.922, 78.96, 79.904,
133 83.80, 85.468, 87.62, 88.906, 91.224, // 40
134 92.906, 95.94, 98.0, 101.07, 102.906,
135 106.42, 107.868, 112.412, 114.818, 118.711, // 50
136 121.760, 127.60, 126.904, 131.29, 132.905,
137 137.328, 138.906, 140.116, 140.908, 144.24, // 60
138 145.0, 150.36, 151.964, 157.25, 158.925,
139 162.50, 164.930, 167.26, 168.934, 173.04, // 70
140 174.967, 178.49, 180.948, 183.84, 186.207,
141 190.23, 192.217, 195.078, 196.967, 200.59, // 80
142 204.383, 207.2, 208.980, 209.0, 210.0,
143 222.0, 223.0, 226.0, 227.0, 232.038, // 90
144 231.036, 238.029, 237.0, 244.0, 243.0,
145 247.0, 247.0, 251.0, 252.0, 257.0, // 100
146 258.0, 259.0, 262.0, 261.0, 262.0,
147 263.0, 264.0, 265.0, 268.0, 269.0 // 110
148 };
149
150 // van der Waals radii for graphics--these determine the size of the spheres
151 // These were collected from the elements list in Open Babel
152 // (0.170 nm seems to be an "unknown" value
153
154 const fGL element::vdwr[ELEMENT_SYMBOLS] =
155 {
156 0.120, 0.140, 0.180, 0.170, 0.208, 0.170, 0.155, 0.150, 0.155, 0.160,
157 0.231, 0.170, 0.205, 0.210, 0.185, 0.180, 0.181, 0.191, 0.280, 0.197, // 20
158 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.160, 0.140, 0.140,
159 0.190, 0.170, 0.185, 0.190, 0.190, 0.200, 0.244, 0.170, 0.170, 0.170, // 40
160 0.170, 0.170, 0.170, 0.170, 0.170, 0.163, 0.172, 0.160, 0.190, 0.220,
161 0.220, 0.210, 0.198, 0.220, 0.262, 0.170, 0.170, 0.170, 0.170, 0.170, // 60
162 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170,
163 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.175, 0.166, 0.155, // 80
164 0.200, 0.202, 0.240, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170,
165 0.170, 0.190, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, // 100
166 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170, 0.170
167 };
168
element(void)169 element::element(void)
170 {
171 atomic_number = NOT_DEFINED; // set to a dummy atom by default!!!
172 }
173
174 // unknown symbols are thought to be "wildcard elements" which MUST have their atomic numbers
175 // equal to minus one (that is, NOT_DEFINED). if this logic is changed, some bad problems will
176 // emerge in the ring search and in typerules...
177
element(char * p1)178 element::element(char * p1)
179 {
180 i32s n1 = 0;
181 while (n1 < ELEMENT_SYMBOLS && strcmp(symbol[n1], p1)) n1++;
182
183 if (n1 < ELEMENT_SYMBOLS) atomic_number = n1 + 1;
184 else atomic_number = NOT_DEFINED;
185 }
186
element(i32s p1)187 element::element(i32s p1)
188 {
189 if (p1 < 1 || p1 > ELEMENT_SYMBOLS) atomic_number = NOT_DEFINED;
190 else atomic_number = p1;
191 }
192
~element(void)193 element::~element(void)
194 {
195 }
196
GetString(void) const197 const char * element::GetString(void) const
198 {
199 if (atomic_number == NOT_DEFINED) return "DUMMY_ATOM";
200 else return string[atomic_number - 1];
201 }
202
GetAtomicNumber(void) const203 const i32s element::GetAtomicNumber(void) const
204 {
205 return atomic_number;
206 }
207
208 // the symbol for atomic_number NOT_DEFINED (= -1) might affect the atomtype rule class "typerule",
209 // but it seems to be OK to return symbol "Du" (a "wildcard" setting is selected for all unknown ones).
210
GetSymbol(void) const211 const char * element::GetSymbol(void) const
212 {
213 if (atomic_number == NOT_DEFINED) return "Du";
214 else return symbol[atomic_number - 1];
215 }
216
GetColor(void) const217 const fGL * element::GetColor(void) const
218 {
219 static fGL not_defined_color[3] = { 0.5, 0.4, 0.3 };
220
221 if (atomic_number == NOT_DEFINED) return not_defined_color; // just return something usable also in this case...
222 else return color[atomic_number - 1];
223 }
224
GetAtomicMass(void) const225 fGL element::GetAtomicMass(void) const
226 {
227 if (atomic_number == NOT_DEFINED) return -1.0;
228 else return mass[atomic_number - 1];
229 }
230
GetVDWRadius(void) const231 fGL element::GetVDWRadius(void) const
232 {
233 if (atomic_number == NOT_DEFINED) return -1.0;
234 else return vdwr[atomic_number - 1];
235 }
236
operator ++(void)237 void element::operator++(void)
238 {
239 if (++atomic_number > ELEMENT_SYMBOLS) atomic_number = 1;
240 }
241
operator --(void)242 void element::operator--(void)
243 {
244 if (--atomic_number < 1) atomic_number = ELEMENT_SYMBOLS;
245 }
246
247 /*################################################################################################*/
248
crec(void)249 crec::crec(void)
250 {
251 atmr = NULL;
252 bndr = NULL;
253 }
254
crec(atom * p1,bond * p2)255 crec::crec(atom * p1, bond * p2)
256 {
257 atmr = p1;
258 bndr = p2;
259 }
260
~crec(void)261 crec::~crec(void)
262 {
263 }
264
operator ==(const crec & p1) const265 bool crec::operator==(const crec & p1) const
266 {
267 return (bndr == p1.bndr);
268 }
269
270 /*################################################################################################*/
271
atom(void)272 atom::atom(void)
273 {
274 mdl = NULL;
275 my_glname = GLNAME_UNREGISTERED;
276 }
277
atom(element p1,const fGL * p2,i32u p3)278 atom::atom(element p1, const fGL * p2, i32u p3)
279 {
280 mdl = NULL;
281 my_glname = GLNAME_UNREGISTERED;
282
283 el = p1;
284 formal_charge = 0;
285
286 atmtp = NOT_DEFINED;
287 atmtp_E = NOT_DEFINED;
288 atmtp_s[0] = 0; // initialize to a zero-length string.
289
290 charge = 0.0;
291 mass = el.GetAtomicMass();
292
293 vdwr = el.GetVDWRadius();
294
295 fGL data[3] = { 0.0, 0.0, 0.0 }; // default coordinates...
296 if (p2 != NULL) { data[0] = p2[0]; data[1] = p2[1]; data[2] = p2[2]; }
297
298 crd_table_size_loc = p3;
299 if (crd_table_size_loc < 1) assertion_failed(__FILE__, __LINE__, "crd_table_size_loc < 1");
300
301 crd_table = new fGL[crd_table_size_loc * 3];
302 for (i32u n1 = 0;n1 < crd_table_size_loc;n1++) // be sure to initialize the whole array -> valid floats!!!
303 {
304 crd_table[n1 * 3 + 0] = data[0];
305 crd_table[n1 * 3 + 1] = data[1];
306 crd_table[n1 * 3 + 2] = data[2];
307 }
308
309 for (i32u i1 = 0;i1 < 4;i1++) id[i1] = NOT_DEFINED;
310 builder_res_id = NOT_DEFINED;
311
312 index = NOT_DEFINED;
313 varind = NOT_DEFINED;
314
315 flags = 0;
316
317 ecomp_grp_i = 0; // the "default" group index is zero!
318 }
319
atom(const atom & p1)320 atom::atom(const atom & p1)
321 {
322 mdl = NULL; // strict...
323 my_glname = GLNAME_UNREGISTERED; // strict...
324
325 el = p1.el;
326 formal_charge = p1.formal_charge;
327
328 atmtp = p1.atmtp;
329 atmtp_E = p1.atmtp_E;
330 strcpy(atmtp_s, p1.atmtp_s);
331
332 charge = p1.charge;
333 mass = p1.mass;
334
335 vdwr = p1.vdwr;
336
337 cr_list = p1.cr_list;
338
339 crd_table_size_loc = p1.crd_table_size_loc;
340 if (crd_table_size_loc < 1) assertion_failed(__FILE__, __LINE__, "crd_table_size_loc < 1");
341
342 crd_table = new fGL[crd_table_size_loc * 3];
343 for (i32u n1 = 0;n1 < crd_table_size_loc;n1++) // copy as floats -> the arrays always should contain valid data!!!
344 {
345 crd_table[n1 * 3 + 0] = p1.crd_table[n1 * 3 + 0];
346 crd_table[n1 * 3 + 1] = p1.crd_table[n1 * 3 + 1];
347 crd_table[n1 * 3 + 2] = p1.crd_table[n1 * 3 + 2];
348 }
349
350 for (i32u n1 = 0;n1 < 4;n1++) id[n1] = p1.id[n1];
351 builder_res_id = p1.builder_res_id;
352
353 index = p1.index;
354 varind = p1.varind;
355
356 flags = p1.flags;
357
358 ecomp_grp_i = p1.ecomp_grp_i;
359 }
360
~atom(void)361 atom::~atom(void)
362 {
363 delete[] crd_table;
364 }
365
GetCRD(i32u cs)366 const fGL * atom::GetCRD(i32u cs)
367 {
368 if (cs >= crd_table_size_loc) assertion_failed(__FILE__, __LINE__, "cs >= crd_table_size_loc");
369
370 return & (crd_table[cs * 3]);
371 }
372
SetCRD(i32s cs,fGL x,fGL y,fGL z)373 void atom::SetCRD(i32s cs, fGL x, fGL y, fGL z)
374 {
375 if (cs < 0)
376 {
377 for (i32u n1 = 0;n1 < crd_table_size_loc;n1++) // NOT_DEFINED -> set for all csets...
378 {
379 crd_table[n1 * 3 + 0] = x;
380 crd_table[n1 * 3 + 1] = y;
381 crd_table[n1 * 3 + 2] = z;
382 }
383 }
384 else
385 {
386 if (cs >= (i32s) crd_table_size_loc) assertion_failed(__FILE__, __LINE__, "cs >= crd_table_size_loc");
387
388 crd_table[cs * 3 + 0] = x;
389 crd_table[cs * 3 + 1] = y;
390 crd_table[cs * 3 + 2] = z;
391 }
392 }
393
GetSelected() const394 bool atom::GetSelected() const
395 {
396 if (flags & ATOMFLAG_USER_SELECTED) return true;
397 return false;
398 }
399
SetSelected(bool l)400 void atom::SetSelected(bool l)
401 {
402 if(l) flags |= ATOMFLAG_USER_SELECTED;
403 else flags &= ~ATOMFLAG_USER_SELECTED;
404 }
405
GetLocked() const406 bool atom::GetLocked() const
407 {
408 if (flags & ATOMFLAG_USER_LOCKED) return true;
409 return false;
410 }
411
SetLocked(bool l)412 void atom::SetLocked(bool l)
413 {
414 if(l) flags |= ATOMFLAG_USER_LOCKED;
415 else flags &= ~ATOMFLAG_USER_LOCKED;
416 }
417
418 // atoms will be sorted according to their molecule, chain and residue numbers.
419 // sorting the container will then arrange molecules/chains/residues in continuous blocks.
420
operator <(const atom & p1) const421 bool atom::operator<(const atom & p1) const
422 {
423 for (i32s n1 = 0;n1 < 3;n1++)
424 {
425 if (id[n1] != p1.id[n1]) return (id[n1] < p1.id[n1]);
426 }
427
428 return false;
429 }
430
431 // for atoms, equality is tested using pointers -> you can find the
432 // iterator (using STL's find-function) if the pointer is known.
433
operator ==(const atom & p1) const434 bool atom::operator==(const atom & p1) const
435 {
436 return (this == (& p1));
437 }
438
439 /*################################################################################################*/
440
441 // eof
442