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 = ⌖
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