1 /*! \file lib/xmap.h 2 Header file for crystal maps 3 */ 4 //C Copyright (C) 2000-2006 Kevin Cowtan and University of York 5 //L 6 //L This library is free software and is distributed under the terms 7 //L and conditions of version 2.1 of the GNU Lesser General Public 8 //L Licence (LGPL) with the following additional clause: 9 //L 10 //L `You may also combine or link a "work that uses the Library" to 11 //L produce a work containing portions of the Library, and distribute 12 //L that work under terms of your choice, provided that you give 13 //L prominent notice with each copy of the work that the specified 14 //L version of the Library is used in it, and that you include or 15 //L provide public access to the complete corresponding 16 //L machine-readable source code for the Library including whatever 17 //L changes were used in the work. (i.e. If you make changes to the 18 //L Library you must distribute those, but you do not need to 19 //L distribute source or object code to those portions of the work 20 //L not covered by this licence.)' 21 //L 22 //L Note that this clause grants an additional right and does not impose 23 //L any additional restriction, and so does not affect compatibility 24 //L with the GNU General Public Licence (GPL). If you wish to negotiate 25 //L other terms, please contact the maintainer. 26 //L 27 //L You can redistribute it and/or modify the library under the terms of 28 //L the GNU Lesser General Public License as published by the Free Software 29 //L Foundation; either version 2.1 of the License, or (at your option) any 30 //L later version. 31 //L 32 //L This library is distributed in the hope that it will be useful, but 33 //L WITHOUT ANY WARRANTY; without even the implied warranty of 34 //L MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 35 //L Lesser General Public License for more details. 36 //L 37 //L You should have received a copy of the CCP4 licence and/or GNU 38 //L Lesser General Public License along with this library; if not, write 39 //L to the CCP4 Secretary, Daresbury Laboratory, Warrington WA4 4AD, UK. 40 //L The GNU Lesser General Public can also be obtained by writing to the 41 //L Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 42 //L MA 02111-1307 USA 43 44 45 #ifndef CLIPPER_XMAP 46 #define CLIPPER_XMAP 47 48 49 #include "fftmap.h" 50 #include "fftmap_sparse.h" 51 #include "derivs.h" 52 53 54 namespace clipper 55 { 56 57 class Xmap_cacheobj 58 { 59 public: 60 class Key 61 { 62 public: Key(const Spgr_descr & spgr_descr,const Grid_sampling & grid)63 Key( const Spgr_descr& spgr_descr, const Grid_sampling& grid ) : 64 spgr_descr_(spgr_descr), grid_sampling_(grid) {} spgr_descr()65 const Spgr_descr& spgr_descr() const { return spgr_descr_; } grid_sampling()66 const Grid_sampling& grid_sampling() const { return grid_sampling_; } 67 private: 68 Spgr_descr spgr_descr_; 69 Grid_sampling grid_sampling_; 70 }; 71 72 Xmap_cacheobj( const Key& xmap_cachekey ); //!< construct entry 73 bool matches( const Key& xmap_cachekey ) const; //!< compare entry 74 String format() const; //!< string description 75 // data 76 Key key; //!< key 77 Grid_sampling xtl_grid; //!< grid for the cell 78 Grid_range asu_grid; //!< grid for the ASU 79 Grid_range map_grid; //!< grid for the ASU, plus border 80 int nsym; // number of symops 81 std::vector<unsigned char> asu; //!< ASU flag array 82 std::vector<Isymop> isymop; //!< Integerised symops 83 std::vector<int> du, dv, dw; //!< symmetry grid shifts to index 84 Array2d<unsigned char> symperm; //!< Perumtation matrix of symops 85 Mat33<> mat_grid_orth; //!< for backward compatibility 86 static Mutex mutex; //!< thread safety 87 }; 88 89 90 //! Xmap_base: base for crystallographic map class 91 /*! 92 The crystallographic map class stores a map of arbitrary data 93 type. Its main difference from a 3-d array is that the data extent 94 appears to be infinite, and yet internally only a unique ASU is 95 stored. Iterators provide efficient access to data. 96 97 This base contains everything except the data, which is templated 98 in the derived type Xmap<T> 99 */ 100 class Xmap_base 101 { 102 public: 103 enum FFTtype { Default, Normal, Sparse }; //!< FFT backend selection 104 105 //! test if object has been initialised 106 bool is_null() const; 107 108 //! get the cell cell()109 const Cell& cell() const { return cell_; } 110 //! get the spacegroup spacegroup()111 const Spacegroup& spacegroup() const { return spacegroup_; } 112 //! get the cell grid grid_sampling()113 const Grid_sampling& grid_sampling() const { return grid_sam_; } 114 //! get the ASU grid grid_asu()115 const Grid_range& grid_asu() const { return cacheref.data().asu_grid; } 116 //! map coordinate from index 117 /*! \param index The index. \return The corresponding grid coordinate. */ coord_of(const int & index)118 inline Coord_grid coord_of( const int& index ) const 119 { return cacheref.data().map_grid.deindex( index ); } 120 //! map index from coordinate 121 /*! This does not check symmetry equivalents. \param coord The coordinate. 122 \return The index, or -1 if it does not exist. */ index_of(const Coord_grid & coord)123 inline int index_of( const Coord_grid& coord ) const { 124 if ( cacheref.data().asu_grid.in_grid( coord ) ) { 125 const int i = cacheref.data().map_grid.index( coord ); 126 if ( asu[ i ] == 0 ) return i; 127 } 128 return -1; 129 } 130 //! function to pick right cell repeat for any grid coord to_map_unit(const Coord_grid & pos)131 Coord_grid to_map_unit( const Coord_grid& pos ) const 132 { return pos.unit( grid_sam_ ); } 133 134 //! return the orthogonal-to-grid coordinate operator (translation is zero) operator_orth_grid()135 const RTop<>& operator_orth_grid() const { return rt_orth_grid; } 136 //! return the grid-to-orthogonal coordinate operator (translation is zero) operator_grid_orth()137 const RTop<>& operator_grid_orth() const { return rt_grid_orth; } 138 //! convert map coordinate to orthogonal 139 /*! \param cm The grid coordinate to be converted. 140 \return The equivalent orthogonal coordinate. */ coord_orth(const Coord_map & cm)141 inline Coord_orth coord_orth( const Coord_map& cm ) const 142 { return Coord_orth( rt_grid_orth.rot()*cm ); } 143 //! convert orthogonal coordinate to map 144 /*! \param co The orthogonal coordinate to be converted. 145 \return The equivalent grid coordinate. */ coord_map(const Coord_orth & co)146 inline Coord_map coord_map( const Coord_orth& co ) const 147 { return Coord_map ( rt_orth_grid.rot()*co ); } 148 149 //! (This method is for compatibility with NXmap - it always returns true) in_map(const Coord_grid &)150 bool in_map( const Coord_grid& ) const { return true; } 151 //! (This method is for compatibility with NXmap - it always returns true) in_map(const Coord_map & cm)152 template<class I> bool in_map( const Coord_map& cm ) const { return true; } 153 154 //! get multiplicity of a map grid point 155 int multiplicity( const Coord_grid& pos ) const; 156 157 //! Map reference base class 158 /*! This is a reference to an Map. It forms a base class for 159 index-like and coordinate-like Map references. If you write a 160 method which will work with either, then specify this instead of 161 either of the derived classed. \internal */ 162 class Map_reference_base 163 { 164 public: 165 //! return the parent Xmap base_xmap()166 inline const Xmap_base& base_xmap() const { return *map_; } 167 //! Get the index into the map data array index()168 inline const int& index() const { return index_; } 169 //! Check for end of map last()170 bool last() const { return ( index_ >= map_->map_grid.size() ); } 171 protected: 172 //! pointer to map for which this Map_reference_index is defined 173 const Xmap_base* map_; 174 //! integer index_ into map data array 175 int index_; 176 }; 177 178 //! Map reference with index-like behaviour 179 /*! This is a reference to a map coordinate. It behaves like a 180 simple index into the map, but can be easily converted into a 181 coordinate as and when required. It also implements methods for 182 iterating through the unique portion of a map. It is very 183 compact, but coord() involves some overhead and loses any 184 information concerning symmetry equivelents. 185 186 \note The following methods are inherited from 187 Map_reference_base but are documented here for convenience: 188 base_xmap(), index(), last(). 189 */ 190 class Map_reference_index : public Map_reference_base 191 { 192 public: 193 //! Null constructor Map_reference_index()194 Map_reference_index() {} 195 //! Constructor: takes parent map Map_reference_index(const Xmap_base & map)196 explicit Map_reference_index( const Xmap_base& map ) 197 { map_ = ↦ index_=0; next(); } 198 //! Constructor: takes parent map and coord Map_reference_index(const Xmap_base & map,const Coord_grid & pos)199 Map_reference_index( const Xmap_base& map, const Coord_grid& pos ) { map_ = ↦ int sym; map_->find_sym( pos, index_, sym ); } 200 //! Get current grid coordinate coord()201 inline Coord_grid coord() const 202 { return map_->map_grid.deindex(index_); } 203 //! Get current value of orthogonal coordinate coord_orth()204 inline const Coord_orth coord_orth() const 205 { return Coord_orth( map_->rt_grid_orth.rot() * coord().coord_map() ); } 206 //! Set current value of coordinate - optimised for nearby coords set_coord(const Coord_grid & pos)207 inline Map_reference_index& set_coord( const Coord_grid& pos ) 208 { int sym; map_->find_sym( pos, index_, sym ); return *this; } 209 //! Simple increment next()210 inline Map_reference_index& next() { 211 do { 212 index_++; if ( last() ) break; 213 } while ( map_->asu[index_] != 0 ); 214 return *this; 215 } 216 //! Index of neighbouring point 217 /* Use for e.g. peak search. Valid for -1 <= du/dv/dw <= 1 only. 218 \param du/dv/dw Coordinate offset. \return Map index. */ index_offset(const int & du,const int & dv,const int & dw)219 inline int index_offset(const int& du,const int& dv,const int& dw) const { 220 int i = index_ + du*map_->du[0] + dv*map_->dv[0] + dw*map_->dw[0]; 221 if ( map_->asu[i] != 0 ) { i = map_->map_grid.index( map_->to_map_unit( map_->map_grid.deindex(i).transform( map_->isymop[map_->asu[i]-1] ) ) ); } 222 return i; 223 } 224 // inherited functions listed for documentation purposes 225 //-- const Xmap_base& base_xmap() const; 226 //-- const int& index() const; 227 //-- bool last() const; 228 }; 229 230 //! Map reference with coordinate-like behaviour 231 /*! This is a reference to a map coordinate. It behaves like a 232 coordinate, but also stores the index of the corresponding point 233 in the map, and the symmetry operator required to get there. It 234 also implements methods for iterating through the a map. Since 235 the current coordinate and symmetry are stored, coord() is 236 fast. However, it requires 1 pointer and 5 words of storage. 237 238 \note The following methods are inherited from 239 Map_reference_base but are documented here for convenience: 240 base_xmap(), index(), last(). 241 */ 242 class Map_reference_coord : public Map_reference_base 243 { 244 public: 245 //! Null constructor Map_reference_coord()246 Map_reference_coord() {} 247 //! Constructor: takes parent map Map_reference_coord(const Xmap_base & map)248 explicit Map_reference_coord( const Xmap_base& map ) 249 { map_ = ↦ index_ = 0; next(); } 250 //! Constructor: takes parent map and coord Map_reference_coord(const Xmap_base & map,const Coord_grid & pos)251 Map_reference_coord( const Xmap_base& map, const Coord_grid& pos ) { 252 map_ = ↦ 253 pos_ = pos; 254 map_->find_sym( pos_, index_, sym_ ); 255 } 256 //! Get current value of coordinate coord()257 inline const Coord_grid& coord() const { return pos_; } 258 //! Get current value of orthogonal coordinate coord_orth()259 inline const Coord_orth coord_orth() const 260 { return Coord_orth( map_->rt_grid_orth.rot() * coord().coord_map() ); } 261 //! Get current symmetry operator sym()262 inline const int& sym() const { return sym_; } 263 //! Set current value of coordinate - optimised for nearby coords 264 Map_reference_coord& set_coord( const Coord_grid& pos ); 265 //! Simple increment 266 /*! Use of this function resets the stored coordinate and sym */ next()267 inline Map_reference_coord& next() { 268 sym_ = 0; 269 do { 270 index_++; if ( last() ) break; 271 } while ( map_->asu[index_] != 0 ); 272 pos_ = map_->map_grid.deindex(index_); 273 return *this; 274 } 275 // Increment u,v,w next_u()276 inline Map_reference_coord& next_u() { pos_.u()++; index_ += map_->du[sym_]; if (map_->asu[index_] != 0) edge(); return *this; } //!< increment u next_v()277 inline Map_reference_coord& next_v() { pos_.v()++; index_ += map_->dv[sym_]; if (map_->asu[index_] != 0) edge(); return *this; } //!< increment v next_w()278 inline Map_reference_coord& next_w() { pos_.w()++; index_ += map_->dw[sym_]; if (map_->asu[index_] != 0) edge(); return *this; } //!< increment w prev_u()279 inline Map_reference_coord& prev_u() { pos_.u()--; index_ -= map_->du[sym_]; if (map_->asu[index_] != 0) edge(); return *this; } //!< increment u prev_v()280 inline Map_reference_coord& prev_v() { pos_.v()--; index_ -= map_->dv[sym_]; if (map_->asu[index_] != 0) edge(); return *this; } //!< decrement v prev_w()281 inline Map_reference_coord& prev_w() { pos_.w()--; index_ -= map_->dw[sym_]; if (map_->asu[index_] != 0) edge(); return *this; } //!< decrement w 282 //! Assignment operator from a coord 283 inline Map_reference_coord& operator =( const Coord_grid& pos ) 284 { return set_coord( pos ); } 285 // inherited functions listed for documentation purposes 286 //-- const Xmap_base& base_xmap() const; 287 //-- const int& index() const; 288 //-- bool last() const; 289 290 protected: 291 //! Current symop 292 int sym_; 293 //! Current coord 294 Coord_grid pos_; 295 296 //! Reset index for a different symop when we hit the map border 297 void edge(); 298 }; 299 300 //! return a Map_reference_index for this map first()301 Map_reference_index first() const { return Map_reference_index( *this ); } 302 //! return a Map_reference_coord for this map first_coord()303 Map_reference_coord first_coord() const { return Map_reference_coord( *this ); } 304 //! set/get default backend type default_type()305 static FFTtype& default_type() { return default_type_; } 306 protected: 307 ObjectCache<Xmap_cacheobj>::Reference cacheref; //!< object cache reference 308 const unsigned char* asu; //!< fast access ptr 309 const Isymop* isymop; //!< fast access ptr 310 const int* du; //!< fast access ptr 311 const int* dv; //!< fast access ptr 312 const int* dw; //!< fast access ptr 313 Grid_range asu_grid; //!< fast access copy 314 Grid_range map_grid; //!< fast access copy 315 int nsym; //!< fast access copy 316 317 Cell cell_; //!< unit cell 318 Spacegroup spacegroup_; //!< spacegroup 319 Grid_sampling grid_sam_; //!< grid for the whole cell 320 321 RTop<> rt_orth_grid; //!< orth->grid operator 322 RTop<> rt_grid_orth; //!< grid->orth operator 323 324 //! Null constructor, for later initialisation 325 Xmap_base(); 326 //! initialiser 327 void init( const Spacegroup& spacegroup, const Cell& cell, const Grid_sampling& grid_sam ); 328 inline void find_sym( const Coord_grid& base, int& index, int& sym ) const; 329 void asu_error( const Coord_grid& pos ) const; 330 331 static FFTtype default_type_; //!< default backend type 332 333 friend class Xmap_base::Map_reference_base; 334 friend class Xmap_base::Map_reference_index; 335 friend class Xmap_base::Map_reference_coord; 336 }; 337 338 339 340 341 //! Xmap<T>: actual crystallographic map class 342 /*! 343 The crystallographic map class stores a map of arbitrary data 344 type. Its main difference from a 3-d array is that the data extent 345 appears to be infinite, and yet internally only a unique ASU is 346 stored. Iterators provide efficient access to data. 347 348 This is derived from Xmap_base, and adds the templatised data 349 itself and the methods which deal with it. 350 351 \note The following methods are inherited from Xmap_base but are 352 documented here for convenience: cell(), spacegroup(), 353 grid_sampling(), grid_asu(), in_asu(), multiplicity(), 354 to_map_unit(), first(), first_coord(). 355 */ 356 template<class T> class Xmap : public Xmap_base 357 { 358 public: 359 //! Null constructor, for later initialisation Xmap()360 Xmap() {} 361 //! constructor: from spacegroup, cell, and grid Xmap(const Spacegroup & spacegroup,const Cell & cell,const Grid_sampling & grid_sam)362 Xmap( const Spacegroup& spacegroup, const Cell& cell, const Grid_sampling& grid_sam ) { init( spacegroup, cell, grid_sam ); } 363 //! initialiser: from spacegroup, cell, and grid init(const Spacegroup & spacegroup,const Cell & cell,const Grid_sampling & grid_sam)364 void init( const Spacegroup& spacegroup, const Cell& cell, const Grid_sampling& grid_sam ) { Xmap_base::init( spacegroup, cell, grid_sam ); list.resize( cacheref.data().asu.size() ); } 365 366 //! get data by Map_reference_index 367 inline const T& operator[] (const Xmap_base::Map_reference_index& ix) const 368 { return list[ix.index()]; } 369 //! set data by Map_reference_index 370 inline T& operator[] (const Xmap_base::Map_reference_index& ix) 371 { return list[ix.index()]; } 372 373 //! get data by Map_reference_coord 374 inline const T& operator[] (const Xmap_base::Map_reference_coord& ix) const 375 { return list[ix.index()]; } 376 //! set data by Map_reference_coord 377 inline T& operator[] (const Xmap_base::Map_reference_coord& ix) 378 { return list[ix.index()]; } 379 380 //! get a density value for an arbitrary position 381 const T& get_data( const Coord_grid& pos ) const; 382 //! set a density value for an arbitrary position 383 void set_data( const Coord_grid& pos, const T& val ); 384 //! get data by index (not recommended) 385 inline const T& get_data( const int& index ) const; 386 //! set data by index (not recommended) 387 bool set_data( const int& index, const T& val ); 388 389 //! get map value for fractional coord using supplied interpolator 390 template<class I> T interp( const Coord_frac& pos ) const; 391 //! get map value and grad for fractional coord using supplied interpolator 392 template<class I> void interp_grad( const Coord_frac& pos, T& val, Grad_frac<T>& grad ) const; 393 //! get map value and curv for fractional coord using supplied interpolator 394 template<class I> void interp_curv( const Coord_frac& pos, T& val, Grad_frac<T>& grad, Curv_frac<T>& curv ) const; 395 //! get map value for map coord using supplied interpolator 396 template<class I> T interp( const Coord_map& pos ) const; 397 //! get map value and grad for map coord using supplied interpolator 398 template<class I> void interp_grad( const Coord_map& pos, T& val, Grad_map<T>& grad ) const; 399 //! get map value and curv for map coord using supplied interpolator 400 template<class I> void interp_curv( const Coord_map& pos, T& val, Grad_map<T>& grad, Curv_map<T>& curv ) const; 401 402 //! FFT from reflection list to map 403 template<class H> void fft_from( const H& fphidata, const FFTtype type = Default ); 404 //! FFT from map to reflection list 405 template<class H> void fft_to ( H& fphidata, const FFTtype type = Default ) const; 406 407 // inherited functions listed for documentation purposes 408 //-- const Cell& cell() const; 409 //-- const Spacegroup& spacegroup() const; 410 //-- const Grid_sampling& grid_sampling() const; 411 //-- const Grid_range& grid_asu() const; 412 //-- inline Coord_grid coord_of( const int& index ) const; 413 //-- inline int index_of( const Coord_grid& coord ) const; 414 //-- const int multiplicity( const Coord_grid& pos ) const; 415 //-- const Coord_grid to_map_unit( const Coord_grid& pos ) const; 416 //-- const Map_reference_index first() const; 417 //-- const Map_reference_coord first_coord() const; 418 419 //! assignment operator: assigns a single value to the whole map 420 const T& operator =( const T& value ); 421 //! add another map to this one 422 const Xmap<T>& operator +=( const Xmap<T>& other ); 423 //! subtract another map from this one 424 const Xmap<T>& operator -=( const Xmap<T>& other ); 425 426 private: 427 std::vector<T> list; 428 }; 429 430 431 432 // implementations 433 find_sym(const Coord_grid & base,int & index,int & sym)434 void Xmap_base::find_sym( const Coord_grid& base, int& index, int& sym ) const 435 { 436 // first deal with first symop, and cache for highest performance 437 Coord_grid rot = to_map_unit( base ); 438 if ( asu_grid.in_grid( rot ) ) { 439 index = map_grid.index( rot ); 440 if ( asu[ index ] == 0 ) { 441 sym = 0; 442 } else { 443 sym = asu[ index ] - 1; 444 index = map_grid.index( to_map_unit( base.transform(isymop[sym]) ) ); 445 } 446 } else { 447 // now deal with other symops 448 for ( sym = 1; sym < nsym; sym++ ) { 449 rot = to_map_unit( base.transform( isymop[sym] ) ); 450 if ( asu_grid.in_grid( rot ) ) { 451 index = map_grid.index( rot ); 452 if ( asu[ index ] == 0 ) return; 453 } 454 } 455 index = 0; // redundent, to avoid compiler warnings 456 asu_error( base ); 457 } 458 return; 459 } 460 461 462 /*! Accessing the data by coordinate, rather than by 463 Map_reference_index or Map_reference_coord, involves a symmetry 464 lookup and is therefore slow. Avoid using these methods when you 465 can. */ get_data(const Coord_grid & pos)466 template<class T> const T& Xmap<T>::get_data( const Coord_grid& pos ) const 467 { 468 int index, sym; 469 find_sym( pos, index, sym ); 470 return list[ index ]; 471 } 472 473 /*! Accessing the data by coordinate, rather than by 474 Map_reference_index or Map_reference_coord, involves a symmetry 475 lookup and is therefore slow. Avoid using these methods when you 476 can. */ set_data(const Coord_grid & pos,const T & val)477 template<class T> void Xmap<T>::set_data( const Coord_grid& pos, const T& val ) 478 { 479 int index, sym; 480 find_sym( pos, index, sym ); 481 list[ index ] = val; 482 } 483 484 /*! Accessing the data by index, rather than by Map_reference_index 485 or Map_reference_coord, is generally to be avoided since the 486 indices do not start at zero and do not increase 487 contiguously. These methods are only useful when a large number of 488 references into a map must be stored, e.g. for sorting into 489 density order. */ get_data(const int & index)490 template<class T> const T& Xmap<T>::get_data( const int& index ) const 491 { return list[index]; } 492 493 /*! Accessing the data by index, rather than by Map_reference_index 494 or Map_reference_coord, is generally to be avoided since the 495 indices do not start at zero and do not increase 496 contiguously. These methods are only useful when a large number of 497 references into a map must be stored, e.g. for sorting into 498 density order. 499 \return true if data was set, i.e. index is valid. */ set_data(const int & index,const T & val)500 template<class T> bool Xmap<T>::set_data( const int& index, const T& val ) 501 { 502 if ( index >= 0 && index < list.size() ) 503 if ( asu[index] == 0 ) { 504 list[index] = val; 505 return true; 506 } 507 return false; 508 } 509 510 /*! The value of the map at the desired non-grid fractional 511 coordinate are calculated using the supplied interpolator template. 512 \code 513 Coord_frac f( u, v, w ); 514 y = xmap.interp<Interp_cubic>( f ); 515 \endcode 516 \param pos The fractional coord at which the density is to be calcuated. 517 \return The value of the density at that point. */ interp(const Coord_frac & pos)518 template<class T> template<class I> T Xmap<T>::interp( const Coord_frac& pos ) const 519 { 520 T val; 521 I::interp( *this, pos.coord_map( grid_sam_ ), val ); 522 return val; 523 } 524 525 526 /*! The value of the map at the desired non-grid fractional 527 coordinate and its gradient are calculated using 528 the supplied interpolator template. 529 \param pos The fractional coord at which the density is to be calcuated. 530 \param val The value of the density at that point. 531 \param grad The interpolated gradient vector with respect to the 532 fractional coordinates (see Cell::coord_orth). */ interp_grad(const Coord_frac & pos,T & val,Grad_frac<T> & grad)533 template<class T> template<class I> void Xmap<T>::interp_grad( const Coord_frac& pos, T& val, Grad_frac<T>& grad ) const 534 { 535 Grad_map<T> g; 536 I::interp_grad( *this, pos.coord_map( grid_sam_ ), val, g ); 537 grad = g.grad_frac( grid_sam_ ); 538 } 539 540 541 /*! The value of the map at the desired non-grid fractional 542 coordinate and its gradient and curvature are calculated using 543 the supplied interpolator template. e.g. 544 \param pos The fractional coord at which the density is to be calcuated. 545 \param val The value of the density at that point. 546 \param grad The interpolated gradient vector with respect to the 547 fractional coordinates (see Cell::coord_orth). 548 \param curv The interpolated curvature matrix with respect to the 549 fractional coordinates (see Cell::coord_orth). */ interp_curv(const Coord_frac & pos,T & val,Grad_frac<T> & grad,Curv_frac<T> & curv)550 template<class T> template<class I> void Xmap<T>::interp_curv( const Coord_frac& pos, T& val, Grad_frac<T>& grad, Curv_frac<T>& curv ) const 551 { 552 Grad_map<T> g; 553 Curv_map<T> c; 554 I::interp_curv( *this, pos.coord_map( grid_sam_ ), val, g, c ); 555 grad = g.grad_frac( grid_sam_ ); 556 curv = c.curv_frac( grid_sam_ ); 557 } 558 559 560 /*! The value of the map at the desired non-grid map 561 coordinate are calculated using the supplied interpolator template. 562 \code 563 Coord_map m( u, v, w ); 564 y = xmap.interp<Interp_cubic>( m ); 565 \endcode 566 \param pos The map coord at which the density is to be calcuated. 567 \return The value of the density at that point. */ interp(const Coord_map & pos)568 template<class T> template<class I> T Xmap<T>::interp( const Coord_map& pos ) const 569 { 570 T val; 571 I::interp( *this, pos, val ); 572 return val; 573 } 574 575 576 /*! The value of the map at the desired non-grid map 577 coordinate and its gradient are calculated using 578 the supplied interpolator template. 579 \param pos The map coord at which the density is to be calcuated. 580 \param val The value of the density at that point. 581 \param grad The interpolated gradient vector with respect to the 582 map coordinates (see Cell::coord_orth). */ interp_grad(const Coord_map & pos,T & val,Grad_map<T> & grad)583 template<class T> template<class I> void Xmap<T>::interp_grad( const Coord_map& pos, T& val, Grad_map<T>& grad ) const 584 { I::interp_grad( *this, pos, val, grad ); } 585 586 587 /*! The value of the map at the desired non-grid map 588 coordinate and its gradient and curvature are calculated using 589 the supplied interpolator template. e.g. 590 \param pos The map coord at which the density is to be calcuated. 591 \param val The value of the density at that point. 592 \param grad The interpolated gradient vector with respect to the 593 map coordinates (see Cell::coord_orth). 594 \param curv The interpolated curvature matrix with respect to the 595 map coordinates (see Cell::coord_orth). */ interp_curv(const Coord_map & pos,T & val,Grad_map<T> & grad,Curv_map<T> & curv)596 template<class T> template<class I> void Xmap<T>::interp_curv( const Coord_map& pos, T& val, Grad_map<T>& grad, Curv_map<T>& curv ) const 597 { I::interp_curv( *this, pos, val, grad, curv ); } 598 599 600 /*! An FFT is calculated using the provided reflection list of 601 F_phi, and used to fill this map. The reflection list is unchanged. 602 \param fphidata The reflection data list to use 603 */ fft_from(const H & fphidata,const FFTtype type)604 template<class T> template<class H> void Xmap<T>::fft_from( const H& fphidata, const FFTtype type ) 605 { 606 if ( type == Sparse || ( type == Default && default_type() == Sparse ) ) { 607 // make a sparse fftmap 608 FFTmap_sparse_p1_hx fftmap( grid_sampling() ); 609 // copy from reflection data 610 typename H::HKL_reference_index ih; 611 ffttype f, phi0, phi1; 612 int sym; 613 for ( ih = fphidata.first_data(); !ih.last(); fphidata.next_data( ih ) ) { 614 f = fphidata[ih].f(); 615 if ( f != 0.0 ) { 616 phi0 = fphidata[ih].phi(); 617 const HKL& hkl = ih.hkl(); 618 fftmap.set_hkl( hkl, 619 std::complex<ffttype>( f*cos(phi0), f*sin(phi0) ) ); 620 for ( sym = 1; sym < spacegroup_.num_primops(); sym++ ) { 621 phi1 = phi0 + hkl.sym_phase_shift( spacegroup_.symop(sym) ); 622 fftmap.set_hkl( hkl.transform( isymop[sym] ), 623 std::complex<ffttype>( f*cos(phi1), f*sin(phi1) ) ); 624 } 625 } 626 } 627 // require output ASU coords 628 for ( Map_reference_index ix = first(); !ix.last(); ix.next() ) 629 fftmap.require_real_data( ix.coord() ); 630 // do fft 631 fftmap.fft_h_to_x(1.0/cell().volume()); 632 // fill map ASU 633 for ( Map_reference_index ix = first(); !ix.last(); ix.next() ) 634 (*this)[ix] = fftmap.real_data( ix.coord() ); 635 } else { 636 // make a normal fftmap 637 FFTmap_p1 fftmap( grid_sampling() ); 638 // copy from reflection data 639 typename H::HKL_reference_index ih; 640 ffttype f, phi0, phi1; 641 int sym; 642 for ( ih = fphidata.first_data(); !ih.last(); fphidata.next_data( ih ) ) { 643 f = fphidata[ih].f(); 644 if ( f != 0.0 ) { 645 phi0 = fphidata[ih].phi(); 646 const HKL& hkl = ih.hkl(); 647 fftmap.set_hkl( hkl, 648 std::complex<ffttype>( f*cos(phi0), f*sin(phi0) ) ); 649 for ( sym = 1; sym < spacegroup_.num_primops(); sym++ ) { 650 phi1 = phi0 + hkl.sym_phase_shift( spacegroup_.symop(sym) ); 651 fftmap.set_hkl( hkl.transform( isymop[sym] ), 652 std::complex<ffttype>( f*cos(phi1), f*sin(phi1) ) ); 653 } 654 } 655 } 656 // do fft 657 fftmap.fft_h_to_x(1.0/cell().volume()); 658 // fill map ASU 659 for ( Map_reference_index ix = first(); !ix.last(); ix.next() ) 660 (*this)[ix] = fftmap.real_data( ix.coord() ); 661 } 662 } 663 664 665 /*! The Fourier transform of this map is calculated and used to fill 666 a reflection list of F_phi. The map is unchanged. 667 668 Arguably this should be part of hkl_data<F_phi<T>>. But that 669 requires writing a specialisation of hkl_data for F_phi. This is 670 simpler and imposes less demands on the compiler. 671 \param fphidata The reflection data list to set. 672 */ fft_to(H & fphidata,const FFTtype type)673 template<class T> template<class H> void Xmap<T>::fft_to ( H& fphidata, const FFTtype type ) const 674 { 675 if ( type == Sparse || ( type == Default && default_type() == Sparse ) ) { 676 // make a sparse fftmap 677 FFTmap_sparse_p1_xh fftmap( grid_sampling() ); 678 // copy from map data 679 ffttype f; 680 int sym; 681 for ( Map_reference_index ix = first(); !ix.last(); ix.next() ) { 682 f = (*this)[ix]; 683 if ( f != 0.0 ) { 684 fftmap.real_data( ix.coord() ) = f; 685 for ( sym = 1; sym < cacheref.data().nsym; sym++ ) 686 fftmap.real_data( 687 ix.coord().transform( isymop[sym] ).unit( grid_sam_ ) ) = f; 688 } 689 } 690 // require output ASU coords 691 typename H::HKL_reference_index ih; 692 for ( ih = fphidata.first(); !ih.last(); ih.next() ) 693 fftmap.require_hkl( ih.hkl() ); 694 // do fft 695 fftmap.fft_x_to_h(cell().volume()); 696 // fill data ASU 697 for ( ih = fphidata.first(); !ih.last(); ih.next() ) { 698 std::complex<ffttype> c = fftmap.get_hkl( ih.hkl() ); 699 fphidata[ih].f() = std::abs(c); 700 fphidata[ih].phi() = std::arg(c); 701 } 702 } else { 703 // make a normal fftmap 704 FFTmap_p1 fftmap( grid_sampling() ); 705 // copy from map data 706 ffttype f; 707 int sym; 708 for ( Map_reference_index ix = first(); !ix.last(); ix.next() ) { 709 f = (*this)[ix]; 710 if ( f != 0.0 ) { 711 fftmap.real_data( ix.coord() ) = f; 712 for ( sym = 1; sym < cacheref.data().nsym; sym++ ) 713 fftmap.real_data( 714 ix.coord().transform( isymop[sym] ).unit( grid_sam_ ) ) = f; 715 } 716 } 717 // do fft 718 fftmap.fft_x_to_h(cell().volume()); 719 // fill data ASU 720 typename H::HKL_reference_index ih; 721 for ( ih = fphidata.first(); !ih.last(); ih.next() ) { 722 std::complex<ffttype> c = fftmap.get_hkl( ih.hkl() ); 723 fphidata[ih].f() = std::abs(c); 724 fphidata[ih].phi() = std::arg(c); 725 } 726 } 727 } 728 729 730 /*! All values, including missing values, are overwritten by the value. 731 \param value The value to which the map is to be set. */ 732 template<class T> const T& Xmap<T>::operator =( const T& value ) 733 { 734 // copy value into map 735 for ( Map_reference_index im = first(); !im.last(); im.next() ) 736 list[im.index()] = value; 737 return value; 738 } 739 740 741 /*! The map grids and spacegroups must match. */ 742 template<class T> const Xmap<T>& Xmap<T>::operator +=( const Xmap<T>& other ) 743 { 744 if ( spacegroup().hash() != other.spacegroup().hash() || 745 grid_sampling() != other.grid_sampling() ) 746 Message::message( Message_fatal( "Xmap: map mismatch in +=" ) ); 747 for ( Map_reference_index im = first(); !im.last(); im.next() ) 748 list[im.index()] += other[im]; 749 return (*this); 750 } 751 752 /*! The map grids and spacegroups must match. */ 753 template<class T> const Xmap<T>& Xmap<T>::operator -=( const Xmap<T>& other ) 754 { 755 if ( spacegroup().hash() != other.spacegroup().hash() || 756 grid_sampling() != other.grid_sampling() ) 757 Message::message( Message_fatal( "Xmap: map mismatch in -=" ) ); 758 for ( Map_reference_index im = first(); !im.last(); im.next() ) 759 list[im.index()] -= other[im]; 760 return (*this); 761 } 762 763 764 } // namespace clipper 765 766 #endif 767