View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2024.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.realspace.parsers;
39  
40  import static java.lang.String.format;
41  
42  import ffx.crystal.Crystal;
43  import ffx.crystal.SpaceGroupInfo;
44  import ffx.realspace.RealSpaceRefinementData;
45  import java.io.DataInputStream;
46  import java.io.FileInputStream;
47  import java.nio.ByteBuffer;
48  import java.nio.ByteOrder;
49  import java.util.logging.Level;
50  import java.util.logging.Logger;
51  import org.apache.commons.configuration2.CompositeConfiguration;
52  
53  /**
54   * CCP4MapFilter class.
55   *
56   * @author Timothy D. Fenn
57   * @see <a href="http://www.ccp4.ac.uk/html/maplib.html" target="_blank">CCP4 map format</a>
58   * @see <a href="http://www.ccp4.ac.uk/dist/html/library.html" target="_blank">CCP4 library
59   *     documentation</a>
60   * @since 1.0
61   */
62  public class CCP4MapFilter implements RealSpaceFileFilter {
63  
64    private static final Logger logger = Logger.getLogger(CCP4MapFilter.class.getName());
65  
66    /** {@inheritDoc} */
67    @Override
68    public Crystal getCrystal(String fileName, CompositeConfiguration properties) {
69      int imapData;
70      int spaceGroup = -1;
71      double cellA = -1.0;
72      double cellB = -1.0;
73      double cellC = -1.0;
74      double cellAlpha = -1.0;
75      double cellBeta = -1.0;
76      double cellGamma = -1.0;
77  
78      ByteOrder byteOrder = ByteOrder.nativeOrder();
79      FileInputStream fileInputStream;
80      DataInputStream dataInputStream;
81  
82      // First determine byte order of file versus system.
83      try {
84        fileInputStream = new FileInputStream(fileName);
85        dataInputStream = new DataInputStream(fileInputStream);
86  
87        dataInputStream.skipBytes(212);
88        byte[] bytes = new byte[4];
89        dataInputStream.read(bytes, 0, 4);
90        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
91  
92        imapData = byteBuffer.order(ByteOrder.BIG_ENDIAN).getInt();
93        String stampString = Integer.toHexString(imapData);
94  
95        switch (stampString.charAt(0)) {
96          case '1':
97          case '3':
98            if (byteOrder.equals(ByteOrder.LITTLE_ENDIAN)) {
99              byteOrder = ByteOrder.BIG_ENDIAN;
100           }
101           break;
102         case '4':
103           if (byteOrder.equals(ByteOrder.BIG_ENDIAN)) {
104             byteOrder = ByteOrder.LITTLE_ENDIAN;
105           }
106           break;
107       }
108       fileInputStream.close();
109     } catch (Exception e) {
110       String message = " Fatal exception reading CCP4 map.\n";
111       logger.log(Level.SEVERE, message, e);
112     }
113 
114     try {
115       fileInputStream = new FileInputStream(fileName);
116       dataInputStream = new DataInputStream(fileInputStream);
117 
118       dataInputStream.skipBytes(40);
119       byte[] bytes = new byte[80];
120       dataInputStream.read(bytes, 0, 80);
121       ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
122 
123       cellA = byteBuffer.order(byteOrder).getFloat();
124       cellB = byteBuffer.order(byteOrder).getFloat();
125       cellC = byteBuffer.order(byteOrder).getFloat();
126       cellAlpha = byteBuffer.order(byteOrder).getFloat();
127       cellBeta = byteBuffer.order(byteOrder).getFloat();
128       cellGamma = byteBuffer.order(byteOrder).getFloat();
129 
130       for (int i = 0; i < 3; i++) {
131         byteBuffer.order(byteOrder).getInt();
132       }
133       for (int i = 0; i < 3; i++) {
134         byteBuffer.order(byteOrder).getFloat();
135       }
136 
137       spaceGroup = byteBuffer.order(byteOrder).getInt();
138       fileInputStream.close();
139     } catch (Exception e) {
140       String message = " Fatal exception reading CCP4 map.\n";
141       logger.log(Level.SEVERE, message, e);
142     }
143 
144     return new Crystal(
145         cellA,
146         cellB,
147         cellC,
148         cellAlpha,
149         cellBeta,
150         cellGamma,
151         SpaceGroupInfo.spaceGroupNames[spaceGroup - 1]);
152   }
153 
154   /** {@inheritDoc} */
155   @Override
156   public boolean readFile(
157       String filename, RealSpaceRefinementData refinementdata, CompositeConfiguration properties) {
158 
159     int imapData;
160     double cellA, cellB, cellC, cellAlpha, cellBeta, cellGamma;
161     String stampString;
162 
163     ByteOrder byteOrder = ByteOrder.nativeOrder();
164     FileInputStream fileInputStream;
165     DataInputStream dataInputStream;
166 
167     double min = Double.POSITIVE_INFINITY;
168     double max = Double.NEGATIVE_INFINITY;
169     double mean = 0.0;
170     double sd = 0.0;
171     double rmsd = 0.0;
172 
173     // First determine byte order of file versus system
174     try {
175       fileInputStream = new FileInputStream(filename);
176       dataInputStream = new DataInputStream(fileInputStream);
177 
178       dataInputStream.skipBytes(212);
179       byte[] bytes = new byte[4];
180       dataInputStream.read(bytes, 0, 4);
181       ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
182 
183       imapData = byteBuffer.order(ByteOrder.BIG_ENDIAN).getInt();
184       stampString = Integer.toHexString(imapData);
185       switch (stampString.charAt(0)) {
186         case '1':
187         case '3':
188           if (byteOrder.equals(ByteOrder.LITTLE_ENDIAN)) {
189             byteOrder = ByteOrder.BIG_ENDIAN;
190           }
191           break;
192         case '4':
193           if (byteOrder.equals(ByteOrder.BIG_ENDIAN)) {
194             byteOrder = ByteOrder.LITTLE_ENDIAN;
195           }
196           break;
197       }
198       if (logger.isLoggable(Level.INFO)) {
199         StringBuilder sb = new StringBuilder();
200         sb.append(format(" Opening CCP4 map: %s\n", filename));
201         logger.info(sb.toString());
202       }
203 
204       fileInputStream.close();
205     } catch (Exception e) {
206       String message = " Fatal exception reading CCP4 map.\n";
207       logger.log(Level.SEVERE, message, e);
208     }
209 
210     try {
211       fileInputStream = new FileInputStream(filename);
212       dataInputStream = new DataInputStream(fileInputStream);
213 
214       byte[] bytes = new byte[2048];
215 
216       dataInputStream.read(bytes, 0, 1024);
217       ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
218 
219       int[] ext = new int[3];
220       ext[0] = byteBuffer.order(byteOrder).getInt();
221       ext[1] = byteBuffer.order(byteOrder).getInt();
222       ext[2] = byteBuffer.order(byteOrder).getInt();
223 
224       // mode (2 = reals, only one we accept)
225       int mode = byteBuffer.order(byteOrder).getInt();
226 
227       int[] ori = new int[3];
228       ori[0] = byteBuffer.order(byteOrder).getInt();
229       ori[1] = byteBuffer.order(byteOrder).getInt();
230       ori[2] = byteBuffer.order(byteOrder).getInt();
231 
232       int[] ni = new int[3];
233       ni[0] = byteBuffer.order(byteOrder).getInt();
234       ni[1] = byteBuffer.order(byteOrder).getInt();
235       ni[2] = byteBuffer.order(byteOrder).getInt();
236 
237       cellA = byteBuffer.order(byteOrder).getFloat();
238       cellB = byteBuffer.order(byteOrder).getFloat();
239       cellC = byteBuffer.order(byteOrder).getFloat();
240       cellAlpha = byteBuffer.order(byteOrder).getFloat();
241       cellBeta = byteBuffer.order(byteOrder).getFloat();
242       cellGamma = byteBuffer.order(byteOrder).getFloat();
243 
244       int[] axisi = new int[3];
245       for (int i = 0; i < 3; i++) {
246         int axis = byteBuffer.order(byteOrder).getInt();
247         switch (axis) {
248           case 1:
249             axisi[0] = i;
250             break;
251           case 2:
252             axisi[1] = i;
253             break;
254           case 3:
255             axisi[2] = i;
256             break;
257         }
258       }
259 
260       min = byteBuffer.order(byteOrder).getFloat();
261       max = byteBuffer.order(byteOrder).getFloat();
262       mean = byteBuffer.order(byteOrder).getFloat();
263       int sg = byteBuffer.order(byteOrder).getInt();
264       int nsymb = byteBuffer.order(byteOrder).getInt();
265       int skew = byteBuffer.order(byteOrder).getInt();
266 
267       for (int i = 0; i < 12; i++) {
268         byteBuffer.order(byteOrder).getFloat();
269       }
270 
271       for (int i = 0; i < 15; i++) {
272         byteBuffer.order(byteOrder).getInt();
273       }
274 
275       byte[] word = new byte[2048];
276       byteBuffer.order(byteOrder).get(word, 0, 4);
277       String mapString = new String(word);
278       sd = byteBuffer.order(byteOrder).getFloat();
279       rmsd = byteBuffer.order(byteOrder).getFloat();
280 
281       if (logger.isLoggable(Level.INFO)) {
282         StringBuilder sb = new StringBuilder();
283         sb.append(format("  Column origin:  %d\t Extent: %d\n", ori[0], ext[0]));
284         sb.append(format("  Row origin:     %d\t Extent: %d\n", ori[1], ext[1]));
285         sb.append(format("  Section origin: %d\t Extent: %d\n", ori[2], ext[2]));
286         sb.append(format("  Axis order:     %d %d %d\n", axisi[0], axisi[1], axisi[2]));
287         sb.append(format("  Number of X, Y, Z columns: %d %d %d\n", ni[0], ni[1], ni[2]));
288         sb.append(format("  Spacegroup:     %d (%s)\n", sg, SpaceGroupInfo.spaceGroupNames[sg - 1]));
289         sb.append(
290             format(
291                 "  Cell: %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
292                 cellA, cellB, cellC, cellAlpha, cellBeta, cellGamma));
293         logger.info(sb.toString());
294       }
295 
296       int nlabel = byteBuffer.order(byteOrder).getInt();
297       for (int i = 0; i < 10; i++) {
298         byteBuffer.order(byteOrder).get(word, 0, 80);
299         mapString = new String(word);
300       }
301 
302       if (nsymb > 0) {
303         byteBuffer.rewind();
304         dataInputStream.read(bytes, 0, nsymb);
305         for (int i = 0; i < nsymb / 80; i += 80) {
306           byteBuffer.order(byteOrder).get(word, 0, 80);
307           mapString = new String(word);
308         }
309       }
310 
311       byteBuffer.rewind();
312       dataInputStream.read(bytes, 0, 2048);
313       refinementdata.setData(new double[ext[0] * ext[1] * ext[2]]);
314       int[] ijk = new int[3];
315       int index, x, y, z;
316       refinementdata.setOrigin(ori[axisi[0]], ori[axisi[1]], ori[axisi[2]]);
317       int nx = ext[axisi[0]];
318       int ny = ext[axisi[1]];
319       int nz = ext[axisi[2]];
320       refinementdata.setExtent(nx, ny, nz);
321       refinementdata.setNI(ni[0], ni[1], ni[2]);
322       for (ijk[2] = 0; ijk[2] < ext[2]; ijk[2]++) {
323         for (ijk[1] = 0; ijk[1] < ext[1]; ijk[1]++) {
324           for (ijk[0] = 0; ijk[0] < ext[0]; ijk[0]++) {
325             x = ijk[axisi[0]];
326             y = ijk[axisi[1]];
327             z = ijk[axisi[2]];
328             index = x + nx * (y + ny * z);
329             refinementdata.getData()[index] = byteBuffer.order(byteOrder).getFloat();
330             if (!byteBuffer.hasRemaining()) {
331               byteBuffer.rewind();
332               dataInputStream.read(bytes, 0, 2048);
333             }
334           }
335         }
336       }
337       fileInputStream.close();
338     } catch (Exception e) {
339       String message = " Fatal exception reading CCP4 map.\n";
340       logger.log(Level.SEVERE, message, e);
341     }
342 
343     return true;
344   }
345 }