1 /* phs_io.cpp: class file for reflection data  phs importer */
2 //C Copyright (C) 2000-2006 Kevin Cowtan and University of York
3 //L
4 //L  This library is free software and is distributed under the terms
5 //L  and conditions of version 2.1 of the GNU Lesser General Public
6 //L  Licence (LGPL) with the following additional clause:
7 //L
8 //L     `You may also combine or link a "work that uses the Library" to
9 //L     produce a work containing portions of the Library, and distribute
10 //L     that work under terms of your choice, provided that you give
11 //L     prominent notice with each copy of the work that the specified
12 //L     version of the Library is used in it, and that you include or
13 //L     provide public access to the complete corresponding
14 //L     machine-readable source code for the Library including whatever
15 //L     changes were used in the work. (i.e. If you make changes to the
16 //L     Library you must distribute those, but you do not need to
17 //L     distribute source or object code to those portions of the work
18 //L     not covered by this licence.)'
19 //L
20 //L  Note that this clause grants an additional right and does not impose
21 //L  any additional restriction, and so does not affect compatibility
22 //L  with the GNU General Public Licence (GPL). If you wish to negotiate
23 //L  other terms, please contact the maintainer.
24 //L
25 //L  You can redistribute it and/or modify the library under the terms of
26 //L  the GNU Lesser General Public License as published by the Free Software
27 //L  Foundation; either version 2.1 of the License, or (at your option) any
28 //L  later version.
29 //L
30 //L  This library is distributed in the hope that it will be useful, but
31 //L  WITHOUT ANY WARRANTY; without even the implied warranty of
32 //L  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
33 //L  Lesser General Public License for more details.
34 //L
35 //L  You should have received a copy of the CCP4 licence and/or GNU
36 //L  Lesser General Public License along with this library; if not, write
37 //L  to the CCP4 Secretary, Daresbury Laboratory, Warrington WA4 4AD, UK.
38 //L  The GNU Lesser General Public can also be obtained by writing to the
39 //L  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
40 //L  MA 02111-1307 USA
41 
42 #include "phs_io.h"
43 
44 extern "C" {
45 #include <stdio.h>
46 }
47 
48 
49 namespace clipper {
50 
51 
52 /*! Constructing an PHSfile does nothing except flag the object as not
53   attached to any file for either input or output */
PHSfile()54 PHSfile::PHSfile()
55 {
56   mode = NONE;
57 }
58 
59 
60 /*! Close any files which were left open. This is particularly
61   important since to access the PHS file efficiently, data reads and
62   writes are deferred until the file is closed. */
~PHSfile()63 PHSfile::~PHSfile()
64 {
65   switch ( mode ) {
66   case READ:
67     close_read(); break;
68   case WRITE:
69     close_write(); break;
70   case NONE:
71     break;
72   }
73 }
74 
75 
76 /*! The file is opened for reading. This PHSfile object will remain
77   attached to this file until it is closed. Until that occurs, no
78   other file may be opened with this object, however another PHSfile
79   object could be used to access another file.
80   \param filename_in The input filename or pathname. */
open_read(const String filename_in)81 void PHSfile::open_read( const String filename_in )
82 {
83   if ( mode != NONE )
84     Message::message( Message_fatal( "PHSfile: open_read - File already open" ) );
85 
86   // open the phs
87   f_sigf_i = NULL; phi_wt_i = NULL;
88   filename = filename_in;
89 
90   FILE* phs = fopen( filename.c_str(), "r" );
91   if ( phs == NULL )
92     Message::message( Message_fatal( "PHSfile: open_read  - Could not read: "+filename ) );
93   fclose( phs );
94 
95   mode = READ;
96 }
97 
98 
99 /*! Close the file after reading. This command also actually fills in
100   the data in any HKL_data structures which have been marked for
101   import. */
close_read()102 void PHSfile::close_read()
103 {
104   if ( mode != READ )
105     Message::message( Message_fatal( "PHSfile: no file open for read" ) );
106 
107   // make sure the data list is sized
108   if ( f_sigf_i != NULL ) f_sigf_i->update();
109   if ( phi_wt_i != NULL ) phi_wt_i->update();
110 
111   int h, k, l;
112   HKL hkl;
113   xtype x1[2], x2[2];
114   float f1, f2, f3, f4;
115 
116   char line[240];
117   FILE* phs = fopen( filename.c_str(), "r" );
118   if ( phs == NULL )
119     Message::message( Message_fatal( "PHSfile: import_hkl_data  - Could not read: "+filename ) );
120   // read the data from the PHS
121   while ( fgets( line, 240, phs ) != NULL ) {
122     f1 = f2 = f3 = f4 = 0.0;  // default sigf to 0 in case missing
123     sscanf( line, " %i %i %i %f %f %f %f", &h, &k, &l, &f1, &f2, &f3, &f4 );
124     hkl = HKL( h, k, l );
125     x1[0] = xtype(f1);
126     x1[1] = xtype(f4);
127     x2[0] = xtype(Util::d2rad(ftype(f3)));
128     x2[1] = xtype(f2);
129     if ( f_sigf_i != NULL ) f_sigf_i->data_import( hkl, x1 );
130     if ( phi_wt_i != NULL ) phi_wt_i->data_import( hkl, x2 );
131   }
132   fclose( phs );
133 
134   mode = NONE;
135 }
136 
137 
138 /*! The file is opened for writing. This will be a new file, created
139   entirely from data from within the program, rather than by extending
140   an existing file. Similar restrictions apply as for open_read().
141 
142   \param filename_out The output filename or pathname. */
open_write(const String filename_out)143 void PHSfile::open_write( const String filename_out )
144 {
145   if ( mode != NONE )
146     Message::message( Message_fatal( "PHSfile: open_write - File already open" ) );
147 
148   // open the output phs
149   hkl_ptr = NULL;
150   f_sigf_o = NULL; phi_wt_o = NULL;
151   filename = filename_out;
152 
153   FILE* phs = fopen( filename.c_str(), "w" );
154   if ( phs == NULL )
155     Message::message( Message_fatal( "PHSfile: open_write - Could not write: "+filename ) );
156   fclose( phs );
157 
158   mode = WRITE;
159 }
160 
161 
162 /*! Close the file after writing. This command also actually writes
163   the data reflection list from the HKL_info object and the data from
164   any HKL_data objects which have been marked for import. */
close_write()165 void PHSfile::close_write()
166 {
167   if ( mode != WRITE )
168     Message::message( Message_fatal( "PHSfile: close_write - no file open for write" ) );
169 
170   // export the marked list data to an phs file
171   if ( hkl_ptr == NULL )
172     Message::message( Message_fatal( "PHSfile: close_write - no refln list exported" ) );
173   const HKL_info& hklinf = *hkl_ptr;
174 
175   HKL hkl;
176   xtype x1[2], x2[2];
177   float f1, f2, f3, f4;
178   f1 = f2 = f3 = f4 = 0.0;
179 
180   FILE* phs = fopen( filename.c_str(), "w" );
181   if ( phs == NULL )
182     Message::message( Message_fatal( "PHSfile: close_write - Could not write: "+filename ) );
183   HKL_info::HKL_reference_index ih;
184   for ( ih = hklinf.first(); !ih.last(); ih.next() ) {
185     hkl = ih.hkl();
186     if ( f_sigf_o != NULL ) f_sigf_o->data_export( hkl, x1 );
187     if ( phi_wt_o != NULL ) phi_wt_o->data_export( hkl, x2 );
188     f1 = float(x1[0]);
189     f4 = float(x1[1]);
190     f3 = float(Util::rad2d(ftype(x2[0])));
191     f2 = float(x2[1]);
192     fprintf( phs, "%6i %6i %6i %11.3f %11.3f %11.3f %11.3f\n",
193 	     hkl.h(), hkl.k(), hkl.l(), f1, f2, f3, f4 );
194   }
195   fclose( phs );
196 
197   mode = NONE;
198 }
199 
200 
201 /*! Get the resolution limit from the PHS file.
202   Since a PHS file does not contain cell information, a Cell object
203   must be supplied, which will be used to determine the resultion.
204   The result is the resolution determined by the most extreme
205   reflection in the file.
206   \return The resolution. */
resolution(const Cell & cell) const207 Resolution PHSfile::resolution( const Cell& cell ) const
208 {
209   if ( mode != READ )
210     Message::message( Message_fatal( "PHSfile: resolution - no file open for read" ) );
211 
212   HKL hkl;
213   int h, k, l;
214   char line[240];
215   FILE* phs = fopen( filename.c_str(), "r" );
216   if ( phs == NULL )
217     Message::message( Message_fatal( "PHSfile: resolution - Could not read: "+filename ) );
218   // read the reflections from the phs
219   ftype slim = 0.0;
220   while ( fgets( line, 240, phs ) != NULL ) {
221     sscanf( line, " %i %i %i", &h, &k, &l );
222     hkl = HKL( h, k, l );
223     slim = Util::max( slim, hkl.invresolsq(cell) );
224   }
225   fclose( phs );
226 
227   return Resolution( 1.0/sqrt(slim) );
228 }
229 
230 
231 /*! Import the list of reflection HKLs from an PHS file into an
232   HKL_info object. If the resolution limit of the HKL_info object is
233   lower than the limit of the file, any excess reflections will be
234   rejected, as will any systematic absences or duplicates.
235   \param target The HKL_info object to be initialised. */
import_hkl_info(HKL_info & target)236 void PHSfile::import_hkl_info( HKL_info& target )
237 {
238   if ( mode != READ )
239     Message::message( Message_fatal( "PHSfile: import_hkl_info - no file open for read" ) );
240 
241   std::vector<HKL> hkls;
242   HKL hkl;
243   int h, k, l;
244   char line[240];
245   FILE* phs = fopen( filename.c_str(), "r" );
246   if ( phs == NULL )
247     Message::message( Message_fatal( "PHSfile: import_hkl_info - Could not read: "+filename ) );
248   // read the reflections from the phs
249   ftype slim = target.resolution().invresolsq_limit();
250   while ( fgets( line, 240, phs ) != NULL ) {
251     sscanf( line, " %i %i %i", &h, &k, &l );
252     hkl = HKL( h, k, l );
253     if ( hkl.invresolsq(target.cell()) < slim ) hkls.push_back( hkl );
254   }
255   fclose( phs );
256 
257   target.add_hkl_list( hkls );
258 }
259 
260 
261 /*! Import data from an PHS file into an HKL_data object.
262 
263   This routine does not actually read any data, but rather marks the
264   data to be read when the file is closed.
265 
266   The data to be read (F_sigF or Phi_fom) will be selected based on
267   the type of the HKL_data object.
268 
269   \param cdata The HKL_data object into which data is to be imported. */
import_hkl_data(HKL_data_base & cdata)270 void PHSfile::import_hkl_data( HKL_data_base& cdata )
271 {
272   if ( mode != READ )
273     Message::message( Message_fatal( "PHSfile: import_hkl_data - no file open for read" ) );
274 
275   if      ( cdata.type() == data32::F_sigF::type()  ) f_sigf_i = &cdata;
276   else if ( cdata.type() == data32::Phi_fom::type() ) phi_wt_i = &cdata;
277   else
278     Message::message( Message_fatal( "PHSfile: import_hkl_data - data must be F_sigF or Phi_fom" ) );
279 }
280 
281 
282 /*! Export the list of reflection HKLs to an PHS file from an
283   HKL_info object. */
export_hkl_info(const HKL_info & target)284 void PHSfile::export_hkl_info( const HKL_info& target )
285 {
286   if ( mode != WRITE )
287     Message::message( Message_fatal( "PHSfile: export_hkl_info - no file open for write" ) );
288   hkl_ptr = &target;
289 }
290 
291 
292 /*! Export data from an HKL_data object into an PHS file.
293 
294   This routine does not actually write any data, but rather marks the
295   data to be written when the file is closed.
296 
297   The data to be read (F_sigF or Phi_fom) will be selected based on
298   the type of the HKL_data object.
299 
300   \param cdata The HKL_data object from which data is to be exported. */
export_hkl_data(const HKL_data_base & cdata)301 void PHSfile::export_hkl_data( const HKL_data_base& cdata )
302 {
303   if ( mode != WRITE )
304     Message::message( Message_fatal( "PHSfile: export_hkl_data - no file open for write" ) );
305 
306   if      ( cdata.type() == data32::F_sigF::type()  ) f_sigf_o = &cdata;
307   else if ( cdata.type() == data32::Phi_fom::type() ) phi_wt_o = &cdata;
308   else
309     Message::message( Message_fatal( "PHSfile: export_hkl_data - data must be F_sigF or Phi_fom" ) );
310 }
311 
312 
313 } // namespace clipper
314