1 /******************************************************************************
2
3 This source file is part of the Avogadro project.
4
5 Copyright 2012 Kitware, Inc.
6
7 This source code is released under the New BSD License, (the "License").
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14
15 ******************************************************************************/
16
17 #include "elements.h"
18
19 #include "avogadrocore.h"
20 #include "elementdata.h"
21 #include "utilities.h"
22
23 #include <algorithm>
24 #include <cctype>
25 #include <vector>
26
27 using Avogadro::Core::isCustomElement;
28
29 namespace Avogadro {
30 namespace Core {
31
32 // Handle custom element identifiers:
33 namespace {
34 const static std::string CustomElementSymbolPrefix = "X";
35 const static std::string CustomElementNamePrefix = "CustomElement_";
36
37 static std::vector<std::string> CustomElementSymbols;
38 static std::vector<std::string> CustomElementNames;
39
40 // Match carbon's radii
41 static double CustomElementCovalentRadius = element_covalent[6];
42 static double CustomElementVDWRadius = element_VDW[6];
43
encodeCustomElement(unsigned char atomicNumber)44 inline std::string encodeCustomElement(unsigned char atomicNumber)
45 {
46 std::string result;
47 if (isCustomElement(atomicNumber)) {
48 result.resize(2);
49 unsigned char index = atomicNumber - Avogadro::CustomElementMin;
50 result[0] = 'a' + static_cast<char>(index / 26);
51 result[1] = 'a' + static_cast<char>(index % 26);
52 }
53 return result;
54 }
55
decodeCustomElement(const std::string & str)56 inline unsigned char decodeCustomElement(const std::string& str)
57 {
58 if (str.size() == 2) {
59 if (str[0] >= 'a' && str[0] <= 'z' && str[1] >= 'a' && str[1] <= 'z') {
60 return CustomElementMin + static_cast<unsigned char>(str[0] - 'a') * 26 +
61 static_cast<unsigned char>(str[1] - 'a');
62 }
63 }
64 return Avogadro::InvalidElement;
65 }
66
interpretCustomElementName(const std::string & name)67 inline unsigned char interpretCustomElementName(const std::string& name)
68 {
69 if (startsWith(name, CustomElementNamePrefix)) {
70 const std::string number(name.substr(CustomElementNamePrefix.size()));
71 return decodeCustomElement(number);
72 }
73 return InvalidElement;
74 }
75
createCustomElementName(unsigned char atomicNumber)76 inline std::string createCustomElementName(unsigned char atomicNumber)
77 {
78 return CustomElementNamePrefix + encodeCustomElement(atomicNumber);
79 }
80
customElementName(unsigned char atomicNumber)81 inline const char* customElementName(unsigned char atomicNumber)
82 {
83 return CustomElementNames[atomicNumber - CustomElementMin].c_str();
84 }
85
interpretCustomElementSymbol(const std::string & symbol)86 inline unsigned char interpretCustomElementSymbol(const std::string& symbol)
87 {
88 if (symbol.size() == 3)
89 return decodeCustomElement(symbol.substr(1));
90 return InvalidElement;
91 }
92
createCustomElementSymbol(unsigned char atomicNumber)93 inline std::string createCustomElementSymbol(unsigned char atomicNumber)
94 {
95 return CustomElementSymbolPrefix + encodeCustomElement(atomicNumber);
96 }
97
customElementSymbol(unsigned char atomicNumber)98 inline const char* customElementSymbol(unsigned char atomicNumber)
99 {
100 return CustomElementSymbols[atomicNumber - CustomElementMin].c_str();
101 }
102
customElementColor(unsigned char atomicNumber)103 inline unsigned char* customElementColor(unsigned char atomicNumber)
104 {
105 return Core::element_color[atomicNumber % element_count];
106 }
107
108 // Initialize the static lookup tables.
109 class InitializeCustomElementTables
110 {
111 public:
InitializeCustomElementTables()112 InitializeCustomElementTables()
113 {
114 CustomElementSymbols.resize(CustomElementCount);
115 CustomElementNames.resize(CustomElementCount);
116 std::string suffix;
117 for (unsigned char i = CustomElementMin; i <= CustomElementMax; ++i) {
118 suffix = encodeCustomElement(i);
119 CustomElementSymbols[i - CustomElementMin] =
120 CustomElementSymbolPrefix + suffix;
121 CustomElementNames[i - CustomElementMin] =
122 CustomElementNamePrefix + suffix;
123 }
124 }
125 } CustomElementTableInitializer;
126
127 } // end anon namespace
128
Elements()129 Elements::Elements()
130 {
131 }
132
~Elements()133 Elements::~Elements()
134 {
135 }
136
elementCount()137 unsigned char Elements::elementCount()
138 {
139 return element_count;
140 }
141
atomicNumberFromName(const std::string & name)142 unsigned char Elements::atomicNumberFromName(const std::string& name)
143 {
144 for (unsigned char i = 0; i < element_count; ++i)
145 if (name == element_names[i])
146 return i;
147
148 return interpretCustomElementName(name);
149 }
150
atomicNumberFromSymbol(const std::string & symbol)151 unsigned char Elements::atomicNumberFromSymbol(const std::string& symbol)
152 {
153 if (symbol.length() == 1) {
154 switch (symbol[0]) {
155 case 'H':
156 return 1;
157 case 'B':
158 return 5;
159 case 'C':
160 return 6;
161 case 'N':
162 return 7;
163 case 'O':
164 return 8;
165 case 'F':
166 return 9;
167 case 'P':
168 return 15;
169 case 'S':
170 return 16;
171 case 'K':
172 return 19;
173 case 'V':
174 return 23;
175 case 'Y':
176 return 39;
177 case 'I':
178 return 53;
179 case 'W':
180 return 74;
181 case 'U':
182 return 92;
183 default:
184 return InvalidElement;
185 }
186 } else {
187 for (unsigned char i = 0; i < element_count; ++i)
188 if (symbol == element_symbols[i])
189 return i;
190 return interpretCustomElementSymbol(symbol);
191 }
192 }
193
guessAtomicNumber(const std::string & inputStr)194 unsigned char Elements::guessAtomicNumber(const std::string& inputStr)
195 {
196 std::string str(trimmed(inputStr));
197 if (str.empty())
198 return InvalidElement;
199
200 // atomic number?
201 bool ok;
202 int atomicNumberInt = lexicalCast<int>(str, ok);
203 if (ok)
204 return static_cast<unsigned char>(atomicNumberInt);
205
206 // Format string as text
207 std::transform(str.begin(), str.end(), str.begin(), tolower);
208 str[0] = static_cast<char>(toupper(static_cast<int>(str[0])));
209
210 int length = str.size();
211 unsigned char atomicNumber;
212 while (length > 0) {
213 if (length > 3)
214 atomicNumber = atomicNumberFromName(str.substr(0, length));
215 else
216 atomicNumber = atomicNumberFromSymbol(str.substr(0, length));
217 if (atomicNumber != InvalidElement)
218 break;
219 length--;
220 }
221
222 return atomicNumber;
223 }
224
name(unsigned char atomicNumber)225 const char* Elements::name(unsigned char atomicNumber)
226 {
227 if (atomicNumber < element_count)
228 return element_names[atomicNumber];
229 else if (isCustomElement(atomicNumber))
230 return customElementName(atomicNumber);
231 else
232 return element_names[0];
233 }
234
symbol(unsigned char atomicNumber)235 const char* Elements::symbol(unsigned char atomicNumber)
236 {
237 if (atomicNumber < element_count)
238 return element_symbols[atomicNumber];
239 else if (isCustomElement(atomicNumber))
240 return customElementSymbol(atomicNumber);
241 else
242 return element_symbols[0];
243 }
244
mass(unsigned char atomicNumber)245 double Elements::mass(unsigned char atomicNumber)
246 {
247 if (atomicNumber < element_count)
248 return element_masses[atomicNumber];
249 else
250 return element_masses[0];
251 }
252
radiusVDW(unsigned char atomicNumber)253 double Elements::radiusVDW(unsigned char atomicNumber)
254 {
255 if (atomicNumber < element_count)
256 return element_VDW[atomicNumber];
257 else if (isCustomElement(atomicNumber))
258 return CustomElementVDWRadius;
259 else
260 return element_VDW[0];
261 }
262
radiusCovalent(unsigned char atomicNumber)263 double Elements::radiusCovalent(unsigned char atomicNumber)
264 {
265 if (atomicNumber < element_count)
266 return element_covalent[atomicNumber];
267 else if (isCustomElement(atomicNumber))
268 return CustomElementCovalentRadius;
269 else
270 return element_covalent[0];
271 }
272
color(unsigned char atomicNumber)273 const unsigned char* Elements::color(unsigned char atomicNumber)
274 {
275 if (atomicNumber < element_count)
276 return element_color[atomicNumber];
277 else if (isCustomElement(atomicNumber))
278 return customElementColor(atomicNumber);
279 else
280 return element_color[0];
281 }
282
283 } // end Core namespace
284 } // end Avogadro namespace
285