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