Xmipp  v3.23.11-Nereus
symop-map-generator.cpp
Go to the documentation of this file.
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <cassert>
28 
29 #include <array>
30 #include <iostream>
31 #include <iomanip>
32 #include <fstream>
33 #include <regex>
34 #include <map>
35 #include <filesystem>
36 
37 #include <cstdlib>
38 
39 namespace fs = std::filesystem;
40 
41 std::regex kNameRx(R"(^(\d+) +(\d+) +(\d+) +(\S+) +(\S+) +(\S+) +'([^']+)'( +'([^']+)')?(?: +!.+)?$)");
42 
44 {
45  public:
47 
48  std::array<int,15> parse(const std::string& s)
49  {
50  m_p = s.begin();
51  m_e = s.end();
52  m_lookahead = next_token();
53 
54  parsepart(0);
55  match((Token)',');
56  parsepart(1);
57  match((Token)',');
58  parsepart(2);
59 
60  if (m_lookahead != 0 or m_p != m_e)
61  throw std::runtime_error("symmetry expression contains more data than expected");
62 
63  return {
64  m_rot[0][0], m_rot[0][1], m_rot[0][2],
65  m_rot[1][0], m_rot[1][1], m_rot[1][2],
66  m_rot[2][0], m_rot[2][1], m_rot[2][2],
67  m_trn[0][0], m_trn[0][1],
68  m_trn[1][0], m_trn[1][1],
69  m_trn[2][0], m_trn[2][1]
70  };
71  }
72 
73  private:
74 
75  enum Token : int { Eof = 0, Number = 256, XYZ };
76 
77  std::string to_string(Token t)
78  {
79  switch (t)
80  {
81  case Eof: return "end of expression";
82  case Number: return "number";
83  case XYZ: return "'x', 'y' or 'z'";
84  default:
85  if (isprint(t))
86  return std::string({'\'', static_cast<char>(t), '\''});
87  return "invalid character " + std::to_string(static_cast<int>(t));
88  }
89  }
90 
91  Token next_token()
92  {
93  Token result = Eof;
94  while (m_p != m_e)
95  {
96  char ch = *m_p++;
97  if (ch == ' ')
98  continue;
99 
100  switch (ch)
101  {
102  case 'x':
103  case 'X':
104  result = XYZ;
105  m_nr = 0;
106  break;
107 
108  case 'y':
109  case 'Y':
110  result = XYZ;
111  m_nr = 1;
112  break;
113 
114  case 'z':
115  case 'Z':
116  result = XYZ;
117  m_nr = 2;
118  break;
119 
120  default:
121  if (isdigit(ch))
122  {
123  m_nr = ch - '0';
124  result = Number;
125  }
126  else
127  result = (Token)ch;
128  break;
129  }
130  break;
131  }
132 
133  return result;
134  }
135 
136  void match(Token token)
137  {
138  if (m_lookahead != token)
139  throw std::runtime_error("Unexpected character " + to_string(m_lookahead) + " expected " + to_string(token));
140 
141  m_lookahead = next_token();
142  }
143 
144  void parsepart(int row)
145  {
146  do
147  {
148  int sign = m_lookahead == '-' ? -1 : 1;
149  if (m_lookahead == '-' or m_lookahead == '+')
150  match(m_lookahead);
151 
152  if (m_lookahead == Number)
153  {
154  m_trn[row][0] = sign * m_nr;
155  match(Number);
156 
157  match((Token)'/');
158 
159  m_trn[row][1] = m_nr;
160  match(Number);
161  }
162  else
163  {
164  m_rot[row][m_nr] = sign;
165  match(XYZ);
166  }
167  }
168  while (m_lookahead == '+' or m_lookahead == '-');
169  }
170 
171  Token m_lookahead;
172  int m_nr;
173 
174  std::string m_s;
175  std::string::const_iterator m_p, m_e;
176 
177  int m_rot[3][3] = {};
178  int m_trn[3][2] = {};
179 };
180 
181 std::array<int,15> move_symop(std::array<int,15> symop, const std::array<int,15>& cenop)
182 {
183  for (int i = 9; i < 15; i += 2)
184  {
185  if (cenop[i] == 0)
186  continue;
187 
188  assert(cenop[i + 1] != 0);
189 
190  if (symop[i] == 0)
191  {
192  assert(symop[i + 1] == 0);
193  symop[i] = cenop[i];
194  symop[i + 1] = cenop[i + 1];
195  continue;
196  }
197 
198  if (symop[i + 1] == cenop[i + 1])
199  symop[i] += cenop[i];
200  else
201  {
202  int d = symop[i + 1] * cenop[i + 1];
203  int n = symop[i] * cenop[i + 1] + symop[i + 1] * cenop[i];
204 
205  symop[i] = n;
206  symop[i + 1] = d;
207  }
208 
209  for (int j = 5; j > 1; --j)
210  if (symop[i] % j == 0 and symop[i + 1] % j == 0)
211  {
212  symop[i] /= j;
213  symop[i + 1] /= j;
214  }
215 
216  symop[i] = (symop[i] + symop[i + 1]) % symop[i + 1];
217 
218  if (symop[i] == 0)
219  symop[i + 1] = 0;
220  }
221 
222  return symop;
223 }
224 
225 int main(int argc, char* const argv[])
226 {
227  using namespace std::literals;
228 
229  fs::path tmpFile;
230 
231  try
232  {
233  if (argc != 3)
234  {
235  std::cerr << "Usage symop-map-generator <input-file> <output-file>" << std::endl;
236  exit(1);
237  }
238 
239  fs::path input(argv[1]);
240  fs::path output(argv[2]);
241 
242  tmpFile = output.parent_path() / (output.filename().string() + ".tmp");
243 
244  std::ofstream out(tmpFile);
245  if (not out.is_open())
246  throw std::runtime_error("Failed to open output file");
247 
248  // --------------------------------------------------------------------
249 
250  // store symop data here
251  std::vector<std::tuple<int,int,std::array<int,15>>> data;
252 
253  // -----------------------------------------------------------------------
254 
255  struct SymInfoBlock
256  {
257  int nr;
258  std::string xHM;
259  std::string Hall;
260  std::string old[2];
261  };
262 
263  std::map<int,SymInfoBlock> symInfo;
264  int symopnr, mysymnr = 10000;
265 
266  std::ifstream file(input);
267  if (not file.is_open())
268  throw std::runtime_error("Could not open syminfo.lib file");
269 
270  enum class State { skip, spacegroup } state = State::skip;
271 
272  std::string line;
273 
274  const std::regex rx(R"(^symbol +(Hall|xHM|old) +'(.+?)'(?: +'(.+?)')?$)"),
275  rx2(R"(symbol ccp4 (\d+))");;
276 
277  SymInfoBlock cur = {};
278 
279  std::vector<std::array<int,15>> symops, cenops;
280 
281  while (getline(file, line))
282  {
283  switch (state)
284  {
285  case State::skip:
286  if (line == "begin_spacegroup")
287  {
288  state = State::spacegroup;
289  symopnr = 1;
290  ++mysymnr;
291  cur = { mysymnr };
292  }
293  break;
294 
295  case State::spacegroup:
296  {
297  std::smatch m;
298  if (std::regex_match(line, m, rx))
299  {
300  if (m[1] == "old")
301  {
302  cur.old[0] = m[2];
303  if (m[3].matched)
304  cur.old[1] = m[3];
305  }
306  else if (m[1] == "xHM")
307  cur.xHM = m[2];
308  else if (m[1] == "Hall")
309  cur.Hall = m[2];
310  }
311  else if (regex_match(line, m, rx2))
312  {
313  int nr = stoi(m[1]);
314  if (nr != 0)
315  cur.nr = nr;
316  }
317  else if (line.compare(0, 6, "symop ") == 0)
318  {
319  SymopParser p;
320  symops.emplace_back(p.parse(line.substr(6)));
321  }
322  else if (line.compare(0, 6, "cenop ") == 0)
323  {
324  SymopParser p;
325  cenops.emplace_back(p.parse(line.substr(6)));
326  }
327  else if (line == "end_spacegroup")
328  {
329  for (auto& cenop: cenops)
330  {
331  for (auto symop: symops)
332  {
333  symop = move_symop(symop, cenop);
334 
335  data.emplace_back(cur.nr, symopnr, symop);
336  ++symopnr;
337  }
338  }
339 
340  symInfo.emplace(cur.nr, cur);
341  state = State::skip;
342 
343  symops.clear();
344  cenops.clear();
345  }
346  break;
347  }
348  }
349  }
350 
351  // --------------------------------------------------------------------
352 
353  sort(data.begin(), data.end());
354 
355  // --------------------------------------------------------------------
356 
357  out << R"(// This file was generated from $CLIBD/symop.lib
358 // and $CLIBD/syminfo.lib using symop-map-generator,
359 // part of the PDB-REDO suite of programs.
360 
361 #include "cif++/symmetry.hpp"
362 
363 namespace cif
364 {
365 
366 const space_group kSpaceGroups[] =
367 {
368 )";
369 
370  std::vector<std::tuple<std::string,int,std::string,std::string>> spacegroups;
371 
372  for (auto& [nr, info]: symInfo)
373  {
374  spacegroups.emplace_back(info.old[0], nr, info.xHM, info.Hall);
375  if (info.old[1].empty() == false)
376  spacegroups.emplace_back(info.old[1], nr, info.xHM, info.Hall);
377  }
378 
379  sort(spacegroups.begin(), spacegroups.end());
380 
381  for (auto [old, nr, xHM, Hall]: spacegroups)
382  {
383  old = '"' + old + '"' + std::string(20 - old.length(), ' ');
384  xHM = '"' + xHM + '"' + std::string(30 - xHM.length(), ' ');
385 
386  for (std::string::size_type p = Hall.length(); p > 0; --p)
387  {
388  if (Hall[p - 1] == '"')
389  Hall.insert(p - 1, "\\", 1);
390  }
391 
392  Hall = '"' + Hall + '"' + std::string(40 - Hall.length(), ' ');
393 
394  out << "\t{ " << old << ", " << xHM << ", " << Hall << ", " << nr << " }," << std::endl;
395  }
396 
397 out << R"(
398 };
399 
400 const size_t kNrOfSpaceGroups = sizeof(kSpaceGroups) / sizeof(space_group);
401 
402 const symop_datablock kSymopNrTable[] = {
403 )" << std::endl;
404 
405  int spacegroupNr = 0;
406  for (auto& sd: data)
407  {
408  int sp, o;
409  std::tie(sp, o, std::ignore) = sd;
410 
411  if (sp > spacegroupNr)
412  out << " // " << symInfo[sp].xHM << std::endl;
413  spacegroupNr = sp;
414 
415  out << " { " << std::setw(3) << sp
416  << ", " << std::setw(3) << o << ", { ";
417  for (auto& i: std::get<2>(sd))
418  out << std::setw(2) << i << ',';
419  out << " } }," << std::endl;
420  }
421 
422  out << R"(};
423 
424 const size_t kSymopNrTableSize = sizeof(kSymopNrTable) / sizeof(symop_datablock);
425 
426 } // namespace mmcif
427 )" << std::endl;
428 
429  out.close();
430  fs::rename(tmpFile, output);
431  }
432  catch (const std::exception& ex)
433  {
434  std::cerr << std::endl
435  << "Program terminated due to error:" << std::endl
436  << ex.what() << std::endl;
437  }
438 
439  return 0;
440 }
std::array< int, 15 > parse(const std::string &s)
double sign
#define i
doublereal * d
int main(int argc, char *const argv[])
std::regex kNameRx(R"(^(\) +(\) +(\) +(\) +(\) +(\) +'([^']+)'( +'([^']+)')?(?: +!.+)?$)")
std::array< int, 15 > move_symop(std::array< int, 15 > symop, const std::array< int, 15 > &cenop)
void sort(struct DCEL_T *dcel)
Definition: sorting.cpp:18
#define j
int m
std::string to_string(bond_type bondType)
Definition: compound.cpp:43
int * n