1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.potential.parsers;
39
40 import static ffx.potential.bonded.Bond.logNoBondType;
41 import static java.lang.Double.parseDouble;
42 import static java.lang.Integer.parseInt;
43 import static java.lang.String.format;
44
45 import ffx.crystal.Crystal;
46 import ffx.crystal.SymOp;
47 import ffx.potential.MolecularAssembly;
48 import ffx.potential.Utilities.FileType;
49 import ffx.potential.bonded.Atom;
50 import ffx.potential.bonded.Bond;
51 import ffx.potential.parameters.AtomType;
52 import ffx.potential.parameters.BondType;
53 import ffx.potential.parameters.ForceField;
54 import java.io.BufferedReader;
55 import java.io.BufferedWriter;
56 import java.io.File;
57 import java.io.FileNotFoundException;
58 import java.io.FileReader;
59 import java.io.FileWriter;
60 import java.io.IOException;
61 import java.util.ArrayList;
62 import java.util.HashMap;
63 import java.util.List;
64 import java.util.OptionalDouble;
65 import java.util.logging.Level;
66 import java.util.logging.Logger;
67 import java.util.regex.Matcher;
68 import java.util.regex.Pattern;
69 import org.apache.commons.configuration2.CompositeConfiguration;
70 import org.jogamp.vecmath.Vector3d;
71
72
73
74
75
76
77
78 public class XYZFilter extends SystemFilter {
79
80 private static final Logger logger = Logger.getLogger(XYZFilter.class.getName());
81 private BufferedReader bufferedReader = null;
82 private int snapShot;
83 private String remarkLine;
84
85
86
87
88
89
90
91
92
93
94 public XYZFilter(
95 List<File> files,
96 MolecularAssembly system,
97 ForceField forceField,
98 CompositeConfiguration properties) {
99 super(files, system, forceField, properties);
100 this.fileType = FileType.XYZ;
101 }
102
103
104
105
106
107
108
109
110
111
112 public XYZFilter(
113 File file,
114 MolecularAssembly system,
115 ForceField forceField,
116 CompositeConfiguration properties) {
117 super(file, system, forceField, properties);
118 this.fileType = FileType.XYZ;
119 }
120
121
122
123
124
125
126
127
128 public static boolean readOnto(File newFile, MolecularAssembly oldSystem) {
129 if (newFile == null || !newFile.exists() || oldSystem == null) {
130 return false;
131 }
132 try (BufferedReader br = new BufferedReader(new FileReader(newFile))) {
133 String data = br.readLine();
134 if (data == null) {
135 return false;
136 }
137 String[] tokens = data.trim().split(" +");
138 int num_atoms = parseInt(tokens[0]);
139 if (num_atoms != oldSystem.getAtomList().size()) {
140 return false;
141 }
142
143 br.mark(10000);
144 data = br.readLine();
145 if (!readPBC(data, oldSystem)) {
146 br.reset();
147 }
148
149 double[][] d = new double[num_atoms][3];
150 for (int i = 0; i < num_atoms; i++) {
151 if (!br.ready()) {
152 return false;
153 }
154 data = br.readLine();
155 if (data == null) {
156 logger.warning(format(" Check atom %d.", (i + 1)));
157 return false;
158 }
159 tokens = data.trim().split(" +");
160 if (tokens.length < 6) {
161 logger.warning(format(" Check atom %d.", (i + 1)));
162 return false;
163 }
164 d[i][0] = parseDouble(tokens[2]);
165 d[i][1] = parseDouble(tokens[3]);
166 d[i][2] = parseDouble(tokens[4]);
167 }
168 List<Atom> atoms = oldSystem.getAtomList();
169 for (Atom a : atoms) {
170 int index = a.getIndex() - 1;
171 a.setXYZ(d[index]);
172 }
173 oldSystem.center();
174 oldSystem.setFile(newFile);
175 return true;
176 } catch (Exception e) {
177 return false;
178 }
179 }
180
181 private static boolean firstTokenIsInteger(String data) {
182 if (data == null) {
183 return false;
184 }
185
186
187 data = data.trim();
188 if (data.equals("")) {
189 return false;
190 }
191
192
193 try {
194 String[] tokens = data.split(" +");
195 parseInt(tokens[0]);
196 return true;
197 } catch (NumberFormatException e) {
198 return false;
199 }
200 }
201
202
203
204
205
206
207
208 private static boolean readPBC(String data, MolecularAssembly activeMolecularAssembly) {
209 if (firstTokenIsInteger(data)) {
210 return false;
211 }
212
213 String[] tokens = data.trim().split(" +");
214 if (tokens.length == 6) {
215 CompositeConfiguration config = activeMolecularAssembly.getProperties();
216 double a = parseDouble(tokens[0]);
217 double b = parseDouble(tokens[1]);
218 double c = parseDouble(tokens[2]);
219 double alpha = parseDouble(tokens[3]);
220 double beta = parseDouble(tokens[4]);
221 double gamma = parseDouble(tokens[5]);
222 config.setProperty("a-axis", a);
223 config.setProperty("b-axis", b);
224 config.setProperty("c-axis", c);
225 config.setProperty("alpha", alpha);
226 config.setProperty("beta", beta);
227 config.setProperty("gamma", gamma);
228
229 Crystal crystal = activeMolecularAssembly.getCrystal();
230 if (crystal != null) {
231 crystal.changeUnitCellParameters(a, b, c, alpha, beta, gamma);
232 }
233 }
234 return true;
235 }
236
237
238 @Override
239 public void closeReader() {
240 if (bufferedReader != null) {
241 try {
242 bufferedReader.close();
243 } catch (IOException ex) {
244 logger.warning(format(" Exception in closing XYZ filter: %s", ex));
245 }
246 }
247 }
248
249 @Override
250 public int countNumModels() {
251 File xyzFile = activeMolecularAssembly.getFile();
252 int nAtoms = activeMolecularAssembly.getAtomArray().length;
253 Pattern crystInfoPattern =
254 Pattern.compile(
255 "^ *(?:[0-9]+\\.[0-9]+ +){3}(?:-?[0-9]+\\.[0-9]+ +){2}(?:-?[0-9]+\\.[0-9]+) *$");
256
257 try (BufferedReader br = new BufferedReader(new FileReader(xyzFile))) {
258 String line = br.readLine();
259 int nSnaps = 0;
260
261 while (line != null) {
262 assert parseInt(line.trim().split("\\s+")[0]) == nAtoms;
263
264 line = br.readLine();
265 Matcher m = crystInfoPattern.matcher(line);
266 if (m.matches()) {
267
268 br.readLine();
269 }
270
271 for (int i = 1; i < nAtoms; i++) {
272 br.readLine();
273 }
274
275 ++nSnaps;
276 line = br.readLine();
277 }
278 return nSnaps;
279 } catch (Exception ex) {
280 logger.log(
281 Level.WARNING, String.format(" Exception reading trajectory file %s: %s", xyzFile, ex));
282 return 1;
283 }
284 }
285
286
287 @Override
288 public OptionalDouble getLastReadLambda() {
289 String[] toks = remarkLine.split("\\s+");
290 int nToks = toks.length;
291 for (int i = 0; i < (nToks - 1); i++) {
292 if (toks[i].equals("Lambda:")) {
293 return OptionalDouble.of(Double.parseDouble(toks[i + 1]));
294 }
295 }
296 return OptionalDouble.empty();
297 }
298
299 @Override
300 public String[] getRemarkLines() {
301 return new String[] {remarkLine};
302 }
303
304 @Override
305 public int getSnapshot() {
306 return snapShot;
307 }
308
309
310
311
312
313
314 @Override
315 public boolean readFile() {
316 File xyzFile = activeMolecularAssembly.getFile();
317
318 if (forceField == null) {
319 logger.warning(format(" No force field is associated with %s.", xyzFile.toString()));
320 return false;
321 }
322 try (BufferedReader br = new BufferedReader(new FileReader(xyzFile))) {
323 String data = br.readLine();
324
325 while (data != null && data.trim().equals("")) {
326 data = br.readLine();
327 }
328 if (data == null) {
329 return false;
330 }
331 String[] tokens = data.trim().split(" +", 2);
332 int numberOfAtoms = parseInt(tokens[0]);
333 if (numberOfAtoms < 1) {
334 return false;
335 }
336 if (tokens.length == 2) {
337 getActiveMolecularSystem().setName(tokens[1]);
338 }
339 logger.info(format(" Opening %s with %d atoms\n", xyzFile.getName(), numberOfAtoms));
340 remarkLine = data.trim();
341
342
343 br.mark(10000);
344 data = br.readLine();
345 if (!readPBC(data, activeMolecularAssembly)) {
346 br.reset();
347 }
348
349
350 HashMap<Integer, Integer> labelHash = new HashMap<>();
351 int[] label = new int[numberOfAtoms];
352 int[][] bonds = new int[numberOfAtoms][8];
353 double[][] d = new double[numberOfAtoms][3];
354 boolean renumber = false;
355 atomList = new ArrayList<>();
356
357 for (int i = 0; i < numberOfAtoms; i++) {
358 if (!br.ready()) {
359 return false;
360 }
361 data = br.readLine();
362 if (data == null) {
363 logger.warning(
364 format(
365 " Check atom %d in %s.", (i + 1), activeMolecularAssembly.getFile().getName()));
366 return false;
367 }
368 tokens = data.trim().split(" +");
369 if (tokens.length < 6) {
370 logger.warning(
371 format(
372 " Check atom %d in %s.", (i + 1), activeMolecularAssembly.getFile().getName()));
373 return false;
374 }
375
376 label[i] = parseInt(tokens[0]);
377
378 if (label[i] != i + 1) {
379 renumber = true;
380 }
381 String atomName = tokens[1];
382 d[i][0] = parseDouble(tokens[2]);
383 d[i][1] = parseDouble(tokens[3]);
384 d[i][2] = parseDouble(tokens[4]);
385 int type = parseInt(tokens[5]);
386 AtomType atomType = forceField.getAtomType(Integer.toString(type));
387 if (atomType == null) {
388 StringBuilder message = new StringBuilder("Check atom type ");
389 message.append(type).append(" for Atom ").append(i + 1);
390 message.append(" in ").append(activeMolecularAssembly.getFile().getName());
391 logger.warning(message.toString());
392 return false;
393 }
394 Atom a = new Atom(i + 1, atomName, atomType, d[i]);
395 atomList.add(a);
396
397 int numberOfBonds = tokens.length - 6;
398 for (int b = 0; b < 8; b++) {
399 if (b < numberOfBonds) {
400 int bond = parseInt(tokens[6 + b]);
401 bonds[i][b] = bond;
402 } else {
403 bonds[i][b] = 0;
404 }
405 }
406 }
407
408 if (br.ready()) {
409
410 data = br.readLine().trim();
411 while (data.equals("") && br.ready()) {
412 data = br.readLine().trim();
413 }
414 tokens = data.split(" +", 2);
415 if (tokens.length > 0) {
416 try {
417 int archiveNumberOfAtoms = parseInt(tokens[0]);
418 if (archiveNumberOfAtoms == numberOfAtoms) {
419 setType(FileType.ARC);
420 }
421 } catch (NumberFormatException e) {
422
423 }
424 }
425 }
426
427 if (renumber) {
428 for (int i = 0; i < numberOfAtoms; i++) {
429 if (labelHash.containsKey(label[i])) {
430 logger.warning(format(" Two atoms have the same index: %d.", label[i]));
431 return false;
432 }
433 labelHash.put(label[i], i + 1);
434 }
435 for (int i = 0; i < numberOfAtoms; i++) {
436 int j = -1;
437 while (j < 3 && bonds[i][++j] > 0) {
438 bonds[i][j] = labelHash.get(bonds[i][j]);
439 }
440 }
441 }
442 bondList = new ArrayList<>();
443 int[] c = new int[2];
444 for (int a1 = 1; a1 <= numberOfAtoms; a1++) {
445 int j = -1;
446 while (j < 7 && bonds[a1 - 1][++j] > 0) {
447 int a2 = bonds[a1 - 1][j];
448 if (a1 < a2) {
449 if (a2 > numberOfAtoms) {
450 logger.warning(
451 format(
452 " Check the bond between %d and %d in %s.",
453 a1, a2, activeMolecularAssembly.getFile().getName()));
454 return false;
455 }
456
457 boolean bidirectional = false;
458 int k = -1;
459 while (k < 7 && bonds[a2 - 1][++k] > 0) {
460 int a3 = bonds[a2 - 1][k];
461 if (a3 == a1) {
462 bidirectional = true;
463 break;
464 }
465 }
466 if (!bidirectional) {
467 logger.warning(
468 format(
469 " Check the bond between %d and %d in %s.",
470 a1, a2, activeMolecularAssembly.getFile().getName()));
471 return false;
472 }
473 Atom atom1 = atomList.get(a1 - 1);
474 Atom atom2 = atomList.get(a2 - 1);
475 if (atom1 == null || atom2 == null) {
476 logger.warning(
477 format(
478 " Check the bond between %d and %d in %s.",
479 a1, a2, activeMolecularAssembly.getFile().getName()));
480 return false;
481 }
482 Bond bond = new Bond(atom1, atom2);
483 BondType bondType = forceField.getBondType(atom1.getAtomType(), atom2.getAtomType());
484 if (bondType == null) {
485 logNoBondType(atom1, atom2, forceField);
486 } else {
487 bond.setBondType(bondType);
488 }
489 bondList.add(bond);
490 }
491 }
492 }
493 return true;
494 } catch (IOException e) {
495 logger.severe(e.toString());
496 }
497 return false;
498 }
499
500
501 @Override
502 public boolean readNext() {
503 return readNext(false);
504 }
505
506
507
508
509
510
511
512 @Override
513 public boolean readNext(boolean resetPosition) {
514 return readNext(resetPosition, true);
515 }
516
517
518
519
520
521
522
523 @Override
524 public boolean readNext(boolean resetPosition, boolean print) {
525 return readNext(resetPosition, print, true);
526 }
527
528
529
530
531
532 public boolean readNext(boolean resetPosition, boolean print, boolean parse) {
533 try {
534 String data;
535 Atom[] atoms = activeMolecularAssembly.getAtomArray();
536 int nSystem = atoms.length;
537
538 if (bufferedReader == null && !resetPosition) {
539 bufferedReader = new BufferedReader(new FileReader(currentFile));
540
541 for (int i = 0; i < nSystem + 1; i++) {
542 data = bufferedReader.readLine();
543 while (!firstTokenIsInteger(data)) {
544 data = bufferedReader.readLine();
545 }
546 }
547 snapShot = 1;
548 } else if (resetPosition) {
549
550 bufferedReader = new BufferedReader(new FileReader(currentFile));
551 snapShot = 0;
552 }
553
554 snapShot++;
555
556 data = bufferedReader.readLine();
557
558 while (data != null && data.trim().equals("")) {
559 data = bufferedReader.readLine();
560 }
561 if (data == null) {
562 return false;
563 }
564
565 if (print) {
566 if (parse) {
567 logger.info(format("\n Attempting to read snapshot %d.", snapShot));
568 } else {
569 logger.info(format("\n Skipping snapshot %d.", snapShot));
570 }
571 }
572 if (parse) {
573 try {
574 String[] tokens = data.trim().split(" +");
575 int nArchive = parseInt(tokens[0]);
576 if (nArchive != nSystem) {
577 String message =
578 format("Number of atoms mismatch (Archive: %d, System: %d).", nArchive, nSystem);
579 if (dieOnMissingAtom) {
580 logger.severe(message);
581 }
582 logger.warning(message);
583 return false;
584 }
585 if(tokens.length > 1) {
586 activeMolecularAssembly.setName(tokens[1]);
587 }
588 } catch (NumberFormatException e) {
589 logger.warning(e.toString());
590 return false;
591 }
592
593 remarkLine = data;
594
595
596 bufferedReader.mark(10000);
597 data = bufferedReader.readLine();
598 if (!readPBC(data, activeMolecularAssembly)) {
599 bufferedReader.reset();
600 }
601
602 for (int i = 0; i < nSystem; i++) {
603 data = bufferedReader.readLine();
604
605 while (data != null && data.trim().equals("")) {
606 data = bufferedReader.readLine();
607 }
608 String[] tokens = data.trim().split(" +");
609 if (tokens.length < 6) {
610 String message = format("Check atom %d in %s.", (i + 1), currentFile.getName());
611 logger.warning(message);
612 return false;
613 }
614 double x = parseDouble(tokens[2]);
615 double y = parseDouble(tokens[3]);
616 double z = parseDouble(tokens[4]);
617 int xyzIndex = atoms[i].getIndex();
618 if (xyzIndex != i + 1) {
619 String message =
620 format(
621 "Archive atom index %d being read onto system atom index %d.", i + 1, xyzIndex);
622 logger.warning(message);
623 }
624 atoms[i].moveTo(x, y, z);
625 }
626 }else{
627
628 bufferedReader.mark(10000);
629 data = bufferedReader.readLine();
630 if (!readPBC(data, activeMolecularAssembly)) {
631 bufferedReader.reset();
632 }
633
634 for (int i = 0; i < nSystem; i++) {
635 data = bufferedReader.readLine();
636
637 while (data != null && data.trim().equals("")) {
638 data = bufferedReader.readLine();
639 }
640 }
641 }
642 return true;
643 } catch (FileNotFoundException e) {
644 String message = format("Exception opening file %s.", currentFile);
645 logger.log(Level.WARNING, message, e);
646 } catch (IOException e) {
647 String message = format("Exception reading from file %s.", currentFile);
648 logger.log(Level.WARNING, message, e);
649 }
650 return false;
651 }
652
653
654 @Override
655 public boolean writeFile(File saveFile, boolean append, String[] extraLines) {
656 if (saveFile == null) {
657 return false;
658 }
659
660 File newFile = saveFile;
661 if (!append) {
662 newFile = version(saveFile);
663 }
664 activeMolecularAssembly.setFile(newFile);
665 if (activeMolecularAssembly.getName() == null) {
666 activeMolecularAssembly.setName(newFile.getName());
667 }
668
669 try (FileWriter fw = new FileWriter(newFile, append && newFile.exists());
670 BufferedWriter bw = new BufferedWriter(fw)) {
671
672 int numberOfAtoms = activeMolecularAssembly.getAtomList().size();
673 StringBuilder sb =
674 new StringBuilder(format("%7d %s", numberOfAtoms, activeMolecularAssembly.getName()));
675 if (extraLines != null) {
676 for (String line : extraLines) {
677 line = line.replaceAll("\n", " ");
678 sb.append(" ").append(line);
679 }
680 }
681 String output = sb.append("\n").toString();
682 bw.write(output);
683
684 Crystal crystal = activeMolecularAssembly.getCrystal();
685 if (crystal!=null && !crystal.aperiodic()) {
686 Crystal uc = crystal.getUnitCell();
687 String params =
688 format("%14.8f%14.8f%14.8f%14.8f%14.8f%14.8f\n",
689 uc.a, uc.b, uc.c, uc.alpha, uc.beta, uc.gamma);
690 bw.write(params);
691 }
692
693 Atom a2;
694 StringBuilder line;
695 StringBuilder[] lines = new StringBuilder[numberOfAtoms];
696
697 List<Atom> atoms = activeMolecularAssembly.getAtomList();
698 Vector3d offset = activeMolecularAssembly.getOffset();
699 for (Atom a : atoms) {
700 if (vdwH) {
701 line =
702 new StringBuilder(
703 format(
704 "%7d %3s%14.8f%14.8f%14.8f%6d",
705 a.getIndex(),
706 a.getAtomType().name,
707 a.getRedX() - offset.x,
708 a.getRedY() - offset.y,
709 a.getRedZ() - offset.z,
710 a.getType()));
711 } else {
712 line =
713 new StringBuilder(
714 format(
715 "%7d %3s%14.8f%14.8f%14.8f%6d",
716 a.getIndex(),
717 a.getAtomType().name,
718 a.getX() - offset.x,
719 a.getY() - offset.y,
720 a.getZ() - offset.z,
721 a.getType()));
722 }
723 for (Bond b : a.getBonds()) {
724 a2 = b.get1_2(a);
725 line.append(format("%8d", a2.getIndex()));
726 }
727 lines[a.getIndex() - 1] = line.append("\n");
728 }
729 try {
730 for (int i = 0; i < numberOfAtoms; i++) {
731 bw.write(lines[i].toString());
732 }
733 } catch (IOException e) {
734 String message =
735 format(
736 " There was an unexpected error writing to %s.",
737 getActiveMolecularSystem().toString());
738 logger.log(Level.WARNING, message, e);
739 return false;
740 }
741 } catch (IOException e) {
742 String message =
743 format(
744 " There was an unexpected error writing to %s.",
745 getActiveMolecularSystem().toString());
746 logger.log(Level.WARNING, message, e);
747 return false;
748 }
749 return true;
750 }
751
752
753
754
755
756
757
758
759
760 public boolean writeFileAsP1(File saveFile, boolean append, Crystal crystal) {
761 return writeFileAsP1(saveFile, append, crystal, null);
762 }
763
764
765
766
767
768
769
770
771
772
773 public boolean writeFileAsP1(
774 File saveFile, boolean append, Crystal crystal, String[] extraLines) {
775 if (saveFile == null) {
776 return false;
777 }
778
779 File newFile = saveFile;
780 if (!append) {
781 newFile = version(saveFile);
782 }
783 activeMolecularAssembly.setFile(newFile);
784 activeMolecularAssembly.setName(newFile.getName());
785
786 try (FileWriter fw = new FileWriter(newFile, append && newFile.exists());
787 BufferedWriter bw = new BufferedWriter(fw)) {
788 int nSymm = crystal.spaceGroup.symOps.size();
789
790 int numberOfAtoms = activeMolecularAssembly.getAtomList().size() * nSymm;
791 StringBuilder sb =
792 new StringBuilder(format("%7d %s", numberOfAtoms, activeMolecularAssembly.toString()));
793 if (extraLines != null) {
794 for (String line : extraLines) {
795 line = line.replaceAll("\n", " ");
796 sb.append(" ").append(line);
797 }
798 }
799 String output = sb.append("\n").toString();
800 bw.write(output);
801
802 if (!crystal.aperiodic()) {
803 Crystal uc = crystal.getUnitCell();
804 String params = format("%14.8f%14.8f%14.8f%14.8f%14.8f%14.8f\n",
805 uc.a, uc.b, uc.c, uc.alpha, uc.beta, uc.gamma);
806 bw.write(params);
807 }
808
809 Atom a2;
810 StringBuilder line;
811 StringBuilder[] lines = new StringBuilder[numberOfAtoms];
812
813 Atom[] atoms = activeMolecularAssembly.getAtomArray();
814 double[] xyz = new double[3];
815 for (int iSym = 0; iSym < nSymm; iSym++) {
816 SymOp symOp = crystal.spaceGroup.getSymOp(iSym);
817 int indexOffset = iSym * atoms.length;
818 for (Atom a : atoms) {
819 int index = a.getIndex() + indexOffset;
820 String id = a.getAtomType().name;
821 if (vdwH) {
822 a.getRedXYZ(xyz);
823 } else {
824 xyz[0] = a.getX();
825 xyz[1] = a.getY();
826 xyz[2] = a.getZ();
827 }
828 crystal.applySymOp(xyz, xyz, symOp);
829 int type = a.getType();
830 line =
831 new StringBuilder(
832 format("%7d %3s%14.8f%14.8f%14.8f%6d", index, id, xyz[0], xyz[1], xyz[2], type));
833 for (Bond b : a.getBonds()) {
834 a2 = b.get1_2(a);
835 line.append(format("%8d", a2.getIndex() + indexOffset));
836 }
837 lines[index - 1] = line.append("\n");
838 }
839 }
840 try {
841 for (int i = 0; i < numberOfAtoms; i++) {
842 bw.write(lines[i].toString());
843 }
844 } catch (IOException e) {
845 String message =
846 format(
847 " There was an unexpected error writing to %s.",
848 getActiveMolecularSystem().toString());
849 logger.log(Level.WARNING, message, e);
850 return false;
851 }
852 } catch (IOException e) {
853 String message =
854 format(
855 " There was an unexpected error writing to %s.",
856 getActiveMolecularSystem().toString());
857 logger.log(Level.WARNING, message, e);
858 return false;
859 }
860 return true;
861 }
862 }