1 /* xmap.cpp: implementation file for crystal maps */
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
43 #include "xmap.h"
44 #include "clipper_instance.h"
45
46
47 namespace clipper {
48
49
50 Message_ctor message_ctor_xmap( " [Xmap: constructed]" );
51
52
53 Mutex Xmap_cacheobj::mutex = Mutex();
54
Xmap_cacheobj(const Key & xmap_cachekey)55 Xmap_cacheobj::Xmap_cacheobj( const Key& xmap_cachekey ) :
56 key( xmap_cachekey )
57 {
58 Spacegroup spacegroup_( xmap_cachekey.spgr_descr() );
59
60 xtl_grid = xmap_cachekey.grid_sampling();
61
62 // Get the map grid - must contain ASU
63 map_grid = asu_grid =
64 Grid_range( xtl_grid, spacegroup_.asu_min(), spacegroup_.asu_max() );
65 map_grid.add_border(1);
66
67 // Create the intergised symops (assumes legal grid) &
68 // Precalculate shifts to index due to symmetry transformed grid steps
69 int sym;
70 nsym = spacegroup_.num_symops();
71 isymop.resize( nsym );
72 du.resize( nsym );
73 dv.resize( nsym );
74 dw.resize( nsym );
75 for ( sym = 0; sym < nsym; sym++ ) {
76 Isymop op = Isymop( spacegroup_.symop(sym), xtl_grid );
77 isymop[sym] = op;
78 du[sym] = map_grid.Grid::index( Coord_grid( op.rot()*Coord_grid(1,0,0) ) );
79 dv[sym] = map_grid.Grid::index( Coord_grid( op.rot()*Coord_grid(0,1,0) ) );
80 dw[sym] = map_grid.Grid::index( Coord_grid( op.rot()*Coord_grid(0,0,1) ) );
81 }
82
83 // now store the symmetry permutations
84 symperm.resize( nsym, nsym );
85 for ( int s1 = 0; s1 < nsym; s1++ )
86 for ( int s2 = 0; s2 < nsym; s2++ )
87 symperm( s1, s2 ) = spacegroup_.product_op( s1, s2 );
88
89 // Flag all non-ASU points in the grid with sym number + 1
90 Coord_grid base, rot;
91 asu.clear();
92 asu.resize( map_grid.size(), 255 ); // set all non-asu flags to 255
93 for ( base = asu_grid.min(); !base.last(asu_grid); base.next(asu_grid) ) {
94 for ( sym = 1; sym < nsym; sym++ ) {
95 rot = base.transform(isymop[sym]).unit(xtl_grid);
96 if ( asu_grid.in_grid( rot ) )
97 if ( asu[ map_grid.index( rot ) ] == 0 ) break;
98 }
99 if ( sym == nsym ) asu[ map_grid.index( base ) ] = 0;
100 }
101 for ( base = map_grid.min(); !base.last(map_grid); base.next(map_grid) )
102 if ( asu[ map_grid.index( base ) ] == 255 ) {
103 for ( sym = 0; sym < nsym; sym++ ) {
104 rot = base.transform(isymop[sym]).unit(xtl_grid);
105 if ( asu_grid.in_grid( rot ) )
106 if ( asu[ map_grid.index( rot ) ] == 0 ) break;
107 }
108 asu[ map_grid.index( base ) ] = sym + 1;
109 }
110 }
111
matches(const Key & xmap_cachekey) const112 bool Xmap_cacheobj::matches( const Key& xmap_cachekey ) const
113 {
114 return
115 key.spgr_descr().hash() == xmap_cachekey.spgr_descr().hash() &&
116 key.grid_sampling().nu() == xmap_cachekey.grid_sampling().nu() &&
117 key.grid_sampling().nv() == xmap_cachekey.grid_sampling().nv() &&
118 key.grid_sampling().nw() == xmap_cachekey.grid_sampling().nw();
119 }
120
format() const121 String Xmap_cacheobj::format() const
122 {
123 return key.spgr_descr().symbol_hall() + " " + key.grid_sampling().format();
124 }
125
126
127 Xmap_base::FFTtype Xmap_base::default_type_ = Xmap_base::Sparse;
128
129
130 /*! For later initialisation: see init() */
Xmap_base()131 Xmap_base::Xmap_base()
132 {
133 Message::message( message_ctor_xmap );
134 }
135
set_coord(const Coord_grid & pos)136 Xmap_base::Map_reference_coord& Xmap_base::Map_reference_coord::set_coord( const Coord_grid& pos )
137 {
138 // use pos_ as a temporary variable to try out the current symop
139 pos_ = map_->to_map_unit( pos.transform(map_->isymop[sym_]) );
140 if ( map_->asu_grid.in_grid( pos_ ) ) {
141 index_ = map_->map_grid.index( pos_ );
142 if ( map_->asu[ index_ ] == 0 ) {
143 pos_ = pos;
144 return *this;
145 }
146 }
147 map_->find_sym( pos, index_, sym_ ); // general case
148 pos_ = pos; // store the unmodified coord
149 return *this;
150 }
151
edge()152 void Xmap_base::Map_reference_coord::edge()
153 {
154 int newsym = map_->asu[index_]-1;
155 index_ = map_->map_grid.index( map_->to_map_unit( map_->map_grid.deindex(index_).transform( map_->isymop[newsym] ) ) );
156 sym_ = map_->cacheref.data().symperm( newsym, sym_ );
157 }
158
159
160 /*! The Xmap is initialised with a given cell, spacegroup, and grid
161 sampling. A unique assymetric unit (ASU) of grid cells is selected
162 and will be used to store a unique set of data.
163
164 If any of the parameters have null values, the existing values will
165 be unchanged. The object will only be fully initialised once all
166 parameters are available.
167 \param spacegroup The spacegroup for the map
168 \param cell The cell for the map
169 \param grid_sam The grid sampling for the map,
170 i.e. the sampling along each axis for one whole cell */
init(const Spacegroup & spacegroup,const Cell & cell,const Grid_sampling & grid_sam)171 void Xmap_base::init( const Spacegroup& spacegroup, const Cell& cell, const Grid_sampling& grid_sam )
172 {
173 // set parameters
174 spacegroup_ = spacegroup;
175 cell_ = cell;
176 grid_sam_ = grid_sam;
177
178 // check parameters
179 if ( is_null() ) return;
180
181 // get cache ref and fast access copies
182 Xmap_cacheobj::Key key( spacegroup, grid_sam );
183 cacheref = ClipperInstantiator::instance().xmap_cache().cache( key );
184 asu = &(cacheref.data().asu[0]);
185 isymop = &(cacheref.data().isymop[0]);
186 du = &(cacheref.data().du[0]);
187 dv = &(cacheref.data().dv[0]);
188 dw = &(cacheref.data().dw[0]);
189 asu_grid = cacheref.data().asu_grid;
190 map_grid = cacheref.data().map_grid;
191 nsym = cacheref.data().nsym;
192
193 // store orthogonal conversions
194 rt_grid_orth = RTop<>( cell_.matrix_orth()*grid_sam_.matrix_grid_frac() );
195 rt_orth_grid = rt_grid_orth.inverse();
196 }
197
198
199 /*! \return true if the object has not been initalised. */
is_null() const200 bool Xmap_base::is_null() const
201 { return ( spacegroup_.is_null() || cell_.is_null() || grid_sam_.is_null() ); }
202
203
204 /*! The multiplicity is the number of times the spacegroup operators
205 map a particular grid point onto itself. This is required in order
206 to properly weight map statistics so as to get the same result from
207 just an ASU as using the whole cell.
208 \param pos The coordinate of the grid point.
209 \return The multiplicty of the point.
210 */
multiplicity(const Coord_grid & pos) const211 int Xmap_base::multiplicity( const Coord_grid& pos ) const
212 {
213 int mult = 1;
214 Coord_grid base = pos.unit(grid_sam_);
215 for ( int sym = 1; sym < cacheref.data().nsym; sym++ )
216 if ( base.transform(isymop[sym]).unit(grid_sam_) == base ) mult++;
217 return mult;
218 }
219
asu_error(const Coord_grid & pos) const220 void Xmap_base::asu_error( const Coord_grid& pos ) const
221 {
222 std::cerr << "Failure to find grid coordinate " << pos.format() << std::endl;
223 std::cerr << "Possible integer overflow or conversion from NaN" << std::endl;
224 Message::message( Message_fatal( "Xmap: Internal map ASU error - " +
225 cacheref.data().format() ) );
226 }
227
228
229 // compile templates
230
231 template class Xmap<unsigned char>;
232 template class Xmap<char>;
233 template class Xmap<unsigned short>;
234 template class Xmap<short>;
235 template class Xmap<unsigned int>;
236 template class Xmap<int>;
237 template class Xmap<ftype32>;
238 template class Xmap<ftype64>;
239
240
241 } // namespace clipper
242