1 #include "listfile.h"
2 #include <QtCore>
3 #include <QTextStream>
4 #include "deprecation.h"
5
6 /*
7 * This file handles the ShelXl lst file during and after the refinement
8 *
9 * TODO:
10 * - Make running SHELXL more visual. e.g. progress bar (especially while writing cif file)
11 *
12 L.S.:
13 wR2 = 0.165168 before cycle 1 for 29437 data and 2607 / 2607 parameters
14 GooF = S = 1.509; Restrained GooF = 1.434 for 3259 restraints
15 Mean shift/esd = 0.013 Maximum = 1.375 for U23 C54 at 09:31:33
16 Max. shift = 0.008 A for C54 Max. dU =-0.010 for C54
17 *
18 CGLS:
19 wR2 = 0.165155 before cycle 1 for 29437 data and 2607 / 2607 parameters
20 GooF = S = 1.509; Restrained GooF = 1.434 for 3257 restraints
21 Max. shift = 0.004 A for C54 Max. dU =-0.007 for C54
22 */
23
ListFileHandler(QString lfpath,QObject * parent)24 ListFileHandler::ListFileHandler(QString lfpath, QObject *parent) : QObject(parent)
25 {
26 REL_RESTR_CARDS << "SAME"<< "SADI"<< "SIMU"<< "RIGU"<< "ISOR"<< "NCSY"<< "FLAT" << "DELU";
27 my_lstpath = lfpath;
28 //QFileSystemWatcher fw; // The filesystem watcher doesn't work in my windows 8.1
29 //fw.addPath(*my_lstpath); // I am not shure why I added it? It works also without. DK
30 success = false; // turns to true if refinement was a sucess.
31 listfcontent = new QStringList;
32 listfcontent->append(this->loadLst());
33 }
34
35
loadLst()36 QStringList ListFileHandler::loadLst(){
37 //! Reads the SHELXL lst file from disk
38 //! and returns it as a QStringlist
39 QFile file(my_lstpath);
40 QStringList lstList;
41 if (file.open(QFile::ReadOnly | QFile::Text)) {
42 QTextStream textStream(&file);
43 while (true) {
44 QString line = textStream.readLine();
45 if (line.isNull()) {
46 emit lstFinished();
47 break;
48 }
49 if (line.isEmpty()) {
50 continue;
51 } else {
52 lstList.append(line);
53 }
54 }
55 }
56 file.close();
57 return lstList;
58 }
59
listfileparser()60 QVector<QStringList> ListFileHandler::listfileparser() {
61 /*!
62 Gathers the residuals of the SHELXL lst file.
63 It searches for the final cycle summary and then for " Disagreeable restraints".
64 End is reached with ' Summary of restraints'.
65 Ported from: https://github.com/dkratzert/DSR-db
66
67 Disagreeable restraints before cycle 6
68
69 Observed Target Error Sigma Restraint
70
71 0.1487 0.0400 SAME/SADI O1_1b C2_1b O1_1b C4_1b
72
73 */
74 if (listfcontent->isEmpty()) {
75 QVector<QStringList> dummy;
76 return dummy;
77 }
78 bool disag = false;
79 bool final = false;
80 QVector<QStringList> disargeelist;
81 int num = 0;
82 foreach(QString line, *listfcontent) {
83 QStringList splitline;
84 splitline = line.split(" ", skipEmptyParts);
85 if (splitline.isEmpty()) {
86 continue;
87 }
88 if (splitline[0].startsWith("Observed")) {
89 continue;
90 }
91 if (line.startsWith(" Final Structure Factor")) {
92 final = true;
93 }
94 if (final && line.startsWith(" Disagreeable restraints")) {
95 disag = true;
96 continue;
97 }
98 if (line.startsWith(" Summary of restraints applied")) {
99 final = false;
100 disag = false;
101 }
102 if (line.contains("RIGU")) {
103 continue; // leave out RIGU, it produces too many lines...
104 }
105 if (splitline.size() < 2) continue;
106 if (disag) {
107 // in this case, the desired line is found:
108 disargeelist.append(lineformatter(splitline));
109 num = num+1;
110 if (num > 500) {
111 // Cutting restraints list. Too many bad restraints...
112 return disargeelist;
113 }
114 }
115 }
116 return disargeelist;
117 }
118
119
lineformatter(QStringList line)120 QStringList ListFileHandler::lineformatter(QStringList line) {
121 /*!
122 takes care of some extra things with different restraints. For example
123 RIGU xy should be in one column.
124 Ported from: https://github.com/dkratzert/DSR-db
125 */
126 int num = 0;
127 int pos = 0;
128 foreach(QString i, line) {
129 i = i.replace('/', ' ');
130 if (i[0].isLetter()){
131 pos = num;
132 break;
133 }
134 num += 1;
135 }
136 // remove the part symbol from e.g. F1_2a:
137 /*
138 num = 0;
139 foreach (QString i, line) {
140 line[num] = remove_partsymbol(i);
141 num += 1;
142 } */
143 // joining columns without numbers:
144 QStringList posline = line.mid(pos, -1);
145 QString joinline = posline.join(" ");
146 QStringList newline = line.mid(0, pos);
147 line = newline;
148 line.append(joinline);
149 QString tline = line.join(" ");
150 foreach (QString n, REL_RESTR_CARDS) {
151 if (tline.contains(n, Qt::CaseInsensitive)) {
152 // adding placeholders for empty fields:
153 QStringList nline;
154 nline.append("-");
155 nline.append("-");
156 nline.append(line);
157 return nline;
158 }
159 }
160 return line;
161 }
162
163
table_maker(QVector<QStringList> tabledata)164 QString ListFileHandler::table_maker(QVector<QStringList> tabledata) {
165 /*!
166 Builds a html table out of a datalist from the final
167 cycle summary of a shelxl list file.
168 */
169 QStringList table;
170 QString header;
171 QString footer;
172 QString html;
173 table.clear();
174 foreach(QStringList line, tabledata) {
175 table.append(this->row(line));
176 }
177 header = QString(
178 "<body style=\"font-family:SansSerif; font-size:11pt;\">"
179 "<table>"
180 "<tr>"
181 "<td width=60% align=left>"
182 "<b>List of most disagreeable restraints:</b> "
183 "</td>"
184 "<td width=40% align=right>"
185 "</td>"
186 "</tr>"
187 "</table>");
188 footer = "</body>";
189 html = QString(
190 "%1"
191 "<table border=0 cellpadding=0 cellspacing=6 width=100% >"
192 "<tr>"
193 "<td align='center'> Observed </td>"
194 "<td align='center'> Target </td>"
195 "<td align='center'> Error </td>"
196 "<td align='center'> Sigma </td>"
197 "<td align='left'> Restraint </td>"
198 "</tr>"
199 "%2"
200 "</table>"
201 "%3").arg(header, table.join("\n"), footer);
202
203 if(table.isEmpty()) {
204 //return header+empty_data;
205 return QString(header+"All restraint deviations are within their standard deviation.");
206 //return QString("");
207 }
208 return html;
209 }
210
row(QStringList rowdata)211 QString ListFileHandler::row(QStringList rowdata) {
212 /*!
213 creates a table row for the restraints list.
214 :type rowdata: list
215 */
216 QStringList td;
217 td.clear();
218 QString row = "";
219 QString bgcolor = "";
220 if (rowdata.size() >= 5) {
221 bool ok1 = false;
222 bool ok2 = false;
223 rowdata[2].toFloat(&ok1);
224 rowdata[3].toFloat(&ok2);
225 if (ok1 && ok2) {
226 if (qAbs(rowdata.at(2).toDouble()) > 2.5*rowdata[3].toDouble()) {
227 bgcolor = QString("bgcolor='#ffec99'"); // bgcolor='#FFD100' // yellow
228 }
229 if (qAbs(rowdata.at(2).toDouble()) > 3.5*rowdata[3].toDouble()) {
230 bgcolor = QString("bgcolor='#ff9fac'"); // bgcolor='#FF1030' // red
231 }
232 }
233 }
234 int num = 0;
235 foreach (QString item, rowdata) {
236 bool ok = false;
237 item.toDouble(&ok);
238 if (ok) {
239 // align right for numbers:
240 if (num < 2) {
241 // do not colorize the first two columns:
242 td.append(QString("<td align='right'> %1 </td>").arg(item));
243 } else {
244 td.append(QString("<td align='right' %1> %2 </td>").arg(bgcolor, item));
245 }
246 } else {
247 if (item.startsWith('-')) {
248 // only a minus sign
249 td.append(QString("<td align='center'> %1 </td>").arg(item));
250 } else {
251 if (num < 4) {
252 td.append(QString("<td align='right'> %1 </td>").arg(item));
253 continue;
254 }
255 // align left for words:
256 td.append(QString("<td align='left'> %1 </td>").arg(item));
257 }
258 }
259 num += 1;
260 }
261 if (td.isEmpty()) {
262 row = "<tr> No (disagreeable) restraints found in .lst file. </tr>";
263 } else {
264 row = QString("<tr> %1 </tr>").arg(td.join(""));
265 }
266 td.clear();
267 return row;
268 }
269
restraintsTable()270 QString ListFileHandler::restraintsTable() {
271 QString txt;
272 txt.append(table_maker(listfileparser()));
273 return txt;
274 }
275
getSuccess() const276 bool ListFileHandler::getSuccess() const {
277 return success;
278 }
279
setSuccess(bool value)280 void ListFileHandler::setSuccess(bool value) {
281 success = value;
282 }
283
thetaFromLst()284 QString ListFileHandler::thetaFromLst() {
285 //! Max. 2-theta = 55.30
286 //! -8 =< h =< 8, -21 =< k =< 21, -21 =< l =< 21, Max. 2-theta = 55.30
287 //! I might need this later
288 QString theta = "";
289 foreach(QString line, *listfcontent) {
290 if (line.contains("Max. 2-theta")) {
291 theta = line.section("theta", 1, 1).split(" ", skipEmptyParts).at(1);
292 }
293 }
294 return theta;
295 }
296
297
298 // ##########################################################################
299
300
XLOutputParser(QObject * parent)301 XLOutputParser::XLOutputParser(QObject *parent) : QObject(parent) {
302 //! Handles the content of the SHELXL list file.
303 //! Methods with "current" in the name return values of the current state
304 //! in the continuously growing SHELXL list file.
305 //! Methods with "final" return the values after successful refinement.
306 //!
307 // The constructor:
308 ls_cycles = 0;
309 listf_data.cmdline = "";
310 listf_data.xlversion = "";
311 listf_data.threads = "";
312 listf_data.procs = "";
313 listf_data.rint = "";
314 listf_data.rsigma = "";
315 listf_data.wr2 = "";
316 listf_data.cycle = "";
317 listf_data.data = "0";
318 listf_data.current_parameters = "0";
319 listf_data.all_parameters = "0";
320 listf_data.curGoof = " ";
321 listf_data.curRGoof = " ";
322 listf_data.R1_4sig = "";
323 listf_data.finalwR2 = "";
324 listf_data.maxshift_esd = "";
325 listf_data.maxshiftfor = "";
326 listf_data.meanshift = "";
327 listf_data.maxshift = "";
328 listf_data.dU = "";
329 listf_data.dUfor = "";
330 listf_data.peak = "";
331 listf_data.hole = "";
332 listf_data.peakpos = "";
333 listf_data.holepos = "";
334 listf_data.peakdist = "";
335 listf_data.holedist = "";
336 listf_data.warning = "";
337 listf_data.warnings.clear();
338 listf_data.time = "";
339
340 rgr.Goof = 0.0;
341 rgr.cycle = 0.0;
342 rgr.dU = 0.0;
343 rgr.dUfor = "";
344 rgr.wR2 = 0.0;
345 rgr.final_wR2 = 0.0;
346 rgr.max_shift_esd_for = "";
347 rgr.maxshift = 0.0;
348 rgr.maxshift_esd = 0.0;
349 rgr.maxshiftfor = "";
350 rgr.meanshift = 0.0;
351 rgr.warnings.clear();
352 rgr.time = 0.0;
353 warnings.clear();
354 }
355
356
residualsGraphDisplay()357 RGraph XLOutputParser::residualsGraphDisplay() {
358 //! Returns a data structure that collects the values of
359 //! wR2, R1, Goof, ... during refinement to display them as
360 //! a graph.
361 // collect data from each line and append it to RGraph
362 rgr.Goof = listf_data.curGoof.toDouble();
363 rgr.wR2 = listf_data.wr2.toDouble();
364 rgr.maxshift = listf_data.maxshift.toDouble();
365 rgr.meanshift = listf_data.meanshift.toDouble();
366 rgr.cycle = listf_data.cycle.toInt();
367 rgr.final_wR2 = listf_data.finalwR2.toDouble();
368 rgr.warnings = listf_data.warnings;
369 return rgr;
370 }
371
372
fillListFileData(QString line)373 void XLOutputParser::fillListFileData(QString line) {
374 //! Fills listf_data with data but it is only filled
375 //! if the respective strings contain data
376 QStringList tproc = xl_threads(line);
377 QString cmdline = xl_cmdline(line);
378 QString version = xl_version(line);
379 QStringList rintsig = xl_rint_rsigma(line);
380 QStringList wr2data = xl_current_wr2_data_param(line);
381 QString R1_4sig = xl_final_R1_4sig(line);
382 QString R1_all = xl_final_R1all(line);
383 QString finalwR2 = xl_final_wR2(line);
384 QStringList goofs = xl_current_goof(line);
385 QStringList peakvalues = xl_peak(line);
386 QStringList holevalues = xl_hole(line);
387 //QStringList fgoofs = xl_final_goofs(line);
388 QStringList maxshifts = xl_current_max_shift(line);
389 QStringList meanshifts = xl_current_meanshift_esd(line);
390 xl_collect_warnings(line);
391 QStringList flackvals = xl_flacksvals(line);
392 QString timeval = xl_timeval(line);
393
394 // Only fill listf_data with values if there are any:
395 if (!cmdline.isEmpty()) {
396 listf_data.cmdline = cmdline;
397 }
398 if (!version.isEmpty()) {
399 listf_data.xlversion = version;
400 }
401 if ((!tproc[0].isEmpty()) && (!tproc[1].isEmpty())) {
402 listf_data.threads = tproc[0];
403 listf_data.procs = tproc[1];
404 }
405 if ((!rintsig[0].isEmpty()) && (!rintsig[1].isEmpty())) {
406 listf_data.rint = rintsig[0];
407 listf_data.rsigma = rintsig[1];
408 }
409 if (!wr2data.at(0).isEmpty()) {
410 listf_data.wr2 = wr2data.at(0);
411 }
412 if (!wr2data.at(1).isEmpty()) {
413 emit newLScycle();
414 listf_data.cycle = wr2data.at(1);
415 }
416 if (!wr2data.at(2).isEmpty()) {
417 listf_data.data = wr2data.at(2);
418 }
419 if (!wr2data.at(3).isEmpty()) {
420 listf_data.current_parameters = wr2data.at(3);
421 }
422 if (!wr2data.at(4).isEmpty()) {
423 listf_data.all_parameters = wr2data.at(4);
424 }
425 if (!goofs[0].isEmpty() && !goofs[1].isEmpty()) {
426 listf_data.curGoof = goofs[0];
427 listf_data.curRGoof = goofs[1];
428 }
429 if (!goofs[2].isEmpty()) {
430 listf_data.nrestraints = goofs[2];
431 }
432 if (!R1_4sig.isEmpty()) {
433 listf_data.R1_4sig = R1_4sig;
434 }
435 if (!R1_all.isEmpty()) {
436 listf_data.R1_all = R1_all;
437 }
438 if (!finalwR2.isEmpty()) {
439 listf_data.finalwR2 = finalwR2;
440 }
441 if (!maxshifts[0].isEmpty() && !maxshifts[1].isEmpty()) {
442 //shifts.append(maxshift);
443 //shifts.append(maxshiftfor);
444 //shifts.append(dU);
445 //shifts.append(dUfor);
446 listf_data.maxshift = maxshifts[0];
447 listf_data.maxshiftfor = maxshifts[1];
448 listf_data.dU = maxshifts[2];
449 listf_data.dUfor = maxshifts[3];
450 }
451 if (!meanshifts[0].isEmpty() && !meanshifts[2].isEmpty()) {
452 //shifts.append(meanshift);
453 //shifts.append(maxshift_esd);
454 //shifts.append(max_esd_shiftfor);
455 listf_data.meanshift = meanshifts[0];
456 listf_data.maxshift_esd = meanshifts[1];
457 listf_data.max_shift_esd_for = meanshifts[2];
458 }
459 if (!holevalues[0].isEmpty() && !holevalues[1].isEmpty() && !holevalues[2].isEmpty()
460 && !holevalues[3].isEmpty()) {
461 listf_data.hole = holevalues[0];
462 listf_data.holepos = holevalues[1];
463 listf_data.holedist = holevalues[2];
464 listf_data.holefrom = holevalues[3];
465 }
466 if (!peakvalues[0].isEmpty() && !peakvalues[1].isEmpty() && !peakvalues[2].isEmpty()
467 && !peakvalues[3].isEmpty()) {
468 listf_data.peak = peakvalues[0];
469 listf_data.peakpos = peakvalues[1];
470 listf_data.peakdist = peakvalues[2];
471 listf_data.peakfrom = peakvalues[3];
472 }
473 if (!flackvals[0].isEmpty()) {
474 listf_data.flack = flackvals.at(0);
475 }
476 if (!flackvals[1].isEmpty()) {
477 listf_data.parson = flackvals.at(1);
478 }
479 if (!timeval.isEmpty()) {
480 listf_data.time = timeval;
481 }
482 }
483
residualsTextDisplay(QString & line,int ls_cycles)484 QString XLOutputParser::residualsTextDisplay(QString &line, int ls_cycles) {
485 //! returns a html string to display the refinement results in a QLabel
486 this->ls_cycles = ls_cycles;
487 fillListFileData(line);
488 QString html_output = "";
489 QString html_final = "";
490 QString wr2line = "";
491 QString shiftyellow = "";
492 QString shift_esd_yellow = "";
493 QString dUyellow = "";
494 QString cycleText = "";
495 QString progressbar = "";
496 float restr_ratio = 0.0;
497 float data_to_param_ratio = 0.0;
498 if (!listf_data.data.isEmpty() && !listf_data.nrestraints.isEmpty() && !listf_data.all_parameters.isEmpty()){
499 restr_ratio = (listf_data.data.toDouble()+listf_data.nrestraints.toInt())/listf_data.all_parameters.toDouble();
500 data_to_param_ratio = listf_data.data.toFloat()/listf_data.all_parameters.toFloat();
501 }
502 if (!listf_data.R1_4sig.isEmpty() && !listf_data.finalwR2.isEmpty()) { // final values:
503 html_final = QString("<tr><td align=right><b><i>wR</i><sub>2</sub> = </b></td> <td><b> %2% </b>(all data) </td>"
504 " <td align=right><b><i>R</i><sub>1</sub></b> [<i>I</i> > 4σ<i>I</i>] = </td> <td><b>%1%</b> (%9% all data)</td></tr>"
505 "<tr><td align=right>Highest peak = </td> <td> %3 eÅ<sup>-3</sup> at %4 Å from %7 </td>"
506 " <td align=right>Deepest hole = </td> <td> %5 eÅ<sup>-3</sup> at %6 Å from %8 </td></tr>"
507 )
508 .arg(listf_data.R1_4sig.toDouble()*100, 4, 'f', 2, 0) // 1
509 .arg(listf_data.finalwR2.toDouble()*100, 4, 'f', 2, 0) // 2
510 .arg(listf_data.peak) // 3
511 .arg(listf_data.peakdist) // 4
512 .arg(listf_data.hole) // 5
513 .arg(listf_data.holedist) // 6
514 .arg(listf_data.peakfrom) // 7
515 .arg(listf_data.holefrom) // 8
516 .arg(listf_data.R1_all.toDouble()*100, 4, 'f', 2, 0) // 9
517 ;
518 // One of flack or parson exists:
519 if (!listf_data.flack.isEmpty() || !listf_data.parson.isEmpty()) {
520 // both exist:
521 if (!listf_data.flack.isEmpty() && !listf_data.parson.isEmpty()) {
522 wr2line = QString("<tr><td align=right> <b>Flack X </b>= </td> <td> %1 (Parsons' method)</td> <td> </td> </tr> "
523 "<tr><td align=right> </td> <td> %2 (classical fit)</td> <td> </td> </tr>").arg(listf_data.parson).arg(listf_data.flack);
524 }
525 // Only classical exists:
526 if (!listf_data.flack.isEmpty() && listf_data.parson.isEmpty()) {
527 wr2line = QString("<tr><td align=right> <b>Flack X </b>= </td> <td> %1 (classical fit)</td> "
528 "<td> </td> </tr>").arg(listf_data.flack);
529 }
530 // Only Parsons exists:
531 if (!listf_data.parson.isEmpty() && listf_data.flack.isEmpty()){
532 wr2line = QString("<tr><td align=right> <b>Flack X </b>= </td> <td> %1 (Parsons' method)</td> "
533 "<td> </td> </tr>").arg(listf_data.parson);
534 }
535 } else { // no flack parameter:
536 wr2line = ""; // No Table row to prevent empty line
537 }
538 } else { // shelxl is currently runnig:
539 html_final = "";
540 wr2line = QString("<tr><td align=right> <i>wR</i><sub>2</sub> = </td> <td> %7% </td></tr>")
541 .arg(listf_data.wr2.toDouble()*100, 4, 'f', 2);
542 }
543 if (qAbs(listf_data.maxshift.toDouble()) > 0.005) {
544 shiftyellow = QString("bgcolor=#ffec99");
545 }
546 if (qAbs(listf_data.maxshift_esd.toDouble()) > 0.01) {
547 shift_esd_yellow = QString("bgcolor=#ffec99");
548 }
549 if (qAbs(listf_data.dU.toDouble()) > 0.005) {
550 dUyellow = QString("bgcolor=#ffec99");
551 }
552 int repeat = 12;
553 if (listf_data.cycle.toInt() < ls_cycles) {
554 int progress;
555 progress = int((listf_data.cycle.toFloat() / ls_cycles)*10);
556 progressbar = QString("<td bgcolor=#69CB3F >%1</td>").arg(QString(" ").repeated(repeat)).repeated(progress)
557 +QString("<td bgcolor=#D0D0D0 >%1</td>").arg(QString(" ").repeated(repeat)).repeated(10-progress);
558 cycleText = QString("<tr><td> <b>Cycle %1 of %2</b> </td></tr>")
559 .arg(listf_data.cycle) // 1
560 .arg(ls_cycles) // 2
561 ;
562 } else {
563 cycleText = QString("<tr><td> <b>Final Cycle of %1</b></td></tr>")
564 .arg(ls_cycles); // 1
565 progressbar = QString("<td bgcolor=#69CB3F>%1</td>").arg(QString(" ").repeated(repeat)).repeated(10);
566 }
567 html_output = QString(
568 "<body style=\"font-family:SansSerif; font-size:11pt;\">"
569 "<H2>Running SHELXL %1</H2> "
570 "<table cellpadding=3% align=left>"
571 "<tr><td colspan=2 align=left> <table><tr> %2 </tr></table> </td></tr>"
572 "<tr><td> %3 threads on %4 processors </td></tr>"
573 "<tr><td> Using %5 data and %6 of %7 parameters (ratio %8; %11 with restraints) </td></tr>"
574 "<tr><td><i>R</i><sub>int</sub> = %9%, <i>R</i><sub>σ</sub> = %10% </td></tr>"
575 "</table>")
576 .arg(listf_data.xlversion) // 1
577 .arg(progressbar) // 2
578 .arg(listf_data.threads) // 3
579 .arg(listf_data.procs) // 4
580 .arg(listf_data.data) // 5
581 .arg(listf_data.current_parameters) // 6
582 .arg(listf_data.all_parameters) // 7
583 .arg(data_to_param_ratio, 10, 'f', 1) // 8 data/restr. ratio
584 .arg(listf_data.rint.toFloat()*100, 10, 'f', 2) // 9
585 .arg(listf_data.rsigma.toFloat()*100, 10, 'f', 2) // 10
586 .arg(restr_ratio, 10, 'f', 1) // 11 (data+restraints)/parameter
587 ;
588
589 QString maxshift_row = "";
590
591 if (!listf_data.maxshift_esd.isEmpty()) {
592 maxshift_row = QString("<tr><td align=right> Max. shift = </td> <td %1> %2 @ %3 </td> </tr>")
593 .arg(shift_esd_yellow) // 1 color of max shifting param.
594 .arg(listf_data.maxshift_esd) // 2
595 .arg(listf_data.max_shift_esd_for) // 3
596 ;
597 }
598
599 QString xyz_shift_row = "";
600
601 if (!listf_data.maxshift.isEmpty()) {
602 xyz_shift_row = QString("<tr><td align=right> Max. xyz shift = </td> <td %1> %2 Å @ %3 </td>"
603 " <td align=right> Max. ΔU = </td> <td %4> %5 @ %6 </td></tr>")
604 .arg(shiftyellow) // 1
605 .arg(listf_data.maxshift) // 2
606 .arg(listf_data.maxshiftfor) // 3
607 .arg(dUyellow) // 4
608 .arg(listf_data.dU) // 5
609 .arg(listf_data.dUfor) // 6
610 ;
611 }
612
613 QString html_output2 = QString("<table cellpadding=2%>"
614 "%1"
615 "%2"
616 "%3"
617 "<tr><td align=right> <i>GooF</i> = </td> <td> %4 </td>"
618 " <td align=right width=18%> Restr. <i>GooF</i> = </td> <td> %5 </td></tr>"
619 "%6"
620 "%7"
621 "</table>"
622 "<table><tr><td bgcolor=#ffec99><b> %8 </b></td></tr></table>"
623 "</body>")
624 .arg(cycleText) // 1
625 .arg(html_final) // 2
626 .arg(wr2line) // 3 //wr2
627 .arg(listf_data.curGoof) // 4
628 .arg(listf_data.curRGoof) // 5
629 .arg(xyz_shift_row) // 6
630 .arg(maxshift_row) // 7
631 .arg(listf_data.warnings.join("<br>")) // 8
632
633 ;
634 if (!listf_data.wr2.isEmpty()) {
635 html_output += html_output2;
636 } else {
637 // In this case, no refinement happened:
638 if (!listf_data.warnings.isEmpty()) {
639 // even if no refinenemt happened, I want to display the warnings:
640 html_output += QString("<table><tr><td bgcolor=#ffec99> %2 </td></tr></table>")
641 .arg(listf_data.warnings.join("<br>"));
642 } else {
643 // no warning, but still waiting for output from SHLEXL:
644 html_output += QString("<b>Waiting for output from SHELXL...</b>");
645 }
646 }
647 if (!listf_data.time.isEmpty() && listf_data.wr2.isEmpty()) {
648 // SHELXL finished regularly (time elapsed output), but no refinement happened (wr2 is empty)
649 html_output += QString("<br><b>SHELXL failed to run! Please inspect the instructions.</b>");
650 }
651 return html_output;
652 }
653
654
xl_version(QString line)655 QString XLOutputParser::xl_version(QString line) {
656 //! Returns the running shelxl version
657 //! " + Copyright(C) George M. Sheldrick 1993-2014 Version 2014/7 +"
658 QRegExp versionregex = QRegExp("Version\\s+\\d+\\/\\d+");
659 QString version;
660 QStringList linesplit;
661 if (line.contains(versionregex)) {
662 linesplit = line.split(" ", skipEmptyParts);
663 int index = linesplit.indexOf("Version");
664 version = linesplit.at(index+1);
665 }
666 return version;
667 }
668
xl_threads(QString line)669 QStringList XLOutputParser::xl_threads(QString line) {
670 //! Returns on how many threads and processors shelxl is running
671 //! "Running 6 threads on 8 processors"
672 QStringList threadproc;
673 QString threads = "";
674 QString processors = "";
675 QStringList linesplit;
676 QRegExp tprocregex = QRegExp("Running\\s+\\d\\s+threads\\s+on\\s+\\d\\s+processors");
677 if (line.contains(tprocregex)) {
678 linesplit = line.split(" ", skipEmptyParts);
679 threads = linesplit.at(1);
680 processors = linesplit.at(4);
681 }
682 threadproc.append(threads);
683 threadproc.append(processors);
684 return threadproc;
685 }
686
xl_cmdline(QString line)687 QString XLOutputParser::xl_cmdline(QString line) {
688 //! Returns the command line options shelxl was started with
689 //! " Command line parameters: p21c -a50000 -b3000 -c624 -t6"
690 QString cmdline;
691 if (line.contains("Command line parameters:")) {
692 cmdline = line;
693 }
694 return cmdline;
695 }
696
xl_current_wr2_data_param(QString line)697 QStringList XLOutputParser::xl_current_wr2_data_param(QString line) {
698 //! Returns the number of data (reflections) shelxl is refining against.
699 //! This is without sigma cutoff:
700 //! " wR2 = 0.4016 before cycle 1 for 10786 data and 737 / 737 parameters"
701 //! returns list of [wR2, cycles, data, current_parameters, all_parameters]
702 QStringList linesplit;
703 QString wr2 = "";
704 QString cycle = "";
705 QString data = "";
706 QString current_parameters = "";
707 QString all_parameters = "";
708 QStringList alldata;
709 if (line.contains("wR2") && line.contains("cycle") && line.contains("data")
710 && (line.split(" ", skipEmptyParts).size() >= 12) ) {
711 linesplit = line.split(" ", skipEmptyParts);
712 wr2 = linesplit.at(2);
713 cycle = linesplit.at(5);
714 data = linesplit.at(7);
715 current_parameters = linesplit.at(10);
716 all_parameters = linesplit.at(12);
717 }
718 alldata.append(wr2);
719 alldata.append(cycle);
720 alldata.append(data);
721 alldata.append(current_parameters);
722 alldata.append(all_parameters);
723 return alldata;
724 }
725
xl_rint_rsigma(QString line)726 QStringList XLOutputParser::xl_rint_rsigma(QString line) {
727 //! Returns Rint and Rsigma of the dataset.
728 //! " R(int) = 0.0504 R(sigma) = 0.0585 Friedel opposites merged"
729 //chuebsch: this crashed:
730 //Data: 19 unique, 0 suppressed R(int) = 0.0000 R(sigma) =13.2352
731 //
732 QString rint = "";
733 QString rsigma = "";
734 QStringList linesplit, rvals;
735 QString l=line.remove('=');
736 if (line.contains("R(sigma)")) {
737 linesplit = l.split(" ", skipEmptyParts);
738 int RintInd = linesplit.indexOf(QRegExp("R\\(int\\)"));
739 if ((RintInd != -1) && linesplit.length() > RintInd+1) {//>= leads to segmentation fault
740 rint = linesplit.at(RintInd+1);
741 }
742 int RsigInd = linesplit.indexOf(QRegExp("R\\(sigma\\)"));
743 if ((RsigInd != -1) && linesplit.length() > RsigInd+1) {//>= leads to segmentation fault
744 rsigma = linesplit.at(RsigInd+1);
745 }//else qDebug()<<linesplit<<RsigInd;
746
747 }
748 rvals.append(rint);
749 rvals.append(rsigma);
750 return rvals;
751 }
752
xl_current_goof(QString line)753 QStringList XLOutputParser::xl_current_goof(QString line) {
754 //! Returns the current Goof of the refinement. This value is
755 //! the last value in the continuesly growing lst file.
756 //! "GooF = S = 4.130; Restrained GooF = 5.432 for 1662 restraints"
757 QString goof;
758 QString rgoof;
759 QString restraints;
760 QStringList linesplit;
761 QStringList goofs;
762 if (line.contains("Restrained GooF") && line.contains("restraints")
763 && (line.split(" ", skipEmptyParts).size() >= 8)) {
764 linesplit = line.split(" ", skipEmptyParts);
765 goof = linesplit.at(4);
766 goof.remove(QChar(';'));
767 rgoof = linesplit.at(8);
768 restraints = linesplit.at(10);
769 }
770 goofs.append(goof);
771 goofs.append(rgoof);
772 goofs.append(restraints);
773 return goofs;
774 }
775
xl_final_goofs(QString line)776 QStringList XLOutputParser::xl_final_goofs(QString line) {
777 //! Returns the final Goof after refinement finished.
778 //! "wR2 = 0.2277, GooF = S = 2.275, Restrained GooF = 2.122 for all data"
779 QString goof;
780 QString rgoof;
781 QStringList linesplit;
782 QStringList goofs;
783 if (line.contains("for all data") && (line.split(" ", skipEmptyParts).size() >= 11) ) {
784 linesplit = line.split(" ", skipEmptyParts);
785 goof = linesplit.at(7);
786 goof.remove(QChar(','));
787 rgoof = linesplit.at(11);
788 }
789 goofs.append(goof);
790 goofs.append(rgoof);
791 return goofs;
792 }
793
794
xl_current_meanshift_esd(QString line)795 QStringList XLOutputParser::xl_current_meanshift_esd(QString line) {
796 //! Returns the current shift per esd.
797 //! "Mean shift/esd = 0.016 Maximum = -8.976 for U11 C6 at 09:36:30
798 QStringList shifts;
799 QString meanshift = "";
800 QString maxshift_esd = "";
801 QString max_esd_shiftfor = "";
802 QStringList linesplit;
803 if (line.contains("shift/esd") && line.contains("Maximum")
804 && (line.split(" ", skipEmptyParts).size() >= 6) ) {
805 linesplit = line.split(" ", skipEmptyParts);
806 meanshift = linesplit.at(3);
807 maxshift_esd = linesplit.at(6);
808 max_esd_shiftfor = line.split("for", skipEmptyParts).at(1).trimmed()
809 .split("at", skipEmptyParts).at(0).trimmed();
810 }
811 shifts.append(meanshift);
812 shifts.append(maxshift_esd);
813 shifts.append(max_esd_shiftfor);
814 return shifts;
815 }
816
817
xl_current_max_shift(QString line)818 QStringList XLOutputParser::xl_current_max_shift(QString line) {
819 //! Returns the maximum shift during the refinement.
820 //! "Max. shift = 0.000 A for H26C Max. dU =-0.007 for C6"
821 //! "=-0.007 for C6"
822 QString maxshift;
823 QString maxshiftfor;
824 QString dU;
825 QString dUfor;
826 QStringList linesplit;
827 QStringList shifts;
828 if (line.contains("Max. shift") && line.contains("dU") && line.contains("for")
829 && (line.split(" ", skipEmptyParts).size() >= 6) ) {
830 linesplit = line.split(" ", skipEmptyParts);
831 maxshift = linesplit.at(3);
832 maxshiftfor = linesplit.at(6);
833 dU = line.split("dU").at(1).trimmed().remove("=").split(" ", skipEmptyParts).at(0);
834 dUfor = line.split("for").at(2).trimmed();
835 }
836 shifts.append(maxshift);
837 shifts.append(maxshiftfor);
838 shifts.append(dU);
839 shifts.append(dUfor);
840 return shifts;
841 }
842
843
xl_current_warning(QString line)844 QString XLOutputParser::xl_current_warning(QString line) {
845 //! Returns a Warning if there is any in the current line.
846 QRegExp warnregexp = QRegExp("\\*\\*"); //.*\\*\\*");
847 QString warn = "";
848 if ( line.contains(warnregexp) ) {
849 warn = line.simplified();
850 }
851 return warn;
852 }
853
xl_collect_warnings(QString line)854 void XLOutputParser::xl_collect_warnings(QString line) {
855 //! Returns all warning that occoured during refinement.
856 QRegExp warnregexp = QRegExp("\\*\\*"); //.*\\*\\*");
857 if ( line.contains(warnregexp) ) {
858 warnings.append(line.simplified());
859 }
860 if (line.contains("CANNOT OPEN FILE")) {
861 warnings.append(line.simplified());
862 }
863 listf_data.warnings = warnings;
864 rgr.warnings = warnings;
865 }
866
xl_final_R1_4sig(QString line)867 QString XLOutputParser::xl_final_R1_4sig(QString line) {
868 // R1 = 0.0401 for 7085 Fo > 4sig(Fo) and 0.0796 for all 10786 data
869 QString r1_4sigma = "";
870 QStringList linesplit;
871 if (line.contains("R1") && line.contains("4sig") && line.contains("for all")) {
872 linesplit = line.split(" ", skipEmptyParts);
873 r1_4sigma = linesplit.at(2);
874 r1_4sigma.remove(QChar(','));
875 }
876 return r1_4sigma;
877 }
878
xl_final_R1all(QString line)879 QString XLOutputParser::xl_final_R1all(QString line) {
880 // R1 = 0.0766 for 10786 unique reflections after merging for Fourier
881 QString r1all = "";
882 QStringList linesplit;
883 if (line.contains("R1") && line.contains("merging for Fourier") && line.contains("for")) {
884 linesplit = line.split(" ", skipEmptyParts);
885 r1all = linesplit.at(2);
886 r1all.remove(QChar(','));
887 }
888 return r1all;
889 }
890
891
xl_final_wR2(QString line)892 QString XLOutputParser::xl_final_wR2(QString line) {
893 QString finalwr2;
894 QStringList linesplit;
895 if (line.contains("wR2") && line.contains("for all data")) {
896 linesplit = line.split(" ", skipEmptyParts);
897 finalwr2 = linesplit.at(2);
898 finalwr2.remove(QChar(','));
899 }
900 return finalwr2;
901 }
902
xl_peak(QString line)903 QStringList XLOutputParser::xl_peak(QString line) {
904 //! Returns a list of the highest peak and the position
905 // Highest peak 8.15 at 0.3160 0.7496 0.4960 [ 1.30 A from F12 ]
906 QStringList values;
907 QString peak = "";
908 QString coord = "";
909 QString dist = "";
910 QString from = "";
911 QStringList linesplit;
912 if (line.contains("Highest peak") && line.contains("from")
913 && (line.split(" ", skipEmptyParts).size() >= 6) ) {
914 linesplit = line.split(" ", skipEmptyParts);
915 peak = linesplit.at(2);
916 coord = linesplit.at(4)+" "+linesplit.at(5)+" "+linesplit.at(6);
917 dist = line.split("[").at(1).split("]").at(0).trimmed().split(" ").at(0);
918 from = line.split("[").at(1).split("]").at(0).trimmed().split(" ").at(3);
919 }
920 values.append(peak);
921 values.append(coord);
922 values.append(dist);
923 values.append(from);
924 return values;
925 }
926
xl_hole(QString line)927 QStringList XLOutputParser::xl_hole(QString line) {
928 //! Returns a list of the deepest hole and the position
929 // Deepest hole -0.74 at 0.4337 0.4402 0.7821 [ 0.84 A from GA1 ]
930 QStringList values;
931 QString hole = "";
932 QString coord = "";
933 QString dist = "";
934 QString from = "";
935 QStringList linesplit;
936 if (line.contains("Deepest hole") && line.contains("from")
937 && (line.split(" ", skipEmptyParts).size() >= 12) ) {
938 linesplit = line.split(" ", skipEmptyParts);
939 hole = linesplit.at(2);
940 coord = linesplit.at(4)+" "+linesplit.at(5)+" "+linesplit.at(6);
941 dist = line.split("[").at(1).split("]").at(0).trimmed().split(" ").at(0);
942 from = line.split("[").at(1).split("]").at(0).trimmed().split(" ").at(3);
943 }
944 values.append(hole);
945 values.append(coord);
946 values.append(dist);
947 values.append(from);
948 return values;
949 }
950
xl_flacksvals(QString line)951 QStringList XLOutputParser::xl_flacksvals(QString line) {
952 //! Flack x = -0.449(792) by classical fit to all intensities
953 //! Flack x = -0.315(296) from 3107 selected quotients (Parsons' method)
954 QStringList values;
955 QString flack = "";
956 QString parson = "";
957 QStringList linesplit;
958 if (line.contains("Flack x") && line.contains("classical fit")
959 && (!line.contains("No quotients"))
960 && (line.split(" ", skipEmptyParts).size() >= 3) ) {
961 linesplit = line.split(" ", skipEmptyParts);
962 flack = linesplit.at(3);
963 }
964 if (line.contains("Flack x") && line.contains("Parsons' method")
965 && (line.split(" ", skipEmptyParts).size() >= 3) ) {
966 linesplit = line.split(" ", skipEmptyParts);
967 parson = linesplit.at(3);
968
969 }
970 values.append(flack);
971 values.append(parson);
972 return values;
973 }
974
xl_timeval(QString line)975 QString XLOutputParser::xl_timeval(QString line) {
976 //! + pn_a finished at 12:33:29 Total elapsed time: 0.00 secs +
977 //! returns the elapsed time of a SHELXL run
978 QStringList linesplit;
979 QString time = "";
980 if (line.contains("finished") && line.contains("time")) {
981 linesplit = line.split(" ", skipEmptyParts);
982 time = linesplit.at(linesplit.indexOf("time:")+1);
983 }
984 return time;
985 }
986