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-2025.
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 ffx.crystal.Crystal;
41  import ffx.crystal.SpaceGroupInfo;
42  import ffx.realspace.RealSpaceRefinementData;
43  import org.apache.commons.configuration2.CompositeConfiguration;
44  
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  
52  import static java.lang.String.format;
53  
54  /**
55   * CCP4MapFilter class.
56   *
57   * @author Timothy D. Fenn
58   * @see <a href="http://www.ccp4.ac.uk/html/maplib.html" target="_blank">CCP4 map format</a>
59   * @see <a href="http://www.ccp4.ac.uk/dist/html/library.html" target="_blank">CCP4 library
60   *     documentation</a>
61   * @since 1.0
62   */
63  public class CCP4MapFilter implements RealSpaceFileFilter {
64  
65    private static final Logger logger = Logger.getLogger(CCP4MapFilter.class.getName());
66  
67    /** {@inheritDoc} */
68    @Override
69    public Crystal getCrystal(String fileName, CompositeConfiguration properties) {
70      int imapData;
71      int spaceGroup = -1;
72      double cellA = -1.0;
73      double cellB = -1.0;
74      double cellC = -1.0;
75      double cellAlpha = -1.0;
76      double cellBeta = -1.0;
77      double cellGamma = -1.0;
78  
79      ByteOrder byteOrder = ByteOrder.nativeOrder();
80      FileInputStream fileInputStream;
81      DataInputStream dataInputStream;
82  
83      // First determine byte order of file versus system.
84      try {
85        fileInputStream = new FileInputStream(fileName);
86        dataInputStream = new DataInputStream(fileInputStream);
87  
88        dataInputStream.skipBytes(212);
89        byte[] bytes = new byte[4];
90        dataInputStream.read(bytes, 0, 4);
91        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
92  
93        imapData = byteBuffer.order(ByteOrder.BIG_ENDIAN).getInt();
94        String stampString = Integer.toHexString(imapData);
95  
96        switch (stampString.charAt(0)) {
97          case '1':
98          case '3':
99            if (byteOrder.equals(ByteOrder.LITTLE_ENDIAN)) {
100             byteOrder = ByteOrder.BIG_ENDIAN;
101           }
102           break;
103         case '4':
104           if (byteOrder.equals(ByteOrder.BIG_ENDIAN)) {
105             byteOrder = ByteOrder.LITTLE_ENDIAN;
106           }
107           break;
108       }
109       fileInputStream.close();
110     } catch (Exception e) {
111       String message = " Fatal exception reading CCP4 map.\n";
112       logger.log(Level.SEVERE, message, e);
113     }
114 
115     try {
116       fileInputStream = new FileInputStream(fileName);
117       dataInputStream = new DataInputStream(fileInputStream);
118 
119       dataInputStream.skipBytes(40);
120       byte[] bytes = new byte[80];
121       dataInputStream.read(bytes, 0, 80);
122       ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
123 
124       cellA = byteBuffer.order(byteOrder).getFloat();
125       cellB = byteBuffer.order(byteOrder).getFloat();
126       cellC = byteBuffer.order(byteOrder).getFloat();
127       cellAlpha = byteBuffer.order(byteOrder).getFloat();
128       cellBeta = byteBuffer.order(byteOrder).getFloat();
129       cellGamma = byteBuffer.order(byteOrder).getFloat();
130 
131       for (int i = 0; i < 3; i++) {
132         byteBuffer.order(byteOrder).getInt();
133       }
134       for (int i = 0; i < 3; i++) {
135         byteBuffer.order(byteOrder).getFloat();
136       }
137 
138       spaceGroup = byteBuffer.order(byteOrder).getInt();
139       fileInputStream.close();
140     } catch (Exception e) {
141       String message = " Fatal exception reading CCP4 map.\n";
142       logger.log(Level.SEVERE, message, e);
143     }
144 
145     return new Crystal(
146         cellA,
147         cellB,
148         cellC,
149         cellAlpha,
150         cellBeta,
151         cellGamma,
152         SpaceGroupInfo.spaceGroupNames[spaceGroup - 1]);
153   }
154 
155   /** {@inheritDoc} */
156   @Override
157   public boolean readFile(
158       String filename, RealSpaceRefinementData refinementdata, CompositeConfiguration properties) {
159 
160     int imapData;
161     double cellA, cellB, cellC, cellAlpha, cellBeta, cellGamma;
162     String stampString;
163 
164     ByteOrder byteOrder = ByteOrder.nativeOrder();
165     FileInputStream fileInputStream;
166     DataInputStream dataInputStream;
167 
168     double min = Double.POSITIVE_INFINITY;
169     double max = Double.NEGATIVE_INFINITY;
170     double mean = 0.0;
171     double sd = 0.0;
172     double rmsd = 0.0;
173 
174     // First determine byte order of file versus system
175     try {
176       fileInputStream = new FileInputStream(filename);
177       dataInputStream = new DataInputStream(fileInputStream);
178 
179       dataInputStream.skipBytes(212);
180       byte[] bytes = new byte[4];
181       dataInputStream.read(bytes, 0, 4);
182       ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
183 
184       imapData = byteBuffer.order(ByteOrder.BIG_ENDIAN).getInt();
185       stampString = Integer.toHexString(imapData);
186       switch (stampString.charAt(0)) {
187         case '1':
188         case '3':
189           if (byteOrder.equals(ByteOrder.LITTLE_ENDIAN)) {
190             byteOrder = ByteOrder.BIG_ENDIAN;
191           }
192           break;
193         case '4':
194           if (byteOrder.equals(ByteOrder.BIG_ENDIAN)) {
195             byteOrder = ByteOrder.LITTLE_ENDIAN;
196           }
197           break;
198       }
199       if (logger.isLoggable(Level.INFO)) {
200         StringBuilder sb = new StringBuilder();
201         sb.append(format(" Opening CCP4 map: %s\n", filename));
202         logger.info(sb.toString());
203       }
204 
205       fileInputStream.close();
206     } catch (Exception e) {
207       String message = " Fatal exception reading CCP4 map.\n";
208       logger.log(Level.SEVERE, message, e);
209     }
210 
211     try {
212       fileInputStream = new FileInputStream(filename);
213       dataInputStream = new DataInputStream(fileInputStream);
214 
215       byte[] bytes = new byte[2048];
216 
217       dataInputStream.read(bytes, 0, 1024);
218       ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
219 
220       int[] ext = new int[3];
221       ext[0] = byteBuffer.order(byteOrder).getInt();
222       ext[1] = byteBuffer.order(byteOrder).getInt();
223       ext[2] = byteBuffer.order(byteOrder).getInt();
224 
225       // mode (2 = reals, only one we accept)
226       int mode = byteBuffer.order(byteOrder).getInt();
227 
228       int[] ori = new int[3];
229       ori[0] = byteBuffer.order(byteOrder).getInt();
230       ori[1] = byteBuffer.order(byteOrder).getInt();
231       ori[2] = byteBuffer.order(byteOrder).getInt();
232 
233       int[] ni = new int[3];
234       ni[0] = byteBuffer.order(byteOrder).getInt();
235       ni[1] = byteBuffer.order(byteOrder).getInt();
236       ni[2] = byteBuffer.order(byteOrder).getInt();
237 
238       cellA = byteBuffer.order(byteOrder).getFloat();
239       cellB = byteBuffer.order(byteOrder).getFloat();
240       cellC = byteBuffer.order(byteOrder).getFloat();
241       cellAlpha = byteBuffer.order(byteOrder).getFloat();
242       cellBeta = byteBuffer.order(byteOrder).getFloat();
243       cellGamma = byteBuffer.order(byteOrder).getFloat();
244 
245       int[] axisi = new int[3];
246       for (int i = 0; i < 3; i++) {
247         int axis = byteBuffer.order(byteOrder).getInt();
248         switch (axis) {
249           case 1:
250             axisi[0] = i;
251             break;
252           case 2:
253             axisi[1] = i;
254             break;
255           case 3:
256             axisi[2] = i;
257             break;
258         }
259       }
260 
261       min = byteBuffer.order(byteOrder).getFloat();
262       max = byteBuffer.order(byteOrder).getFloat();
263       mean = byteBuffer.order(byteOrder).getFloat();
264       int sg = byteBuffer.order(byteOrder).getInt();
265       int nsymb = byteBuffer.order(byteOrder).getInt();
266       int skew = byteBuffer.order(byteOrder).getInt();
267 
268       for (int i = 0; i < 12; i++) {
269         byteBuffer.order(byteOrder).getFloat();
270       }
271 
272       for (int i = 0; i < 15; i++) {
273         byteBuffer.order(byteOrder).getInt();
274       }
275 
276       byte[] word = new byte[2048];
277       byteBuffer.order(byteOrder).get(word, 0, 4);
278       String mapString = new String(word);
279       sd = byteBuffer.order(byteOrder).getFloat();
280       rmsd = byteBuffer.order(byteOrder).getFloat();
281 
282       if (logger.isLoggable(Level.INFO)) {
283         StringBuilder sb = new StringBuilder();
284         sb.append(format("  Column origin:  %d\t Extent: %d\n", ori[0], ext[0]));
285         sb.append(format("  Row origin:     %d\t Extent: %d\n", ori[1], ext[1]));
286         sb.append(format("  Section origin: %d\t Extent: %d\n", ori[2], ext[2]));
287         sb.append(format("  Axis order:     %d %d %d\n", axisi[0], axisi[1], axisi[2]));
288         sb.append(format("  Number of X, Y, Z columns: %d %d %d\n", ni[0], ni[1], ni[2]));
289         sb.append(format("  Spacegroup:     %d (%s)\n", sg, SpaceGroupInfo.spaceGroupNames[sg - 1]));
290         sb.append(
291             format(
292                 "  Cell: %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
293                 cellA, cellB, cellC, cellAlpha, cellBeta, cellGamma));
294         logger.info(sb.toString());
295       }
296 
297       int nlabel = byteBuffer.order(byteOrder).getInt();
298       for (int i = 0; i < 10; i++) {
299         byteBuffer.order(byteOrder).get(word, 0, 80);
300         mapString = new String(word);
301       }
302 
303       if (nsymb > 0) {
304         byteBuffer.rewind();
305         dataInputStream.read(bytes, 0, nsymb);
306         for (int i = 0; i < nsymb / 80; i += 80) {
307           byteBuffer.order(byteOrder).get(word, 0, 80);
308           mapString = new String(word);
309         }
310       }
311 
312       byteBuffer.rewind();
313       dataInputStream.read(bytes, 0, 2048);
314       refinementdata.setData(new double[ext[0] * ext[1] * ext[2]]);
315       int[] ijk = new int[3];
316       int index, x, y, z;
317       refinementdata.setOrigin(ori[axisi[0]], ori[axisi[1]], ori[axisi[2]]);
318       int nx = ext[axisi[0]];
319       int ny = ext[axisi[1]];
320       int nz = ext[axisi[2]];
321       refinementdata.setExtent(nx, ny, nz);
322       refinementdata.setNI(ni[0], ni[1], ni[2]);
323       for (ijk[2] = 0; ijk[2] < ext[2]; ijk[2]++) {
324         for (ijk[1] = 0; ijk[1] < ext[1]; ijk[1]++) {
325           for (ijk[0] = 0; ijk[0] < ext[0]; ijk[0]++) {
326             x = ijk[axisi[0]];
327             y = ijk[axisi[1]];
328             z = ijk[axisi[2]];
329             index = x + nx * (y + ny * z);
330             refinementdata.getData()[index] = byteBuffer.order(byteOrder).getFloat();
331             if (!byteBuffer.hasRemaining()) {
332               byteBuffer.rewind();
333               dataInputStream.read(bytes, 0, 2048);
334             }
335           }
336         }
337       }
338       fileInputStream.close();
339     } catch (Exception e) {
340       String message = " Fatal exception reading CCP4 map.\n";
341       logger.log(Level.SEVERE, message, e);
342     }
343 
344     return true;
345   }
346 }