Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ElectronDensityAtomwise.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file src/core/scoring/electron_density_atomwise/ElectronDensityAtomwise.cc
11 /// @brief elec_dens_atomwise scoring method implementation
12 /// @author Fang-Chieh Chou
13 
14 // Unit headers
16 
17 // Package headers
20 
21 // Project headers
22 #include <core/pose/Pose.hh>
23 #include <core/scoring/Energies.hh>
25 #include <core/kinematics/Edge.hh>
28 #include <basic/options/option.hh>
29 #include <basic/Tracer.hh>
30 
31 #include <numeric/constants.hh>
32 #include <numeric/fourier/FFT.hh>
33 #include <numeric/xyzMatrix.hh>
34 #include <numeric/xyzVector.hh>
35 #include <numeric/xyz.functions.hh>
36 #include <numeric/xyzVector.io.hh>
37 #include <numeric/statistics.functions.hh>
38 
40 
41 //
42 #include <basic/options/keys/edensity.OptionKeys.gen.hh>
43 
44 // Utility headers
45 #include <utility/string_util.hh>
46 
47 // C++ headers
48 #include <fstream>
49 #include <limits>
50 
51 
52 //Auto Headers
55 #include <core/id/AtomID.hh>
56 #include <core/kinematics/RT.hh>
57 
58 
59 #ifdef WIN32
60  #define _USE_MATH_DEFINES
61  #include <math.h>
62 #endif
63 
64 
65 
66 namespace core {
67 namespace scoring {
68 namespace electron_density_atomwise {
69 
70 using namespace core;
71 using namespace basic::options;
72 
73 #ifndef WIN32
74 const core::Real FLT_MAX = 1e37;
75 #endif
76 
77 
78 static basic::Tracer TR ( "core.scoring.electron_density_atomwise.ElectronDensityAtomwise" );
79 
80 
81 
82 /// null constructor
84  is_map_loaded = false;
85  is_score_precomputed = false;
86  grid = numeric::xyzVector< int > ( 0, 0, 0 );
87  orig = numeric::xyzVector< int > ( 0, 0, 0 );
88  cell_dimensions = numeric::xyzVector< float > ( 1, 1, 1 );
89  cell_angles = numeric::xyzVector< float > ( 90, 90, 90 );
90  // resolution ... set in readMRCandResize
91  map_reso = -1.0;
92 }
93 
94 ////////
95 //Functions used for map loading
96 
97 const int CCP4HDSIZE = 1024; // size of CCP4/MRC header
98 
99 inline float d2r ( float d ) {
100  return ( d * M_PI / 180.0 );
101 }
102 inline double d2r ( double d ) {
103  return ( d * M_PI / 180.0 );
104 }
105 inline float square ( float x ) {
106  return ( x * x );
107 }
108 inline double square ( double x ) {
109  return ( x * x );
110 }
111 
112 // x mod y, returns z in [0,y-1]
113 inline int pos_mod ( int x, int y ) {
114  int r = x % y;
115 
116  if ( r < 0 ) r += y;
117 
118  return r;
119 }
120 inline float pos_mod ( float x, float y ) {
121  float r = std::fmod ( x, y );
122 
123  if ( r < 0 ) r += y;
124 
125  return r;
126 }
127 inline double pos_mod ( double x, double y ) {
128  double r = std::fmod ( x, y );
129 
130  if ( r < 0 ) r += y;
131 
132  return r;
133 }
134 
135 // Endianness swap
136 // Only works with aligned 4-byte quantities
137 static void swap4_aligned ( void *v, long ndata ) {
138  int *data = ( int * ) v;
139  long i;
140  int *N;
141 
142  for ( i = 0; i < ndata; i++ ) {
143  N = data + i;
144  *N = ( ( ( *N >> 24 ) & 0xff ) | ( ( *N & 0xff ) << 24 ) | ( ( *N >> 8 ) & 0xff00 ) | ( ( *N & 0xff00 ) << 8 ) );
145  }
146 }
147 
148 //////
150  // recompute reciprocal cell
151  // f2c, c2f
152  core::Real ca = cos ( d2r ( cell_angles[0] ) ), cb = cos ( d2r ( cell_angles[1] ) ), cg = cos ( d2r ( cell_angles[2] ) );
153  core::Real sa = sin ( d2r ( cell_angles[0] ) ), sb = sin ( d2r ( cell_angles[1] ) ), sg = sin ( d2r ( cell_angles[2] ) );
154  // conversion from fractional cell coords to cartesian coords
156  cell_dimensions[0] , cell_dimensions[1] * cg, cell_dimensions[2] * cb,
157  0.0, cell_dimensions[1] * sg, cell_dimensions[2] * ( ca - cb * cg ) / sg,
158  0.0, 0.0 , cell_dimensions[2] * sb * sqrt ( 1.0 - square ( ( cb * cg - ca ) / ( sb * sg ) ) ) );
159  core::Real D = f2c.det();
160 
161  if ( D == 0 ) {
162  TR << "[ WARNING ] Invalid crystal cell dimensions." << std::endl;
163  return;
164  }
165 
166  // c2f is inverse of f2c
168  ( f2c ( 2, 2 ) * f2c ( 3, 3 ) - f2c ( 2, 3 ) * f2c ( 3, 2 ) ) / D,
169  - ( f2c ( 1, 2 ) * f2c ( 3, 3 ) - f2c ( 1, 3 ) * f2c ( 3, 2 ) ) / D,
170  ( f2c ( 1, 2 ) * f2c ( 2, 3 ) - f2c ( 1, 3 ) * f2c ( 2, 2 ) ) / D,
171  - ( f2c ( 2, 1 ) * f2c ( 3, 3 ) - f2c ( 3, 1 ) * f2c ( 2, 3 ) ) / D,
172  ( f2c ( 1, 1 ) * f2c ( 3, 3 ) - f2c ( 1, 3 ) * f2c ( 3, 1 ) ) / D,
173  - ( f2c ( 1, 1 ) * f2c ( 2, 3 ) - f2c ( 1, 3 ) * f2c ( 2, 1 ) ) / D,
174  ( f2c ( 2, 1 ) * f2c ( 3, 2 ) - f2c ( 3, 1 ) * f2c ( 2, 2 ) ) / D,
175  - ( f2c ( 1, 1 ) * f2c ( 3, 2 ) - f2c ( 1, 2 ) * f2c ( 3, 1 ) ) / D,
176  ( f2c ( 1, 1 ) * f2c ( 2, 2 ) - f2c ( 1, 2 ) * f2c ( 2, 1 ) ) / D );
177  cell_volume = cell_dimensions[0] * cell_dimensions[1] * cell_dimensions[2] * sqrt ( 1 - square ( ca ) - square ( cb ) - square ( cg ) + 2 * ca * cb * cg );
178  // reciprocal space cell dimensions
179  r_cell_dimensions[0] = cell_dimensions[1] * cell_dimensions[2] * sa / cell_volume;
180  r_cell_dimensions[1] = cell_dimensions[0] * cell_dimensions[2] * sb / cell_volume;
181  r_cell_dimensions[2] = cell_dimensions[0] * cell_dimensions[1] * sg / cell_volume;
182  cos_r_cell_angles[0] = cos ( asin ( std::min ( std::max ( cell_volume / ( cell_dimensions[0] * cell_dimensions[1] * cell_dimensions[2] * sb * sg ) , -1.0 ) , 1.0 ) ) );
183  cos_r_cell_angles[1] = cos ( asin ( std::min ( std::max ( cell_volume / ( cell_dimensions[0] * cell_dimensions[1] * cell_dimensions[2] * sa * sg ) , -1.0 ) , 1.0 ) ) );
184  cos_r_cell_angles[2] = cos ( asin ( std::min ( std::max ( cell_volume / ( cell_dimensions[0] * cell_dimensions[1] * cell_dimensions[2] * sa * sb ) , -1.0 ) , 1.0 ) ) );
185  r_cell_volume = 1.0 / cell_volume;
186 }
187 /////////////////////////////////////
188 // parse symmops from ccp4 map header
190  using core::kinematics::RT;
191  symmOps.clear();
192 
193  if ( symList.size() == 0 ) { // no symminfo in header, assume P 1
194  symmOps.push_back ( RT ( numeric::xyzMatrix< core::Real >::identity(),
195  numeric::xyzVector< core::Real > ( 0.0, 0.0, 0.0 ) ) );
196  }
197 
198  for ( int i = 1; i <= ( int ) symList.size(); ++i ) {
199  std::string line = symList[i];
200  utility::vector1< std::string > rows = utility::string_split ( line, ',' );
201 
202  if ( rows.size() != 3 ) {
203  TR.Error << "[ ERROR ] invalid symmop in map file" << std::endl;
204  TR.Error << line << std::endl;
205  TR.Error << "Setting symmetry to P1 and continuing!" << line << std::endl;
206  // should we throw an exception here???? nah, just set symm to P1 and continue
207  symmOps.clear();
208  symmOps.push_back ( RT ( numeric::xyzMatrix< core::Real >::identity(),
209  numeric::xyzVector< core::Real > ( 0.0, 0.0, 0.0 ) ) );
210  return;
211  }
212 
213  // _REALLY_ simple parser
216  int k;
217 
218  for ( int j = 0; j < 3; ++j ) {
219  k = rows[j+1].find ( '/' );
220 
221  if ( k != ( int ) std::string::npos ) {
222  // numerator
223  int startNum = rows[j+1].find_last_not_of ( "0123456789", k - 1 ) + 1;
224  int startDenom = k + 1;
225  float denom = std::atof ( &rows[j+1][startDenom] );
226  // make sure this shift corresponds to a point in the map
227  trans[j] = std::atof ( &rows[j+1][startNum] ) / denom;
228  } else {
229  trans[j] = 0;
230  }
231 
232  if ( rows[j+1].find ( "-X" ) != std::string::npos )
233  rot ( j + 1, 1 ) = -1;
234  else if ( rows[j+1].find ( "X" ) != std::string::npos )
235  rot ( j + 1, 1 ) = 1;
236 
237  if ( rows[j+1].find ( "-Y" ) != std::string::npos )
238  rot ( j + 1, 2 ) = -1;
239  else if ( rows[j+1].find ( "Y" ) != std::string::npos )
240  rot ( j + 1, 2 ) = 1;
241 
242  if ( rows[j+1].find ( "-Z" ) != std::string::npos )
243  rot ( j + 1, 3 ) = -1;
244  else if ( rows[j+1].find ( "Z" ) != std::string::npos )
245  rot ( j + 1, 3 ) = 1;
246  }
247 
248  symmOps.push_back ( RT ( rot, trans ) );
249  }
250 
251  return;
252 }
253 
254 
255 /////////////////////////////////////
256 // expand density to cover unit cell
257 // maintain origin
259  numeric::xyzVector< int > extent ( density.u1(), density.u2(), density.u3() );
260 
261  // if it already covers unit cell do nothing
262  if ( grid[0] == extent[0] && grid[1] == extent[1] && grid[2] == extent[2] )
263  return;
264 
265  ObjexxFCL::FArray3D< float > newDensity ( grid[0], grid[1], grid[2], 0.0 );
266  // copy the block
267  int limX = std::min ( extent[0], grid[0] ),
268  limY = std::min ( extent[1], grid[1] ),
269  limZ = std::min ( extent[2], grid[2] );
270 
271  for ( int x = 1; x <= limX; ++x )
272  for ( int y = 1; y <= limY; ++y )
273  for ( int z = 1; z <= limZ; ++z ) {
274  newDensity ( x, y, z ) = density ( x, y, z );
275  }
276 
277  // apply symmetry
278  // why backwards? it is a mystery
279  for ( int x = grid[0]; x >= 1; --x )
280  for ( int y = grid[1]; y >= 1; --y )
281  for ( int z = grid[2]; z >= 1; --z ) {
282  if ( x <= limX && y <= limY && z <= limZ )
283  continue;
284 
286  ( ( core::Real ) x + orig[0] - 1 ) / grid[0],
287  ( ( core::Real ) y + orig[1] - 1 ) / grid[1],
288  ( ( core::Real ) z + orig[2] - 1 ) / grid[2] );
289 
290  for ( int symm_idx = 1; symm_idx <= ( int ) symmOps.size(); symm_idx++ ) {
292  symmOps[symm_idx].get_rotation() * fracX + symmOps[symm_idx].get_translation();
293  // indices of symm copy
294  int Sx = pos_mod ( ( int ) floor ( SfracX[0] * grid[0] + 0.5 - orig[0] ) , grid[0] ) + 1;
295  int Sy = pos_mod ( ( int ) floor ( SfracX[1] * grid[1] + 0.5 - orig[1] ) , grid[1] ) + 1 ;
296  int Sz = pos_mod ( ( int ) floor ( SfracX[2] * grid[2] + 0.5 - orig[2] ) , grid[2] ) + 1 ;
297 
298  if ( Sx <= limX && Sy <= limY && Sz <= limZ ) {
299  newDensity ( x, y, z ) = density ( Sx, Sy, Sz );
300  }
301  }
302  }
303 
304  // new map!
305  density = newDensity;
306 }
307 
308 /////////////////////////////////////
309 // resize a map (using FFT-interpolation)
310 void ElectronDensityAtomwise::resize ( core::Real approxGridSpacing ) {
311  // potentially expand map to cover entire unit cell
312  if ( grid[0] != density.u1() || grid[1] != density.u2() || grid[2] != density.u3() ) {
313  TR << "[ ERROR ] resize() not supported for maps not covering the entire unit cell." << std::endl;
314  TR << " " << grid[0] << " != " << density.u1()
315  << " || " << grid[1] << " != " << density.u2()
316  << " || " << grid[2] << " != " << density.u3() << std::endl;
317  exit ( 1 );
318  }
319 
320  // compute new dimensions & origin
321  numeric::xyzVector<int> newDims, newGrid;
323  newDims[0] = ( int ) floor ( cell_dimensions[0] / approxGridSpacing + 0.5 );
324  newDims[1] = ( int ) floor ( cell_dimensions[1] / approxGridSpacing + 0.5 );
325  newDims[2] = ( int ) floor ( cell_dimensions[2] / approxGridSpacing + 0.5 );
326  newOri[0] = newDims[0] * orig[0] / ( ( core::Real ) grid[0] );
327  newOri[1] = newDims[1] * orig[1] / ( ( core::Real ) grid[1] );
328  newOri[2] = newDims[2] * orig[2] / ( ( core::Real ) grid[2] );
329  newGrid = newDims;
330  ObjexxFCL::FArray3D< std::complex<double> > newDensity;
331  newDensity.dimension ( newDims[0], newDims[1], newDims[2] );
332  TR << "Resizing " << density.u1() << "x" << density.u2() << "x" << density.u3() << " to "
333  << newDensity.u1() << "x" << newDensity.u2() << "x" << newDensity.u3() << std::endl;
334  // convert map to complex<double>
335  ObjexxFCL::FArray3D< std::complex<double> > Foldmap, Fnewmap;
336  Fnewmap.dimension ( newDims[0], newDims[1], newDims[2] );
337  // fft
338  ObjexxFCL::FArray3D< std::complex<double> > cplx_density;
339  cplx_density.dimension ( density.u1() , density.u2() , density.u3() );
340 
341  for ( int i = 0; i < density.u1() *density.u2() *density.u3(); ++i ) cplx_density[i] = ( double ) density[i];
342 
343  numeric::fourier::fft3 ( cplx_density, Foldmap );
344 
345  // reshape (handles both shrinking and growing in each dimension)
346  for ( int i = 0; i < Fnewmap.u1() *Fnewmap.u2() *Fnewmap.u3(); ++i ) Fnewmap[i] = std::complex<double> ( 0, 0 );
347 
348  numeric::xyzVector<int> nyq ( std::min ( Foldmap.u1(), Fnewmap.u1() ) / 2,
349  std::min ( Foldmap.u2(), Fnewmap.u2() ) / 2,
350  std::min ( Foldmap.u3(), Fnewmap.u3() ) / 2 );
351  numeric::xyzVector<int> nyqplus1_old ( std::max ( Foldmap.u1() - ( std::min ( Foldmap.u1(), Fnewmap.u1() ) - nyq[0] ) + 1 , nyq[0] + 1 ) ,
352  std::max ( Foldmap.u2() - ( std::min ( Foldmap.u2(), Fnewmap.u2() ) - nyq[1] ) + 1 , nyq[1] + 1 ) ,
353  std::max ( Foldmap.u3() - ( std::min ( Foldmap.u3(), Fnewmap.u3() ) - nyq[2] ) + 1 , nyq[2] + 1 ) );
354  numeric::xyzVector<int> nyqplus1_new ( std::max ( Fnewmap.u1() - ( std::min ( Foldmap.u1(), Fnewmap.u1() ) - nyq[0] ) + 1 , nyq[0] + 1 ) ,
355  std::max ( Fnewmap.u2() - ( std::min ( Foldmap.u2(), Fnewmap.u2() ) - nyq[1] ) + 1 , nyq[1] + 1 ) ,
356  std::max ( Fnewmap.u3() - ( std::min ( Foldmap.u3(), Fnewmap.u3() ) - nyq[2] ) + 1 , nyq[2] + 1 ) );
357 
358  for ( int i = 1; i <= Fnewmap.u1(); i++ )
359  for ( int j = 1; j <= Fnewmap.u2(); j++ )
360  for ( int k = 1; k <= Fnewmap.u3(); k++ ) {
361  if ( i - 1 <= nyq[0] ) {
362  if ( j - 1 <= nyq[1] ) {
363  if ( k - 1 <= nyq[2] )
364  Fnewmap ( i, j, k ) = Foldmap ( i, j, k );
365  else if ( k - 1 >= nyqplus1_new[2] )
366  Fnewmap ( i, j, k ) = Foldmap ( i, j, k - nyqplus1_new[2] + nyqplus1_old[2] );
367  } else if ( j - 1 >= nyqplus1_new[1] ) {
368  if ( k - 1 <= nyq[2] )
369  Fnewmap ( i, j, k ) = Foldmap ( i, j - nyqplus1_new[1] + nyqplus1_old[1], k );
370  else if ( k - 1 >= nyqplus1_new[2] )
371  Fnewmap ( i, j, k ) = Foldmap ( i, j - nyqplus1_new[1] + nyqplus1_old[1], k - nyqplus1_new[2] + nyqplus1_old[2] );
372  }
373  } else if ( i - 1 >= nyqplus1_new[0] ) {
374  if ( j - 1 <= nyq[1] ) {
375  if ( k - 1 <= nyq[2] )
376  Fnewmap ( i, j, k ) = Foldmap ( i - nyqplus1_new[0] + nyqplus1_old[0], j, k );
377  else if ( k - 1 >= nyqplus1_new[2] )
378  Fnewmap ( i, j, k ) = Foldmap ( i - nyqplus1_new[0] + nyqplus1_old[0], j, k - nyqplus1_new[2] + nyqplus1_old[2] );
379  } else if ( j - 1 >= nyqplus1_new[1] ) {
380  if ( k - 1 <= nyq[2] )
381  Fnewmap ( i, j, k ) = Foldmap ( i - nyqplus1_new[0] + nyqplus1_old[0], j - nyqplus1_new[1] + nyqplus1_old[1], k );
382  else if ( k - 1 >= nyqplus1_new[2] )
383  Fnewmap ( i, j, k ) = Foldmap ( i - nyqplus1_new[0] + nyqplus1_old[0],
384  j - nyqplus1_new[1] + nyqplus1_old[1],
385  k - nyqplus1_new[2] + nyqplus1_old[2] );
386  }
387  }
388  }
389 
390  // ifft
391  numeric::fourier::ifft3 ( Fnewmap, newDensity );
392  // update density
393  density.dimension ( newDims[0], newDims[1], newDims[2] );
394 
395  for ( int i = 0; i < newDims[0]*newDims[1]*newDims[2] ; ++i )
396  density[i] = ( float ) newDensity[i].real();
397 
398  grid = newGrid;
399  orig = newOri;
400  TR << " new extent: " << density.u1() << " x " << density.u2() << " x " << density.u3() << std::endl;
401  TR << " new origin: " << orig[0] << " x " << orig[1] << " x " << orig[2] << std::endl;
402  TR << " new grid: " << grid[0] << " x " << grid[1] << " x " << grid[2] << std::endl;
403 }
404 
405 ///////////////////////////////////////////////////////////////////////////
406 //Load in the CCP4 map
407 void
409  TR << "Loading Density Map" << std::endl;
410 
411  if ( !basic::options::option[ basic::options::OptionKeys::edensity::mapfile ].user() ) {
412  utility_exit_with_message ( "No density map specified for electron density scoring." );
413  }
414 
415  std::string map_file = basic::options::option[ basic::options::OptionKeys::edensity::mapfile ]();
416  map_reso = basic::options::option[ basic::options::OptionKeys::edensity::mapreso ]();
417  grid_spacing = basic::options::option[ basic::options::OptionKeys::edensity::grid_spacing ]();
418  std::fstream mapin ( map_file.c_str() , std::ios::binary | std::ios::in );
419  char mapString[4], symData[81];
420  int crs2xyz[3], extent[3], mode, symBytes, origin_xyz[3];
421  int xyz2crs[3], vol_xsize, vol_ysize, vol_zsize;
422  int xIndex, yIndex, zIndex, vol_xySize, coord[3];
423  long dataOffset, filesize;
424  float *rowdata;
425  bool swap = false;
426 
427  if ( !mapin ) {
428  TR << "[ ERROR ] Error opening MRC map " << map_file << ". Not loading map." << std::endl;
429  utility_exit_with_message ( "Fail to load the density map." );
430  }
431 
432  if ( !mapin.read ( reinterpret_cast <char*> ( extent ), 3 * sizeof ( int ) )
433  || !mapin.read ( reinterpret_cast <char*> ( &mode ), 1 * sizeof ( int ) )
434  || !mapin.read ( reinterpret_cast <char*> ( &origin_xyz[0] ), 3 * sizeof ( int ) )
435  || !mapin.read ( reinterpret_cast <char*> ( &grid[0] ), 3 * sizeof ( int ) )
436  || !mapin.read ( reinterpret_cast <char*> ( &cell_dimensions[0] ), 3 * sizeof ( float ) )
437  || !mapin.read ( reinterpret_cast <char*> ( &cell_angles[0] ), 3 * sizeof ( float ) )
438  || !mapin.read ( reinterpret_cast <char*> ( crs2xyz ), 3 * sizeof ( int ) ) ) {
439  TR << "[ ERROR ] Improperly formatted line in MRC map. Not loading map." << std::endl;
440  utility_exit_with_message ( "Fail to load the density map." );
441  }
442 
443  // Check the number of bytes used for storing symmetry operators
444  mapin.seekg ( 92, std::ios::beg );
445 
446  if ( !mapin.read ( reinterpret_cast <char*> ( &symBytes ), 1 * sizeof ( int ) ) ) {
447  TR << "[ ERROR ] Failed reading symmetry bytes record. Not loading map." << "\n";
448  utility_exit_with_message ( "Fail to load the density map." );
449  }
450 
451  // alt: MRC files have floating-point origin info at byte 196
452  // read this and try to figure out if it is used
453  float altorigin[3];
454  mapin.seekg ( 196, std::ios::beg );
455 
456  if ( !mapin.read ( reinterpret_cast <char*> ( altorigin ), 3 * sizeof ( float ) ) ) {
457  TR << "[ ERROR ] Improperly formatted line in MRC map. Not loading map." << std::endl;
458  utility_exit_with_message ( "Fail to load the density map." );
459  }
460 
461  // Check for the string "MAP" at byte 208, indicating a CCP4 file.
462  mapin.seekg ( 208, std::ios::beg );
463  mapString[3] = '\0';
464 
465  if ( !mapin.read ( mapString, 3 ) || ( std::string ( mapString ) != "MAP" ) ) {
466  TR << "[ ERROR ] 'MAP' string missing, not a valid MRC map. Not loading map." << std::endl;
467  utility_exit_with_message ( "Fail to load the density map." );
468  }
469 
470  // Check the file endianness
471  if ( mode != 2 ) {
472  swap4_aligned ( &mode, 1 );
473 
474  if ( mode != 2 ) {
475  TR << "[ ERROR ] Non-real (32-bit float) data types are unsupported. Not loading map." << std::endl;
476  utility_exit_with_message ( "Fail to load the density map." );
477  } else {
478  swap = true; // enable byte swapping
479  }
480  }
481 
482  // Swap all the information obtained from the header
483  if ( swap ) {
484  swap4_aligned ( extent, 3 );
485  swap4_aligned ( &origin_xyz[0], 3 );
486  swap4_aligned ( &altorigin[0], 3 );
487  swap4_aligned ( &grid[0], 3 );
488  swap4_aligned ( &cell_dimensions[0], 3 );
489  swap4_aligned ( &cell_angles[0], 3 );
490  swap4_aligned ( crs2xyz, 3 );
491  swap4_aligned ( &symBytes, 1 );
492  }
493 
494  TR << " Setting resolution to " << map_reso << "A" << std::endl;
495  TR << " Read density map'" << map_file << "'" << std::endl;
496  TR << " extent: " << extent[0] << " x " << extent[1] << " x " << extent[2] << std::endl;
497  TR << " origin: " << origin_xyz[0] << " x " << origin_xyz[1] << " x" << origin_xyz[2] << std::endl;
498  TR << " altorigin: " << altorigin[0] << " x " << altorigin[1] << " x " << altorigin[2] << std::endl;
499  TR << " grid: " << grid[0] << " x " << grid[1] << " x " << grid[2] << std::endl;
500  TR << " celldim: " << cell_dimensions[0] << " x " << cell_dimensions[1] << " x " << cell_dimensions[2] << std::endl;
501  TR << " cellangles: " << cell_angles[0] << " x " << cell_angles[1] << " x " << cell_angles[2] << std::endl;
502  TR << " crs2xyz: " << crs2xyz[0] << " x " << crs2xyz[1] << " x " << crs2xyz[2] << std::endl;
503  TR << " symBytes: " << symBytes << std::endl;;
504  // Check the dataOffset: this fixes the problem caused by files claiming
505  // to have symmetry records when they do not.
506  mapin.seekg ( 0, std::ios::end );
507  filesize = mapin.tellg();
508  dataOffset = filesize - 4 * ( extent[0] * extent[1] * extent[2] );
509 
510  if ( dataOffset != ( CCP4HDSIZE + symBytes ) ) {
511  if ( dataOffset == CCP4HDSIZE ) {
512  // Bogus symmetry record information
513  TR << "[ WARNING ] File contains bogus symmetry record. Continuing." << std::endl;
514  symBytes = 0;
515  } else if ( dataOffset < CCP4HDSIZE ) {
516  TR << "[ ERROR ] File appears truncated and doesn't match header. Not loading map." << std::endl;
517  utility_exit_with_message ( "Fail to load the density map." );
518  } else if ( ( dataOffset > CCP4HDSIZE ) && ( dataOffset < ( 1024 * 1024 ) ) ) {
519  // Fix for loading SPIDER files which are larger than usual
520  // In this specific case, we must absolutely trust the symBytes record
521  dataOffset = CCP4HDSIZE + symBytes;
522  TR << "[ WARNING ] File is larger than expected and doesn't match header. Reading anyway." << std::endl;
523  } else {
524  TR << "[ ERROR ] File is MUCH larger than expected and doesn't match header. Not loading map." << std::endl;
525  utility_exit_with_message ( "Fail to load the density map." );
526  }
527  }
528 
529  // Read symmetry records -- organized as 80-byte lines of text.
531  symData[80] = '\0';
532 
533  if ( symBytes != 0 ) {
534  TR << "Symmetry records found:" << std::endl;
535  mapin.seekg ( CCP4HDSIZE, std::ios::beg );
536 
537  for ( int i = 0; i < symBytes / 80; i++ ) {
538  mapin.read ( symData, 80 );
539  symList.push_back ( symData );
540  TR << symData << std::endl;
541  }
542  } else {
543  // no symm info; assume P 1
544  symList.push_back ( "X, Y, Z" );
545  }
546 
547  initializeSymmOps ( symList );
548 
549  // check extent and grid interval counts
550  if ( grid[0] == 0 && extent[0] > 0 ) {
551  grid[0] = extent[0] - 1;
552  TR << "[ WARNING ] Fixed X interval count. Continuing." << std::endl;
553  }
554 
555  if ( grid[1] == 0 && extent[1] > 0 ) {
556  grid[1] = extent[1] - 1;
557  TR << "[ WARNING ] Fixed Y interval count. Continuing." << std::endl;
558  }
559 
560  if ( grid[2] == 0 && extent[2] > 0 ) {
561  grid[2] = extent[2] - 1;
562  TR << "[ WARNING ] Fixed Z interval count. Continuing." << std::endl;
563  }
564 
565  // Mapping between CCP4 column, row, section and Cartesian x, y, z.
566  if ( crs2xyz[0] == 0 && crs2xyz[1] == 0 && crs2xyz[2] == 0 ) {
567  TR << "[ WARNING ] All crs2xyz records are zero." << std::endl;
568  TR << "[ WARNING ] Setting crs2xyz to 1, 2, 3 and continuing." << std::endl;
569  crs2xyz[0] = 1;
570  crs2xyz[1] = 2;
571  crs2xyz[2] = 3;
572  }
573 
574  xyz2crs[crs2xyz[0] - 1] = 0;
575  xyz2crs[crs2xyz[1] - 1] = 1;
576  xyz2crs[crs2xyz[2] - 1] = 2;
577  xIndex = xyz2crs[0];
578  yIndex = xyz2crs[1];
579  zIndex = xyz2crs[2];
580  vol_xsize = extent[xIndex];
581  vol_ysize = extent[yIndex];
582  vol_zsize = extent[zIndex];
583  vol_xySize = vol_xsize * vol_ysize;
584  // coord = <col, row, sec>
585  // extent = <colSize, rowSize, secSize>
586  rowdata = new float[extent[0]];
587  mapin.seekg ( dataOffset, std::ios::beg );
588  // 'alloc' changes ordering of "extent"
589  density.dimension ( vol_xsize, vol_ysize, vol_zsize );
590 
591  for ( coord[2] = 1; coord[2] <= extent[2]; coord[2]++ ) {
592  for ( coord[1] = 1; coord[1] <= extent[1]; coord[1]++ ) {
593  // Read an entire row of data from the file, then write it into the
594  // datablock with the correct slice ordering.
595  if ( mapin.eof() ) {
596  TR << "[ ERROR ] Unexpected end-of-file. Not loading map." << std::endl;
597  utility_exit_with_message ( "Fail to load the density map." );
598  }
599 
600  if ( mapin.fail() ) {
601  TR << "[ ERROR ] Problem reading the file. Not loading map." << std::endl;
602  utility_exit_with_message ( "Fail to load the density map." );
603  }
604 
605  if ( !mapin.read ( reinterpret_cast< char* > ( rowdata ), sizeof ( float ) *extent[0] ) ) {
606  TR << "[ ERROR ] Error reading data row. Not loading map." << std::endl;
607  utility_exit_with_message ( "Fail to load the density map." );
608  }
609 
610  for ( coord[0] = 1; coord[0] <= extent[0]; coord[0]++ ) {
611  density ( coord[xyz2crs[0]], coord[xyz2crs[1]], coord[xyz2crs[2]] ) = rowdata[coord[0] - 1];
612  }
613  }
614  }
615 
616  if ( swap == 1 )
617  swap4_aligned ( &density[0], vol_xySize * vol_zsize );
618 
619  delete [] rowdata;
620  mapin.close();
621  orig[0] = origin_xyz[xyz2crs[0]];
622  orig[1] = origin_xyz[xyz2crs[1]];
623  orig[2] = origin_xyz[xyz2crs[2]];
624  // grid doesnt seemed to get remapped in ccp4 maps
625  ///////////////////////////////////
626  /// POST PROCESSING
627  // expand to unit cell
628  computeCrystParams();
629 
630  //fpd change this so if the alt origin is non-zero use it
631  if ( altorigin[0] != 0 && altorigin[0] != 0 && altorigin[0] != 0 &&
632  ( altorigin[0] > -10000 && altorigin[0] < 10000 ) &&
633  ( altorigin[1] > -10000 && altorigin[1] < 10000 ) &&
634  ( altorigin[2] > -10000 && altorigin[2] < 10000 )
635  ) {
636  orig[0] = altorigin[xyz2crs[0]];
637  orig[1] = altorigin[xyz2crs[1]];
638  orig[2] = altorigin[xyz2crs[2]];
639  numeric::xyzVector<core::Real> fracX = c2f * ( orig );
640  orig = numeric::xyzVector<core::Real> ( fracX[0] * grid[0] , fracX[1] * grid[1] , fracX[2] * grid[2] );
641  TR << "Using ALTERNATE origin\n";
642  TR << " origin =" << orig[0] << " x " << orig[1] << " x " << orig[2] << std::endl;
643  }
644 
645  expandToUnitCell();
646 
647  // resample the map
648  if ( grid_spacing > 0 ) resize ( grid_spacing );
649 
650  // grid spacing in each dim
651  max_del_grid = std::max ( cell_dimensions[0] / ( ( double ) grid[0] ) , cell_dimensions[1] / ( ( double ) grid[1] ) );
652  max_del_grid = std::max ( max_del_grid , cell_dimensions[2] / ( ( double ) grid[2] ) );
653  calculate_index2cart();
654  is_map_loaded = true;
655 }
656 
657 //////////////////////////////////////////////////////////////////////////
658 //compute index to cartesian transformation
659 void
662  1 / double ( grid[0] ), 0, 0,
663  0, 1 / double ( grid[1] ), 0,
664  0, 0, 1 / double ( grid[2] ) );
666  grid[0], 0, 0,
667  0, grid[1], 0,
668  0, 0, grid[2] );
669  i2c = f2c * i2f;
670  c2i = f2i * c2f;
671 }
672 
673 ///////////////////////////////////////////////////////////////////////
674 //Convert a vector from fractional coordinate to index coordinate
678  index_vector[0] = frac_vector[0] * grid[0];
679  index_vector[1] = frac_vector[1] * grid[1];
680  index_vector[2] = frac_vector[2] * grid[2];
681  return index_vector;
682 }
683 
684 //Convert a vector from index coordinate to fractional coordinate
688  frac_vector[0] = index_vector[0] / grid[0];
689  frac_vector[1] = index_vector[1] / grid[1];
690  frac_vector[2] = index_vector[2] / grid[2];
691  return frac_vector;
692 }
696  frac_vector[0] = ( double ) index_vector[0] / grid[0];
697  frac_vector[1] = ( double ) index_vector[1] / grid[1];
698  frac_vector[2] = ( double ) index_vector[2] / grid[2];
699  return frac_vector;
700 }
701 
702 //Convert a vector from xyz coordinate to index coordinate, shift w/ respect to the origin and fold into the unit cell
705  numeric::xyzVector< Real > index_vector;
706  index_vector = c2i * xyz_vector;
707  index_vector[0] = pos_mod ( index_vector[0] - orig[0], ( double ) grid[0] );
708  index_vector[1] = pos_mod ( index_vector[1] - orig[1], ( double ) grid[1] );
709  index_vector[2] = pos_mod ( index_vector[2] - orig[2], ( double ) grid[2] );
710  return index_vector;
711 }
712 
713 //////////////////////////////////////////////////////////////////////////
714 //generate 1d gaussian function and store it.
715 void
717  const Real PI = numeric::constants::f::pi;
718  //Calculate up to 4*sigma
719  gaussian_max_d = 4 * sigma;
720  //Using interval of 0.01 Angstong
721  Size gaussian_size = Size( std::ceil ( gaussian_max_d / 0.01 ) );
722 
723  for ( Size i = 0; i <= gaussian_size; ++i ) {
724  Real calc_value = exp ( - ( i * 0.01 ) * ( i * 0.01 ) / ( 2.0 * sigma * sigma ) ) / ( sqrt ( 2.0 * PI ) * sigma );
725  atom_gaussian_value.push_back ( calc_value );
726  }
727 }
728 
729 //Return the value of 1D gaussian given the distance using stored values
732  if ( dist >= gaussian_max_d ) return 0.0;
733 
734  return atom_gaussian_value[ ( int ) std::floor ( dist*100.0 + 0.5 ) +1];
735 }
736 ///////////////////////////////////////////////////
737 //return the weight of atom given its element type
740  if ( elt == "C" ) return 6;
741 
742  if ( elt == "N" ) return 7;
743 
744  if ( elt == "O" ) return 8;
745 
746  if ( elt == "P" ) return 15;
747 
748  if ( elt == "S" ) return 16;
749 
750  if ( elt == "X" ) return 0; // centroid
751 
752  // default to C
753  TR.Warning << "[ WARNING ] Unknown atom " << elt << std::endl;
754  return 6;
755 }
756 //////////////////////////////////////////////////////////////////
757 //Trilinear Interpolation
760  ObjexxFCL::FArray3D< double > & score,
761  numeric::xyzVector< core::Real > const & index ) {
762  int lower_bound[3], upper_bound[3];
763  double residual[3];
764 
765  // find bounding grid points
766  for ( int i = 0; i < 3; ++i ) {
767  lower_bound[i] = ( int ) ( std::ceil ( index[i] ) );
768  upper_bound[i] = lower_bound[i] + 1;
769 
770  if ( upper_bound[i] > grid[i] ) upper_bound[i] = 1;
771 
772  residual[i] = index[i] + 1 - lower_bound[i];
773  }
774 
775  double &c000 = score ( lower_bound[0], lower_bound[1], lower_bound[2] );
776  double &c100 = score ( upper_bound[0], lower_bound[1], lower_bound[2] );
777  double &c010 = score ( lower_bound[0], upper_bound[1], lower_bound[2] );
778  double &c001 = score ( lower_bound[0], lower_bound[1], upper_bound[2] );
779  double &c110 = score ( upper_bound[0], upper_bound[1], lower_bound[2] );
780  double &c101 = score ( upper_bound[0], lower_bound[1], upper_bound[2] );
781  double &c011 = score ( lower_bound[0], upper_bound[1], upper_bound[2] );
782  double &c111 = score ( upper_bound[0], upper_bound[1], upper_bound[2] );
783  //interpolate at x dimension (R is the residual coord)
784  Real cR00 = c000 + residual[0] * ( c100 - c000 );
785  Real cR10 = c010 + residual[0] * ( c110 - c010 );
786  Real cR01 = c001 + residual[0] * ( c101 - c001 );
787  Real cR11 = c011 + residual[0] * ( c111 - c011 );
788  //interpolate at y dimension
789  Real cRR0 = cR00 + residual[1] * ( cR10 - cR00 );
790  Real cRR1 = cR01 + residual[1] * ( cR11 - cR01 );
791  //interpolate at z dimension
792  Real cRRR = cRR0 + residual[2] * ( cRR1 - cRR0 );
793  return cRRR;
794 }
795 
798  ObjexxFCL::FArray3D< double > & score,
799  numeric::xyzVector< core::Real > const & index ) {
800  int lower_bound[3], upper_bound[3];
801  double residual[3];
803 
804  // find bounding grid points
805  for ( int i = 0; i < 3; ++i ) {
806  lower_bound[i] = ( int ) ( floor ( index[i] + 1 ) );
807  upper_bound[i] = lower_bound[i] + 1;
808 
809  if ( upper_bound[i] > grid[i] ) upper_bound[i] = 1;
810 
811  residual[i] = index[i] + 1 - lower_bound[i];
812  }
813 
814  double &c000 = score ( lower_bound[0], lower_bound[1], lower_bound[2] );
815  double &c100 = score ( upper_bound[0], lower_bound[1], lower_bound[2] );
816  double &c010 = score ( lower_bound[0], upper_bound[1], lower_bound[2] );
817  double &c001 = score ( lower_bound[0], lower_bound[1], upper_bound[2] );
818  double &c110 = score ( upper_bound[0], upper_bound[1], lower_bound[2] );
819  double &c101 = score ( upper_bound[0], lower_bound[1], upper_bound[2] );
820  double &c011 = score ( lower_bound[0], upper_bound[1], upper_bound[2] );
821  double &c111 = score ( upper_bound[0], upper_bound[1], upper_bound[2] );
822  //interpolate at x dimension (x) (R is the residual coord)
823  Real cR00 = c000 + residual[0] * ( c100 - c000 );
824  Real cR10 = c010 + residual[0] * ( c110 - c010 );
825  Real cR01 = c001 + residual[0] * ( c101 - c001 );
826  Real cR11 = c011 + residual[0] * ( c111 - c011 );
827  //interpolate at y dimension (x->y)
828  Real cRR0 = cR00 + residual[1] * ( cR10 - cR00 );
829  Real cRR1 = cR01 + residual[1] * ( cR11 - cR01 );
830  //Get the z gradient (x->y->z)
831  grad[2] = cRR1 - cRR0;
832  //interpolate at z dimension (x->z)
833  Real cR0R = cR00 + residual[2] * ( cR01 - cR00 );
834  Real cR1R = cR10 + residual[2] * ( cR11 - cR10 );
835  //Get the y gradient (x->z->y)
836  grad[1] = cR1R - cR0R;
837  //interpolate at y dimension (y)
838  Real c0R0 = c000 + residual[1] * ( c010 - c000 );
839  Real c1R0 = c100 + residual[1] * ( c110 - c100 );
840  Real c0R1 = c001 + residual[1] * ( c011 - c001 );
841  Real c1R1 = c101 + residual[1] * ( c111 - c101 );
842  //interpolate at z dimension (y->z)
843  Real c0RR = c0R0 + residual[2] * ( c0R1 - c0R0 );
844  Real c1RR = c1R0 + residual[2] * ( c1R1 - c1R0 );
845  //get the x gradient (y->z->x)
846  grad[0] = c1RR - c0RR;
847  return grad;
848 }
849 
850 ///////////////////////////////////////////////////////////////////
851 //Spline interpolation
854  ObjexxFCL::FArray3D< double > & coeffs ,
855  numeric::xyzVector< core::Real > const & idxX ) const {
856  int dims[3] = { coeffs.u3(), coeffs.u2(), coeffs.u1() };
857  core::Real pt[3] = {idxX[2], idxX[1], idxX[0]};
858  core::Real retval = core::scoring::electron_density::SplineInterp::interp3 ( &coeffs[0], dims, pt, 3 );
859  return retval;
860 }
861 
862 void
863 ElectronDensityAtomwise::spline_coeffs ( ObjexxFCL::FArray3D< double > & data ,
864  ObjexxFCL::FArray3D< double > & coeffs ) {
865  int dims[3] = { data.u3(), data.u2(), data.u1() };
866  coeffs = data;
868 }
869 //////////////////////////////////////////////////////////////////
870 //Compute Normalization factor given a pose
871 void
873  if ( is_score_precomputed ) return;
874 
875  //rho_calc_array initialization
876  ObjexxFCL::FArray3D< double > rho_calc_array;
877  rho_calc_array.dimension ( density.u1() , density.u2() , density.u3() );
878 
879  for ( int i = 0; i < density.u1() *density.u2() *density.u3(); ++i ) {
880  rho_calc_array[i] = 0.0;
881  }
882 
883  //Generate gaussian function for the electron density of the atoms.
884  Real map_reso = basic::options::option[ basic::options::OptionKeys::edensity::mapreso ]();
885  Real atom_gaussian_sigma = 0.30 + 0.18 * map_reso;
886  generate_gaussian_1d ( atom_gaussian_sigma );
887  //Calculate the weight and the fractional coordinates of the atoms
888  Size n_res = pose.total_residue();
889  Size sum_weight = 0;
890 
891  for ( Size i = 1; i <= n_res; ++i ) { //rsd
892  conformation::Residue const &rsd ( pose.residue ( i ) );
893  Size n_heavyatom_rsd = rsd.nheavyatoms();
894  utility::vector1< Size > weight_rsd;
895 
896  // skip virtual residues
897  if ( rsd.aa() == core::chemical::aa_vrt ) {
898  atom_weight_stored.push_back ( weight_rsd );
899  continue;
900  }
901 
902  for ( Size j = 1; j <= n_heavyatom_rsd; ++j ) { //atom
903  chemical::AtomTypeSet const & atom_type_set ( rsd.atom_type_set() );
904  //get the weight of each atom (element based)
905  std::string element = atom_type_set[rsd.atom_type_index ( j ) ].element();
906  Size weight = get_atom_weight ( element );
907  sum_weight += weight;
908  weight_rsd.push_back ( weight );
909  //Compute the atom position in unit cell (index coord)
910  numeric::xyzVector< core::Real > coord_index = xyz2index_in_cell ( rsd.xyz( j ) );
912  numeric::xyzVector< core::Real > grid_half ( grid[0] * 0.5,
913  grid[1] * 0.5, grid[1] * 0.5 );
914 
915  //Compute rho_calc
916  for ( int x = 1; x <= density.u1(); ++x ) {
917  //distance from the atom to point in the map (x)
918  dist_index[0] = coord_index[0] - ( x - 1 );
919 
920  //fold to make it in the range [-0.5*grid, 0.5*grid]
921  if ( dist_index[0] > grid_half[0] ) dist_index[0] -= grid[0];
922 
923  if ( dist_index[0] <= - grid_half[0] ) dist_index[0] += grid[0];
924 
925  //skip if the dist is too large
926  numeric::xyzVector<Real> dist_x = i2c * numeric::xyzVector<Real> ( dist_index[0], 0.0, 0.0 );
927 
928  if ( dist_x.length() > gaussian_max_d ) continue;
929 
930  for ( int y = 1; y <= density.u2(); ++y ) {
931  //distance from the atom to point in the map (y)
932  dist_index[1] = coord_index[1] - ( y - 1 );
933 
934  //fold to make it in the range [-0.5*grid, 0.5*grid]
935  if ( dist_index[1] > grid_half[1] ) dist_index[1] -= grid[1];
936 
937  if ( dist_index[1] <= - grid_half[1] ) dist_index[1] += grid[1];
938 
939  //skip if the dist is too large
940  numeric::xyzVector<Real> dist_xy = i2c * numeric::xyzVector<Real> ( dist_index[0], dist_index[1], 0.0 );
941 
942  if ( dist_xy.length() > gaussian_max_d ) continue;
943 
944  for ( int z = 1; z <= density.u3(); ++z ) {
945  //distance from the atom to point in the map (y)
946  dist_index[2] = coord_index[2] - ( z - 1 );
947 
948  //fold to make it in the range [-0.5*grid, 0.5*grid]
949  if ( dist_index[2] > grid_half[2] ) dist_index[2] -= grid[2];
950 
951  if ( dist_index[2] <= - grid_half[2] ) dist_index[2] += grid[2];
952 
953  //skip if the dist is too large
954  numeric::xyzVector<Real> dist_xyz = i2c * dist_index;
955  Real dist = dist_xyz.length();
956 
957  if ( dist > gaussian_max_d ) continue;
958 
959  rho_calc_array ( x, y, z ) += gaussian_1d ( dist ) * weight;
960  }
961  }
962  }
963  }
964 
965  atom_weight_stored.push_back ( weight_rsd );
966  }
967 
968  Real sum_rho_calc = 0.0;
969  Real sum_rho_calc_square = 0.0;
970  Real sum_rho_obs = 0.0;
971  Real sum_rho_obs_square = 0.0;
972  Real sum_rho_calc_times_rho_obs = 0.0;
973  Size n_grid_points = 0;
974 
975  for ( int i = 0; i < density.u1() *density.u2() *density.u3(); ++i ) {
976  float rho_obs = density[i];
977  Real rho_calc = rho_calc_array[i];
978 
979  if ( rho_calc < 1.0e-2 ) {
980  continue;
981  }
982 
983  //compute all factors required for normalization
984  n_grid_points++;
985  sum_rho_calc += rho_calc;
986  sum_rho_calc_square += rho_calc * rho_calc;
987  sum_rho_obs += rho_obs;
988  sum_rho_obs_square += rho_obs * rho_obs;
989  sum_rho_calc_times_rho_obs += rho_calc * rho_obs;
990  }
991 
992  //calculate the real-space correlation coefficient (rscc)
993  //rscc = (<xy> - <x><y>) / sqrt( (<x^2> -<x>^2) * (<y^2> -<y>^2) )
994  // = <dx dy> / sqrt( <dx dx> + <dy dy> )
995  Real rscc = ( sum_rho_calc_times_rho_obs - sum_rho_calc * sum_rho_obs / n_grid_points ) / ( sqrt ( sum_rho_calc_square - sum_rho_calc * sum_rho_calc / n_grid_points ) * sqrt ( sum_rho_obs_square - sum_rho_obs * sum_rho_obs / n_grid_points ) );
996  //Compute Normalization, Score = -sum_weight * rscc = normalization * <dx dy>
997  //Per atom energy = normalization * ( sum(rho_atom*rho_obs) - sum(rho_atom) * avg_rho_obs )
998  normalization = - ( ( double ) sum_weight ) / ( sqrt ( sum_rho_calc_square - sum_rho_calc * sum_rho_calc / n_grid_points ) * sqrt ( sum_rho_obs_square - sum_rho_obs * sum_rho_obs / n_grid_points ) );
999  avg_rho_obs = sum_rho_obs / n_grid_points;
1000  TR << "RSCC of starting pose = " << rscc << std::endl;
1001  TR << "Score of starting pose = " << - ( rscc * sum_weight ) << std::endl;
1002  TR << "normalization factor = " << normalization << std::endl;
1003  TR << "avg_rho_obs = " << avg_rho_obs << std::endl;
1004 }
1005 
1006 //Pre-compute the unweighted score of atom in a grid
1007 void
1009  if ( is_score_precomputed ) return;
1010 
1011  ObjexxFCL::FArray3D< double > unweighted_score;
1012  ObjexxFCL::FArray3D< std::complex<double> > density_transformed,
1013  atom_dens_transformed, atom_dens, cplx_score, cplx_density;
1014  atom_dens.dimension ( density.u1() , density.u2() , density.u3() );
1015 
1016  for ( int i = 0; i < density.u1() *density.u2() *density.u3(); ++i ) {
1017  atom_dens[i] = 0.0;
1018  }
1019 
1020  //compute the gaussian density of an atom
1021  Real sum_rho_calc = 0.0;
1023  numeric::xyzVector< core::Real > grid_half ( grid[0] * 0.5,
1024  grid[1] * 0.5, grid[2] * 0.5 );
1025 
1026  for ( int x = 1; x <= atom_dens.u1(); ++x ) {
1027  //distance from the atom to point in the map (x)
1028  dist_index[0] = x - 1;
1029 
1030  //fold to make it in the range [-0.5*grid, 0.5*grid]
1031  if ( dist_index[0] > grid_half[0] ) dist_index[0] -= grid[0];
1032 
1033  if ( dist_index[0] <= - grid_half[0] ) dist_index[0] += grid[0];
1034 
1035  //skip if the dist is too large
1036  numeric::xyzVector<Real> dist_x = i2c * numeric::xyzVector<Real> ( dist_index[0], 0.0, 0.0 );
1037 
1038  if ( dist_x.length() > gaussian_max_d ) continue;
1039 
1040  for ( int y = 1; y <= atom_dens.u2(); ++y ) {
1041  //distance from the atom to point in the map (y)
1042  dist_index[1] = y - 1;
1043 
1044  //fold to make it in the range [-0.5*grid, 0.5*grid]
1045  if ( dist_index[1] > grid_half[1] ) dist_index[1] -= grid[1];
1046 
1047  if ( dist_index[1] <= - grid_half[1] ) dist_index[1] += grid[1];
1048 
1049  //skip if the dist is too large
1050  numeric::xyzVector<Real> dist_xy = i2c * numeric::xyzVector<Real> ( dist_index[0], dist_index[1], 0.0 );
1051 
1052  if ( dist_xy.length() > gaussian_max_d ) continue;
1053 
1054  for ( int z = 1; z <= atom_dens.u3(); ++z ) {
1055  //distance from the atom to point in the map (y)
1056  dist_index[2] = z - 1;
1057 
1058  //fold to make it in the range [-0.5*grid, 0.5*grid]
1059  if ( dist_index[2] > grid_half[2] ) dist_index[2] -= grid[2];
1060 
1061  if ( dist_index[2] <= - grid_half[2] ) dist_index[2] += grid[2];
1062 
1063  numeric::xyzVector<Real> dist_xyz = i2c * dist_index;
1064  Real dist = dist_xyz.length();
1065  atom_dens ( x, y, z ) = gaussian_1d ( dist );
1066  sum_rho_calc += gaussian_1d ( dist );
1067  }
1068  }
1069  }
1070 
1071  //Compute convolution using fft
1072  numeric::fourier::fft3_dynamic ( atom_dens, atom_dens_transformed );
1073  atom_dens.clear();
1074  cplx_density.dimension ( density.u1() , density.u2() , density.u3() );
1075 
1076  for ( int i = 0; i < density.u1() *density.u2() *density.u3(); ++i ) {
1077  cplx_density[i] = ( double ) density[i];
1078  }
1079 
1080  density.clear();
1081  numeric::fourier::fft3_dynamic ( cplx_density, density_transformed );
1082  cplx_density.clear();
1083 
1084  for ( int i = 0; i < density_transformed.u1() *density_transformed.u2() *density_transformed.u3(); ++i ) {
1085  density_transformed[i] *= atom_dens_transformed[i];
1086  }
1087 
1088  atom_dens_transformed.clear();
1089  numeric::fourier::ifft3_dynamic ( density_transformed, cplx_score );
1090  density_transformed.clear();
1091  unweighted_score.dimension ( cplx_score.u1() , cplx_score.u2() , cplx_score.u3() );
1092 
1093  for ( int i = 0; i < unweighted_score.u1() *unweighted_score.u2() *unweighted_score.u3(); ++i ) {
1094  unweighted_score[i] = cplx_score[i].real();
1095  unweighted_score[i] -= sum_rho_calc * avg_rho_obs;
1096  unweighted_score[i] *= normalization;
1097  }
1098 
1099  cplx_score.clear();
1100  //compute spline coefficient for interpolation
1101  spline_coeffs ( unweighted_score, unweighted_score_coeff );
1102  unweighted_score.clear();
1103  is_score_precomputed = true;
1104 }
1105 ///////////////////////////////////////////////////////////////////////
1106 //Return the score of a given residue
1107 core::Real
1109  // skip virtual residues
1110  if ( rsd.aa() == core::chemical::aa_vrt ) return 0.0;
1111 
1112  Size n_heavyatom_rsd = rsd.nheavyatoms();
1113  Size rsd_id = rsd.seqpos();
1114  Real total_score = 0.0;
1115 
1116  for ( Size j = 1 ; j <= n_heavyatom_rsd; ++j ) {
1117  //Skip virtual atoms
1118  if ( rsd.is_virtual(j) ) continue;
1119  //get the weight of each atom (element based)
1120  Size weight = atom_weight_stored[rsd_id][j];
1121  //Compute the atom position in unit cell (index coord)
1122  numeric::xyzVector< Real > coord_index = xyz2index_in_cell ( rsd.xyz( j ) );
1123  Real score = weight * spline_interpolation ( unweighted_score_coeff, coord_index );
1124  total_score += score;
1125  }
1126 
1127  return total_score;
1128 }
1129 
1130 //Return the gradient of an atom
1133  const & rsd_id, core::Size const & atm_id ) {
1134 
1135  //Skip virtual atoms
1136  if ( pose.residue( rsd_id ).is_virtual( atm_id ) ) {
1137  return numeric::xyzVector< core::Real > (0, 0, 0);
1138  }
1139 
1140  //get the weight of the atom (element based)
1141  Size &weight = atom_weight_stored[rsd_id][atm_id];
1142  Real incre = 0.00000001;
1143  numeric::xyzVector< Real > atmxyz = pose.residue ( rsd_id ).xyz( atm_id );
1144  numeric::xyzVector< Real > coord_index = xyz2index_in_cell ( atmxyz );
1145  numeric::xyzVector< Real > coord_index_dx = coord_index;
1146  numeric::xyzVector< Real > coord_index_dy = coord_index;
1147  numeric::xyzVector< Real > coord_index_dz = coord_index;
1148  coord_index_dx[0] += incre;
1149  coord_index_dy[1] += incre;
1150  coord_index_dz[2] += incre;
1152  Real score_atom = spline_interpolation ( unweighted_score_coeff, coord_index );
1153  grad[0] = ( spline_interpolation ( unweighted_score_coeff, coord_index_dx ) -
1154  score_atom ) / incre;
1155  grad[1] = ( spline_interpolation ( unweighted_score_coeff, coord_index_dy ) -
1156  score_atom ) / incre;
1157  grad[2] = ( spline_interpolation ( unweighted_score_coeff, coord_index_dz ) -
1158  score_atom ) / incre;
1159  numeric::xyzMatrix<core::Real> i2c_gradient = c2i;
1160  i2c_gradient.transpose();
1161  grad = weight * i2c_gradient * grad;
1162  return grad;
1163 }
1164 
1165 ///////////////////////////////////////////////////////////////////////////
1167  static ElectronDensityAtomwise theDensityMap;
1168 
1169  if ( !theDensityMap.isMapLoaded() ) {
1170  // Initialize ElectronDensity object
1171  theDensityMap.readMRCandResize();
1172  }
1173 
1174  return theDensityMap;
1175 }
1176 //////////////////////////////////////////////////////////////////////////
1177 
1178 } // electron_density_atomwise
1179 } // scoring
1180 } // core
1181