Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ElectronDensity.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 core/scoring/methods/electron_density/ElectronDensity.cc
11 /// @brief Scoring a structure against an electron density map
12 /// @author Frank DiMaio
13 
14 // Unit Headers
17 
18 #ifdef WIN32
19  #define _USE_MATH_DEFINES
20  #include <math.h>
21  #ifndef WIN_PYROSETTA
22  #include <windows.h>
23  #endif
24 #endif
25 
26 // Project headers
27 #include <core/pose/Pose.hh>
28 #include <core/scoring/Energies.hh>
30 #include <core/kinematics/Edge.hh>
33 #include <basic/options/option.hh>
35 #include <basic/Tracer.hh>
36 // AUTO-REMOVED #include <core/conformation/PointGraph.hh>
37 // AUTO-REMOVED #include <core/conformation/find_neighbors.hh>
38 
39 #include <numeric/xyzMatrix.hh>
40 #include <numeric/xyzVector.hh>
41 #include <numeric/xyz.functions.hh>
42 #include <numeric/xyzVector.io.hh>
43 #include <numeric/statistics.functions.hh>
44 #include <numeric/fourier/FFT.hh>
45 
46 // AUTO-REMOVED #include <ObjexxFCL/format.hh>
47 
48 //
49 #include <basic/options/keys/edensity.OptionKeys.gen.hh>
50 #include <basic/options/keys/patterson.OptionKeys.gen.hh>
51 
52 #include <basic/resource_manager/ResourceManager.hh>
53 #include <basic/resource_manager/util.hh>
54 
55 // Utility headers
56 #include <utility/string_util.hh>
57 
58 // C++ headers
59 #include <fstream>
60 #include <limits>
61 
64 #include <core/id/AtomID.hh>
65 #include <utility/vector1.hh>
66 #include <utility/excn/Exceptions.hh>
67 
68 //Auto Headers
70 #ifndef WIN32
71  #include <pthread.h>
72 #endif
73 
74 namespace core {
75 namespace scoring {
76 namespace electron_density {
77 
78 /// @details Auto-generated virtual destructor
80 
81 using basic::T;
82 using basic::Tracer;
83 basic::Tracer TR("core.scoring.electron_density.ElectronDensity");
84 
85 #ifdef GL_GRAPHICS
86 // protect access to density from viewer thread
87 pthread_mutex_t density_map_db_mut_ = PTHREAD_MUTEX_INITIALIZER;
88 #endif
89 
90 using namespace core;
91 using namespace basic::options;
92 
93 const int CCP4HDSIZE = 1024; // size of CCP4/MRC header
94 
95 
96 /////////////////////////////// ///////////////////////////////
97 /////////////////////////////// ///////////////////////////////
98 /////////////////////////////// ///////////////////////////////
99 //
100 // one-liners
101 inline float d2r(float d) { return (d*M_PI/180.0); }
102 inline double d2r(double d) { return (d*M_PI/180.0); }
103 inline float square(float x) { return (x*x); }
104 inline double square(double x) { return (x*x); }
105 
106 
107 // x mod y, returns z in [-y/2,y/2]
108 inline int min_mod(int x,int y) {
109  int r=x%y; if (r<-y/2) r+=y;if (r>=y/2) r-=y;
110  return r;
111 }
112 inline float min_mod(float x,float y) {
113  float r=std::fmod(x,y); if (r<-0.5*y) r+=y;if (r>=0.5*y) r-=y;
114  return r;
115 }
116 inline double min_mod(double x,double y) {
117  double r=std::fmod(x,y); if (r<-0.5*y) r+=y;if (r>=0.5*y) r-=y;
118  return r;
119 }
120 
121 // missing density test
122 // pose_from_pdb randomizing missing density with:
123 // ai.x = ai.x + 900.000 + RG.uniform()*100.000;
125  if ( X.length() >= 1500 ) {
126  return true;
127  }
128  return false;
129 }
130 
131 // Endianness swap
132 // Only works with aligned 4-byte quantities
133 static void swap4_aligned(void *v, long ndata) {
134  int *data = (int *) v;
135  long i;
136  int *N;
137  for (i=0; i<ndata; i++) {
138  N = data + i;
139  *N=(((*N>>24)&0xff) | ((*N&0xff)<<24) | ((*N>>8)&0xff00) | ((*N&0xff00)<<8));
140  }
141 }
142 
143 /////////////////////////////// ///////////////////////////////
144 /////////////////////////////// ///////////////////////////////
145 /////////////////////////////// ///////////////////////////////
146 
148  if(basic::resource_manager::ResourceManager::get_instance()->
149  has_resource_with_description("electron_density")){
150 
151  ElectronDensityOP electron_density(
152  basic::resource_manager::get_resource< ElectronDensity >(
153  "electron_density"));
154 
155  return *electron_density;
156  } else {
157  return getDensityMap_legacy();
158  }
159 }
160 
161 //
163  static ElectronDensity theDensityMap;
164 
165 #ifdef GL_GRAPHICS
166  pthread_mutex_lock(&density_map_db_mut_);
167 #endif
168 
169  if (!theDensityMap.isMapLoaded()) {
170  // load map from disk
171  TR << "Loading Density Map" << std::endl;
172  if (!basic::options::option[ basic::options::OptionKeys::edensity::mapfile ].user()) {
173  TR.Warning << "[ Warning ] No density map specified." << std::endl;
174  //TR << "[ ERROR ] Density map score will not be used.\n";
175  //exit(1);
176  } else {
177  std::string mapfile = basic::options::option[ basic::options::OptionKeys::edensity::mapfile ]();
178  core::Real mapreso = basic::options::option[ basic::options::OptionKeys::edensity::mapreso ]();
179  core::Real mapsampling = basic::options::option[ basic::options::OptionKeys::edensity::grid_spacing ]();
180 
181  // Initialize ElectronDensity object
182  bool map_loaded = theDensityMap.readMRCandResize( mapfile , mapreso , mapsampling );
183 
184  if (!map_loaded) {
185  TR << "[ ERROR ] Error loading density map named '" << mapfile << "'" << std::endl;
186  //TR << "[ ERROR ] Density map score will not be used.\n";
187  exit(1);
188  }
189  }
190  }
191 
192 #ifdef GL_GRAPHICS
193  pthread_mutex_unlock(&density_map_db_mut_);
194 #endif
195 
196 
197  return theDensityMap;
198 }
199 
200 
201 /// null constructor
203  init();
204 }
205 
206 
207 // "rho_calc" constructor
209  core::Size nposes = poses.size();
210  this->reso = reso;
211 
212  //1 get bounds
213  numeric::xyzVector< core::Real > d_min(0,0,0), d_max(0,0,0);
214  bool is_set = false;
215  const core::Real FLUFF = 10.0; // add a bounding box
216  for (core::Size n=1; n<=nposes; ++n) {
217  core::pose::Pose &pose = *(poses[n]);
218  int nres = pose.total_residue();
219  //core::Real nCoM=0;
220 
221  for (int i=1 ; i<=nres; ++i) {
222  conformation::Residue const &rsd_i (pose.residue(i));
223  if ( (rsd_i.aa() == core::chemical::aa_vrt) || (scoring_mask_.find(i) != scoring_mask_.end()) ) continue;
224  int nheavyatoms = rsd_i.nheavyatoms();
225  for (int j=1 ; j<=nheavyatoms; ++j) {
226  numeric::xyzVector< core::Real > const &xyz_ij = rsd_i.atom(j).xyz();
227  if (is_missing_density( xyz_ij )) continue;
228  if (!is_set) {
229  d_min = d_max = xyz_ij;
230  is_set = true;
231  }
232  d_min[0] = std::min(d_min[0],xyz_ij[0]); d_min[1] = std::min(d_min[1],xyz_ij[1]); d_min[2] = std::min(d_min[2],xyz_ij[2]);
233  d_max[0] = std::max(d_max[0],xyz_ij[0]); d_max[1] = std::max(d_max[1],xyz_ij[1]); d_max[2] = std::max(d_max[2],xyz_ij[2]);
234  }
235  }
236  }
237 
238  // figure out our grid
239  numeric::xyzVector< core::Real > extent = ( (d_max - d_min) + 2*FLUFF)/apix;
240  grid[0] = findSampling5(extent[0], 2);
241  grid[1] = findSampling5(extent[1], 2);
242  grid[2] = findSampling5(extent[2], 2);
244  real_apix[0] = ( (d_max[0] - d_min[0]) + 2*FLUFF) / ((core::Real)grid[0]);
245  real_apix[1] = ( (d_max[1] - d_min[1]) + 2*FLUFF) / ((core::Real)grid[1]);
246  real_apix[2] = ( (d_max[2] - d_min[2]) + 2*FLUFF) / ((core::Real)grid[2]);
247 
248  // make fake crystal data
249  cellAngles[0] = cellAngles[1] = cellAngles[2] = 90;
250  cellDimensions[0] = grid[0]*real_apix[0];
251  cellDimensions[1] = grid[1]*real_apix[1];
252  cellDimensions[2] = grid[2]*real_apix[2];
253  computeCrystParams();
254  TR << " celldim: " << cellDimensions[0] << " x " << cellDimensions[1] << " x " << cellDimensions[2] << std::endl;
255  TR << " cellangles: " << cellAngles[0] << " x " << cellAngles[1] << " x " << cellAngles[2] << std::endl;
256 
257  // find the origin
258  numeric::xyzVector< core::Real > frac_dmin = c2f*(d_min - FLUFF);
259  origin[0] = std::floor(frac_dmin[0]*grid[0]);
260  origin[1] = std::floor(frac_dmin[1]*grid[1]);
261  origin[2] = std::floor(frac_dmin[2]*grid[2]);
262  efforigin = origin;
263 
264  // atom_mask
265  OneGaussianScattering cscat = get_A( "C" );
266  core::Real mask_min = 2.0 * sqrt( 2.0 / cscat.k(PattersonB,reso/2) ); //?
267  TR.Warning << "ATOM_MASK: " << mask_min << std::endl;
268  ATOM_MASK = mask_min;
269 
270  // 2 rho_calc
271  density.dimension(grid[0],grid[1],grid[2]);
272  for (int i=0; i<density.u1()*density.u2()*density.u3(); ++i) density[i]=0.0;
274  numeric::xyzVector< core::Real > atm_i, atm_j, del_ij;
275  const core::Real ATOM_MASK_PADDING = 1.5;
276  for (Size n=1; n<=nposes; ++n) {
277  core::pose::Pose &pose = *(poses[n]);
278  int nres = pose.total_residue();
279  for (int i=1 ; i<=nres; ++i) {
280  conformation::Residue const &rsd_i (pose.residue(i));
281 
282  // skip vrts & masked reses
283  if ( rsd_i.aa() == core::chemical::aa_vrt ) continue;
284  if ( scoring_mask_.find(i) != scoring_mask_.end() ) continue;
285  int nheavyatoms = rsd_i.nheavyatoms();
286  for (int j=1 ; j<=nheavyatoms; ++j) {
287  conformation::Atom const &atom_i( rsd_i.atom(j) );
288  chemical::AtomTypeSet const & atom_type_set( rsd_i.atom_type_set() );
289  std::string elt_i = atom_type_set[ rsd_i.atom_type_index( j ) ].element();
290  OneGaussianScattering sig_j = get_A( elt_i );
291  core::Real k = sig_j.k( PattersonB, std::max( apix, reso/2 ) );
292  core::Real C = sig_j.C( k );
293 
294  if ( is_missing_density( atom_i.xyz() ) ) continue;
295  if ( C < 1e-6 ) continue;
296 
297  cartX = atom_i.xyz() - getTransform();
298  fracX = c2f*cartX;
299  atm_i[0] = pos_mod (fracX[0]*grid[0] - origin[0] + 1 , (double)grid[0]);
300  atm_i[1] = pos_mod (fracX[1]*grid[1] - origin[1] + 1 , (double)grid[1]);
301  atm_i[2] = pos_mod (fracX[2]*grid[2] - origin[2] + 1 , (double)grid[2]);
302 
303  for (int z=1; z<=density.u3(); ++z) {
304  atm_j[2] = z;
305  del_ij[2] = (atm_i[2] - atm_j[2]) / grid[2];
306  // wrap-around??
307  if (del_ij[2] > 0.5) del_ij[2]-=1.0;
308  if (del_ij[2] < -0.5) del_ij[2]+=1.0;
309 
310  del_ij[0] = del_ij[1] = 0.0;
311  if ((f2c*del_ij).length_squared() > (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) continue;
312 
313  for (int y=1; y<=density.u2(); ++y) {
314  atm_j[1] = y;
315 
316  // early exit?
317  del_ij[1] = (atm_i[1] - atm_j[1]) / grid[1] ;
318  // wrap-around??
319  if (del_ij[1] > 0.5) del_ij[1]-=1.0;
320  if (del_ij[1] < -0.5) del_ij[1]+=1.0;
321  del_ij[0] = 0.0;
322  if ((f2c*del_ij).length_squared() > (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) continue;
323 
324  for (int x=1; x<=density.u1(); ++x) {
325  atm_j[0] = x;
326 
327  // early exit?
328  del_ij[0] = (atm_i[0] - atm_j[0]) / grid[0];
329  // wrap-around??
330  if (del_ij[0] > 0.5) del_ij[0]-=1.0;
331  if (del_ij[0] < -0.5) del_ij[0]+=1.0;
332 
333  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
334  core::Real d2 = (cart_del_ij).length_squared();
335 
336  if (d2 <= (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) {
337  core::Real atm = C*exp(-k*d2);
338  density(x,y,z) += atm;
339  }
340  }
341  }
342  }
343  }
344  }
345  }
346 }
347 
348 void
350  isLoaded = false;
351 
352  grid = numeric::xyzVector< int >(0,0,0);
353  efforigin = origin = numeric::xyzVector< int >(0,0,0);
354  cellDimensions = numeric::xyzVector< float >(1,1,1);
355  cellAngles = numeric::xyzVector< float >(90,90,90);
356 
357  // command line overrides defaults
358  reso = basic::options::option[ basic::options::OptionKeys::edensity::mapreso ]();
359  ATOM_MASK = basic::options::option[ basic::options::OptionKeys::edensity::atom_mask ]();
360  CA_MASK = basic::options::option[ basic::options::OptionKeys::edensity::ca_mask ]();
361  WINDOW_ = basic::options::option[ basic::options::OptionKeys::edensity::sliding_window ]();
362  score_window_context_ = basic::options::option[ basic::options::OptionKeys::edensity::score_sliding_window_context ]();
363  remap_symm_ = basic::options::option[ basic::options::OptionKeys::edensity::score_symm_complex ]();
364  force_apix_ = basic::options::option[ basic::options::OptionKeys::edensity::force_apix ]();
365 
366  // more defaults
367  DensScoreInMinimizer = true;
368  ExactDerivatives = basic::options::option[ basic::options::OptionKeys::edensity::debug_derivatives ]();
369 
370  PattersonB = basic::options::option[ basic::options::OptionKeys::patterson::model_B ]();
371  PattersonMinR = 3.0;
372  PattersonMaxR = 20.0;
373  if (basic::options::option[ basic::options::OptionKeys::patterson::radius_cutoffs ].user() ) {
374  utility::vector1< core::Real > radius_cuts = basic::options::option[ basic::options::OptionKeys::patterson::radius_cutoffs ]();
375  if (radius_cuts.size() == 1) {
376  PattersonMinR = radius_cuts[1];
377  } else if (radius_cuts.size() >= 2) {
378  PattersonMinR = std::min( radius_cuts[1] , radius_cuts[2] );
379  PattersonMaxR = std::max( radius_cuts[1] , radius_cuts[2] );
380  }
381  }
382 
383  p_extent = p_origin = numeric::xyzVector< core::Real >(0,0,0);
384  p_grid = numeric::xyzVector< core::Size >(0,0,0);
385 
386  // only used when computing exact derivatives
387  NUM_DERIV_H = 0.1;
388  NUM_DERIV_H_CEN = NUM_DERIV_H;
389 }
390 
391 // gradient of density
393  numeric::xyzVector<core::Real> const & idxX ) const {
395  dx[0] = interp_spline( coeff_grad_x, idxX );
396  dx[1] = interp_spline( coeff_grad_y, idxX );
397  dx[2] = interp_spline( coeff_grad_z, idxX );
398  return dx;
399 }
400 
401 
402 /////////////////////////////////////
403 /// Match a residue to the density map, returning correlation coefficient between
404 /// map and pose
406  core::pose::Pose const &pose,
407  std::string axis )
408 {
409  // make sure map is loaded
410  if (!isLoaded) {
411  TR << "[ ERROR ] ElectronDensity::matchPose called but no map is loaded!\n";
413  }
414 
415  core::Size axis_Z = 2, axis_X = 0, axis_Y = 1;
416  if (axis == "X") {
417  axis_Z = 0; axis_X = 1; axis_Y = 2;
418  }
419  if (axis == "Y") {
420  axis_Z = 1; axis_X = 2; axis_Y = 0;
421  }
422 
423  rho_calc.dimension(density.u1() , density.u2() , density.u3());
424  for (int i=0; i<density.u1()*density.u2()*density.u3(); ++i) rho_calc[i]=0.0;
425 
426  int nres = pose.total_residue();
428  numeric::xyzVector< core::Real > atm_i, atm_j, del_ij, atm_idx_ij;
429  core::Real SC_scaling = basic::options::option[ basic::options::OptionKeys::edensity::sc_scaling ]();
430 
431  // stats
432  core::Real maxRadius = 0;
433  core::Real minHeight = 0;
434  core::Real maxHeight = 0;
435  numeric::xyzVector< core::Real > poseCoM(0,0,0);
436  core::Size sum_atoms = 0;
437  for (int i=1 ; i<=nres; ++i) {
438  conformation::Residue const &rsd_i (pose.residue(i));
439  if ( (rsd_i.aa() == core::chemical::aa_vrt) || (scoring_mask_.find(i) != scoring_mask_.end()) ) continue;
440  int nheavyatoms = rsd_i.nheavyatoms();
441  for (int j=1 ; j<=nheavyatoms; ++j) {
442  numeric::xyzVector< core::Real > const &xyz_ij = rsd_i.atom(j).xyz();
443  if (is_missing_density( xyz_ij )) continue;
444  poseCoM = poseCoM + xyz_ij;
445  sum_atoms+=1;
446  }
447  }
448  poseCoM /= sum_atoms;
449 
450  /// 1: rho_c
451  for (int i=1 ; i<=nres; ++i) {
452  conformation::Residue const &rsd_i (pose.residue(i));
453 
454  // skip vrts & masked reses
455  if ( rsd_i.aa() == core::chemical::aa_vrt ) continue;
456  if ( scoring_mask_.find(i) != scoring_mask_.end() ) continue;
457  int nheavyatoms = rsd_i.nheavyatoms();
458 
459  for (int j=1 ; j<=nheavyatoms; ++j) {
460  conformation::Atom const &atm_i( rsd_i.atom(j) );
461  chemical::AtomTypeSet const & atom_type_set( rsd_i.atom_type_set() );
462  std::string elt_i = atom_type_set[ rsd_i.atom_type_index( j ) ].element();
463  OneGaussianScattering sig_j = get_A( elt_i );
464  core::Real k = sig_j.k( PattersonB, max_del_grid );
465  core::Real C = sig_j.C( k );
466 
467  if ( (Size) j > rsd_i.last_backbone_atom())
468  C *= SC_scaling;
469  if ( is_missing_density( atm_i.xyz() ) ) continue;
470  if ( C < 1e-6 ) continue;
471 
472  // stats
473  core::Real thisH = (atm_i.xyz()[axis_Z] - poseCoM[axis_Z]);
474  minHeight = std::min( minHeight , thisH );
475  maxHeight = std::max( maxHeight , thisH );
476 
477  core::Real thisR2 = square(atm_i.xyz()[axis_X] - poseCoM[axis_X]) + square(atm_i.xyz()[axis_Y] - poseCoM[axis_Y]);
478  maxRadius = std::max( maxRadius , thisR2 );
479 
480  cartX = atm_i.xyz() - getTransform();
481  fracX = c2f*cartX;
482  atm_idx_ij[0] = pos_mod (fracX[0]*grid[0] - origin[0] + 1 , (double)grid[0]);
483  atm_idx_ij[1] = pos_mod (fracX[1]*grid[1] - origin[1] + 1 , (double)grid[1]);
484  atm_idx_ij[2] = pos_mod (fracX[2]*grid[2] - origin[2] + 1 , (double)grid[2]);
485 
486  for (int z=1; z<=density.u3(); ++z) {
487  atm_j[2] = z;
488  del_ij[2] = (atm_idx_ij[2] - atm_j[2]) / grid[2];
489  if (del_ij[2] > 0.5) del_ij[2]-=1.0;
490  if (del_ij[2] < -0.5) del_ij[2]+=1.0;
491 
492  del_ij[0] = del_ij[1] = 0.0;
493  if ((f2c*del_ij).length_squared() > (ATOM_MASK+1)*(ATOM_MASK+1)) continue; // early exit
494 
495  for (int y=1; y<=density.u2(); ++y) {
496  atm_j[1] = y;
497 
498  del_ij[1] = (atm_idx_ij[1] - atm_j[1]) / grid[1] ;
499  if (del_ij[1] > 0.5) del_ij[1]-=1.0;
500  if (del_ij[1] < -0.5) del_ij[1]+=1.0;
501  del_ij[0] = 0.0;
502  if ((f2c*del_ij).length_squared() > (ATOM_MASK+1)*(ATOM_MASK+1)) continue; // early exit
503 
504  for (int x=1; x<=density.u1(); ++x) {
505  atm_j[0] = x;
506  del_ij[0] = (atm_idx_ij[0] - atm_j[0]) / grid[0];
507  if (del_ij[0] > 0.5) del_ij[0]-=1.0;
508  if (del_ij[0] < -0.5) del_ij[0]+=1.0;
509 
510  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
511  core::Real d2 = (cart_del_ij).length_squared();
512  if (d2 <= (ATOM_MASK+1)*(ATOM_MASK+1)) {
513  core::Real atm = C*exp(-k*d2);
514  rho_calc(x,y,z) += atm;
515  }
516  }
517  }
518  }
519  }
520  }
521  maxRadius = sqrt( maxRadius );
522 
523  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
524  ElectronDensity(rho_calc,1.0, numeric::xyzVector< core::Real >(0,0,0), false).writeMRC( "rho_calc.mrc" );
525  ElectronDensity(density,1.0, numeric::xyzVector< core::Real >(0,0,0), false).writeMRC( "rho_obs.mrc" );
526  }
527 
528  /// 2: resample in cylindrical shells
529  core::Real shell_spacing = max_del_grid;
530  core::Size nshells = (core::Size) std::ceil( maxRadius / shell_spacing );
531  core::Size height_samples = (core::Size) std::ceil( (maxHeight-minHeight) / shell_spacing );
532  core::Real height_spacing = (maxHeight-minHeight) / (height_samples-1);
533  core::Size radial_samples = (core::Size) std::ceil( 4*M_PI*maxRadius / shell_spacing ); // 2x oversample
534  core::Real radial_spacing = 2*M_PI/radial_samples;
535  TR << "Realignment with max radius = " << maxRadius << std::endl;
536  TR << " #shells = " << nshells << " ( spacing = " << shell_spacing << ")" << std::endl;
537  TR << " #hsteps = " << height_samples << " ( spacing = " << height_spacing << ")" << std::endl;
538  TR << " #sampls = " << radial_samples << " ( spacing = " << radial_spacing*180/M_PI << "deg )" << std::endl;
539 
540  utility::vector1< ObjexxFCL::FArray1D< double > > rho_o_cyl(nshells*height_samples);
541  utility::vector1< ObjexxFCL::FArray1D< double > > rho_c_cyl(nshells*height_samples);
542  for (int r=0; r<(int)nshells ; ++r ) {
543  for (int h=0; h<(int)height_samples ; ++h ) {
544  rho_o_cyl[r*height_samples+h+1].dimension( radial_samples );
545  rho_c_cyl[r*height_samples+h+1].dimension( radial_samples );
546  }
547  }
548 
549  core::Real sumN=0.0;
550  core::Real sumRhoC=0.0, sumRhoO=0.0;
551  core::Real sumRho2C=0.0, sumRho2O=0.0;
552  core::Real Rwt=0.0;
553  for (int r=0; r<(int)nshells ; ++r ){
554  Rwt = 2*M_PI*(r+1)*shell_spacing;
555 
556  for (int h=0; h<(int)height_samples ; ++h ){
557  cartX[axis_Z] = poseCoM[axis_Z] + minHeight + h*height_spacing;
558 
559  for (int theta=0; theta<(int)radial_samples ; ++theta ){
560  cartX[axis_X] = poseCoM[axis_X] + (r+1)*shell_spacing*cos(theta*radial_spacing);
561  cartX[axis_Y] = poseCoM[axis_Y] + (r+1)*shell_spacing*sin(theta*radial_spacing);
562 
563  fracX = c2f*cartX;
564  atm_idx_ij[0] = pos_mod (fracX[0]*grid[0] - origin[0] + 1 , (double)grid[0]);
565  atm_idx_ij[1] = pos_mod (fracX[1]*grid[1] - origin[1] + 1 , (double)grid[1]);
566  atm_idx_ij[2] = pos_mod (fracX[2]*grid[2] - origin[2] + 1 , (double)grid[2]);
567 
568  core::Real thisRhoO = interp_linear( density , atm_idx_ij );
569  core::Real thisRhoC = interp_linear( rho_calc , atm_idx_ij );
570  rho_o_cyl[r*height_samples+h+1][theta] = thisRhoO;
571  rho_c_cyl[r*height_samples+h+1][theta] = thisRhoC;
572 
573  // stats
574  sumN += Rwt;
575  sumRhoC += Rwt*thisRhoC;
576  sumRhoO += Rwt*thisRhoO;
577  sumRho2C += Rwt*thisRhoC*thisRhoC;
578  sumRho2O += Rwt*thisRhoO*thisRhoO;
579  }
580  }
581  }
582  sumRhoC /= sumN;
583  sumRhoO /= sumN;
584  sumRho2C = std::sqrt( sumRho2C/sumN - sumRhoC*sumRhoC );
585  sumRho2O = std::sqrt( sumRho2O/sumN - sumRhoO*sumRhoO );
586 
587  //TR << "rho_c: mean = " << sumRhoC << " sigma = " << sumRho2C << std::endl;
588  //TR << "rho_o: mean = " << sumRhoO << " sigma = " << sumRho2O << std::endl;
589 
590  /// 3: bunch of 1D ffts to get overlap
591  /// weighted sum over shells
592  ObjexxFCL::FArray1D< double > correl_sum, correl_flip_sum, correl_i;
593  ObjexxFCL::FArray1D< std::complex<double> > FrhoO, FrhoC, Fcorrel_i;
594 
595  correl_sum.dimension( radial_samples, 0.0 );
596  correl_flip_sum.dimension( radial_samples, 0.0 );
597 
598  // standardize
599  for (int r=0; r<(int)nshells ; ++r ) {
600  for (int h=0; h<(int)height_samples ; ++h ){
601  for (int theta=0; theta<(int)radial_samples ; ++theta ){
602  rho_o_cyl[r*height_samples+h+1][theta] = (rho_o_cyl[r*height_samples+h+1][theta]-sumRhoO)/sumRho2O;
603  rho_c_cyl[r*height_samples+h+1][theta] = (rho_c_cyl[r*height_samples+h+1][theta]-sumRhoC)/sumRho2C;
604  }
605  }
606  }
607 
608  Fcorrel_i.dimension( radial_samples );
609  for (int r=0; r<(int)nshells ; ++r ) {
610  Rwt = 2*M_PI*(r+1)*shell_spacing;
611 
612  for (int h=0; h<(int)height_samples ; ++h ){
613  /// 1 check non-flipped
614  // fft convolution
615  numeric::fourier::fft(rho_o_cyl[r*height_samples+h+1], FrhoO);
616  numeric::fourier::fft(rho_c_cyl[r*height_samples+h+1], FrhoC);
617 
618  // rotate Fc to Fo
619  for (int theta=0; theta<(int)radial_samples ; ++theta )
620  Fcorrel_i[theta] = FrhoO[theta] * std::conj( FrhoC[theta] );
621 
622  numeric::fourier::ifft(Fcorrel_i, correl_i);
623 
624  for (int theta=0; theta<(int)radial_samples ; ++theta )
625  correl_sum[theta] += Rwt*correl_i[theta];
626 
627  /// 2 check flipped
628  // fft convolution
629  numeric::fourier::fft(rho_c_cyl[r*height_samples+(height_samples-h)], FrhoC);
630 
631  // rotate Fc to Fo
632  for (int theta=0; theta<(int)radial_samples ; ++theta )
633  Fcorrel_i[theta] = FrhoO[theta] * FrhoC[theta];
634 
635  numeric::fourier::ifft(Fcorrel_i, correl_i);
636 
637  for (int theta=0; theta<(int)radial_samples ; ++theta )
638  correl_flip_sum[theta] += Rwt*correl_i[theta];
639  }
640  }
641 
642  int maxTheta = 0;
643  core::Real flipped=1;
644  core::Real maxCC = -sumN;
645  for (int theta=0; theta<(int)radial_samples ; ++theta ) {
646  if (correl_sum[theta] > maxCC) {
647  maxCC = correl_sum[theta];
648  maxTheta = theta;
649  flipped = 1;
650  }
651  if (correl_flip_sum[theta] > maxCC) {
652  maxCC = correl_flip_sum[theta];
653  maxTheta = theta;
654  flipped = -1;
655  }
656  }
657  TR << "Best alignment at theta = " << maxTheta*radial_spacing*180/M_PI << std::endl;
658  TR << " flip = " << flipped << std::endl;
659  TR << " cc = " << maxCC/sumN << " ( " << maxCC << " / " << sumN << " ) " << std::endl;
660 
661  // finally apply rotation to pose
663  rotation(axis_Z+1,axis_X+1) = 0; rotation(axis_Z+1,axis_Y+1) = 0;
664  rotation(axis_X+1,axis_Z+1) = 0; rotation(axis_Y+1,axis_Z+1) = 0;
665  rotation(axis_Z+1,axis_Z+1) = flipped;
666 
667  rotation(axis_X+1,axis_X+1) = cos(maxTheta*radial_spacing);
668  rotation(axis_X+1,axis_Y+1) = -flipped*sin(maxTheta*radial_spacing);
669  rotation(axis_Y+1,axis_X+1) = sin(maxTheta*radial_spacing);
670  rotation(axis_Y+1,axis_Y+1) = flipped*cos(maxTheta*radial_spacing);
671 
672  return rotation;
673 }
674 
675 
676 
677 /////////////////////////////////////
678 // Match a centroid pose to the density map, returning correlation coefficient between
679 // map and pose.
681  core::pose::Pose const &pose,
683  bool cacheCCs /* = false */)
684 {
685  using namespace numeric::statistics;
686 
687  // make sure map is loaded
688  if (!isLoaded) {
689  TR << "[ ERROR ] ElectronDensity::matchCentroidPose called but no map is loaded!\n";
690  return 0.0;
691  }
692 
693  if (!DensScoreInMinimizer) cacheCCs = false;
694 
695  //ObjexxFCL::FArray3D< double > rho_calc, inv_rho_mask;
696  ObjexxFCL::FArray3D< double > inv_rho_mask;
697  rho_calc.dimension(density.u1() , density.u2() , density.u3());
698  inv_rho_mask.dimension(density.u1() , density.u2() , density.u3());
699  for (int i=0; i<density.u1()*density.u2()*density.u3(); ++i) {
700  rho_calc[i]=0.0;
701  inv_rho_mask[i]=1.0;
702  }
703 
704  int nres = pose.total_residue(); //reses.size();
706  numeric::xyzVector< core::Real > atm_i, atm_j, del_ij;
707 
708  // compute RHO_C --> a gaussian at each CA
709  core::Real effReso = std::max( 2.4+0.8*reso , reso );
710  core::Real k=square(M_PI/effReso);
711  core::Real a=33.0; // treat everything as ALA
712  // maybe change this???
713  core::Real C=a*pow(k/M_PI,1.5);
714 
715  // per-atom derivs
718  utility::vector1< utility::vector1< numeric::xyzVector<core::Real> > > rho_dx_mask(nres), rho_dx_atm(nres);
719 
720  // symmetry
721  bool isSymm = (symmInfo.get() != NULL);
722  bool remapSymm = basic::options::option[ basic::options::OptionKeys::edensity::score_symm_complex ]();
723 
724  ///////////////////////////
725  /// 1 COMPUTE RHO_C, MASK
726  const core::Real ATOM_MASK_PADDING = 1.5;
727  for (int i=1 ; i<=nres; ++i) {
728  conformation::Residue const &rsd_i (pose.residue(i));
729 
730  // skip non-protein residues & masked reses
731  if ( !pose.residue_type(i).is_protein() ) continue;
732  if ( scoring_mask_.find(i) != scoring_mask_.end() ) continue;
733 
734  // symm
735  if (isSymm && !symmInfo->bb_is_independent(i) && !remapSymm) { // should this be fa_...??
736  continue; // only score the independent monomer
737  }
738 
739  conformation::Atom const &atm_i( rsd_i.atom("CA") );
740 
741  // skip randomized residues
742  if ( is_missing_density( atm_i.xyz() ) ) continue;
743 
744  cartX = atm_i.xyz() - getTransform();
745  fracX = c2f*cartX;
746  atm_idx[i][0] = pos_mod (fracX[0]*grid[0] - origin[0] + 1 , (double)grid[0]);
747  atm_idx[i][1] = pos_mod (fracX[1]*grid[1] - origin[1] + 1 , (double)grid[1]);
748  atm_idx[i][2] = pos_mod (fracX[2]*grid[2] - origin[2] + 1 , (double)grid[2]);
749 
750 
751  for (int z=1; z<=density.u3(); ++z) {
752  atm_j[2] = z;
753  del_ij[2] = (atm_idx[i][2] - atm_j[2]) / grid[2];
754  // wrap-around??
755  if (del_ij[2] > 0.5) del_ij[2]-=1.0;
756  if (del_ij[2] < -0.5) del_ij[2]+=1.0;
757 
758  del_ij[0] = del_ij[1] = 0.0;
759  if ((f2c*del_ij).length_squared() > (CA_MASK+ATOM_MASK_PADDING)*(CA_MASK+ATOM_MASK_PADDING)) continue;
760 
761  for (int y=1; y<=density.u2(); ++y) {
762  atm_j[1] = y;
763 
764  // early exit?
765  del_ij[1] = (atm_idx[i][1] - atm_j[1]) / grid[1] ;
766  // wrap-around??
767  if (del_ij[1] > 0.5) del_ij[1]-=1.0;
768  if (del_ij[1] < -0.5) del_ij[1]+=1.0;
769  del_ij[0] = 0.0;
770  if ((f2c*del_ij).length_squared() > (CA_MASK+ATOM_MASK_PADDING)*(CA_MASK+ATOM_MASK_PADDING)) continue;
771 
772  for (int x=1; x<=density.u1(); ++x) {
773  atm_j[0] = x;
774 
775  // early exit?
776  del_ij[0] = (atm_idx[i][0] - atm_j[0]) / grid[0];
777  // wrap-around??
778  if (del_ij[0] > 0.5) del_ij[0]-=1.0;
779  if (del_ij[0] < -0.5) del_ij[0]+=1.0;
780 
781  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
782  core::Real d2 = (cart_del_ij).length_squared();
783 
784  if (d2 <= (CA_MASK+ATOM_MASK_PADDING)*(CA_MASK+ATOM_MASK_PADDING)) {
785  core::Real atm = C*exp(-k*d2);
786  core::Real sigmoid_msk = exp( d2 - (ATOM_MASK)*(ATOM_MASK) );
787  core::Real inv_msk = 1/(1+sigmoid_msk);
788 
789  rho_calc(x,y,z) += atm;
790  inv_rho_mask(x,y,z) *= (1 - inv_msk);
791 
792  if (cacheCCs) {
793  int idx = (z-1)*density.u2()*density.u1() + (y-1)*density.u1() + x-1;
794  rho_dx_pt[i].push_back ( idx );
795  rho_dx_atm[i].push_back ( (-2*k*atm)*cart_del_ij );
796 
797  core::Real eps_i = (1-inv_msk), inv_eps_i;
798  if (eps_i == 0) // divide-by-zero
799  inv_eps_i = sigmoid_msk;
800  else
801  inv_eps_i = 1/eps_i;
802 
803  rho_dx_mask[i].push_back( (-2*sigmoid_msk*inv_msk*inv_msk*inv_eps_i)*cart_del_ij );
804  }
805  }
806  }
807  }
808  }
809  }
810 
811  //////////////////////////
812  /// 2 COMPUTE SUMMARY STATISTICS
813  core::Real sumC_i=0, sumO_i=0, sumCO_i=0, vol_i=0, CC_i=0;
814  core::Real sumO2_i=0.0, sumC2_i=0.0, varC_i=0, varO_i=0;
815  core::Real clc_x, obs_x, eps_x;
816 
817  for (int x=0; x<density.u1()*density.u2()*density.u3(); ++x) {
818  // fetch this point
819  clc_x = rho_calc[x];
820  obs_x = density[x];
821  eps_x = 1-inv_rho_mask[x]; //1/(1+exp( (0.01-rho_calc(x,y,z)) * 1000 )); // sigmoidal
822 
823  // SMOOTHED
824  sumCO_i += eps_x*clc_x*obs_x;
825  sumO_i += eps_x*obs_x;
826  sumO2_i += eps_x*obs_x*obs_x;
827  sumC_i += eps_x*clc_x;
828  sumC2_i += eps_x*clc_x*clc_x;
829  vol_i += eps_x;
830  }
831  varC_i = (sumC2_i - sumC_i*sumC_i / vol_i );
832  varO_i = (sumO2_i - sumO_i*sumO_i / vol_i ) ;
833  if (varC_i == 0 || varO_i == 0)
834  CC_i = 0;
835  else
836  CC_i = (sumCO_i - sumC_i*sumO_i/ vol_i) / sqrt( varC_i * varO_i );
837 
838  if (cacheCCs)
839  CC_cen = CC_i;
840 
841 
842  ///////////////////////////
843  /// 3 CALCULATE SYMMETRIC ROTATION MATRICES + SYMM MAPPING at each level
844  if (isSymm && remapSymm && cacheCCs) {
845  compute_symm_rotations( pose, symmInfo );
846  }
847 
848  ///////////////////////////
849  /// 4 CALCULATE PER-CA DERIVATIVES
850  if (cacheCCs) {
851  std::map< core::Size , numeric::xyzMatrix< core::Real > > symmRots;
852  for (int i=1 ; i<=nres; ++i) {
853  if (isSymm && !symmInfo->bb_is_independent(i) && !remapSymm) { // should this be fa_...??
854  continue; // only score the monomer
855  }
856 
857  conformation::Residue const &rsd_i (pose.residue(i)); //( *reses[i] );
858 
859  //if ( rsd_i.aa() == core::chemical::aa_vrt ) continue;
860  if ( !pose.residue_type(i).is_protein() ) continue;
861  if ( scoring_mask_.find(i) != scoring_mask_.end() ) continue;
862 
863  numeric::xyzVector< core::Real > dVdx_ij(0,0,0), dOdx_ij(0,0,0), dO2dx_ij(0,0,0), dCOdx_ij(0,0,0), dC2dx_ij(0,0,0);
864 
865  conformation::Atom const &atm_i( rsd_i.atom("CA") );
866  if ( is_missing_density( atm_i.xyz() ) ) continue;
867 
868  utility::vector1< int > const &rho_dx_pt_ij = rho_dx_pt[i];
869  utility::vector1< numeric::xyzVector<core::Real> > const &rho_dx_mask_ij = rho_dx_mask[i];
870  utility::vector1< numeric::xyzVector<core::Real> > const &rho_dx_atm_ij = rho_dx_atm[i];
871 
872  int npoints = rho_dx_pt_ij.size();
873  for (int n=1; n<=npoints; ++n) {
874  const int x(rho_dx_pt_ij[n]);
875  clc_x = rho_calc[x];
876  obs_x = density[x];
877  core::Real inv_eps_x = inv_rho_mask[x];
878 
879  numeric::xyzVector<double> del_mask = inv_eps_x*rho_dx_mask_ij[n];
880  numeric::xyzVector<double> del_rhoc = rho_dx_atm_ij[n];
881 
882  dVdx_ij += del_mask;
883  dOdx_ij += del_mask*obs_x;
884  dO2dx_ij += del_mask*obs_x*obs_x;
885  dCOdx_ij += del_rhoc*obs_x;
886  dC2dx_ij += 2.0*del_rhoc*clc_x;
887  }
888 
889  // finally compute dCC/dx_ij
890  core::Real f = ( sumCO_i - sumC_i*sumO_i / vol_i );
891  core::Real g = sqrt ( varO_i * varC_i );
892 
893  numeric::xyzVector<core::Real> fprime = dCOdx_ij - 1/(vol_i*vol_i) * ( dOdx_ij*sumC_i*vol_i - sumO_i*sumC_i*dVdx_ij);
894  numeric::xyzVector<core::Real> gprime = 0.5 * (
895  sqrt(varO_i)/sqrt(varC_i) * ( dC2dx_ij + ( sumC_i*sumC_i*dVdx_ij/(vol_i*vol_i) ) ) +
896  sqrt(varC_i)/sqrt(varO_i) * ( dO2dx_ij - ( 1/(vol_i*vol_i) * ( 2*vol_i*sumO_i*dOdx_ij - sumO_i*sumO_i*dVdx_ij ) ) ) );
897 
898  dCCdxs_cen[i] = (g*fprime - f*gprime) / (g*g);
899  }
900  }
901  // >> debugging <<
902  //ElectronDensity(rho_calc, 2.0).writeMRC( "rho_calc.mrc" );
903  //ElectronDensity(inv_rho_mask, 2.0).writeMRC( "inv_rho_mask.mrc" );
904  //exit(1);
905 
906  //std::cerr << "ElectronDensity::matchCentroidPose() returning CC = " << CC_i << " vol = " << vol_i << std::endl;
907 
908  return CC_i;
909 }
910 
911 
912 /////////////////////////////////////
913 /// Match a residue to the density map, returning correlation coefficient between
914 /// map and pose
916  core::pose::Pose const &pose,
918  bool cacheCCs/*=false*/ )
919 {
920  using namespace numeric::statistics;
921 
922  // make sure map is loaded
923  if (!isLoaded) {
924  TR << "[ ERROR ] ElectronDensity::matchPose called but no map is loaded!\n";
925  return 0.0;
926  }
927 
928  if (!DensScoreInMinimizer) cacheCCs = false;
929 
930  //ObjexxFCL::FArray3D< double > rho_calc, inv_rho_mask;
931  ObjexxFCL::FArray3D< double > inv_rho_mask;
932  rho_calc.dimension(density.u1() , density.u2() , density.u3());
933  inv_rho_mask.dimension(density.u1() , density.u2() , density.u3());
934  for (int i=0; i<density.u1()*density.u2()*density.u3(); ++i) {
935  rho_calc[i]=0.0;
936  inv_rho_mask[i]=1.0;
937  }
938 
939  int nres = pose.total_residue(); //reses.size();
941  numeric::xyzVector< core::Real > atm_i, atm_j, del_ij;
942 
943  core::Real SC_scaling = basic::options::option[ basic::options::OptionKeys::edensity::sc_scaling ]();
944 
945  // per-atom derivs
949 
950  // symmetry
951  bool isSymm = (symmInfo.get() != NULL);
952  bool remapSymm = basic::options::option[ basic::options::OptionKeys::edensity::score_symm_complex ]();
953 
954  ///////////////////////////
955  /// 1 COMPUTE RHO_C, MASK
956  const core::Real ATOM_MASK_PADDING = 1.5;
957  for (int i=1 ; i<=nres; ++i) {
958  conformation::Residue const &rsd_i (pose.residue(i)); //( *reses[i] );
959 
960  // skip vrts & masked reses
961  if ( rsd_i.aa() == core::chemical::aa_vrt ) continue;
962  if ( scoring_mask_.find(i) != scoring_mask_.end() ) continue;
963 
964  // symm
965  if (isSymm && !symmInfo->bb_is_independent(i) && !remapSymm) { // should this be fa_...??
966  continue; // only score the independent monomer
967  }
968 
969  int nheavyatoms = rsd_i.nheavyatoms();
970  //int nheavyatoms = rsd_i.last_backbone_atom();
971 
972  atm_idx[i].resize(nheavyatoms);
973  rho_dx_pt[i].resize(nheavyatoms);
974  rho_dx_mask[i].resize(nheavyatoms);
975  rho_dx_atm[i].resize(nheavyatoms);
976 
977  for (int j=1 ; j<=nheavyatoms; ++j) {
978  conformation::Atom const &atm_i( rsd_i.atom(j) ); //(pose.residue(i).atom("CA"));
979 
980  chemical::AtomTypeSet const & atom_type_set( rsd_i.atom_type_set() );
981  std::string elt_i = atom_type_set[ rsd_i.atom_type_index( j ) ].element();
982  OneGaussianScattering sig_j = get_A( elt_i );
983  core::Real k = sig_j.k( PattersonB, max_del_grid );
984  core::Real C = sig_j.C( k );
985 
986  // sidechain weight
987  if ( (Size) j > rsd_i.last_backbone_atom())
988  C *= SC_scaling;
989 
990  // skip randomized residues
991  if ( is_missing_density( atm_i.xyz() ) ) continue;
992 
993  // if this atom's weight is 0 continue
994  if ( C < 1e-6 ) continue;
995 
996  cartX = atm_i.xyz() - getTransform();
997  fracX = c2f*cartX;
998  atm_idx[i][j][0] = pos_mod (fracX[0]*grid[0] - origin[0] + 1 , (double)grid[0]);
999  atm_idx[i][j][1] = pos_mod (fracX[1]*grid[1] - origin[1] + 1 , (double)grid[1]);
1000  atm_idx[i][j][2] = pos_mod (fracX[2]*grid[2] - origin[2] + 1 , (double)grid[2]);
1001 
1002 
1003  for (int z=1; z<=density.u3(); ++z) {
1004  atm_j[2] = z;
1005  del_ij[2] = (atm_idx[i][j][2] - atm_j[2]) / grid[2];
1006  // wrap-around??
1007  if (del_ij[2] > 0.5) del_ij[2]-=1.0;
1008  if (del_ij[2] < -0.5) del_ij[2]+=1.0;
1009 
1010  del_ij[0] = del_ij[1] = 0.0;
1011  if ((f2c*del_ij).length_squared() > (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) continue;
1012 
1013  for (int y=1; y<=density.u2(); ++y) {
1014  atm_j[1] = y;
1015 
1016  // early exit?
1017  del_ij[1] = (atm_idx[i][j][1] - atm_j[1]) / grid[1] ;
1018  // wrap-around??
1019  if (del_ij[1] > 0.5) del_ij[1]-=1.0;
1020  if (del_ij[1] < -0.5) del_ij[1]+=1.0;
1021  del_ij[0] = 0.0;
1022  if ((f2c*del_ij).length_squared() > (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) continue;
1023 
1024  for (int x=1; x<=density.u1(); ++x) {
1025  atm_j[0] = x;
1026 
1027  // early exit?
1028  del_ij[0] = (atm_idx[i][j][0] - atm_j[0]) / grid[0];
1029  // wrap-around??
1030  if (del_ij[0] > 0.5) del_ij[0]-=1.0;
1031  if (del_ij[0] < -0.5) del_ij[0]+=1.0;
1032 
1033  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
1034  core::Real d2 = (cart_del_ij).length_squared();
1035 
1036  if (d2 <= (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) {
1037  // v1 ... just use this it's way faster
1038  core::Real atm = C*exp(-k*d2);
1039  // v2 ... is this ok for non-orthogonal???
1040  //core::Real atm = C*a*exp(-k)*grid[0]*grid[1]*grid[2]*
1041  // ( (errf( cart_del_ij[0]+0.5/grid[0] )-errf( cart_del_ij[0]-0.5/grid[0] ))*
1042  // (errf( cart_del_ij[1]+0.5/grid[1] )-errf( cart_del_ij[1]-0.5/grid[1] ))*
1043  // (errf( cart_del_ij[2]+0.5/grid[2] )-errf( cart_del_ij[2]-0.5/grid[2] )) );
1044  core::Real sigmoid_msk = exp( d2 - (ATOM_MASK)*(ATOM_MASK) );
1045  core::Real inv_msk = 1/(1+sigmoid_msk);
1046 
1047  rho_calc(x,y,z) += atm;
1048  inv_rho_mask(x,y,z) *= (1 - inv_msk);
1049 
1050  if (cacheCCs) {
1051  int idx = (z-1)*density.u2()*density.u1() + (y-1)*density.u1() + x-1;
1052 
1053  core::Real eps_i = (1-inv_msk), inv_eps_i;
1054  if (eps_i == 0) // divide-by-zero
1055  inv_eps_i = sigmoid_msk;
1056  else
1057  inv_eps_i = 1/eps_i;
1058 
1059  rho_dx_pt[i][j].push_back ( idx );
1060  rho_dx_atm[i][j].push_back ( (-2*k*atm)*cart_del_ij );
1061  rho_dx_mask[i][j].push_back( (-2*sigmoid_msk*inv_msk*inv_msk*inv_eps_i)*cart_del_ij );
1062  }
1063  }
1064  }
1065  }
1066  }
1067  }
1068  }
1069 
1070  //////////////////////////
1071  /// 2 COMPUTE SUMMARY STATISTICS
1072  core::Real sumC_i=0, sumO_i=0, sumCO_i=0, vol_i=0, CC_i=0;
1073  core::Real sumO2_i=0.0, sumC2_i=0.0, varC_i=0, varO_i=0;
1074  core::Real clc_x, obs_x, eps_x;
1075 
1076  for (int x=0; x<density.u1()*density.u2()*density.u3(); ++x) {
1077  // fetch this point
1078  clc_x = rho_calc[x];
1079  obs_x = density[x];
1080  eps_x = 1-inv_rho_mask[x]; //1/(1+exp( (0.01-rho_calc(x,y,z)) * 1000 )); // sigmoidal
1081 
1082  // SMOOTHED
1083  sumCO_i += eps_x*clc_x*obs_x;
1084  sumO_i += eps_x*obs_x;
1085  sumO2_i += eps_x*obs_x*obs_x;
1086  sumC_i += eps_x*clc_x;
1087  sumC2_i += eps_x*clc_x*clc_x;
1088  vol_i += eps_x;
1089  }
1090  varC_i = (sumC2_i - sumC_i*sumC_i / vol_i );
1091  varO_i = (sumO2_i - sumO_i*sumO_i / vol_i ) ;
1092  if (varC_i == 0 || varO_i == 0)
1093  CC_i = 0;
1094  else
1095  CC_i = (sumCO_i - sumC_i*sumO_i/ vol_i) / sqrt( varC_i * varO_i );
1096 
1097  if (cacheCCs)
1098  CC_aacen = CC_i;
1099 
1100 
1101  ///////////////////////////
1102  /// 3 CALCULATE SYMMETRIC ROTATION MATRICES + SYMM MAPPING at each level
1103  if (isSymm && remapSymm && cacheCCs) {
1104  compute_symm_rotations( pose, symmInfo );
1105  }
1106 
1107 
1108  ///////////////////////////
1109  /// 4 CALCULATE PER-ATOM DERIVATIVES
1110  if (cacheCCs) {
1111  std::map< core::Size , numeric::xyzMatrix< core::Real > > symmRots;
1112  for (int i=1 ; i<=nres; ++i) {
1113  if (isSymm && !symmInfo->bb_is_independent(i) && !remapSymm) { // should this be fa_...??
1114  continue; // only score the monomer
1115  }
1116 
1117  conformation::Residue const &rsd_i (pose.residue(i)); //( *reses[i] );
1118 
1119  if ( rsd_i.aa() == core::chemical::aa_vrt ) continue;
1120  if ( scoring_mask_.find(i) != scoring_mask_.end() ) continue;
1121 
1122  int nheavyatoms = atm_idx[i].size();
1123  dCCdxs_aacen[i].resize( nheavyatoms, numeric::xyzVector< core::Real >(0,0,0) );
1124 
1125  for (int j=1 ; j<=nheavyatoms; ++j) {
1126  numeric::xyzVector< core::Real > dVdx_ij(0,0,0), dOdx_ij(0,0,0), dO2dx_ij(0,0,0), dCOdx_ij(0,0,0), dC2dx_ij(0,0,0);
1127 
1128  conformation::Atom const &atm_i( rsd_i.atom(j) );
1129  if ( is_missing_density( atm_i.xyz() ) ) continue;
1130 
1131  chemical::AtomTypeSet const & atom_type_set( rsd_i.atom_type_set() );
1132  std::string elt_i = atom_type_set[ rsd_i.atom_type_index( j ) ].element();
1133 
1134  utility::vector1< int > const &rho_dx_pt_ij = rho_dx_pt[i][j];
1135  utility::vector1< numeric::xyzVector<core::Real> > const &rho_dx_mask_ij = rho_dx_mask[i][j];
1136  utility::vector1< numeric::xyzVector<core::Real> > const &rho_dx_atm_ij = rho_dx_atm[i][j];
1137 
1138  int npoints = rho_dx_pt_ij.size();
1139  for (int n=1; n<=npoints; ++n) {
1140  const int x(rho_dx_pt_ij[n]);
1141  clc_x = rho_calc[x];
1142  obs_x = density[x];
1143  core::Real inv_eps_x = inv_rho_mask[x];
1144 
1145  numeric::xyzVector<double> del_mask = inv_eps_x*rho_dx_mask_ij[n];
1146  numeric::xyzVector<double> del_rhoc = rho_dx_atm_ij[n];
1147 
1148  dVdx_ij += del_mask;
1149  dOdx_ij += del_mask*obs_x;
1150  dO2dx_ij += del_mask*obs_x*obs_x;
1151  dCOdx_ij += del_rhoc*obs_x;
1152  dC2dx_ij += 2.0*del_rhoc*clc_x;
1153  }
1154 
1155  // finally compute dCC/dx_ij
1156  core::Real f = ( sumCO_i - sumC_i*sumO_i / vol_i );
1157  core::Real g = sqrt ( varO_i * varC_i );
1158 
1159  numeric::xyzVector<core::Real> fprime = dCOdx_ij - 1/(vol_i*vol_i) * ( dOdx_ij*sumC_i*vol_i - sumO_i*sumC_i*dVdx_ij);
1160  numeric::xyzVector<core::Real> gprime = 0.5 * (
1161  sqrt(varO_i)/sqrt(varC_i) * ( dC2dx_ij + ( sumC_i*sumC_i*dVdx_ij/(vol_i*vol_i) ) ) +
1162  sqrt(varC_i)/sqrt(varO_i) * ( dO2dx_ij - ( 1/(vol_i*vol_i) * ( 2*vol_i*sumO_i*dOdx_ij - sumO_i*sumO_i*dVdx_ij ) ) ) );
1163 
1164  dCCdxs_aacen[i][j] = (g*fprime - f*gprime) / (g*g);
1165  }
1166  }
1167  }
1168  // >> debugging <<
1169  //ElectronDensity(rho_calc, 2.0).writeMRC( "rho_calc.mrc" );
1170  //ElectronDensity(inv_rho_mask, 2.0).writeMRC( "rho_mask_inv.mrc" );
1171  //std::cerr << "ElectronDensity::matchPose() returning CC = " << CC_i << " vol = " << vol_i << std::endl;
1172 
1173  return CC_i;
1174 }
1175 
1177  numeric::xyzVector<core::Real> const & cartX1,
1178  numeric::xyzVector<core::Real> const & cartX2) {
1179  numeric::xyzVector<core::Real> fracX1, fracX2, delt_cart;
1180 
1181  numeric::xyzVector<core::Real> delt_fracX(c2f*(cartX1-cartX2));
1182  for (Size i=0; i<3; ++i) {
1183  while (delt_fracX[i] > 0.5) delt_fracX[i]-=1.0;
1184  while (delt_fracX[i] < -0.5) delt_fracX[i]+=1.0;
1185  }
1186  delt_cart = f2c*delt_fracX;
1187 
1188  //using namespace ObjexxFCL::fmt;
1189  //TR << F(8,3,delt_fracX.x()) << F(8,3,delt_fracX.y()) << F(8,3,delt_fracX.z());
1190  //TR << F(8,3,delt_cart.x()) << F(8,3,delt_cart.y()) << F(8,3,delt_cart.z()) << std::endl;
1191 
1192  //TR << delt_fracX << std::endl;
1193  //TR << f2c.row_x() << std::endl;
1194  //TR << f2c.row_y() << std::endl;
1195  //TR << f2c.row_z() << std::endl;
1196  //TR << delt_cart<< std::endl;
1197 
1198  return delt_cart;
1199 }
1200 
1202  numeric::xyzVector<core::Real> const & cartX_in,
1203  numeric::xyzVector<core::Real> const & cartX_ref) {
1204  // find a copy of cartX_in in any unit cell that is closest to cartX_ref
1205  core::Real distance_squared = cartX_in.distance_squared(cartX_ref);
1206  numeric::xyzVector<core::Real> cartX_out(cartX_in);
1207 
1208  bool searching(true);
1209  while (searching) {
1210  searching = false;
1211  numeric::xyzVector<core::Real> fracX(c2f*cartX_out);
1212 
1213  numeric::xyzVector<core::Real> shift(-1,-1,-1);
1214  for (shift[0] = -1; shift[0] < 1.1; shift[0] += 1) {
1215  for (shift[1] = -1; shift[1] < 1.1; shift[1] += 1) {
1216  for (shift[2] = -1; shift[2] < 1.1; shift[2] += 1) {
1217  if (shift.length_squared() < 0.1) continue;
1218 
1219  numeric::xyzVector<core::Real> fracX_copy(fracX+shift);
1220  numeric::xyzVector<core::Real> cartX_copy = f2c*fracX_copy;
1221 
1222  if (cartX_copy.distance_squared(cartX_ref) < distance_squared) {
1223  searching = true;
1224  cartX_out = cartX_copy;
1225  distance_squared = cartX_copy.distance_squared(cartX_ref);
1226  }
1227  }
1228  }
1229  }
1230  }
1231  return cartX_out;
1232 }
1233 
1234 
1236  numeric::xyzVector<core::Real> const & cartX) {
1237  numeric::xyzVector<core::Real> fracX(c2f*cartX);
1238  for (Size i=0; i<3; ++i) {
1239  while (fracX[i] > 0.5) fracX[i]-=1.0;
1240  while (fracX[i] < -0.5) fracX[i]+=1.0;
1241  }
1242  numeric::xyzVector<core::Real> cartX_uc = f2c*fracX;
1243  return cartX_uc;
1244 }
1245 
1246 
1247 /////////////////////////////////////
1248 /// get Fdrho_d(xyz)
1249 /// compute if not already computed
1250 /// returns pointers to FArray
1252  // x0 = mod(X+cryst(1)/2,cryst(1))-cryst(1)/2;
1253  // drhox = 4*C*k*(x0).*exp( -k*( x0.^2 ) );
1254  int atmid = S.a();
1255  std::map< int,ObjexxFCL::FArray3D< std::complex<double> > >::const_iterator itx = Fdrhoc_dx.find( atmid );
1256 
1257  if (itx == Fdrhoc_dx.end()) {
1258  ObjexxFCL::FArray3D<double> drhoc_dx,drhoc_dy,drhoc_dz;
1260 
1261  core::Real k = S.k( PattersonB, max_del_grid );
1262  core::Real C = S.C( k );
1263 
1264  drhoc_dx.dimension(p_grid[0], p_grid[1], p_grid[2]);
1265  drhoc_dy.dimension(p_grid[0], p_grid[1], p_grid[2]);
1266  drhoc_dz.dimension(p_grid[0], p_grid[1], p_grid[2]);
1267  for (int z=1; z<=(int)p_grid[2]; ++z) {
1268  if (z < (int)p_grid[2]/2)
1269  del_ij[2] = ((core::Real)z - 1.0) / grid[2];
1270  else
1271  del_ij[2] = (((core::Real)z - p_grid[2] - 1.0)) / grid[2];
1272  for (int y=1; y<=(int)p_grid[1]; ++y) {
1273  if (y < (int)p_grid[1]/2)
1274  del_ij[1] = ((core::Real)y - 1.0) / grid[1] ;
1275  else
1276  del_ij[1] = (((core::Real)y - p_grid[1] - 1.0)) / grid[1];
1277  for (int x=1; x<=(int)p_grid[0]; ++x) {
1278  if (x < (int)p_grid[0]/2)
1279  del_ij[0] = ((core::Real)x - 1.0) / grid[0];
1280  else
1281  del_ij[0] = (((core::Real)x - p_grid[0] - 1.0)) / grid[0];
1282 
1283  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij);
1284  core::Real d2 = (cart_del_ij).length_squared();
1285 
1286  drhoc_dx(x,y,z) = cart_del_ij[0] * 4*C*k*exp( -k*d2 );
1287  drhoc_dy(x,y,z) = cart_del_ij[1] * 4*C*k*exp( -k*d2 );
1288  drhoc_dz(x,y,z) = cart_del_ij[2] * 4*C*k*exp( -k*d2 );
1289  }
1290  }
1291  }
1292 
1293  // ffts
1294  Fdrhoc_dx[atmid] = ObjexxFCL::FArray3D< std::complex<double> >();
1295  Fdrhoc_dy[atmid] = ObjexxFCL::FArray3D< std::complex<double> >();
1296  Fdrhoc_dz[atmid] = ObjexxFCL::FArray3D< std::complex<double> >();
1297 
1298  numeric::fourier::fft3(drhoc_dx, Fdrhoc_dx[atmid]);
1299  numeric::fourier::fft3(drhoc_dy, Fdrhoc_dy[atmid]);
1300  numeric::fourier::fft3(drhoc_dz, Fdrhoc_dz[atmid]);
1301  }
1302 
1304  retval.push_back( &Fdrhoc_dx[atmid] );
1305  retval.push_back( &Fdrhoc_dy[atmid] );
1306  retval.push_back( &Fdrhoc_dz[atmid] );
1307 
1308  return retval;
1309 }
1310 
1311 
1312 /////////////////////////////////////
1313 /// setup oversampled maps for fast density scoring
1315  // oversample rho_obs
1316  ObjexxFCL::FArray3D< double > rho_obs_oversample;
1317 
1318  fastgrid[0] = findSampling( 2*grid[0], MINMULT[0] );
1319  fastgrid[1] = findSampling( 2*grid[1], MINMULT[1] );
1320  fastgrid[2] = findSampling( 2*grid[2], MINMULT[2] );
1321 
1322  fastorigin[0] = fastgrid[0]*origin[0] / ((core::Real)grid[0]);
1323  fastorigin[1] = fastgrid[1]*origin[1] / ((core::Real)grid[1]);
1324  fastorigin[2] = fastgrid[2]*origin[2] / ((core::Real)grid[2]);
1325 
1326  resample( density, rho_obs_oversample, fastgrid );
1327  TR << "Resizing " << density.u1() << "x" << density.u2() << "x" << density.u3() << " to "
1328  << rho_obs_oversample.u1() << "x" << rho_obs_oversample.u2() << "x" << rho_obs_oversample.u3() << std::endl;
1329 
1330  // convolute with calculated density
1331  ObjexxFCL::FArray3D< double > rhoc, drhoc_dx, drhoc_dy, drhoc_dz;
1332  OneGaussianScattering S = get_A( "C" );
1333  //int atmid = S.a();
1334 
1336  core::Real k = S.k( PattersonB, max_del_grid );
1337  //core::Real C = S.C( k );
1338 
1339  core::Size natms=0,nres=0;
1340  for (core::Size i=1; i<=pose.total_residue(); ++i) {
1341  if ( pose.residue(i).aa() == core::chemical::aa_vrt ) continue;
1342  nres++;
1343  core::conformation::Residue const& rsd_i = pose.residue(i);
1344  natms += rsd_i.nheavyatoms();
1345  }
1346  //core::Real grid_scale = (V*nres) / ((core::Real)(natms*fastgrid[0]*fastgrid[1]*fastgrid[2]));
1347 
1348  rhoc.dimension(fastgrid[0], fastgrid[1], fastgrid[2]);
1349  drhoc_dx.dimension(fastgrid[0], fastgrid[1], fastgrid[2]);
1350  drhoc_dy.dimension(fastgrid[0], fastgrid[1], fastgrid[2]);
1351  drhoc_dz.dimension(fastgrid[0], fastgrid[1], fastgrid[2]);
1352  for (int z=1; z<=(int)fastgrid[2]; ++z) {
1353  if (z < (int)fastgrid[2]/2)
1354  del_ij[2] = ((core::Real)z - 1.0) / fastgrid[2];
1355  else
1356  del_ij[2] = (((core::Real)z - fastgrid[2] - 1.0)) / fastgrid[2];
1357  for (int y=1; y<=(int)fastgrid[1]; ++y) {
1358  if (y < (int)fastgrid[1]/2)
1359  del_ij[1] = ((core::Real)y - 1.0) / fastgrid[1] ;
1360  else
1361  del_ij[1] = (((core::Real)y - fastgrid[1] - 1.0)) / fastgrid[1];
1362  for (int x=1; x<=(int)fastgrid[0]; ++x) {
1363  if (x < (int)fastgrid[0]/2)
1364  del_ij[0] = ((core::Real)x - 1.0) / fastgrid[0];
1365  else
1366  del_ij[0] = (((core::Real)x - fastgrid[0] - 1.0)) / fastgrid[0];
1367  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij);
1368 
1369  core::Real d2 = (cart_del_ij).length_squared();
1370 
1371  rhoc(x,y,z) = exp(-k*d2);
1372  drhoc_dx(x,y,z) = -cart_del_ij[0] * 2*k*exp( -k*d2 );
1373  drhoc_dy(x,y,z) = -cart_del_ij[1] * 2*k*exp( -k*d2 );
1374  drhoc_dz(x,y,z) = -cart_del_ij[2] * 2*k*exp( -k*d2 );
1375  }
1376  }
1377  }
1378 
1379  ObjexxFCL::FArray3D< std::complex<double> > Frhoo, Frhoc, Fdrhoc_dx, Fdrhoc_dy, Fdrhoc_dz;
1380 
1381  // ffts
1382  numeric::fourier::fft3(rho_obs_oversample, Frhoo);
1383  numeric::fourier::fft3(rhoc, Frhoc);
1384  numeric::fourier::fft3(drhoc_dx, Fdrhoc_dx);
1385  numeric::fourier::fft3(drhoc_dy, Fdrhoc_dy);
1386  numeric::fourier::fft3(drhoc_dz, Fdrhoc_dz);
1387 
1388  // convolute
1389  for (int i=1; i<=rho_obs_oversample.u1(); i++)
1390  for (int j=1; j<=rho_obs_oversample.u2(); j++)
1391  for (int k=1; k<=rho_obs_oversample.u3(); k++) {
1392  Frhoc(i,j,k) *= ( Frhoo(i,j,k) );
1393  Fdrhoc_dx(i,j,k) *= ( Frhoo(i,j,k) );
1394  Fdrhoc_dy(i,j,k) *= ( Frhoo(i,j,k) );
1395  Fdrhoc_dz(i,j,k) *= ( Frhoo(i,j,k) );
1396  }
1397 
1398  numeric::fourier::ifft3( Frhoc , fastdens_score );
1399  numeric::fourier::ifft3( Fdrhoc_dx , fastdens_dscoredx );
1400  numeric::fourier::ifft3( Fdrhoc_dy , fastdens_dscoredy );
1401  numeric::fourier::ifft3( Fdrhoc_dz , fastdens_dscoredz );
1402 
1403  // scale 'fastdens_score' so that the best score is nres/natms
1404  // worst is -nres/natms
1405  core::Real valMin=1e30, valMax=-1e30, mu, sigma;
1406  for (int i=1; i<=rho_obs_oversample.u1(); i++)
1407  for (int j=1; j<=rho_obs_oversample.u2(); j++)
1408  for (int k=1; k<=rho_obs_oversample.u3(); k++) {
1409  valMin = std::min(valMin,fastdens_score(i,j,k));
1410  valMax = std::max(valMax,fastdens_score(i,j,k));
1411  }
1412  sigma = 0.5*(natms/nres)*(valMax-valMin);
1413  mu = 0.5*(valMin+valMax);
1414  for (int i=1; i<=rho_obs_oversample.u1(); i++)
1415  for (int j=1; j<=rho_obs_oversample.u2(); j++)
1416  for (int k=1; k<=rho_obs_oversample.u3(); k++) {
1417  fastdens_score(i,j,k) = ( fastdens_score(i,j,k) - mu ) / sigma;
1418  fastdens_dscoredx(i,j,k) = ( fastdens_dscoredx(i,j,k) ) / sigma;
1419  fastdens_dscoredy(i,j,k) = ( fastdens_dscoredy(i,j,k) ) / sigma;
1420  fastdens_dscoredz(i,j,k) = ( fastdens_dscoredz(i,j,k) ) / sigma;
1421  }
1422 
1423  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
1424  ElectronDensity(rho_obs_oversample,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "fastdens_rhoobs.mrc");
1425  ElectronDensity(fastdens_score,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "fastdens_score.mrc");
1426  ElectronDensity(fastdens_dscoredx,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "fastdens_dscoredx.mrc");
1427  ElectronDensity(fastdens_dscoredy,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "fastdens_dscoredy.mrc");
1428  ElectronDensity(fastdens_dscoredz,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "fastdens_dscoredz.mrc");
1429  }
1430 
1431  // spline coeffs
1432  ObjexxFCL::FArray3D< double > temp_coeffs;
1433  spline_coeffs( fastdens_score, temp_coeffs); fastdens_score = temp_coeffs;
1434  spline_coeffs( fastdens_dscoredx, temp_coeffs); fastdens_dscoredx = temp_coeffs;
1435  spline_coeffs( fastdens_dscoredy, temp_coeffs); fastdens_dscoredy = temp_coeffs;
1436  spline_coeffs( fastdens_dscoredz, temp_coeffs); fastdens_dscoredz = temp_coeffs;
1437 }
1438 
1439 
1440 
1441 
1442 /////////////////////////////////////
1443 /// Precomputes a bunch of stuff for patterson map scoring
1445  bool is_set=false;
1446  int nres = pose.total_residue(); //reses.size();
1447  const core::Real FLUFF = 10.0;
1449  core::Real nCoM=0;
1450 
1451  for (int i=1 ; i<=nres; ++i) {
1452  conformation::Residue const &rsd_i (pose.residue(i));
1453  if ( (rsd_i.aa() == core::chemical::aa_vrt) || (scoring_mask_.find(i) != scoring_mask_.end()) ) continue;
1454  int nheavyatoms = rsd_i.nheavyatoms();
1455  for (int j=1 ; j<=nheavyatoms; ++j) {
1456  numeric::xyzVector< core::Real > const &xyz_ij = rsd_i.atom(j).xyz();
1457  if (is_missing_density( xyz_ij )) continue;
1458  if (!is_set) {
1459  d_min = d_max = xyz_ij;
1460  is_set = true;
1461  }
1462  d_min[0] = std::min(d_min[0],xyz_ij[0]);
1463  d_min[1] = std::min(d_min[1],xyz_ij[1]);
1464  d_min[2] = std::min(d_min[2],xyz_ij[2]);
1465  d_max[0] = std::max(d_max[0],xyz_ij[0]);
1466  d_max[1] = std::max(d_max[1],xyz_ij[1]);
1467  d_max[2] = std::max(d_max[2],xyz_ij[2]);
1468  CoM+=xyz_ij;
1469  nCoM+=1;
1470  }
1471  }
1472  CoM /= nCoM;
1473  d_max -= CoM;
1474  d_min -= CoM;
1475 
1476  // extent <- range + minR
1477  p_extent = d_max - d_min + PattersonMaxR + 2*FLUFF;
1478 
1479  // use current grid spacing to find grid in each dim
1480  // grid has no prime factors >5 so that fft is fast
1481  // grid is even so we can use real->complex fft shortcut (TO DO)
1482  // mutiples depend on input spacegroup
1483  numeric::xyzVector< core::Real > f_extent = c2f*p_extent;
1484  p_grid[0] = findSampling5(f_extent[0]*grid[0] , MINMULT[0]);
1485  p_grid[1] = findSampling5(f_extent[1]*grid[1] , MINMULT[1]);
1486  p_grid[2] = findSampling5(f_extent[2]*grid[2] , MINMULT[2]);
1487 
1488  // center the molecule in our new unit cell
1489  f_extent = c2f*(d_min-FLUFF-PattersonMaxR/2.0);
1490  p_origin[0] = std::floor(f_extent[0]*grid[0]);
1491  p_origin[1] = std::floor(f_extent[1]*grid[1]);
1492  p_origin[2] = std::floor(f_extent[2]*grid[2]);
1493 
1494  // add fluff
1495  d_min = d_min-FLUFF;
1496  d_max = d_max+FLUFF;
1497 
1498  // DEBUGGING -- run p_o and p_c on same grid
1499  p_grid = grid;
1500  p_origin = origin;
1501  TR << "Setting up patterson map grid " << p_grid[0] << "x" << p_grid[1] << "x" << p_grid[2] << std::endl;
1502  TR << " origin " << p_origin[0] << "x" << p_origin[1] << "x" << p_origin[2] << std::endl;
1503  TR << " d_min " << d_min[0] << "x" << d_min[1] << "x" << d_min[2] << std::endl;
1504  TR << " d_max " << d_max[0] << "x" << d_max[1] << "x" << d_max[2] << std::endl;
1505 
1506  // setup precomputed symmetric matrices
1507  // for each matrix symmptr_i = symmptr[i]
1508  // symmptr_i[x] = idx of symm_i(x)
1509  core::Size nsymmrot = symmRotOps.size();
1511  if (nsymmrot > 1 && !basic::options::option[ basic::options::OptionKeys::patterson::dont_use_symm_in_pcalc ]() ) {
1512  TR << "... precomputing " << nsymmrot << " rotations" << std::endl;
1513  symm_ptrs.resize(nsymmrot);
1514 
1515  // init arrays
1516  for (int i=1; i<= (int)nsymmrot; ++i) {
1517  symm_ptrs[i].dimension(p_grid[0], p_grid[1], p_grid[2]);
1518  }
1519 
1520  // build matrices
1521  for (int z=1; z<=(int)p_grid[2]; ++z) {
1522  if (z < (int)p_grid[2]/2) frac_xyz[2] = ((core::Real)z - 1.0) / grid[2];
1523  else frac_xyz[2] = (((core::Real)z - p_grid[2] - 1.0)) / grid[2];
1524  for (int y=1; y<=(int)p_grid[1]; ++y) {
1525  if (y < (int)p_grid[1]/2) frac_xyz[1] = ((core::Real)y - 1.0) / grid[1] ;
1526  else frac_xyz[1] = (((core::Real)y - p_grid[1] - 1.0)) / grid[1];
1527  for (int x=1; x<=(int)p_grid[0]; ++x) {
1528  if (x < (int)p_grid[0]/2) frac_xyz[0] = ((core::Real)x - 1.0) / grid[0];
1529  else frac_xyz[0] = (((core::Real)x - p_grid[0] - 1.0)) / grid[0];
1530  for (int i=1; i<= (int)nsymmrot; ++i) {
1531  // frac coords of symm copy
1532  numeric::xyzVector< core::Real > symm_i_xyz = symmRotOps[i]*frac_xyz;
1533  // idx of symm copy
1535  pos_mod( (int)std::floor(symm_i_xyz[0]*grid[0]+0.5), p_grid[0] ),
1536  pos_mod( (int)std::floor(symm_i_xyz[1]*grid[1]+0.5), p_grid[1] ),
1537  pos_mod( (int)std::floor(symm_i_xyz[2]*grid[2]+0.5), p_grid[2] ) );
1538  symm_ptrs[i](x,y,z) = symm_i_idx[2]*p_grid[1]*p_grid[0] + symm_i_idx[1]*p_grid[0] + symm_i_idx[0];
1539  }
1540  }
1541  }
1542  }
1543  }
1544 
1545  /// compute patterson-space mask, compute S^2 array
1547  PattersonEpsilon.dimension(p_grid[0], p_grid[1], p_grid[2]);
1548  F_s2.dimension(p_grid[0], p_grid[1], p_grid[2]);
1549  core::Real eps_sum = 0;
1550  core::Real minS=999.0, maxS=0.0;
1551  int H,K,L;
1552  for (int z=1; z<=(int)p_grid[2]; ++z) {
1553  H = (z < (int)p_grid[2]/2) ? z-1 : z-p_grid[2] - 1;
1554  if (z < (int)p_grid[2]/2)
1555  del_ij[2] = ((core::Real)z - 1.0) / grid[2];
1556  else
1557  del_ij[2] = (((core::Real)z - p_grid[2] - 1.0)) / grid[2];
1558  for (int y=1; y<=(int)p_grid[1]; ++y) {
1559  K = (y < (int)p_grid[1]/2) ? y-1 : y-p_grid[1]-1;
1560  if (y < (int)p_grid[1]/2)
1561  del_ij[1] = ((core::Real)y - 1.0) / grid[1] ;
1562  else
1563  del_ij[1] = (((core::Real)y - p_grid[1] - 1.0)) / grid[1];
1564  for (int x=1; x<=(int)p_grid[0]; ++x) {
1565  L = (x < (int)p_grid[0]/2) ? x-1 : x-p_grid[0]-1;
1566  if (x < (int)p_grid[0]/2)
1567  del_ij[0] = ((core::Real)x - 1.0) / grid[0];
1568  else
1569  del_ij[0] = (((core::Real)x - p_grid[0] - 1.0)) / grid[0];
1570 
1571  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij);
1572  core::Real d2 = (cart_del_ij).length_squared();
1573 
1574  if (PattersonMinR <= 0) {
1575  PattersonEpsilon(x,y,z) = 1/(1+exp( d2 - PattersonMaxR*PattersonMaxR));
1576  } else {
1577  PattersonEpsilon(x,y,z) = 1/(1+exp( d2 - PattersonMaxR*PattersonMaxR))
1578  * 1/(1+exp( PattersonMinR*PattersonMinR - d2));
1579  }
1580  eps_sum += PattersonEpsilon(x,y,z);
1581  F_s2(x,y,z) = sqrt(S2(H,K,L));
1582  minS = std::min( minS, F_s2(x,y,z));
1583  maxS = std::max( maxS, F_s2(x,y,z));
1584  }
1585  }
1586  }
1587 
1588  // p_o resampled on p_c grid
1589  //ObjexxFCL::FArray3D< double > eps_po;
1590  po_bar = 0.0;
1591  p_o.dimension( p_grid[0], p_grid[1], p_grid[2] );
1592  for (int z=1; z<=(int)p_grid[2]; ++z) {
1593  int dens_z = z;
1594  if (z > (int)p_grid[2]/2) dens_z = (int)grid[2] - (int)p_grid[2] + z;
1595  if (dens_z<=0 || dens_z > grid[2]) {
1596  continue; // patterson mask is bigger than unit cell
1597  }
1598  for (int y=1; y<=(int)p_grid[1]; ++y) {
1599  int dens_y = y;
1600  if (y>(int)p_grid[1]/2) dens_y = (int)grid[1] - (int)p_grid[1] + y;
1601  if (dens_y<=0 || dens_y > grid[1]) {
1602  continue; // patterson mask is bigger than unit cell
1603  }
1604  for (int x=1; x<=(int)p_grid[0]; ++x) {
1605  int dens_x = x;
1606  if (x>(int)p_grid[0]/2) dens_x = (int)grid[0] - (int)p_grid[0] + x;
1607  if (dens_x<=0 || dens_x > grid[0]) {
1608  continue; // patterson mask is bigger than unit cell
1609  }
1610  p_o(x,y,z) = density(dens_x,dens_y,dens_z);
1611  }
1612  }
1613  }
1614 
1615  ////////////////////////
1616  ////////////////////////
1617  // apply Ecalc to input patterson
1618  // bin reflections, normalize so that sum(F^2)=1 in each bin
1619  // truncate at -patterson::resolution_cutoffs
1620  // bin after truncating
1621  // apply sigmaA
1622  lowres_cut = 999.0;
1623  hires_cut = 0.01;
1624  if (basic::options::option[ basic::options::OptionKeys::patterson::resolution_cutoffs ].user() ) {
1625  utility::vector1<core::Real> rescut_in = basic::options::option[ basic::options::OptionKeys::patterson::resolution_cutoffs ]();
1626  if (rescut_in.size() == 1)
1627  hires_cut = rescut_in[1];
1628  if (rescut_in.size() >= 2) {
1629  hires_cut = std::min(rescut_in[1],rescut_in[2]);
1630  lowres_cut = std::max(rescut_in[1],rescut_in[2]);
1631  }
1632  }
1633 
1634  // find resolution bin cutoffs
1635  core::Size nbuckets = basic::options::option[ basic::options::OptionKeys::patterson::nshells ]();
1636  core::Real max_S3 = std::pow( std::min( 1/hires_cut , maxS) , 3.0);
1637  core::Real min_S3 = std::pow( 1/lowres_cut , 3.0);
1638 
1639  // now categorize each point
1640  // save these for normalizing Pcalc's later
1641  bucket_id.dimension( p_grid[0], p_grid[1], p_grid[2] );
1642  for (int i=0; i< (int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1643  // buckets = 1+floor(nb*(S2.^(3/2)-minS^3)/(maxS^3-minS^3));
1644  int bucket_i = 1+(int)std::floor( nbuckets*( std::pow( F_s2[i], 3.0 ) - min_S3 ) / (max_S3 - min_S3) );
1645 
1646  if ( bucket_i <= 0 || bucket_i > (int)nbuckets )
1647  bucket_id[i]=(core::Size)0;
1648  else
1649  bucket_id[i]=(core::Size)bucket_i;
1650  }
1651 
1652  if ( !basic::options::option[ basic::options::OptionKeys::patterson::no_ecalc ]() ) {
1653  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
1654  ElectronDensity(p_o,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "p_obs_unnormalized.mrc");
1655  }
1656 
1657  // per-bucket normalization
1658  ObjexxFCL::FArray3D< std::complex<double> > Fp_o;
1659  numeric::fourier::fft3(p_o, Fp_o);
1660  bucket_counts.resize(nbuckets,0);
1661  utility::vector1<core::Real> F2(nbuckets, 0);
1662  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1663  if (bucket_id[i] > 0) {
1664  F2[ bucket_id[i] ] += std::abs(Fp_o[i]); // should be norm?
1665  bucket_counts[ bucket_id[i] ]++;
1666  }
1667  }
1668  //std::cerr << "HIRES CUT " << hires_cut << " LOWRES CUT " << lowres_cut << std::endl;
1669  //std::cerr << "MAX_S " << std::pow( max_S3 , 1.0/3.0 ) << " MIN_S " << std::pow( min_S3 , 1.0/3.0 ) << std::endl;
1670  for (int i=1; i<=(int)nbuckets; ++i) {
1671  F2[i] /= bucket_counts[ i ];
1672  }
1673 
1674  // multiply F^2 by sigmaA^2
1675  core::Real rmsd = basic::options::option[ basic::options::OptionKeys::patterson::rmsd ]();
1676  core::Real fsol = basic::options::option[ basic::options::OptionKeys::patterson::Fsol ]();
1677  core::Real bsol = basic::options::option[ basic::options::OptionKeys::patterson::Bsol ]();
1678  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1679  if (bucket_id[i] > 0) {
1680  core::Real S2_i = F_s2[i]*F_s2[i];
1681  core::Real sigmaa_i = sqrt( (1-fsol*std::exp(-bsol*S2_i))*std::exp(-8*(M_PI*M_PI/3)*rmsd*rmsd*S2_i) );
1682  Fp_o[i] = sigmaa_i * (std::abs(Fp_o[i]) / F2[ bucket_id[i] ]);
1683  } else {
1684  Fp_o[i] = 0;
1685  }
1686  }
1687 
1688  // back to patterson space
1689  numeric::fourier::ifft3(Fp_o, p_o);
1690  }
1691 
1692  // standardize
1693  // core::Real delta,mean=0,M2=0;
1694  // for (int i=0; i< (int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1695  // delta = p_o[i] - mean;
1696  // mean = mean + delta/(i+1);
1697  // M2 = M2 + delta*(p_o[i] - mean);
1698  // }
1699  // M2 = sqrt(M2/((int)p_grid[0]*p_grid[1]*p_grid[2]));
1700  // for (int i=0; i< (int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1701  // p_o[i] = (p_o[i]-mean)/M2;
1702  // po_bar += p_o[i] * PattersonEpsilon[i];
1703  // }
1704  // po_bar /= eps_sum;
1705 
1706  // normalization in reciprocal space now
1707  po_bar = 0.0;
1708 
1709  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
1710  ElectronDensity(p_o,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "p_obs.mrc" );
1711  }
1712 
1713  // collect scatterers
1714  for (int i=1 ; i<=nres; ++i) {
1715  conformation::Residue const &rsd_i (pose.residue(i));
1716  if ( (rsd_i.aa() == core::chemical::aa_vrt) || (scoring_mask_.find(i) != scoring_mask_.end()) ) continue;
1717  for (int j=1 ; j<=(int)rsd_i.nheavyatoms(); ++j) {
1718  // ensure that this element exists in the precomputed scatterers
1719  getFdrhoc( get_A( rsd_i.atom_type_set()[ rsd_i.atom_type_index( j ) ].element() ) );
1720  }
1721  }
1722 }
1723 
1724 
1725 /////////////////////////////////////
1726 /// Match pose to patterson map
1728  core::pose::Pose const &pose,
1729  bool cacheCCs /*=false */ ) {
1730  using namespace numeric::statistics;
1731 
1732  // make sure map is loaded
1733  if (!isLoaded) {
1734  TR << "[ ERROR ] ElectronDensity::matchPose called but no map is loaded!\n";
1735  return 0.0;
1736  }
1737 
1738  int nres = pose.total_residue(); //reses.size();
1739  numeric::xyzVector< core::Real > cartX, fracX;
1740  numeric::xyzVector< core::Real > atm_i, atm_j, del_ij, atm_idx_ij;
1741 
1742  core::Real SC_scaling = basic::options::option[ basic::options::OptionKeys::patterson::sc_scaling ]();
1743 
1744  ///////////////////////////
1745  //// first time this function is called, we need to set up a bunch of stuff
1746  //// if the pose has moved a lot we need to set up a new grid
1747  // quick check of bounding box, CoM
1748  // bool is_set = false;
1749  // core::Real nCoM=0;
1750  numeric::xyzVector< core::Real > newd_min, newd_max, CoM(0,0,0);
1751  // for (int i=1 ; i<=nres; ++i) {
1752  // conformation::Residue const &rsd_i (pose.residue(i));
1753  // if ( (rsd_i.aa() == core::chemical::aa_vrt) || (scoring_mask_.find(i) != scoring_mask_.end()) ) continue;
1754  // int nheavyatoms = rsd_i.nheavyatoms();
1755  // for (int j=1 ; j<=nheavyatoms; ++j) {
1756  // numeric::xyzVector< core::Real > const &xyz_ij = rsd_i.atom(j).xyz();
1757  // if (is_missing_density( xyz_ij )) continue;
1758  // if (!is_set) {
1759  // newd_min = newd_max = xyz_ij;
1760  // is_set = true;
1761  // }
1762  // newd_min[0] = std::min(newd_min[0],xyz_ij[0]);
1763  // newd_min[1] = std::min(newd_min[1],xyz_ij[1]);
1764  // newd_min[2] = std::min(newd_min[2],xyz_ij[2]);
1765  // newd_max[0] = std::max(newd_max[0],xyz_ij[0]);
1766  // newd_max[1] = std::max(newd_max[1],xyz_ij[1]);
1767  // newd_max[2] = std::max(newd_max[2],xyz_ij[2]);
1768  // CoM+=xyz_ij;
1769  // nCoM+=1;
1770  // }
1771  // }
1772  // CoM /= nCoM;
1773  // newd_max -= CoM;
1774  // newd_min -= CoM;
1775 
1776  // save CoM for repacking
1777  //p_CoM = CoM;
1778 
1779  bool needToSetup = (p_extent.length_squared() == 0);
1780  p_CoM = numeric::xyzVector< core::Real >(0,0,0);
1781  //for (int j=0; j<3; ++j) {
1782  // needToSetup |= newd_min[j] < d_min[j];
1783  // needToSetup |= newd_max[j] > d_max[j];
1784  //}
1785  // do not let the grid change while minimizing
1786  if (needToSetup && ! pose.energies().use_nblist() ) {
1787  setup_patterson_first_time(pose);
1788  }
1789 
1790  // set up arrays sized by p_grid
1791  rho_calc.dimension(p_grid[0], p_grid[1], p_grid[2]);
1792 
1793  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]); ++i) {
1794  rho_calc[i] = 0.0;
1795  }
1796 
1797  ///////////////////////////
1798  /// COMPUTE RHO_C, MASK
1799  /// remember atoms that were used to calculate rho_c
1800  rho_calc_atms.resize(nres);
1801  rho_calc_as.resize(nres);
1802  rho_calc_sum = 0.0;
1803  for (int i=1 ; i<=nres; ++i) {
1804  conformation::Residue const &rsd_i (pose.residue(i));
1805 
1806  // skip vrts & masked reses
1807  if ( (rsd_i.aa() == core::chemical::aa_vrt) || (scoring_mask_.find(i) != scoring_mask_.end()) ) continue;
1808 
1809  int nheavyatoms = rsd_i.nheavyatoms();
1810  rho_calc_atms[i].resize(nheavyatoms);
1811  rho_calc_as[i].resize(nheavyatoms);
1812 
1813  for (int j=1 ; j<=nheavyatoms; ++j) {
1814  conformation::Atom const &atm_i( rsd_i.atom(j) ); //(pose.residue(i).atom("CA"));
1815  chemical::AtomTypeSet const & atom_type_set( rsd_i.atom_type_set() );
1816  std::string elt_i = atom_type_set[ rsd_i.atom_type_index( j ) ].element();
1817  OneGaussianScattering sig_j = get_A( elt_i );
1818  core::Real k = sig_j.k( PattersonB, max_del_grid );
1819  core::Real C = sig_j.C( k );
1820 
1821  if ( (Size) j > rsd_i.last_backbone_atom()+1) // count CB as bb atom
1822  C *= SC_scaling;
1823 
1824  rho_calc_atms[i][j] = atm_i.xyz()-CoM;
1825  rho_calc_as[i][j] = sig_j;
1826 
1827  // skip randomized residues / residues with no mass (e.g. centroids)
1828  if ( is_missing_density( atm_i.xyz() ) || C < 1e-6) {
1829  rho_calc_as[i][j] = OneGaussianScattering(); // weight == 0
1830  continue;
1831  }
1832 
1833  cartX = atm_i.xyz()-CoM;
1834  fracX = c2f*cartX;
1835  // atm_idx_ij[0] = fracX[0]*grid[0] - p_origin[0] + 1;
1836  // atm_idx_ij[1] = fracX[1]*grid[1] - p_origin[1] + 1;
1837  // atm_idx_ij[2] = fracX[2]*grid[2] - p_origin[2] + 1;
1838  atm_idx_ij[0] = pos_mod (fracX[0]*p_grid[0] - p_origin[0] + 1 , (double)p_grid[0]);
1839  atm_idx_ij[1] = pos_mod (fracX[1]*p_grid[1] - p_origin[1] + 1 , (double)p_grid[1]);
1840  atm_idx_ij[2] = pos_mod (fracX[2]*p_grid[2] - p_origin[2] + 1 , (double)p_grid[2]);
1841 
1842  for (int z=1; z<=(int)p_grid[2]; ++z) {
1843  del_ij[2] = (atm_idx_ij[2] - z) / grid[2];
1844  if (del_ij[2] > 0.5) del_ij[2]-=1.0;
1845  if (del_ij[2] < -0.5) del_ij[2]+=1.0;
1846  del_ij[0] = del_ij[1] = 0.0;
1847  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
1848  for (int y=1; y<=(int)p_grid[1]; ++y) {
1849  del_ij[1] = (atm_idx_ij[1] - y) / grid[1] ;
1850  if (del_ij[1] > 0.5) del_ij[1]-=1.0;
1851  if (del_ij[1] < -0.5) del_ij[1]+=1.0;
1852  del_ij[0] = 0.0;
1853  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
1854  for (int x=1; x<=(int)p_grid[0]; ++x) {
1855  del_ij[0] = (atm_idx_ij[0] - x) / grid[0];
1856  if (del_ij[0] > 0.5) del_ij[0]-=1.0;
1857  if (del_ij[0] < -0.5) del_ij[0]+=1.0;
1858 
1859  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
1860  core::Real d2 = (cart_del_ij).length_squared();
1861  if (d2 <= (ATOM_MASK+1)*(ATOM_MASK+1)) {
1862  core::Real atm = C*exp(-k*d2);
1863  rho_calc(x,y,z) += atm;
1864  rho_calc_sum+= atm;
1865  }
1866  }
1867  }
1868  }
1869  }
1870  }
1871 
1872  // rho_c -> patterson
1873  for (int i=0; i< (int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1874  rho_calc[i] /= rho_calc_sum;
1875  }
1876  numeric::fourier::fft3(rho_calc, Frho_calc);
1877 
1878  ObjexxFCL::FArray3D< std::complex<double> > Fcalc2;
1879  Fcalc2.dimension( p_grid[0],p_grid[1],p_grid[2] );
1880 
1881  if ( !basic::options::option[ basic::options::OptionKeys::patterson::no_ecalc ]() ) {
1882  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
1883  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i)
1884  if (bucket_id[i] > 0) {
1885  Fcalc2[i] = std::norm(Frho_calc[i]);
1886  } else {
1887  Fcalc2[i] = 0;
1888  }
1889  numeric::fourier::ifft3(Fcalc2, Pcalc);
1890  ElectronDensity(Pcalc,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "p_calc_unnormalized.mrc");
1891  }
1892 
1893  // normalize by resolution shell
1894  // not while minimizing --> assume normalization fixed during minimizaion
1895  if (! pose.energies().use_nblist()) {
1896  //utility::vector1<core::Real> F2(bucket_counts.size(), 0);
1897  F2 = utility::vector1<core::Real>(bucket_counts.size(), 0);
1898  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1899  if (bucket_id[i] > 0)
1900  F2[ bucket_id[i] ] += std::norm(Frho_calc[i]);
1901  }
1902  for (int i=1; i<=(int)bucket_counts.size(); ++i) {
1903  F2[i] /= bucket_counts[ i ];
1904  }
1905  }
1906 
1907  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1908  if (bucket_id[i] > 0) {
1909  Fcalc2[i] = std::norm(Frho_calc[i]) / F2[ bucket_id[i] ];
1910  Frho_calc[i] = Frho_calc[i] / F2[ bucket_id[i] ];
1911  } else {
1912  Fcalc2[i] = 0;
1913  Frho_calc[i] = 0;
1914  }
1915  }
1916  } else {
1917  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1918  if (bucket_id[i] > 0) {
1919  Fcalc2[i] = std::norm(Frho_calc[i]);
1920  } else {
1921  Fcalc2[i] = 0;
1922  }
1923  }
1924  }
1925 
1926  // back to realspace
1927  numeric::fourier::ifft3(Fcalc2, Pcalc);
1928 
1929  // sum over symmetric orientations
1930  if (symm_ptrs.size() > 1 && !basic::options::option[ basic::options::OptionKeys::patterson::dont_use_symm_in_pcalc ]() ) {
1931  ObjexxFCL::FArray3D< double > Pcalcmonomer = Pcalc;
1932  for (int i=0; i< (int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
1933  for (int j=2; j<=(int)symm_ptrs.size(); ++j) { // j==1 is identity
1934  Pcalc[i] += Pcalcmonomer[ symm_ptrs[j][i] ];
1935  }
1936  }
1937  }
1938 
1939  // correlate
1940  core::Real sumC=0.0, sumC2=0.0, sumO=0.0, sumO2=0.0, sumCO=0.0, vol=0.0;
1941 
1942  sumC=0.0;
1943  sumC2=0.0;
1944  for (int z=1; z<=(int)p_grid[2]; ++z) {
1945  for (int y=1; y<=(int)p_grid[1]; ++y) {
1946  for (int x=1; x<=(int)p_grid[0]; ++x) {
1947  core::Real eps_x = PattersonEpsilon(x,y,z);
1948  if (eps_x < 1e-6) continue;
1949 
1950  core::Real clc_x = Pcalc(x,y,z);
1951 
1952  // find corresponding point in dens_grid
1953  core::Real obs_x = p_o(x,y,z);
1954 
1955  // SMOOTHED
1956  sumCO += eps_x*clc_x*obs_x;
1957  sumO += eps_x*obs_x;
1958  sumO2 += eps_x*obs_x*obs_x;
1959  sumC += eps_x*clc_x;
1960  sumC2 += eps_x*clc_x*clc_x;
1961  vol += eps_x;
1962  }
1963  }
1964  }
1965  core::Real varC = (sumC2 - sumC*sumC / vol );
1966  core::Real varO = (sumO2 - sumO*sumO / vol ) ;
1967 
1968  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
1969  ElectronDensity(Pcalc,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "p_calc.mrc");
1970  ElectronDensity(PattersonEpsilon,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "p_eps.mrc");
1971  }
1972 
1973  ///////////////////////////////
1974  // precompute derivatives
1975  numeric::xyzVector< core::Real > sum_dcc(0,0,0);
1976  core::Size natoms(0);
1977  if (cacheCCs) {
1978  p_sumC = sumC; p_sumC2 = sumC2;
1979  p_sumO = sumO; p_sumO2 = sumO2;
1980  p_sumCO = sumCO; p_vol = vol;
1981 
1982  ObjexxFCL::FArray3D< double > dpcc_dx, dpcc_dy, dpcc_dz;
1983 
1984  for (int i=1 ; i<=nres; ++i) {
1985  conformation::Residue const &rsd_i (pose.residue(i));
1986  dCCdxs_pat[i].resize( rsd_i.nheavyatoms() );
1987  std::fill (dCCdxs_pat[i].begin(), dCCdxs_pat[i].end(), numeric::xyzVector< core::Real >(0.0,0.0,0.0));
1988  }
1989 
1990  core::Real f = (p_sumCO - p_sumC*p_sumO/p_vol);
1991  core::Real g = (varC * varO);
1992  core::Real pc_bar = p_sumC/p_vol;
1993 
1994  // for each scatterer
1995  for (std::map< int,ObjexxFCL::FArray3D< std::complex<double> > >::const_iterator it = Fdrhoc_dx.begin();
1996  it != Fdrhoc_dx.end(); ++it) {
1997  ObjexxFCL::FArray3D< std::complex< double > > &Fdrhoc_dx_i = Fdrhoc_dx[ it->first ];
1998  ObjexxFCL::FArray3D< std::complex< double > > &Fdrhoc_dy_i = Fdrhoc_dy[ it->first ];
1999  ObjexxFCL::FArray3D< std::complex< double > > &Fdrhoc_dz_i = Fdrhoc_dz[ it->first ];
2000 
2001  //OLD conv_p_co = real( ifft( fft(epsilon.*p_o) .* fft(rho_c) .* conj(fft(drhox)) ) );
2002  //OLD conv_p_c = real( ifft( fft(epsilon) .* fft(rho_c) .* conj(fft(drhox)) ) );
2003  //OLD conv_p_c2 = real( ifft( fft(2*epsilon.*p_c) .* fft(rho_c) .* conj(fft(drhox)) ) );
2004  // f = ( sumCO - sumC*sumO/sumV );
2005  // g = ( varC*varO );
2006  // Fconv_p_pcc = fft2( p_mask .* ( (p_o-po_bar)/sqrt(g) - f * varO*(p_c-pc_bar) / (g^1.5) ) ) ...
2007  // .* frho_c .* conj(fft2(drhox));
2008  {
2009  ObjexxFCL::FArray3D< std::complex<double> > Fdpcc_dx, Fdpcc_dy, Fdpcc_dz;
2010  dpcc_dx.dimension(p_grid[0],p_grid[1],p_grid[2]);
2011  for (int i=0; i<(int)(p_grid[2]*p_grid[1]*p_grid[0]); ++i) {
2012  dpcc_dx[i] = PattersonEpsilon[i] *
2013  ( (p_o[i]-po_bar)/sqrt(g) - f * varO * (Pcalc[i]-pc_bar) / std::pow(g,1.5) );
2014  }
2015 
2016  numeric::fourier::fft3(dpcc_dx, Fdpcc_dx);
2017  Fdpcc_dy = Fdpcc_dx;
2018  Fdpcc_dz = Fdpcc_dx;
2019 
2020  for (int i=0; i<(int)(p_grid[2]*p_grid[1]*p_grid[0]); ++i) {
2021  Fdpcc_dx[i] = 1.0/rho_calc_sum * Fdpcc_dx[i] * Frho_calc[i] * std::conj(Fdrhoc_dx_i[i]);
2022  Fdpcc_dy[i] = 1.0/rho_calc_sum * Fdpcc_dy[i] * Frho_calc[i] * std::conj(Fdrhoc_dy_i[i]);
2023  Fdpcc_dz[i] = 1.0/rho_calc_sum * Fdpcc_dz[i] * Frho_calc[i] * std::conj(Fdrhoc_dz_i[i]);
2024  }
2025 
2026  // inverse FFT
2027  // if accuracy is poor may need to do an fft_resize here
2028  // to resample on a finer grid
2029  numeric::fourier::ifft3(Fdpcc_dx, dpcc_dx);
2030  numeric::fourier::ifft3(Fdpcc_dy, dpcc_dy);
2031  numeric::fourier::ifft3(Fdpcc_dz, dpcc_dz);
2032 
2033  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
2034  ElectronDensity(dpcc_dx,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "dpcc_dx.mrc");
2035  ElectronDensity(dpcc_dy,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "dpcc_dy.mrc");
2036  ElectronDensity(dpcc_dz,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "dpcc_dz.mrc");
2037  }
2038  }
2039 
2040  // spline coeffs
2041  ObjexxFCL::FArray3D< double > dpcc_dx_coeffs, dpcc_dy_coeffs, dpcc_dz_coeffs;
2042  if ( basic::options::option[ basic::options::OptionKeys::patterson::use_spline_interpolation ]()) {
2043  spline_coeffs( dpcc_dx, dpcc_dx_coeffs );
2044  spline_coeffs( dpcc_dy, dpcc_dy_coeffs );
2045  spline_coeffs( dpcc_dz, dpcc_dz_coeffs );
2046  }
2047 
2048  // for each atom
2049  for (int i=1 ; i<=nres; ++i) {
2050  conformation::Residue const &rsd_i (pose.residue(i));
2051  if ( rho_calc_as[i].size() == 0 ) continue;
2052 
2053  for (int j=1 ; j<=(int)rsd_i.nheavyatoms(); ++j) {
2054  if (rho_calc_as[i][j].a() != it->first) continue;
2055 
2056  cartX = rsd_i.atom(j).xyz()-CoM;
2057  fracX = c2f*cartX;
2058 
2059  atm_idx_ij[0] = fracX[0]*grid[0] - p_origin[0] + 1;
2060  atm_idx_ij[1] = fracX[1]*grid[1] - p_origin[1] + 1;
2061  atm_idx_ij[2] = fracX[2]*grid[2] - p_origin[2] + 1;
2062 
2063  // may want to do spline interpolation here
2065  if ( basic::options::option[ basic::options::OptionKeys::patterson::use_spline_interpolation ]()) {
2066  dpcc[0] = interp_spline( dpcc_dx_coeffs , atm_idx_ij );
2067  dpcc[1] = interp_spline( dpcc_dy_coeffs , atm_idx_ij );
2068  dpcc[2] = interp_spline( dpcc_dz_coeffs , atm_idx_ij );
2069  } else {
2070  dpcc[0] = interp_linear( dpcc_dx , atm_idx_ij );
2071  dpcc[1] = interp_linear( dpcc_dy , atm_idx_ij );
2072  dpcc[2] = interp_linear( dpcc_dz , atm_idx_ij );
2073  }
2074  dCCdxs_pat[i][j] = dpcc;
2075 
2076  // sum over symmetries
2077  // i _think_ if we don't care about self interactions we just need to multiply by # of symm
2078  if (symm_ptrs.size() > 1 && !basic::options::option[ basic::options::OptionKeys::patterson::dont_use_symm_in_pcalc ]()) {
2079  dCCdxs_pat[i][j] *= symm_ptrs.size();
2080  }
2081  //std::cerr << i << " " << j << " " << atm_idx_ij << " ==> " << dpcc << std::endl;
2082  sum_dcc += dCCdxs_pat[i][j];
2083  natoms++;
2084  }
2085  }
2086  }
2087  sum_dcc /= natoms;
2088  TR.Debug << "sum(grad) = " << sum_dcc << std::endl;
2089 
2090  // renormalize so grads sum to 0
2091  for (int i=1 ; i<=nres; ++i) {
2092  conformation::Residue const &rsd_i (pose.residue(i));
2093  if ( rho_calc_as[i].size() == 0 ) continue;
2094  for (int j=1 ; j<=(int)rsd_i.nheavyatoms(); ++j) {
2095  dCCdxs_pat[i][j] -= sum_dcc;
2096  }
2097  }
2098  }
2099 
2100  ///////////////////////////////
2101  /// DUMP MAPS FOR DEBUGGING
2102  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
2103  //TR << "Patterson correl = " << ( (p_sumCO - p_sumC*p_sumO/ p_vol) / sqrt( varC * varO ) ) << std::endl;
2104  //TR << " sum_co = " << p_sumCO << std::endl;
2105  //TR << " sum_c = " << p_sumC << std::endl;
2106  //TR << " sum_o = " << p_sumO << std::endl;
2107  //TR << " sum_c2 = " << p_sumC2 << std::endl;
2108  //TR << " sum_o2 = " << p_sumO2 << std::endl;
2109 
2110  //if (useMask) ElectronDensity(Pmask,1.0,numeric::xyzVector< core::Real >(0,0,0), true).writeMRC( "p_mask.mrc" );
2111  ElectronDensity(rho_calc,1.0, numeric::xyzVector< core::Real >(0,0,0), false).writeMRC( "rho_calc.mrc" );
2112  }
2113  return ( (sumCO - sumC*sumO/vol) / sqrt( varC * varO ) );
2114 }
2115 
2116 
2117 
2118 /// Rematch the pose to a patterson map, using previous rho_calc with only rsd changed
2119 /// do not change rho_calc or update cache
2120 /// DOES NOT WORK WITH MASK!
2122  int resid = rsd.seqpos();
2123 
2124  // constants
2125  numeric::xyzVector< core::Real > cartX, fracX;
2126  numeric::xyzVector< core::Real > atm_i, atm_j, del_ij, atm_idx_ij;
2127 
2128  // copy old data
2129  ObjexxFCL::FArray3D< double > rho_calc_copy = rho_calc;
2130 
2131  // subtract old residue's density
2132  int nheavyatoms_old = rho_calc_atms[resid].size();
2133  for (int j=1 ; j<=nheavyatoms_old; ++j) {
2134  OneGaussianScattering const &sig_j = rho_calc_as[resid][j];
2135  core::Real k = sig_j.k( PattersonB, max_del_grid );
2136  core::Real C = sig_j.C( k );
2137 
2138  // if this atom's weight is 0 continue
2139  if ( C < 1e-6 ) continue;
2140 
2141  cartX = rho_calc_atms[resid][j];
2142  fracX = c2f*cartX;
2143  atm_idx_ij[0] = fracX[0]*grid[0] - p_origin[0] + 1;
2144  atm_idx_ij[1] = fracX[1]*grid[1] - p_origin[1] + 1;
2145  atm_idx_ij[2] = fracX[2]*grid[2] - p_origin[2] + 1;
2146 
2147  for (int z=1; z<=(int)p_grid[2]; ++z) {
2148  del_ij[2] = (atm_idx_ij[2] - z) / grid[2];
2149  del_ij[0] = del_ij[1] = 0.0;
2150  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
2151  for (int y=1; y<=(int)p_grid[1]; ++y) {
2152  del_ij[1] = (atm_idx_ij[1] - y) / grid[1] ;
2153  del_ij[0] = 0.0;
2154  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
2155  for (int x=1; x<=(int)p_grid[0]; ++x) {
2156  del_ij[0] = (atm_idx_ij[0] - x) / grid[0];
2157 
2158  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
2159  core::Real d2 = (cart_del_ij).length_squared();
2160  if (d2 <= (ATOM_MASK+1)*(ATOM_MASK+1)) {
2161  core::Real atm = C*exp(-k*d2);
2162  rho_calc_copy(x,y,z) -= atm/rho_calc_sum; // reuse old rho_calc_sum
2163  }
2164  }
2165  }
2166  }
2167  }
2168 
2169 
2170  // add density to new, updating cache
2171  int nheavyatoms_new = rsd.nheavyatoms();
2172 
2173  // for (int j=1 ; j<=rsd.natoms(); ++j) {
2174  // cartX = rsd.atom(j).xyz() - p_CoM;
2175  // fracX = rho_calc_atms[resid][j];
2176  // std::cout << j << " " << cartX[0] << "," << cartX[1] << "," << cartX[2] << " " << fracX[0] << "," << fracX[1] << "," << fracX[2];
2177  // if (j<= nheavyatoms_new) std::cout << " *";
2178  // std::cout << std::endl;
2179  // }
2180 
2181  for (int j=1 ; j<=nheavyatoms_new; ++j) {
2182  conformation::Atom const &atm_i( rsd.atom(j) );
2183  chemical::AtomTypeSet const & atom_type_set( rsd.atom_type_set() );
2184  std::string elt_i = atom_type_set[ rsd.atom_type_index( j ) ].element();
2185 
2186  OneGaussianScattering sig_j = get_A( elt_i );
2187  core::Real k = sig_j.k( PattersonB, max_del_grid );
2188  core::Real C = sig_j.C( k );
2189 
2190  // skip randomized residues / residues with no mass (e.g. centroids)
2191  if ( is_missing_density( atm_i.xyz() ) || C < 1e-6) continue;
2192 
2193  cartX = atm_i.xyz() - p_CoM;
2194  fracX = c2f*cartX;
2195  atm_idx_ij[0] = fracX[0]*grid[0] - p_origin[0] + 1;
2196  atm_idx_ij[1] = fracX[1]*grid[1] - p_origin[1] + 1;
2197  atm_idx_ij[2] = fracX[2]*grid[2] - p_origin[2] + 1;
2198 
2199  for (int z=1; z<=(int)p_grid[2]; ++z) {
2200  del_ij[2] = (atm_idx_ij[2] - z) / grid[2];
2201  del_ij[0] = del_ij[1] = 0.0;
2202  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
2203  for (int y=1; y<=(int)p_grid[1]; ++y) {
2204  del_ij[1] = (atm_idx_ij[1] - y) / grid[1] ;
2205  del_ij[0] = 0.0;
2206  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
2207  for (int x=1; x<=(int)p_grid[0]; ++x) {
2208  del_ij[0] = (atm_idx_ij[0] - x) / grid[0];
2209 
2210  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
2211  core::Real d2 = (cart_del_ij).length_squared();
2212  if (d2 <= (ATOM_MASK+1)*(ATOM_MASK+1)) {
2213  core::Real atm = C*exp(-k*d2);
2214  rho_calc_copy(x,y,z) += atm/rho_calc_sum; // reuse old rho_calc_sum
2215  }
2216  }
2217  }
2218  }
2219  }
2220 
2221  // update all saved stuff derived from this
2222  ObjexxFCL::FArray3D< std::complex<double> > Fcalc2;
2223  ObjexxFCL::FArray3D< double > Pcalc_copy;
2224 
2225  numeric::fourier::fft3(rho_calc_copy, Fcalc2);
2226  // normalize by resolution shell
2227  utility::vector1<core::Real> F2(bucket_counts.size(), 0);
2228  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
2229  if (bucket_id[i] > 0)
2230  F2[ bucket_id[i] ] += std::norm(Fcalc2[i]);
2231  }
2232  for (int i=1; i<=(int)bucket_counts.size(); ++i) {
2233  F2[i] /= bucket_counts[ i ];
2234  }
2235 
2236  Fcalc2.dimension( p_grid[0],p_grid[1],p_grid[2] );
2237  for (int i=0; i<(int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
2238  if (bucket_id[i] > 0) {
2239  Fcalc2[i] = std::norm(Fcalc2[i]) / F2[ bucket_id[i] ];
2240  } else {
2241  Fcalc2[i] = 0;
2242  }
2243  }
2244 
2245  numeric::fourier::ifft3(Fcalc2, Pcalc_copy);
2246 
2247  // sum over symmetric orientations
2248  if (symm_ptrs.size() > 1 && !basic::options::option[ basic::options::OptionKeys::patterson::dont_use_symm_in_pcalc ]() ) {
2249  ObjexxFCL::FArray3D< double > Pcalcmonomer = Pcalc_copy;
2250  for (int i=0; i< (int)(p_grid[0]*p_grid[1]*p_grid[2]) ; ++i) {
2251  for (int j=2; j<=(int)symm_ptrs.size(); ++j) { // j==1 is identity
2252  Pcalc_copy[i] += Pcalcmonomer[ symm_ptrs[j][i] ];
2253  }
2254  }
2255  }
2256 
2257  // correlate
2258  core::Real sumC=0.0, sumC2=0.0, sumO=0.0, sumO2=0.0, sumCO=0.0, vol=0.0;
2259 
2260  sumC=0.0;
2261  sumC2=0.0;
2262  for (int z=1; z<=(int)p_grid[2]; ++z) {
2263  for (int y=1; y<=(int)p_grid[1]; ++y) {
2264  for (int x=1; x<=(int)p_grid[0]; ++x) {
2265  core::Real eps_x = PattersonEpsilon(x,y,z);
2266  if (eps_x < 1e-6) continue;
2267 
2268  core::Real clc_x = Pcalc_copy(x,y,z);
2269 
2270  // find corresponding point in dens_grid
2271  core::Real obs_x = p_o(x,y,z);
2272 
2273  // SMOOTHED
2274  sumCO += eps_x*clc_x*obs_x;
2275  sumO += eps_x*obs_x;
2276  sumO2 += eps_x*obs_x*obs_x;
2277  sumC += eps_x*clc_x;
2278  sumC2 += eps_x*clc_x*clc_x;
2279  vol += eps_x;
2280  }
2281  }
2282  }
2283  core::Real varC = (sumC2 - sumC*sumC / vol );
2284  core::Real varO = (sumO2 - sumO*sumO / vol ) ;
2285  return ( (sumCO - sumC*sumO/vol) / sqrt( varC * varO ) );
2286 }
2287 
2288 ////////////////////////////////
2289 ////////////////////////////////
2290 
2292  int resid = rsd.seqpos();
2293 
2294  // constants
2295  numeric::xyzVector< core::Real > cartX, fracX;
2296  numeric::xyzVector< core::Real > atm_i, atm_j, del_ij, atm_idx_ij;
2297 
2298  // subtract old residue's density
2299  int nheavyatoms_old = rho_calc_atms[resid].size();
2300  for (int j=1 ; j<=nheavyatoms_old; ++j) {
2301  OneGaussianScattering const &sig_j = rho_calc_as[resid][j];
2302  core::Real k = sig_j.k( PattersonB, max_del_grid );
2303  core::Real C = sig_j.C( k );
2304 
2305  // if this atom's weight is 0 continue
2306  if ( C < 1e-6 ) continue;
2307 
2308  cartX = rho_calc_atms[resid][j];
2309  fracX = c2f*cartX;
2310  atm_idx_ij[0] = fracX[0]*grid[0] - p_origin[0] + 1;
2311  atm_idx_ij[1] = fracX[1]*grid[1] - p_origin[1] + 1;
2312  atm_idx_ij[2] = fracX[2]*grid[2] - p_origin[2] + 1;
2313 
2314  for (int z=1; z<=(int)p_grid[2]; ++z) {
2315  del_ij[2] = (atm_idx_ij[2] - z) / grid[2];
2316  del_ij[0] = del_ij[1] = 0.0;
2317  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
2318  for (int y=1; y<=(int)p_grid[1]; ++y) {
2319  del_ij[1] = (atm_idx_ij[1] - y) / grid[1] ;
2320  del_ij[0] = 0.0;
2321  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
2322  for (int x=1; x<=(int)p_grid[0]; ++x) {
2323  del_ij[0] = (atm_idx_ij[0] - x) / grid[0];
2324 
2325  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
2326  core::Real d2 = (cart_del_ij).length_squared();
2327  if (d2 <= (ATOM_MASK+1)*(ATOM_MASK+1)) {
2328  core::Real atm = C*exp(-k*d2);
2329  rho_calc(x,y,z) -= atm;
2330  }
2331  }
2332  }
2333  }
2334  }
2335 
2336  // add density to new, updating cache
2337  int nheavyatoms_new = rsd.nheavyatoms();
2338  rho_calc_atms[resid].resize(nheavyatoms_new);
2339  rho_calc_as[resid].resize(nheavyatoms_new);
2340  for (int j=1 ; j<=nheavyatoms_new; ++j) {
2341  conformation::Atom const &atm_i( rsd.atom(j) );
2342  chemical::AtomTypeSet const & atom_type_set( rsd.atom_type_set() );
2343  std::string elt_i = atom_type_set[ rsd.atom_type_index( j ) ].element();
2344 
2345  OneGaussianScattering sig_j = get_A( elt_i );
2346  core::Real k = sig_j.k( PattersonB, max_del_grid );
2347  core::Real C = sig_j.C( k );
2348 
2349  rho_calc_atms[resid][j] = atm_i.xyz()-p_CoM;
2350  rho_calc_as[resid][j] = sig_j;
2351 
2352  // skip randomized residues / residues with no mass (e.g. centroids)
2353  if ( is_missing_density( atm_i.xyz() ) || C < 1e-6) {
2354  rho_calc_as[resid][j] = OneGaussianScattering(); // weight == 0
2355  continue;
2356  }
2357 
2358  cartX = atm_i.xyz();
2359  fracX = c2f*cartX;
2360  atm_idx_ij[0] = fracX[0]*grid[0] - p_origin[0] + 1;
2361  atm_idx_ij[1] = fracX[1]*grid[1] - p_origin[1] + 1;
2362  atm_idx_ij[2] = fracX[2]*grid[2] - p_origin[2] + 1;
2363 
2364  for (int z=1; z<=(int)p_grid[2]; ++z) {
2365  del_ij[2] = (atm_idx_ij[2] - z) / grid[2];
2366  del_ij[0] = del_ij[1] = 0.0;
2367  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
2368  for (int y=1; y<=(int)p_grid[1]; ++y) {
2369  del_ij[1] = (atm_idx_ij[1] - y) / grid[1] ;
2370  del_ij[0] = 0.0;
2371  if ((f2c*del_ij).length_squared() > square(ATOM_MASK+1)) continue;
2372  for (int x=1; x<=(int)p_grid[0]; ++x) {
2373  del_ij[0] = (atm_idx_ij[0] - x) / grid[0];
2374 
2375  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from (x,y,z) to atom_i
2376  core::Real d2 = (cart_del_ij).length_squared();
2377  if (d2 <= (ATOM_MASK+1)*(ATOM_MASK+1)) {
2378  core::Real atm = C*exp(-k*d2);
2379  rho_calc(x,y,z) += atm;
2380  }
2381  }
2382  }
2383  }
2384  }
2385 }
2386 
2387 
2388 
2389 
2390 /////////////////////////////////////
2391 /// Computes the symmatric rotation matrices. Stores mapping in 'symmap'.
2393  core::pose::Pose const &pose,
2395 ) {
2396  // symmetry
2397  bool isSymm = (symmInfo.get() != NULL);
2398  bool remapSymm = basic::options::option[ basic::options::OptionKeys::edensity::score_symm_complex ]();
2399 
2400  if (!isSymm || !remapSymm) return;
2401 
2402  int nsubunits = symmInfo->subunits();
2403  int nres_per = symmInfo->num_independent_residues();
2404 
2405  // mapping at the (non-virtual) leaves
2406  // MUST BE DONE EVERY TIME THE POSE CHANGES
2407  for (int subunit_i=1 ; subunit_i<=nsubunits; ++subunit_i) {
2408  // symm
2409  int startRes = (subunit_i-1)*nres_per+1;
2410  int source_subunit = subunit_i;
2412 
2413  if (!symmInfo->bb_is_independent(startRes)) {
2414  core::Size sourceRes = symmInfo->bb_follows( startRes );
2415  source_subunit = symmInfo->subunit_index( sourceRes );
2416  R_i = numeric::alignVectorSets(
2417  pose.residue(startRes).atom(1).xyz() - pose.residue(startRes).atom(2).xyz(),
2418  pose.residue(startRes).atom(3).xyz() - pose.residue(startRes).atom(2).xyz(),
2419  pose.residue(sourceRes).atom(1).xyz() - pose.residue(sourceRes).atom(2).xyz(),
2420  pose.residue(sourceRes).atom(3).xyz() - pose.residue(sourceRes).atom(2).xyz());
2421  }
2422  // vrt of 0 => from the non-vrt point of view
2423 
2424  utility::vector1<int> mapping_i(nsubunits,0);
2425  mapping_i[ subunit_i ] = source_subunit;
2426  symmap[ -subunit_i ] = make_pair( mapping_i, R_i );
2427  }
2428 
2429  // at the internal VRTs traverse up the tree to get rotations
2430  // mapping only needs to be calculated once for each fold tree, however,
2431  // Rs must still be percolated up the tree.
2432  // because of that, we'll just recompute the mapping each time;
2433  // however, correcting this could save some running time.
2434  int nres = pose.total_residue();
2435  int vrtStart = nres_per*nsubunits;
2436  int nvrts = nres - vrtStart;
2437  utility::vector1<bool> vrts_mapped( nvrts, false );
2438  bool fully_mapped = false;
2439  while ( !fully_mapped ) {
2440  fully_mapped = true;
2441  for (int i=1 ; i<=nvrts; ++i) {
2442  int resid = i+vrtStart;
2443  if (vrts_mapped[i]) {
2444  continue;
2445  }
2447  int nchildren = edges_i.size();
2448 
2449  if (nchildren == 0) {
2450  //TR.Debug << "[ WARNING ] VRT (" << resid << ") at leaf ... ignoring" << std::endl;
2451  symmap[ resid ] = make_pair( utility::vector1<int>(nsubunits,0), numeric::xyzMatrix<core::Real>::rows(1,0,0, 0,1,0, 0,0,1) );
2452  vrts_mapped[i] = true;
2453  } else if ( nchildren == 1) {
2454  // if 1 child, steal mapping from child
2455  int downstream = edges_i[1].stop();
2456  if ( downstream <= vrtStart || vrts_mapped[downstream-vrtStart] ) {
2457  if ( downstream <= vrtStart ) { // do we jump to a subunit?
2458  symmap[ resid ] = symmap[ -symmInfo->subunit_index( downstream ) ];
2459  } else {
2460  symmap[ resid ] = symmap[ downstream ];
2461  }
2462  vrts_mapped[i] = true;
2463  } else {
2464  fully_mapped = false;
2465  }
2466  } else {
2467  // if >= 2 children, merge
2468  bool allChildrenMapped = true;
2469  for (int j=1; j<=nchildren; ++j) {
2470  int downstream = edges_i[j].stop();
2471  if (downstream <= vrtStart) {
2472  TR.Error << "[ Error ] VRT (" << resid << ") contains multiple jumps to subunits! Exiting." << std::endl;
2473  exit(1);
2474  }
2475  allChildrenMapped &= vrts_mapped[ downstream-vrtStart ];
2476  }
2477 
2478  if ( allChildrenMapped ) {
2479  int firstChild = edges_i[1].stop();
2480 
2481  // use rot from 1st child
2482  numeric::xyzMatrix< core::Real > R_i = symmap[ firstChild ].second;
2483 
2484  // the first child keeps its mapping
2485  utility::vector1<int> mapping_i = symmap[ firstChild ].first;
2486 
2487  // for each subunit of each child
2488  for (int j=2; j<=nchildren; ++j) {
2489  utility::vector1<int> const &mapping_j = symmap[ edges_i[j].stop() ].first;
2490  for (int k=1; k<=nsubunits; ++k) {
2491  if (mapping_j[k] == 0) continue; // subunit k is not under child j
2492 
2493  // find the subunit to which R_i maps k
2494  numeric::xyzMatrix< core::Real > R_ik = (symmap[ -k ].second) * R_i; // R_i * R_k
2495  core::Real bestFit = 999999;
2496  int bestL=-1;
2497  for (int l=1; l<=nsubunits; ++l) {
2498  numeric::xyzMatrix< core::Real > R_diff = R_ik - (symmap[ -l ].second);
2499  core::Real thisErr = R_diff.col_x().length_squared() + R_diff.col_y().length_squared() + R_diff.col_z().length_squared();
2500  if (thisErr < bestFit) {
2501  bestFit = thisErr;
2502  bestL = l;
2503  }
2504  }
2505  //std::cerr << "at vrt (" << resid << ") ... mapping " << k << " to " << bestL << " / " << bestFit << std::endl;
2506  mapping_i[ k ] = bestL;
2507  }
2508  }
2509 
2510  symmap[ resid ] = make_pair( mapping_i, R_i );
2511  vrts_mapped[i] = true;
2512  } else {
2513  fully_mapped = false;
2514  }
2515  }
2516  }
2517  }
2518 }
2519 
2520 
2521 
2522 
2524  for (int i=1, iend=pose.total_residue(); i<=iend; ++i) {
2525  if ( pose.residue(i).aa() == core::chemical::aa_vrt ) continue;
2526  core::Size nAtms = pose.residue(i).nheavyatoms();
2527  dCCdxs_res[i].resize( nAtms );
2528  std::fill (dCCdxs_res[i].begin(), dCCdxs_res[i].end(), numeric::xyzVector< core::Real >(0.0,0.0,0.0));
2529  }
2530 }
2531 
2532 
2533 /////////////////////////////////////
2534 /// Match a residue to the density map, returning correlation coefficient between
2535 /// map and residue.
2536 /// Caches information about scoring, to be used in derivative computation
2538  int resid,
2539  core::conformation::Residue const &rsd,
2540  core::pose::Pose const &pose,
2542  bool cacheCCs /* = false */
2543 ) {
2544  // make sure map is loaded
2545  if (!isLoaded) {
2546  TR << "[ ERROR ] ElectronDensity::matchRes called but no map is loaded!\n";
2547  return 0.0;
2548  }
2549 
2550  if ( scoring_mask_.find(resid) != scoring_mask_.end() ) return 0.0;
2551 
2552  // symmetry
2553  bool isSymm = (symmInfo.get() != NULL);
2554  bool remapSymm = basic::options::option[ basic::options::OptionKeys::edensity::score_symm_complex ]();
2555 
2556  // symm
2557  if (isSymm && !symmInfo->bb_is_independent(resid) && !remapSymm) return 0.0; // only score monomer
2558 
2559  //// grab atoms to be included in scoring
2560  //// context atoms - within the window; mask/derivatives computed
2561  //// neighbor atoms - atoms whose density _may_ fall within the mask; no mask/derivs computed
2562  int nres = (int)pose.total_residue();
2563  utility::vector1< conformation::Atom > neighborAtoms, contextAtoms;
2564  utility::vector1< std::pair<core::Size,core::Size> > neighborAtomIds, contextAtomIds;
2565  utility::vector1< OneGaussianScattering > neighborAtomAs, contextAtomAs;
2566 
2567  EnergyGraph const & energy_graph( pose.energies().energy_graph() );
2568  std::set< core::Size > neighborResids;
2569 
2570  Size HALFWINDOW = WINDOW_/2;
2571  Size win_start= resid-HALFWINDOW, win_stop = resid+HALFWINDOW;
2572  for (int i=HALFWINDOW-1; i>=0; --i) {
2573  if ( (resid-i)>1 && pose.fold_tree().is_cutpoint( resid-i-1 ) ) win_start = resid-i;
2574  if ( (resid+i)<=nres && pose.fold_tree().is_cutpoint( resid+i ) ) win_stop = resid+i;
2575  }
2576  win_start = std::max(1, (int)win_start);
2577  win_stop = std::min((int)win_stop, nres);
2578 
2579  // 1: grab context atom ids
2580  // only extend left/right to the next chainbreak
2581  for (Size i=win_start; i<=win_stop; ++i) {
2582  core::conformation::Residue const &rsd_i( pose.residue(i) );
2583 
2584  // calc neighbor residues
2585  if ( score_window_context_ ) {
2587  iru = energy_graph.get_node(i)->const_edge_list_begin(),
2588  irue = energy_graph.get_node(i)->const_edge_list_end();
2589  iru != irue; ++iru ) {
2590  EnergyEdge const * edge( static_cast< EnergyEdge const *> (*iru) );
2591  Size const e1( edge->get_first_node_ind() );
2592  Size const e2( edge->get_second_node_ind() );
2593  Size const j = (e1==i) ? e2 : e1;
2594  if (j<win_start || j>win_stop) {
2595  neighborResids.insert( j );
2596  }
2597  }
2598  }
2599 
2600  if (i==(Size)resid) continue; // already added these atoms
2601  if (!rsd_i.is_polymer()) continue;
2602 
2603  chemical::AtomTypeSet const & atom_type_set( rsd_i.atom_type_set() );
2604 
2605  // BB atoms
2606  for ( core::Size j=1; j<=rsd_i.last_backbone_atom(); ++j ) {
2607  std::string elt_i = atom_type_set[ rsd_i.atom_type_index( j ) ].element();
2608  OneGaussianScattering sig_j = get_A( elt_i );
2609  contextAtoms.push_back( rsd_i.atom( j ) );
2610  contextAtomIds.push_back( std::pair<core::Size,core::Size>(i,j) );
2611  contextAtomAs.push_back( sig_j );
2612  }
2613  // SC atoms
2614  for ( core::Size j=rsd_i.last_backbone_atom()+1; j<=rsd_i.nheavyatoms(); ++j ) {
2615  std::string elt_i = atom_type_set[ rsd_i.atom_type_index( j ) ].element();
2616  OneGaussianScattering sig_j = get_A( elt_i );
2617  neighborAtoms.push_back( rsd_i.atom( j ) );
2618  neighborAtomIds.push_back( std::pair<core::Size,core::Size>(i,j) );
2619  neighborAtomAs.push_back( sig_j );
2620  }
2621  }
2622 
2623  // 2: grab neighbor atom ids
2624  // all atoms from neighborgraph
2625  for (std::set< core::Size >::iterator it=neighborResids.begin(); it!=neighborResids.end(); it++) {
2626  core::conformation::Residue const &rsd_i( pose.residue(*it) );
2627  if (!rsd_i.is_polymer()) continue;
2628  chemical::AtomTypeSet const & atom_type_set( rsd_i.atom_type_set() );
2629  for ( core::Size j=1; j<=rsd_i.nheavyatoms(); ++j ) {
2630  std::string elt_i = atom_type_set[ rsd_i.atom_type_index( j ) ].element();
2631  OneGaussianScattering sig_j = get_A( elt_i );
2632  neighborAtoms.push_back( rsd_i.atom( j ) );
2633  neighborAtomIds.push_back( std::pair<core::Size,core::Size>(*it,j) );
2634  neighborAtomAs.push_back( sig_j );
2635  }
2636  }
2637 
2638  int nResAtms = rsd.nheavyatoms(), nContextAtms=contextAtoms.size(), nNeighborAtoms=neighborAtoms.size();
2639  int nTotalAtms = nResAtms+nContextAtms;
2640 
2641  ///////////////////////////
2642  /// 1 COMPUTE BOUNDING BOX
2643  const core::Real ATOM_MASK_PADDING = 1.5;
2644 
2647 
2648  for ( int j=1; j<=nTotalAtms; ++j ) {
2649  conformation::Atom const &atom (j<=nResAtms? rsd.atom(j) : contextAtoms[j-nResAtms]);
2650  numeric::xyzVector< core::Real > cartX, idxX, fracX;
2651 
2652  if ( is_missing_density( atom.xyz() ) ) continue; // check if coords were randomized
2653 
2654  cartX = atom.xyz() - getTransform();
2655  fracX = c2f*cartX;
2656  idxX = numeric::xyzVector< core::Real >( fracX[0]*grid[0] - origin[0] + 1 ,
2657  fracX[1]*grid[1] - origin[1] + 1 ,
2658  fracX[2]*grid[2] - origin[2] + 1 );
2659  atmList.push_back( idxX );
2660 
2661  fracX = c2f*( cartX-(ATOM_MASK+2*ATOM_MASK_PADDING) );
2662  idxX = numeric::xyzVector< core::Real >( fracX[0]*grid[0] - origin[0] + 1 ,
2663  fracX[1]*grid[1] - origin[1] + 1 ,
2664  fracX[2]*grid[2] - origin[2] + 1 );
2665  idxX_low[0] = std::min(idxX[0],idxX_low[0]);
2666  idxX_low[1] = std::min(idxX[1],idxX_low[1]);
2667  idxX_low[2] = std::min(idxX[2],idxX_low[2]);
2668 
2669  fracX = c2f*( cartX+(ATOM_MASK+2*ATOM_MASK_PADDING) );
2670  idxX = numeric::xyzVector< core::Real >( fracX[0]*grid[0] - origin[0] + 1 ,
2671  fracX[1]*grid[1] - origin[1] + 1 ,
2672  fracX[2]*grid[2] - origin[2] + 1 );
2673  idxX_high[0] = std::max(idxX[0],idxX_high[0]);
2674  idxX_high[1] = std::max(idxX[1],idxX_high[1]);
2675  idxX_high[2] = std::max(idxX[2],idxX_high[2]);
2676  }
2677  int lastMaskedAtom = atmList.size();
2678 
2679  // add in neighbor atoms
2680  // don't let them modify size of bounding box
2681  for ( int j=1; j<=nNeighborAtoms; ++j ) {
2682  conformation::Atom const &atom (neighborAtoms[j]);
2683  numeric::xyzVector< core::Real > cartX, idxX, fracX;
2684  if ( is_missing_density( atom.xyz() ) ) continue; // check if coords were randomized
2685  cartX = atom.xyz() - getTransform();
2686  fracX = c2f*cartX;
2687  idxX = numeric::xyzVector< core::Real >( fracX[0]*grid[0] - origin[0] + 1 ,
2688  fracX[1]*grid[1] - origin[1] + 1 ,
2689  fracX[2]*grid[2] - origin[2] + 1 );
2690  atmList.push_back( idxX );
2691  }
2692 
2693  numeric::xyzVector< int > bbox_min, bbox_max, bbox_dims;
2694  bbox_min[0] = (int)floor(idxX_low[0])-1; bbox_max[0] = (int)ceil(idxX_high[0]); bbox_dims[0] = bbox_max[0]-bbox_min[0];
2695  bbox_min[1] = (int)floor(idxX_low[1])-1; bbox_max[1] = (int)ceil(idxX_high[1]); bbox_dims[1] = bbox_max[1]-bbox_min[1];
2696  bbox_min[2] = (int)floor(idxX_low[2])-1; bbox_max[2] = (int)ceil(idxX_high[2]); bbox_dims[2] = bbox_max[2]-bbox_min[2];
2697 
2698  ObjexxFCL::FArray3D< double > rho_obs, inv_rho_mask, rho_calc_fg, rho_calc_bg;
2699  rho_obs.dimension(bbox_dims[0],bbox_dims[1],bbox_dims[2]);
2700  rho_calc_fg.dimension(bbox_dims[0],bbox_dims[1],bbox_dims[2]);
2701  rho_calc_bg.dimension(bbox_dims[0],bbox_dims[1],bbox_dims[2]);
2702  inv_rho_mask.dimension(bbox_dims[0],bbox_dims[1],bbox_dims[2]);
2703 
2704  for (int x=0; x<bbox_dims[0]*bbox_dims[1]*bbox_dims[2]; ++x) {
2705  rho_obs[x] = 0.0;
2706  rho_calc_fg[x] = 0.0;
2707  rho_calc_bg[x] = 0.0;
2708  inv_rho_mask[x] = 1.0;
2709  }
2710 
2712  utility::vector1< utility::vector1< int > > rho_dx_pt(nTotalAtms);
2713  utility::vector1< utility::vector1< numeric::xyzVector<core::Real> > > rho_dx_mask(nTotalAtms), rho_dx_atm(nTotalAtms);
2714 
2715  ///////////////////////////
2716  /// 2 COMPUTE RHO_C, MASK
2717  chemical::AtomTypeSet const & atom_type_set( rsd.atom_type_set() );
2718  core::Real clc_x, obs_x;
2719  int mapX,mapY,mapZ;
2720 
2721  for (int i=1; i<=(int)atmList.size(); ++i) {
2722  numeric::xyzVector< core::Real > & atm_i = atmList[i];
2723  atm_i[0] -= bbox_min[0];
2724  atm_i[1] -= bbox_min[1];
2725  atm_i[2] -= bbox_min[2];
2726 
2727  numeric::xyzVector< core::Real > atm_j, del_ij;
2728 
2729  core::Real k,C;
2730  if ( i <= nResAtms) {
2731  std::string elt_i = atom_type_set[ rsd.atom_type_index( i ) ].element();
2732  OneGaussianScattering sig_j = get_A( elt_i );
2733  k = sig_j.k( PattersonB, max_del_grid );
2734  C = sig_j.C( k );
2735  } else if (i<= lastMaskedAtom) {
2736  OneGaussianScattering const &sig_j = contextAtomAs[i-nResAtms];
2737  k = sig_j.k( PattersonB, max_del_grid );
2738  C = sig_j.C( k );
2739  } else {
2740  OneGaussianScattering const &sig_j = neighborAtomAs[i-lastMaskedAtom];
2741  k = sig_j.k( PattersonB, max_del_grid );
2742  C = sig_j.C( k );
2743  }
2744 
2745  for (int z=1; z<=bbox_dims[2]; ++z) {
2746  atm_j[2] = z;
2747  del_ij[2] = (atm_i[2] - atm_j[2]) / grid[2];
2748  // wrap-around??
2749  if (del_ij[2] > 0.5) del_ij[2]-=1.0;
2750  if (del_ij[2] < -0.5) del_ij[2]+=1.0;
2751 
2752  del_ij[0] = del_ij[1] = 0.0;
2753  if ((f2c*del_ij).length_squared() > (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) continue;
2754 
2755  mapZ = (z+bbox_min[2]) % grid[2];
2756  if (mapZ <= 0) mapZ += grid[2];
2757  if (mapZ > density.u3()) continue;
2758 
2759  for (int y=1; y<=bbox_dims[1]; ++y) {
2760  atm_j[1] = y;
2761 
2762  // early exit?
2763  del_ij[1] = (atm_i[1] - atm_j[1]) / grid[1] ;
2764  // wrap-around??
2765  if (del_ij[1] > 0.5) del_ij[1]-=1.0;
2766  if (del_ij[1] < -0.5) del_ij[1]+=1.0;
2767  del_ij[0] = 0.0;
2768  if ((f2c*del_ij).length_squared() > (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) continue;
2769 
2770  mapY = (y+bbox_min[1]) % grid[1];
2771  if (mapY <= 0) mapY += grid[1];
2772  if (mapY > density.u2()) continue;
2773 
2774  for (int x=1; x<=bbox_dims[0]; ++x) {
2775  atm_j[0] = x;
2776 
2777  // early exit?
2778  del_ij[0] = (atm_i[0] - atm_j[0]) / grid[0];
2779  // wrap-around??
2780  if (del_ij[0] > 0.5) del_ij[0]-=1.0;
2781  if (del_ij[0] < -0.5) del_ij[0]+=1.0;
2782 
2783  mapX = (x+bbox_min[0]) % grid[0];
2784  if (mapX <= 0) mapX += grid[0];
2785  if (mapX > density.u1()) continue;
2786 
2787  numeric::xyzVector< core::Real > cart_del_ij = (f2c*del_ij); // cartesian offset from atom_i to (x,y,z)
2788  core::Real d2 = (cart_del_ij).length_squared();
2789  if (d2 <= (ATOM_MASK+ATOM_MASK_PADDING)*(ATOM_MASK+ATOM_MASK_PADDING)) {
2790  core::Real atm = C*exp(-k*d2);
2791  core::Real sigmoid_msk = exp( d2 - (ATOM_MASK)*(ATOM_MASK) );
2792  core::Real inv_msk = 1/(1+sigmoid_msk);
2793 
2794  rho_obs(x,y,z) = density(mapX,mapY,mapZ);
2795  if (i<=lastMaskedAtom) {
2796  rho_calc_fg(x,y,z) += atm;
2797  inv_rho_mask(x,y,z) *= (1 - inv_msk);
2798  if (cacheCCs) {
2799  int idx = (z-1)*rho_calc_fg.u2()*rho_calc_fg.u1() + (y-1)*rho_calc_fg.u1() + x-1;
2800 
2801  core::Real eps_i = (1-inv_msk), inv_eps_i;
2802  if (eps_i == 0) // divide-by-zero
2803  inv_eps_i = sigmoid_msk;
2804  else
2805  inv_eps_i = 1/eps_i;
2806 
2807  rho_dx_pt[i].push_back ( idx );
2808  rho_dx_atm[i].push_back ( (-2*k*atm)*cart_del_ij );
2809  rho_dx_mask[i].push_back( (-2*sigmoid_msk*inv_msk*inv_msk*inv_eps_i)*cart_del_ij );
2810  }
2811  } else {
2812  rho_calc_bg(x,y,z) += atm;
2813  }
2814  }
2815  }
2816  }
2817  }
2818  }
2819 
2820  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]() && resid == 1) {
2821  ElectronDensity(rho_obs,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "rho_obs.mrc");
2822  ElectronDensity(inv_rho_mask,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "rho_mask.mrc");
2823  ElectronDensity(rho_calc_bg,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "rho_calc_bg.mrc");
2824  ElectronDensity(rho_calc_fg,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "rho_calc_fg.mrc");
2825  }
2826 
2827  //////////////////////////
2828  /// 2 COMPUTE SUMMARY STATISTICS
2829  core::Real sumC_i=0.0, sumO_i=0.0, sumCO_i=0.0, vol_i=0.0, CC_i=0.0;
2830  core::Real sumO2_i=0.0, sumC2_i=0.0, varC_i=0.0, varO_i=0.0;
2831 
2832  for (int x=0; x<bbox_dims[0]*bbox_dims[1]*bbox_dims[2]; ++x) {
2833  // fetch this point
2834  clc_x = rho_calc_bg[x] + rho_calc_fg[x];
2835  obs_x = rho_obs[x];
2836 
2837  core::Real wt = 1-inv_rho_mask[x];
2838  vol_i += wt;
2839  sumC_i += wt*clc_x;
2840  sumC2_i += wt*clc_x*clc_x;
2841  sumO_i += wt*obs_x;
2842  sumO2_i += wt*obs_x*obs_x;
2843  sumCO_i += wt*clc_x*obs_x;
2844  }
2845  varC_i = (sumC2_i - sumC_i*sumC_i / vol_i );
2846  varO_i = (sumO2_i - sumO_i*sumO_i / vol_i ) ;
2847  if (varC_i == 0 || varO_i == 0)
2848  CC_i = 0;
2849  else
2850  CC_i = (sumCO_i - sumC_i*sumO_i/ vol_i) / sqrt( varC_i * varO_i );
2851 
2852  if (cacheCCs) {
2853  CCs[resid] = CC_i;
2854  }
2855 
2856  ///////////////////////////
2857  /// 4 CALCULATE PER-ATOM DERIVATIVES
2858  if (cacheCCs) {
2859  for (int j=1 ; j<=(int)lastMaskedAtom; ++j) {
2860  utility::vector1< int > const &rho_dx_pt_ij = rho_dx_pt[j];
2861  utility::vector1< numeric::xyzVector<core::Real> > const &rho_dx_mask_ij = rho_dx_mask[j];
2862  utility::vector1< numeric::xyzVector<core::Real> > const &rho_dx_atm_ij = rho_dx_atm[j];
2863 
2864  numeric::xyzVector< core::Real > dVdx_ij(0,0,0), dOdx_ij(0,0,0), dO2dx_ij(0,0,0), dCOdx_ij(0,0,0), dC2dx_ij(0,0,0), dCdx_ij(0,0,0);
2865 
2866  //core::Real k;
2867  /*if ( j <= nResAtms) {
2868  std::string elt_i = atom_type_set[ rsd.atom_type_index( j ) ].element();
2869  OneGaussianScattering sig_j = get_A( elt_i );
2870  //k = sig_j.k( PattersonB, max_del_grid ); // set but never used ~Labonte
2871  } else {
2872  OneGaussianScattering const & sig_j = contextAtomAs[j-nResAtms];
2873  //k = sig_j.k( PattersonB, max_del_grid ); // set but never used ~Labonte
2874  }*/
2875 
2876  int npoints = rho_dx_pt_ij.size();
2877  for (int n=1; n<=npoints; ++n) {
2878  const int x(rho_dx_pt_ij[n]);
2879  clc_x = rho_calc_bg[x] + rho_calc_fg[x];
2880  obs_x = rho_obs[x];
2881  core::Real inv_eps_x = inv_rho_mask[x];
2882  core::Real eps_x = 1-inv_eps_x;
2883 
2884  numeric::xyzVector<double> del_mask = inv_eps_x*rho_dx_mask_ij[n];
2885  numeric::xyzVector<double> del_rhoc = rho_dx_atm_ij[n];
2886 
2887  dVdx_ij += del_mask;
2888  // dC_dx = rhoc.*2.*(1-eps).*(x-xi).*sig_i.*eps_i.^2./(1-eps_i) + 2 * rho_i .* (x-xi) .* (eps);
2889  dCdx_ij += del_mask*clc_x + del_rhoc*eps_x;
2890  dOdx_ij += del_mask*obs_x;
2891  dO2dx_ij += del_mask*obs_x*obs_x;
2892  dC2dx_ij += clc_x*(del_mask*clc_x + 2.0*del_rhoc*eps_x);
2893  dCOdx_ij += obs_x*(del_mask*clc_x + del_rhoc*eps_x);
2894  }
2895 
2896  // finally compute dCC/dx_ij
2897  core::Real f = ( sumCO_i - sumC_i*sumO_i / vol_i );
2898  core::Real g = sqrt ( varO_i * varC_i );
2899 
2900  numeric::xyzVector<core::Real> fprime = dCOdx_ij - 1/(vol_i*vol_i) * (
2901  (dOdx_ij*sumC_i + dCdx_ij*sumO_i)*vol_i - sumO_i*sumC_i*dVdx_ij);
2902  numeric::xyzVector<core::Real> gprime = 0.5 * (
2903  sqrt(varO_i)/sqrt(varC_i) * ( dC2dx_ij - ( 1/(vol_i*vol_i) * ( 2*vol_i*sumC_i*dCdx_ij - sumC_i*sumC_i*dVdx_ij ) ) ) +
2904  sqrt(varC_i)/sqrt(varO_i) * ( dO2dx_ij - ( 1/(vol_i*vol_i) * ( 2*vol_i*sumO_i*dOdx_ij - sumO_i*sumO_i*dVdx_ij ) ) ) );
2905 
2906  std::pair<core::Size,core::Size> const &atomid (j<=nResAtms?
2907  std::pair<core::Size,core::Size>(resid,j) : contextAtomIds[j-nResAtms]);
2908  dCCdxs_res[atomid.first][atomid.second] += (g*fprime - f*gprime) / (g*g);
2909  }
2910  }
2911 
2912  return( CC_i );
2913 }
2914 
2915 /////////////////////////////////////
2916 /// Match a residue to the density map. Use the fast version of the scoring function
2917 core::Real
2919  int resid,
2920  core::conformation::Residue const &rsd,
2921  core::pose::Pose const &pose,
2923 ) {
2924  // make sure map is loaded
2925  if (!isLoaded) {
2926  TR << "[ ERROR ] ElectronDensity::matchResFast called but no map is loaded!\n";
2927  return 0.0;
2928  }
2929 
2930  if ( fastdens_score.u1()*fastdens_score.u2()*fastdens_score.u3() == 0 )
2931  setup_fastscoring_first_time(pose);
2932 
2933  if ( scoring_mask_.find(resid) != scoring_mask_.end() ) return 0.0;
2934 
2935  // symmetry
2936  bool isSymm = (symmInfo.get() != NULL);
2937  bool remapSymm = remap_symm_;
2938 
2939  // symm
2940  if (isSymm && !symmInfo->bb_is_independent(resid) && !remapSymm) return 0.0; // only score monomer
2941 
2942  core::Real score = 0;
2944  for (Size i=1; i<=rsd.nheavyatoms(); ++i) {
2945  fracX = c2f*rsd.atom(i).xyz();
2946  idxX = numeric::xyzVector<core::Real>( fracX[0]*fastgrid[0] - fastorigin[0] + 1,
2947  fracX[1]*fastgrid[1] - fastorigin[1] + 1,
2948  fracX[2]*fastgrid[2] - fastorigin[2] + 1);
2949  score += interp_spline( fastdens_score , idxX );
2950  }
2951 
2952  return score;
2953 }
2954 
2955 
2956 // Compute the gradient (sliding_window density score)
2958  int atmid, int resid,
2960  core::conformation::Residue const &rsd,
2961  core::pose::Pose const &pose,
2963 
2964  // make sure map is loaded
2965  if (!isLoaded) {
2966  TR << "[ ERROR ] ElectronDensity::dCCdx_fastRes called but no map is loaded!\n";
2967  return;
2968  }
2969 
2970  if ( fastdens_score.u1()*fastdens_score.u2()*fastdens_score.u3() == 0 )
2971  setup_fastscoring_first_time(pose);
2972 
2973  dCCdX[0] = dCCdX[1] = dCCdX[2] = 0;
2974 
2975  if ( scoring_mask_.find(resid) != scoring_mask_.end() ) return;
2976  if ( pose.residue(resid).aa() == core::chemical::aa_vrt ) return;
2977 
2978  numeric::xyzVector<core::Real> fracX = c2f*X;
2980  fracX[0]*fastgrid[0] - fastorigin[0] + 1,
2981  fracX[1]*fastgrid[1] - fastorigin[1] + 1,
2982  fracX[2]*fastgrid[2] - fastorigin[2] + 1);
2983  dCCdX[0] = interp_spline( fastdens_dscoredx , idxX );
2984  dCCdX[1] = interp_spline( fastdens_dscoredy , idxX );
2985  dCCdX[2] = interp_spline( fastdens_dscoredz , idxX );
2986 
2987  if (ExactDerivatives) {
2988  numeric::xyzVector<core::Real> dCCdX1 = dCCdX;
2989 
2990  core::conformation::Residue rsd_copy = rsd;
2991 
2992  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0]+NUM_DERIV_H_CEN,X[1],X[2] ) );
2993  core::Real CC_px = getDensityMap().matchResFast( resid, rsd_copy, pose, NULL );
2994 
2995  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0]-NUM_DERIV_H_CEN,X[1],X[2] ) );
2996  core::Real CC_mx = getDensityMap().matchResFast( resid, rsd_copy, pose, NULL );
2997 
2998  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0],X[1]+NUM_DERIV_H_CEN,X[2] ) );
2999  core::Real CC_py = getDensityMap().matchResFast( resid, rsd_copy, pose, NULL );
3000 
3001  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0],X[1]-NUM_DERIV_H_CEN,X[2] ) );
3002  core::Real CC_my = getDensityMap().matchResFast( resid, rsd_copy, pose, NULL );
3003 
3004  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0],X[1],X[2]+NUM_DERIV_H_CEN ) );
3005  core::Real CC_pz = getDensityMap().matchResFast( resid, rsd_copy, pose, NULL );
3006 
3007  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0],X[1],X[2]-NUM_DERIV_H_CEN ) );
3008  core::Real CC_mz = getDensityMap().matchResFast( resid, rsd_copy, pose, NULL );
3009 
3010  // rescore with orig pose
3011  getDensityMap().matchRes( resid, rsd, pose, NULL, false );
3012 
3013  dCCdX[0] = (CC_px-CC_mx)/(2*NUM_DERIV_H_CEN); // * dCCdxs_res_multiplier[resid][atmid];
3014  dCCdX[1] = (CC_py-CC_my)/(2*NUM_DERIV_H_CEN); // * dCCdxs_res_multiplier[resid][atmid];
3015  dCCdX[2] = (CC_pz-CC_mz)/(2*NUM_DERIV_H_CEN); // * dCCdxs_res_multiplier[resid][atmid];
3016 
3017  TR << " " << dCCdX<< " ; " << dCCdX1 << std::endl;
3018  }
3019 }
3020 
3021 /////////////////////////////////////
3022 // Compute the gradient (sliding_window density score)
3024  int atmid,
3025  int resid,
3027  core::conformation::Residue const &rsd,
3028  core::pose::Pose const & pose,
3030 )
3031 {
3032  // make sure map is loaded
3033  if (!isLoaded) {
3034  TR << "[ ERROR ] ElectronDensity::dCCdx_res called but no map is loaded!\n";
3035  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3036  exit(1);
3037  }
3038 
3039  static bool warned=false;
3040  if (!DensScoreInMinimizer) {
3041  if (!warned)
3042  TR << "[ WARNING ] dCCdx_res called but DensityScoreInMinimizer = false ... returning 0" << std::endl;
3043  //warned = true;
3044  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3045  return;
3046  }
3047 
3048  // if we didn't score this residue
3049  // (because it was missing density or masked or a symm copy)
3050  // then don't compute its derivative
3051  if ( (int)dCCdxs_res[resid].size() < atmid ) {
3052  //std::cerr << "no " << resid << "." << atmid << std::endl;
3053  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3054  return;
3055  }
3056 
3057  if (! ExactDerivatives ) {
3058  dCCdX = dCCdxs_res[resid][atmid];
3059  } else {
3060  ////////////////////////////////
3061  ////// debug : compare d_true to d_exact
3062  //
3063  core::conformation::Residue rsd_copy = rsd;
3064 
3065  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0]+NUM_DERIV_H_CEN,X[1],X[2] ) );
3066  core::Real CC_px = getDensityMap().matchRes( resid, rsd_copy, pose, NULL, false );
3067 
3068  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0]-NUM_DERIV_H_CEN,X[1],X[2] ) );
3069  core::Real CC_mx = getDensityMap().matchRes( resid, rsd_copy, pose, NULL, false );
3070 
3071  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0],X[1]+NUM_DERIV_H_CEN,X[2] ) );
3072  core::Real CC_py = getDensityMap().matchRes( resid, rsd_copy, pose, NULL, false );
3073 
3074  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0],X[1]-NUM_DERIV_H_CEN,X[2] ) );
3075  core::Real CC_my = getDensityMap().matchRes( resid, rsd_copy, pose, NULL, false );
3076 
3077  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0],X[1],X[2]+NUM_DERIV_H_CEN ) );
3078  core::Real CC_pz = getDensityMap().matchRes( resid, rsd_copy, pose, NULL, false );
3079 
3080  rsd_copy.atom( atmid ).xyz( numeric::xyzVector<core::Real>( X[0],X[1],X[2]-NUM_DERIV_H_CEN ) );
3081  core::Real CC_mz = getDensityMap().matchRes( resid, rsd_copy, pose, NULL, false );
3082 
3083  // rescore with orig pose
3084  getDensityMap().matchRes( resid, rsd, pose, NULL, false );
3085 
3086  dCCdX[0] = (CC_px-CC_mx)/(2*NUM_DERIV_H_CEN);
3087  dCCdX[1] = (CC_py-CC_my)/(2*NUM_DERIV_H_CEN);
3088  dCCdX[2] = (CC_pz-CC_mz)/(2*NUM_DERIV_H_CEN);
3089 
3090  //////
3091  ////// debug : compare d_true to d_exact
3092  numeric::xyzVector<core::Real> dCCdX1 = dCCdxs_res[resid][atmid];
3093  TR << " " << dCCdX<< " ; " << dCCdX1 << std::endl;
3094  }
3095 }
3096 
3097 
3098 /////////////////////////////////////
3099 // Compute the gradient (whole-structure CA density score)
3102  core::pose::Pose const &pose,
3104  // make sure map is loaded
3105  if (!isLoaded) {
3106  TR << "[ ERROR ] ElectronDensity::dCCdx_cen called but no map is loaded!\n";
3107  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3108  exit(1);
3109  }
3110  // make sure map is loaded
3111  if (!isLoaded) {
3112  TR << "[ ERROR ] ElectronDensity::dCCdx_cen called but no map is loaded!\n";
3113  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3114  exit(1);
3115  }
3116 
3117  static bool warned=false;
3118  if (!DensScoreInMinimizer) {
3119  if (!warned)
3120  TR << "[ WARNING ] dCCdx_cen called but DensityScoreInMinimizer = false ... returning 0" << std::endl;
3121  //warned = true;
3122  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3123  return;
3124  }
3125 
3126  if (! ExactDerivatives ) {
3127  dCCdX = dCCdxs_cen[resid];
3128  } else {
3129  //
3130  core::pose::Pose pose_copy = pose;
3131  id::AtomID id(2,resid);
3132 
3133  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0]+NUM_DERIV_H_CEN,X[1],X[2] ) );
3134  core::Real CC_px = getDensityMap().matchPose( pose_copy , NULL, true );
3135 
3136  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0]-NUM_DERIV_H_CEN,X[1],X[2] ) );
3137  core::Real CC_mx = getDensityMap().matchPose( pose_copy , NULL, true );
3138 
3139  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1]+NUM_DERIV_H_CEN,X[2] ) );
3140  core::Real CC_py = getDensityMap().matchPose( pose_copy , NULL, true );
3141 
3142  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1]-NUM_DERIV_H_CEN,X[2] ) );
3143  core::Real CC_my = getDensityMap().matchPose( pose_copy , NULL, true );
3144 
3145  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1],X[2]+NUM_DERIV_H_CEN ) );
3146  core::Real CC_pz = getDensityMap().matchPose( pose_copy , NULL, true );
3147 
3148  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1],X[2]-NUM_DERIV_H_CEN ) );
3149  core::Real CC_mz = getDensityMap().matchPose( pose_copy , NULL, true );
3150 
3151  // rescore with orig pose
3152  getDensityMap().matchPose( pose , NULL, true );
3153 
3154  dCCdX[0] = (CC_px-CC_mx)/(2*NUM_DERIV_H_CEN);
3155  dCCdX[1] = (CC_py-CC_my)/(2*NUM_DERIV_H_CEN);
3156  dCCdX[2] = (CC_pz-CC_mz)/(2*NUM_DERIV_H_CEN);
3157 
3158  ////// debug : compare d_true to d_exact
3159  numeric::xyzVector<core::Real> dCCdX1 = dCCdxs_cen[resid];
3160  TR << " " << dCCdX<< " ; " << dCCdX1 << std::endl;
3161  }
3162 }
3163 
3164 
3165 /////////////////////////////////////
3166 // Compute the gradient (whole-structure allatom density score)
3167 void ElectronDensity::dCCdx_aacen( int atmid, int resid,
3169  core::pose::Pose const &pose,
3171  // make sure map is loaded
3172  if (!isLoaded) {
3173  TR << "[ ERROR ] ElectronDensity::dCCdx_aacen called but no map is loaded!\n";
3174  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3175  exit(1);
3176  }
3177 
3178  static bool warned=false;
3179  if (!DensScoreInMinimizer) {
3180  if (!warned)
3181  TR << "[ WARNING ] dCCdx_aacen called but DensityScoreInMinimizer = false ... returning 0" << std::endl;
3182  //warned = true;
3183  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3184  return;
3185  }
3186 
3187  // if we didn't score this residue
3188  // (because it was missing density or masked or a symm copy)
3189  // then don't compute its derivative
3190  if ( (int)dCCdxs_aacen[resid].size() < atmid ) {
3191  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3192  return;
3193  }
3194 
3195  if (! ExactDerivatives ) {
3196  dCCdX = dCCdxs_aacen[resid][atmid];
3197  } else {
3198  //
3199  core::pose::Pose pose_copy = pose;
3200  id::AtomID id(atmid,resid);
3201 
3202  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0]+NUM_DERIV_H_CEN,X[1],X[2] ) );
3203  core::Real CC_px = getDensityMap().matchPose( pose_copy , NULL, true );
3204 
3205  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0]-NUM_DERIV_H_CEN,X[1],X[2] ) );
3206  core::Real CC_mx = getDensityMap().matchPose( pose_copy , NULL, true );
3207 
3208  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1]+NUM_DERIV_H_CEN,X[2] ) );
3209  core::Real CC_py = getDensityMap().matchPose( pose_copy , NULL, true );
3210 
3211  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1]-NUM_DERIV_H_CEN,X[2] ) );
3212  core::Real CC_my = getDensityMap().matchPose( pose_copy , NULL, true );
3213 
3214  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1],X[2]+NUM_DERIV_H_CEN ) );
3215  core::Real CC_pz = getDensityMap().matchPose( pose_copy , NULL, true );
3216 
3217  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1],X[2]-NUM_DERIV_H_CEN ) );
3218  core::Real CC_mz = getDensityMap().matchPose( pose_copy , NULL, true );
3219 
3220  // rescore with orig pose
3221  getDensityMap().matchPose( pose , NULL, true );
3222 
3223  dCCdX[0] = (CC_px-CC_mx)/(2*NUM_DERIV_H_CEN);
3224  dCCdX[1] = (CC_py-CC_my)/(2*NUM_DERIV_H_CEN);
3225  dCCdX[2] = (CC_pz-CC_mz)/(2*NUM_DERIV_H_CEN);
3226 
3227  //////
3228  ////// debug : compare d_true to d_exact
3229  numeric::xyzVector<core::Real> dCCdX1 = dCCdxs_aacen[resid][atmid];
3230  TR << " " << dCCdX<< " ; " << dCCdX1 << std::endl;
3231  }
3232 }
3233 
3234 /////////////////////////////////////
3235 // Compute the gradient w.r.t. patterson correlation
3236 void ElectronDensity::dCCdx_pat( int atmid, int resid,
3238  core::pose::Pose const &pose,
3240  // make sure map is loaded
3241  if (!isLoaded) {
3242  TR << "[ ERROR ] ElectronDensity::dCCdx_aacen called but no map is loaded!\n";
3243  exit(1);
3244  }
3245 
3246  static bool warned=false;
3247  if (!DensScoreInMinimizer) {
3248  if (!warned)
3249  TR << "[ WARNING ] dCCdx_pat called but DensityScoreInMinimizer = false ... returning 0" << std::endl;
3250  //warned = true;
3251  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3252  return;
3253  }
3254 
3255  // if we didn't score this residue
3256  // (because it was missing density or masked or a symm copy)
3257  // then don't compute its derivative
3258  if ( (int)dCCdxs_pat[resid].size() < atmid ) {
3259  dCCdX = numeric::xyzVector<core::Real>(0.0,0.0,0.0);
3260  return;
3261  }
3262 
3263  if (! ExactDerivatives ) {
3264  dCCdX = dCCdxs_pat[resid][atmid];
3265  } else {
3266  //
3267  core::pose::Pose pose_copy = pose;
3268  id::AtomID id(atmid,resid);
3269 
3270  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0]+NUM_DERIV_H_CEN,X[1],X[2] ) );
3271  core::Real CC_px = getDensityMap().matchPoseToPatterson( pose_copy , false );
3272 
3273  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0]-NUM_DERIV_H_CEN,X[1],X[2] ) );
3274  core::Real CC_mx = getDensityMap().matchPoseToPatterson( pose_copy , false );
3275 
3276  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1]+NUM_DERIV_H_CEN,X[2] ) );
3277  core::Real CC_py = getDensityMap().matchPoseToPatterson( pose_copy , false );
3278 
3279  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1]-NUM_DERIV_H_CEN,X[2] ) );
3280  core::Real CC_my = getDensityMap().matchPoseToPatterson( pose_copy , false );
3281 
3282  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1],X[2]+NUM_DERIV_H_CEN ) );
3283  core::Real CC_pz = getDensityMap().matchPoseToPatterson( pose_copy , false );
3284 
3285  pose_copy.set_xyz(id, numeric::xyzVector<core::Real>( X[0],X[1],X[2]-NUM_DERIV_H_CEN ) );
3286  core::Real CC_mz = getDensityMap().matchPoseToPatterson( pose_copy , false );
3287 
3288  // rescore with orig pose
3289  getDensityMap().matchPoseToPatterson( pose , false );
3290 
3291  dCCdX[0] = (CC_px-CC_mx)/(2*NUM_DERIV_H_CEN);
3292  dCCdX[1] = (CC_py-CC_my)/(2*NUM_DERIV_H_CEN);
3293  dCCdX[2] = (CC_pz-CC_mz)/(2*NUM_DERIV_H_CEN);
3294 
3295  //////
3296  ////// debug : compare d_true to d_exact
3297  numeric::xyzVector<core::Real> dCCdX1 = dCCdxs_pat[resid][atmid];
3298  TR << resid << " " << atmid << " :: " << dCCdX << " :: " << dCCdX1 << std::endl;
3299  }
3300 }
3301 
3302 /////////////////////////////////////
3303 // ElectronDensity::readMRC(std::string mapfile)
3304 // read an MRC/CCP4 density map
3305 bool
3307  std::string mapfile,
3308  core::Real reso,
3309  core::Real gridSpacing
3310 ) {
3311  std::ifstream mapin(mapfile.c_str() , std::ios::binary | std::ios::in );
3312  bool isLoaded(readMRCandResize(mapin, mapfile, reso, gridSpacing));
3313  mapin.close();
3314 
3315  return isLoaded;
3316 }
3317 
3318 /////////////////////////////////////
3319 // ElectronDensity::readMRC(std::istream mapfile)
3320 // read an MRC/CCP4 density map
3321 bool
3323  std::istream & mapin,
3324  std::string mapfile,
3325  core::Real reso,
3326  core::Real gridSpacing
3327 ) {
3328 
3329  // set map resolution
3330  this->reso = reso;
3331  char mapString[4], symData[81];
3332 
3333  int crs2xyz[3], extent[3], mode, symBytes, grid[3], origin[3];
3334  int xyz2crs[3], vol_xsize, vol_ysize, vol_zsize;
3335  int xIndex, yIndex, zIndex, vol_xySize, coord[3];
3336  long dataOffset, filesize;
3337  float *rowdata;
3338 
3339  bool swap=false;
3340 
3341  if (!mapin) {
3342  TR << "[ ERROR ] Error opening MRC map " << mapfile << ". Not loading map." << std::endl;
3343  return false;
3344  }
3345 
3346  if ( !mapin.read(reinterpret_cast <char*> (extent), 3*sizeof(int))
3347  || !mapin.read(reinterpret_cast <char*> (&mode), 1*sizeof(int))
3348  || !mapin.read(reinterpret_cast <char*> (&origin[0]), 3*sizeof(int))
3349  || !mapin.read(reinterpret_cast <char*> (&grid[0]), 3*sizeof(int))
3350  || !mapin.read(reinterpret_cast <char*> (&cellDimensions[0]), 3*sizeof(float))
3351  || !mapin.read(reinterpret_cast <char*> (&cellAngles[0]), 3*sizeof(float))
3352  || !mapin.read(reinterpret_cast <char*> (crs2xyz), 3*sizeof(int)) ) {
3353  TR << "[ ERROR ] Improperly formatted line in MRC map. Not loading map." << std::endl;
3354  return false;
3355  }
3356 
3357  // Check the number of bytes used for storing symmetry operators
3358  mapin.seekg(92, std::ios::beg);
3359  if ( !mapin.read(reinterpret_cast <char*> (&symBytes), 1*sizeof(int)) ) {
3360  TR << "[ ERROR ] Failed reading symmetry bytes record. Not loading map." << "\n";
3361  return false;
3362  }
3363 
3364  // alt: MRC files have floating-point origin info at byte 196
3365  // read this and try to figure out if it is used
3366  float altorigin[3];
3367  mapin.seekg(196, std::ios::beg);
3368  if ( !mapin.read(reinterpret_cast <char*> (altorigin), 3*sizeof(float)) ) {
3369  TR << "[ ERROR ] Improperly formatted line in MRC map. Not loading map." << std::endl;
3370  return false;
3371  }
3372 
3373  // Check for the string "MAP" at byte 208, indicating a CCP4 file.
3374  mapin.seekg(208, std::ios::beg);
3375  mapString[3] = '\0';
3376  if ( !mapin.read(mapString, 3) || (std::string(mapString) != "MAP")) {
3377  TR << "[ ERROR ] 'MAP' string missing, not a valid MRC map. Not loading map." << std::endl;
3378  return false;
3379  }
3380  // Check the file endianness
3381  if (mode != 2) {
3382  swap4_aligned(&mode, 1);
3383  if (mode != 2) {
3384  TR << "[ ERROR ] Non-real (32-bit float) data types are unsupported. Not loading map." << std::endl;
3385  return false;
3386  } else {
3387  swap = true; // enable byte swapping
3388  }
3389  }
3390 
3391  // Swap all the information obtained from the header
3392  if (swap) {
3393  swap4_aligned(extent, 3);
3394  swap4_aligned(&origin[0], 3);
3395  swap4_aligned(&altorigin[0], 3);
3396  swap4_aligned(&grid[0], 3);
3397  swap4_aligned(&cellDimensions[0], 3);
3398  swap4_aligned(&cellAngles[0], 3);
3399  swap4_aligned(crs2xyz, 3);
3400  swap4_aligned(&symBytes, 1);
3401  }
3402 
3403  TR << " Setting resolution to " << reso << "A" << std::endl;
3404  TR << " atom mask to " << ATOM_MASK << "A" << std::endl;
3405  TR << " CA mask to " << CA_MASK << "A" << std::endl;
3406  TR << " Read density map'" << mapfile << "'" << std::endl;
3407  TR << " extent: " << extent[0] << " x " << extent[1] << " x " << extent[2] << std::endl;
3408  TR << " origin: " << origin[0] << " x " << origin[1] << " x " << origin[2] << std::endl;
3409  TR << " altorigin: " << altorigin[0] << " x " << altorigin[1] << " x " << altorigin[2] << std::endl;
3410  TR << " grid: " << grid[0] << " x " << grid[1] << " x " << grid[2] << std::endl;
3411  TR << " celldim: " << cellDimensions[0] << " x " << cellDimensions[1] << " x " << cellDimensions[2] << std::endl;
3412  TR << " cellangles: " << cellAngles[0] << " x " << cellAngles[1] << " x " << cellAngles[2] << std::endl;
3413  TR << " crs2xyz: " << crs2xyz[0] << " x " << crs2xyz[1] << " x " << crs2xyz[2] << std::endl;
3414  TR << " symBytes: " << symBytes << "\n";
3415 
3416  // Check the dataOffset: this fixes the problem caused by files claiming
3417  // to have symmetry records when they do not.
3418  mapin.seekg(0, std::ios::end);
3419  filesize = mapin.tellg();
3420  dataOffset = filesize - 4*(extent[0]*extent[1]*extent[2]);
3421  if (dataOffset != (CCP4HDSIZE + symBytes)) {
3422  if (dataOffset == CCP4HDSIZE) {
3423  // Bogus symmetry record information
3424  TR << "[ WARNING ] File contains bogus symmetry record. Continuing." << std::endl;
3425  symBytes = 0;
3426  } else if (dataOffset < CCP4HDSIZE) {
3427  TR << "[ ERROR ] File appears truncated and doesn't match header. Not loading map." << std::endl;
3428  return false;
3429  } else if ((dataOffset > CCP4HDSIZE) && (dataOffset < (1024*1024))) {
3430  // Fix for loading SPIDER files which are larger than usual
3431  // In this specific case, we must absolutely trust the symBytes record
3432  dataOffset = CCP4HDSIZE + symBytes;
3433  TR << "[ WARNING ] File is larger than expected and doesn't match header. Reading anyway." << std::endl;
3434  } else {
3435  TR << "[ ERROR ] File is MUCH larger than expected and doesn't match header. Not loading map." << std::endl;
3436  return false;
3437  }
3438  }
3439 
3440  // Read symmetry records -- organized as 80-byte lines of text.
3442  symData[80]='\0';
3443  if (symBytes != 0) {
3444  TR << "Symmetry records found:" << std::endl;
3445  mapin.seekg(CCP4HDSIZE, std::ios::beg);
3446  for (int i = 0; i < symBytes/80; i++) {
3447  mapin.read(symData, 80);
3448  symList.push_back(symData);
3449  TR << symData << std::endl;
3450  }
3451  } else {
3452  // no symm info; assume P 1
3453  symList.push_back("X, Y, Z");
3454  }
3455  initializeSymmOps( symList );
3456 
3457  // check extent and grid interval counts
3458  if (grid[0] == 0 && extent[0] > 0) {
3459  grid[0] = extent[0] - 1;
3460  TR << "[ WARNING ] Fixed X interval count. Continuing." << std::endl;
3461  }
3462  if (grid[1] == 0 && extent[1] > 0) {
3463  grid[1] = extent[1] - 1;
3464  TR << "[ WARNING ] Fixed Y interval count. Continuing." << std::endl;
3465  }
3466  if (grid[2] == 0 && extent[2] > 0) {
3467  grid[2] = extent[2] - 1;
3468  TR << "[ WARNING ] Fixed Z interval count. Continuing." << std::endl;
3469  }
3470 
3471  // Mapping between CCP4 column, row, section and Cartesian x, y, z.
3472  if (crs2xyz[0] == 0 && crs2xyz[1] == 0 && crs2xyz[2] == 0) {
3473  TR << "[ WARNING ] All crs2xyz records are zero." << std::endl;
3474  TR << "[ WARNING ] Setting crs2xyz to 1, 2, 3 and continuing." << std::endl;
3475  crs2xyz[0] = 1; crs2xyz[1] = 2; crs2xyz[2] = 3;
3476  }
3477 
3478  xyz2crs[crs2xyz[0]-1] = 0; xyz2crs[crs2xyz[1]-1] = 1; xyz2crs[crs2xyz[2]-1] = 2;
3479  xIndex = xyz2crs[0]; yIndex = xyz2crs[1]; zIndex = xyz2crs[2];
3480 
3481  vol_xsize = extent[xIndex];
3482  vol_ysize = extent[yIndex];
3483  vol_zsize = extent[zIndex];
3484  vol_xySize = vol_xsize * vol_ysize;
3485 
3486  // coord = <col, row, sec>
3487  // extent = <colSize, rowSize, secSize>
3488  rowdata = new float[extent[0]];
3489  mapin.seekg(dataOffset, std::ios::beg);
3490 
3491  // 'alloc' changes ordering of "extent"
3492  density.dimension( vol_xsize,vol_ysize,vol_zsize );
3493 
3494  for (coord[2] = 1; coord[2] <= extent[2]; coord[2]++) {
3495  for (coord[1] = 1; coord[1] <= extent[1]; coord[1]++) {
3496  // Read an entire row of data from the file, then write it into the
3497  // datablock with the correct slice ordering.
3498  if ( mapin.eof() ) {
3499  TR << "[ ERROR ] Unexpected end-of-file. Not loading map." << std::endl;
3500  return false;
3501  }
3502  if ( mapin.fail() ) {
3503  TR << "[ ERROR ] Problem reading the file. Not loading map." << std::endl;
3504  return false;
3505  }
3506  if ( !mapin.read( reinterpret_cast< char* >(rowdata), sizeof(float)*extent[0]) ) {
3507  TR << "[ ERROR ] Error reading data row. Not loading map." << std::endl;
3508  return false;
3509  }
3510 
3511  for (coord[0] = 1; coord[0] <= extent[0]; coord[0]++) {
3512  density( coord[xyz2crs[0]], coord[xyz2crs[1]], coord[xyz2crs[2]]) = rowdata[coord[0]-1];
3513  }
3514  }
3515  }
3516 
3517  if (swap == 1)
3518  swap4_aligned( &density[0], vol_xySize * vol_zsize);
3519  delete [] rowdata;
3520 
3521  this->origin[0] = origin[xyz2crs[0]];
3522  this->origin[1] = origin[xyz2crs[1]];
3523  this->origin[2] = origin[xyz2crs[2]];
3524 
3525  // grid doesnt seemed to get remapped in ccp4 maps
3526  this->grid[0] = grid[0];
3527  this->grid[1] = grid[1];
3528  this->grid[2] = grid[2];
3529 
3530  // advanced: force the apix value different than what is provided
3532  if (force_apix_ > 0) {
3533  ori_scale[0] = (force_apix_ * this->grid[0]) / cellDimensions[0];
3534  ori_scale[1] = (force_apix_ * this->grid[0]) / cellDimensions[1];
3535  ori_scale[2] = (force_apix_ * this->grid[0]) / cellDimensions[2];
3536  cellDimensions[0] = force_apix_ * this->grid[0];
3537  cellDimensions[1] = force_apix_ * this->grid[1];
3538  cellDimensions[2] = force_apix_ * this->grid[2];
3539  TR << "Forcing apix to " << force_apix_ << std::endl;
3540  }
3541 
3542  ///////////////////////////////////
3543  /// POST PROCESSING
3544  // expand to unit cell
3545  this->computeCrystParams();
3546 
3547  // mrc format maps occasionally specify a real-valued origin in a different spot in the header
3548  if ( altorigin[0]!=0 && altorigin[0]!=0 && altorigin[0]!=0 &&
3549  ( altorigin[0] > -10000 && altorigin[0] < 10000) &&
3550  ( altorigin[1] > -10000 && altorigin[1] < 10000) &&
3551  ( altorigin[2] > -10000 && altorigin[2] < 10000)
3552  ) {
3553  this->origin[0] = altorigin[xyz2crs[0]];
3554  this->origin[1] = altorigin[xyz2crs[1]];
3555  this->origin[2] = altorigin[xyz2crs[2]];
3556  numeric::xyzVector<core::Real> fracX = c2f*(this->origin);
3557  this->origin = numeric::xyzVector<core::Real>( fracX[0]*grid[0] , fracX[1]*grid[1] , fracX[2]*grid[2] );
3558 
3559  TR << "Using ALTERNATE origin\n";
3560  TR << " origin =" << this->origin[0] << " x " << this->origin[1] << " x " << this->origin[2] << std::endl;
3561  }
3562 
3563  // if we force the apix, adjust the origin accordingly
3564  if (force_apix_ > 0) {
3565  this->origin = numeric::xyzVector<core::Real>(
3566  this->origin[0]*ori_scale[0] ,
3567  this->origin[1]*ori_scale[1] ,
3568  this->origin[2]*ori_scale[2] );
3569 
3570  TR << "Force apix repositioning the origin:\n";
3571  TR << " origin =" << this->origin[0] << " x " << this->origin[1] << " x " << this->origin[2] << std::endl;
3572  }
3573 
3574  this->efforigin = this->origin;
3575  this->expandToUnitCell();
3576 
3577  // resample the map
3578  if (gridSpacing > 0) this->resize( gridSpacing );
3579 
3580  // grid spacing in each dim
3581  max_del_grid = std::max( cellDimensions[0]/((double)this->grid[0]) , cellDimensions[1]/((double)this->grid[1]) );
3582  max_del_grid = std::max( max_del_grid , cellDimensions[2]/((double)this->grid[2]) );
3583 
3584  // density scoring low res limit
3585  if (reso/2 > max_del_grid)
3586  max_del_grid = reso/2;
3587 
3588  TR << " max_del_grid =" << max_del_grid << std::endl;
3589 
3590  // potentially adjust mask
3591  {
3592  OneGaussianScattering cscat = get_A( "C" );
3593  // extend mask 2 stdevs from carbon
3594  // stdev = sqrt
3595  core::Real mask_min = 2.0 * sqrt( 2.0 / cscat.k(PattersonB,max_del_grid) );
3596  if (ATOM_MASK < mask_min) {
3597  TR.Warning << "OVERIDING ATOM MASK SETTING (was " << ATOM_MASK << ", now " << mask_min << ")" << std::endl;
3598  ATOM_MASK = mask_min;
3599  }
3600  if (CA_MASK < mask_min) {
3601  TR.Warning << "OVERIDING CA MASK SETTING (was " << CA_MASK << ", now " << mask_min << ")" << std::endl;
3602  CA_MASK = mask_min;
3603  }
3604  }
3605 
3606  // fft
3607  numeric::fourier::fft3(density, Fdensity);
3608 
3609  // post-processing
3610  this->computeStats();
3611  this->computeGradients();
3612 
3613  // we're done!
3614  isLoaded = true;
3615  return isLoaded;
3616 }
3617 
3618 
3619 /////////////////////////////////////
3620 // parse symmops from ccp4 map header
3621 /// also sets MINMULT(XYZ)
3622 /// eventually replace with cctbx
3624  using core::kinematics::RT;
3625 
3626  symmOps.clear();
3627 
3628  if ( symList.size() == 0 ) { // no symminfo in header, assume P 1
3629  symmOps.push_back( RT( numeric::xyzMatrix< core::Real >::identity(),
3630  numeric::xyzVector< core::Real >(0.0,0.0,0.0) ) );
3631  }
3632 
3633  MINMULT[0] = MINMULT[1] = MINMULT[2] = 2;
3634  for (int i=1; i<=(int)symList.size(); ++i) {
3635  std::string line = symList[i];
3636  utility::vector1< std::string > rows = utility::string_split(line, ',');
3637  if ( rows.size() != 3 ) {
3638  TR.Error << "[ ERROR ] invalid symmop in map file" << std::endl;
3639  TR.Error << line << std::endl;
3640  TR.Error << "Setting symmetry to P1 and continuing!" << line << std::endl;
3641 
3642  // should we throw an exception here???? nah, just set symm to P1 and continue
3643  symmOps.clear();
3644  symmOps.push_back( RT( numeric::xyzMatrix< core::Real >::identity(),
3645  numeric::xyzVector< core::Real >(0.0,0.0,0.0) ) );
3646 
3647  return;
3648  }
3649 
3650  // _REALLY_ simple parser
3653  int k;
3654  for (int j=1; j<=3; ++j) {
3655  k = rows[j].find('/');
3656  if (k != (int)std::string::npos) {
3657  // numerator
3658  int startNum = rows[j].find_last_not_of("0123456789",k-1) + 1;
3659  int startDenom = k+1;
3660  float denom = std::atof( &rows[j][startDenom]);
3661 
3662  // make sure this shift corresponds to a point in the map
3663  core::Size oldMinMult = MINMULT[j-1];
3664  while ( std::fmod(MINMULT[j-1] , denom) > 1e-6 ) MINMULT[j-1] += oldMinMult;
3665 
3666  trans[j-1] = std::atof( &rows[j][startNum]) / denom;
3667  } else {
3668  trans[j-1] = 0;
3669  }
3670 
3671  if (rows[j].find("-X") != std::string::npos)
3672  rot(j,1) = -1;
3673  else if (rows[j].find("X") != std::string::npos)
3674  rot(j,1) = 1;
3675 
3676  if (rows[j].find("-Y") != std::string::npos)
3677  rot(j,2) = -1;
3678  else if (rows[j].find("Y") != std::string::npos)
3679  rot(j,2) = 1;
3680 
3681  if (rows[j].find("-Z") != std::string::npos)
3682  rot(j,3) = -1;
3683  else if (rows[j].find("Z") != std::string::npos)
3684  rot(j,3) = 1;
3685  }
3686 
3687  symmOps.push_back( RT( rot, trans ) );
3688 
3689  // remember rotations only for patterson case
3690  // only put one of (-aX,-bY,-cZ) and ( aX,bY,cZ)
3691  // ignore translations
3692  bool dup = false;
3693  for (int i=1; i<=(int)symmRotOps.size(); ++i) {
3694  numeric::xyzMatrix<core::Real> R_i = symmRotOps[i];
3695  if ( ( rot(1,1) == R_i(1,1) && rot(1,2) == R_i(1,2) && rot(1,3) == R_i(1,3)
3696  && rot(2,1) == R_i(2,1) && rot(2,2) == R_i(2,2) && rot(2,3) == R_i(2,3)
3697  && rot(3,1) == R_i(3,1) && rot(3,2) == R_i(3,2) && rot(3,3) == R_i(3,3) ) ||
3698  ( rot(1,1) == -R_i(1,1) && rot(1,2) == -R_i(1,2) && rot(1,3) == -R_i(1,3)
3699  && rot(2,1) == -R_i(2,1) && rot(2,2) == -R_i(2,2) && rot(2,3) == -R_i(2,3)
3700  && rot(3,1) == -R_i(3,1) && rot(3,2) == -R_i(3,2) && rot(3,3) == -R_i(3,3) ) ) {
3701  dup = true;
3702  break;
3703  }
3704  }
3705  if (!dup) {
3706  //std::cerr << " ADD ROTATION " << std::endl
3707  // << rot(1,1) << "," << rot(1,2) << "," << rot(1,3) << std::endl
3708  // << rot(2,1) << "," << rot(2,2) << "," << rot(2,3) << std::endl
3709  // << rot(3,1) << "," << rot(3,2) << "," << rot(3,3) << std::endl;
3710  symmRotOps.push_back( rot );
3711  }
3712  }
3713 
3714  TR << "MINMULT: " << MINMULT[0] << " " << MINMULT[1] << " " << MINMULT[2] << std::endl;
3715  return;
3716 }
3717 
3718 /////////////////////////////////////
3719 // expand density to cover unit cell
3720 // maintain origin
3722  numeric::xyzVector< int > extent( density.u1(), density.u2(), density.u3() );
3723 
3724  // if it already covers unit cell do nothing
3725  if ( grid[0] == extent[0] && grid[1] == extent[1] && grid[2] == extent[2] )
3726  return;
3727 
3728  ObjexxFCL::FArray3D< float > newDensity( grid[0],grid[1],grid[2], 0.0 );
3729 
3730  // copy the block
3731  int limX=std::min(extent[0],grid[0]),
3732  limY=std::min(extent[1],grid[1]),
3733  limZ=std::min(extent[2],grid[2]);
3734  for (int x=1; x<=limX; ++x)
3735  for (int y=1; y<=limY; ++y)
3736  for (int z=1; z<=limZ; ++z) {
3737  newDensity( x,y,z ) = density( x,y,z );
3738  }
3739 
3740  // apply symmetry
3741  // why backwards? it is a mystery
3742  for (int x=grid[0]; x>=1; --x)
3743  for (int y=grid[1]; y>=1; --y)
3744  for (int z=grid[2]; z>=1; --z) {
3745  if (x <= limX && y <= limY && z <= limZ)
3746  continue;
3747 
3749  ( (core::Real)x + origin[0] - 1 ) / grid[0],
3750  ( (core::Real)y + origin[1] - 1 ) / grid[1],
3751  ( (core::Real)z + origin[2] - 1 ) / grid[2] );
3752 
3753  for (int symm_idx=1; symm_idx<=(int)symmOps.size(); symm_idx++) {
3755  symmOps[symm_idx].get_rotation() * fracX + symmOps[symm_idx].get_translation();
3756 
3757  // indices of symm copy
3758  int Sx = pos_mod((int)floor(SfracX[0]*grid[0]+0.5 - origin[0]) , grid[0]) + 1;
3759  int Sy = pos_mod((int)floor(SfracX[1]*grid[1]+0.5 - origin[1]) , grid[1]) + 1 ;
3760  int Sz = pos_mod((int)floor(SfracX[2]*grid[2]+0.5 - origin[2]) , grid[2]) + 1 ;
3761 
3762  if (Sx <= limX && Sy <= limY && Sz <= limZ) {
3763  newDensity( x,y,z ) = density(Sx,Sy,Sz);
3764  }
3765  }
3766  }
3767 
3768  if (basic::options::option[ basic::options::OptionKeys::edensity::debug ]()) {
3769  ElectronDensity(density,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "rho_before_expand.mrc");
3770  ElectronDensity(newDensity,1.0, numeric::xyzVector< core::Real >(0,0,0), false ).writeMRC( "rho_after_expand.mrc");
3771  }
3772 
3773  // new map!
3774  density = newDensity;
3775 }
3776 
3777 
3779  for (int i=1; i<=(int)reses.size(); ++i ) {
3780  TR << " " << reses[i] << ": " << CCs[reses[i]] << std::endl;
3781  }
3782 }
3783 
3784 /////////////////////////////////////
3785 // DEBUGGING: write _this_ map in MATLAB v5 format
3787  using namespace std;
3788 
3789  string outfile = filestem + ".mat";
3790  numeric::xyzVector<int> dims( density.u1(), density.u2(), density.u3() );
3791 
3792  ofstream out;
3793  out.open(outfile.c_str(), ios::out);
3794 
3795  // write file header
3796  short buff_s;
3797  long buff_l;
3798  out.write(
3799  "MATLAB 5.0 MAT-file, Platform: GLNX86 "
3800  " "
3801  " "
3802  " ", 124);
3803  buff_s=0x0100; // endian-ness test
3804  out.write((char*)&buff_s, 2);
3805  buff_s=0x4D49; // code(?)
3806  out.write((char*)&buff_s, 2);
3807 
3808  // write data block header
3809  buff_l = 0x0000000E; // data type (array)
3810  out.write((char*)&buff_l, 4);
3811  buff_l = 4*dims[0]*dims[1]*dims[2] + 64; // number of bytes
3812  out.write((char*)&buff_l, 4);
3813 
3814  // write array header
3815  buff_l = 0x00000006; // array data type (single)
3816  out.write((char*)&buff_l, 4);
3817  buff_l = 0x00000008; // # bytes in array data block
3818  out.write((char*)&buff_l, 4);
3819  buff_l = 0x00000007; // global/logical flags
3820  out.write((char*)&buff_l, 4);
3821  buff_l = 0x00000000; // padding
3822  out.write((char*)&buff_l, 4);
3823 
3824  // write dims array
3825  buff_l = 0x00000005; // dims data type (int32)
3826  out.write((char*)&buff_l, 4);
3827  buff_l = 0x0000000C; // # bytes in dims data block
3828  out.write((char*)&buff_l, 4);
3829  out.write((char*)&dims[0], 12);
3830  buff_l = 0x00000000; // padding
3831  out.write((char*)&buff_l, 4);
3832 
3833  // write name array
3834  buff_l=0x0001; // name data type (int8)
3835  out.write((char*)&buff_l, 4);
3836  buff_l=0x0005; // # bytes in name
3837  out.write((char*)&buff_l, 4);
3838  out.write("match ", 8); // pad with spaces so next write is word-aligned
3839 
3840  // write array
3841  buff_l = 0x00000007; // array data type (single)
3842  out.write((char*)&buff_l, 4);
3843  buff_l = 4*dims[0]*dims[1]*dims[2];
3844  out.write((char*)&buff_l, 4);
3845 
3846  for (int k=1; k<=dims[2]; k++) {
3847  for (int j=1; j<=dims[1]; j++) {
3848  for (int i=1; i<=dims[0]; i++) {
3849  float buff_f = (float) density(i,j,k);
3850  out.write((char*)&buff_f, 4);
3851  }
3852  }
3853  }
3854 
3855  out.close();
3856 
3857  return true;
3858 }
3859 
3860 /////////////////////////////////////
3861 // DEBUGGING: write _this_ map in MRC format
3863  std::fstream outx( (mapfilename).c_str() , std::ios::binary | std::ios::out );
3864 
3865  float buff_f;
3866  int buff_i;
3867  float buff_vf[3];
3868  int buff_vi[3];
3869  int symBytes = 0;
3870 
3871  if (!outx ) {
3872  TR.Error << "[ ERROR ] Error opening MRC map for writing." << std::endl;
3873  return false;
3874  }
3875 
3876  // extent
3877  buff_vi[0] = density.u1(); buff_vi[1] = density.u2(); buff_vi[2] = density.u3();
3878  outx.write(reinterpret_cast <char*>(buff_vi), sizeof(int)*3);
3879 
3880  // mode
3881  buff_i = 2;
3882  outx.write(reinterpret_cast <char*>(&buff_i), sizeof(int));
3883 
3884  // origin
3885  int ori_int[3];
3886  ori_int[0] = (int)std::floor( origin[0] );
3887  ori_int[1] = (int)std::floor( origin[1] );
3888  ori_int[2] = (int)std::floor( origin[2] );
3889  outx.write(reinterpret_cast <char*>(ori_int), sizeof(int)*3);
3890 
3891  // grid
3892  outx.write(reinterpret_cast <char*>(&grid[0]), sizeof(int)*3);
3893 
3894  // cell params
3895  outx.write(reinterpret_cast <char*>(&cellDimensions), sizeof(float)*3);
3896  outx.write(reinterpret_cast <char*>(&cellAngles), sizeof(float)*3);
3897 
3898  // crs2xyz
3899  buff_vi[0] = 1; buff_vi[1] = 2; buff_vi[2] = 3;
3900  outx.write(reinterpret_cast <char*>(buff_vi), sizeof(int)*3);
3901 
3902  // min, max, mean dens
3903  buff_vf[0] = -100.0; buff_vf[1] = 100.0; buff_vf[2] = 0.0;
3904  outx.write(reinterpret_cast <char*>(buff_vf), sizeof(float)*3);
3905 
3906  // 4 bytes junk
3907  buff_i = 0;
3908  outx.write(reinterpret_cast <char*>(&buff_i), sizeof(int));
3909 
3910  // symmops (to do!)
3911  outx.write(reinterpret_cast <char*>(&symBytes), sizeof(int));
3912 
3913  // 104 bytes junk
3914  buff_i = 0;
3915  for (int i=0; i<25; ++i) {
3916  outx.write(reinterpret_cast <char*>(&buff_i), sizeof(int));
3917  }
3918 
3919  // alt origin (MRC)
3920  float ori_float[3];
3921  numeric::xyzVector<core::Real> origin_realspace;
3922  idx2cart ( numeric::xyzVector<core::Real>(1,1,1), origin_realspace );
3923  ori_float[0] = (float)( origin_realspace[0] );
3924  ori_float[1] = (float)( origin_realspace[1] );
3925  ori_float[2] = (float)( origin_realspace[2] );
3926  outx.write(reinterpret_cast <char*>(ori_float), sizeof(float)*3);
3927 
3928  // Write "MAP" at byte 208, indicating a CCP4 file.
3929  char buff_s[80]; strcpy(buff_s, "MAP DD");
3930  outx.write(reinterpret_cast <char*>(buff_s), 8);
3931 
3932  // fill remainder of head with junk
3933  int nJunkWords = (CCP4HDSIZE - 216) /4;
3934  buff_i = 0;
3935  for (int i=0; i<nJunkWords; ++i) {
3936  outx.write(reinterpret_cast <char*>(&buff_i), sizeof(int));
3937  }
3938 
3939  // data
3940  int coord[3];
3941  for (coord[2] = 1; coord[2] <= density.u3(); coord[2]++) {
3942  for (coord[1] = 1; coord[1] <= density.u2(); coord[1]++) {
3943  for (coord[0] = 1; coord[0] <= density.u1(); coord[0]++) {
3944  buff_f = (float) density(coord[0],coord[1],coord[2]);
3945  outx.write(reinterpret_cast <char*>(&buff_f), sizeof(float));
3946  }
3947  }
3948  }
3949 
3950  return true;
3951 }
3952 
3953 
3954 /////////////////////////////////////
3955 // resize a map (using FFT-interpolation)
3956 void ElectronDensity::resize( core::Real approxGridSpacing ) {
3957  // potentially expand map to cover entire unit cell
3958  if ( grid[0] != density.u1() || grid[1] != density.u2() || grid[2] != density.u3() ){
3959  TR << "[ ERROR ] resize() not supported for maps not covering the entire unit cell."<< std::endl;
3960  TR << " " << grid[0] << " != " << density.u1()
3961  << " || " << grid[1] << " != " << density.u2()
3962  << " || " << grid[2] << " != " << density.u3() << std::endl;
3963  exit(1);
3964  }
3965 
3966  // compute new dimensions & origin
3967  numeric::xyzVector<int> newDims, newGrid;
3969 
3970  //fpd since we're doing a bunch of FFTs now resize this to something with no large prime factors
3971  newDims[0] = findSampling( cellDimensions[0] / approxGridSpacing , MINMULT[0] );
3972  newDims[1] = findSampling( cellDimensions[1] / approxGridSpacing , MINMULT[1] );
3973  newDims[2] = findSampling( cellDimensions[2] / approxGridSpacing , MINMULT[2] );
3974 
3975  newOri[0] = newDims[0]*origin[0] / ((core::Real)grid[0]);
3976  newOri[1] = newDims[1]*origin[1] / ((core::Real)grid[1]);
3977  newOri[2] = newDims[2]*origin[2] / ((core::Real)grid[2]);
3978  newGrid = newDims;
3979 
3980  ObjexxFCL::FArray3D< double > newDensity;
3981 
3982  resample( density, newDensity, newDims );
3983  TR << "Resizing " << density.u1() << "x" << density.u2() << "x" << density.u3() << " to "
3984  << newDensity.u1() << "x" << newDensity.u2() << "x" << newDensity.u3() << std::endl;
3985 
3986  // update density
3987  density.dimension( newDims[0], newDims[1], newDims[2] );
3988  for (int i=0; i< newDims[0]*newDims[1]*newDims[2] ; ++i)
3989  density[i] = (float)newDensity[i];
3990  this->grid = newGrid;
3991  this->efforigin = origin = newOri;
3992 
3993  TR << " new extent: " << density.u1() << " x " << density.u2() << " x " << density.u3() << std::endl;
3994  TR << " new origin: " << origin[0] << " x " << origin[1] << " x " << origin[2] << std::endl;
3995  TR << " new grid: " << grid[0] << " x " << grid[1] << " x " << grid[2] << std::endl;
3996 }
3997 
3998 
3999 /////////////////////////////////////
4000 // compute gradients of density --- used to calculate surface normals in visualizer
4002 #ifdef GL_GRAPHICS
4003  numeric::xyzVector<int> dims( density.u1(), density.u2(), density.u3() );
4004 
4005  // Allocate arrays
4006  ObjexxFCL::FArray3D< float > grad_x, grad_y, grad_z;
4007  grad_x.dimension( dims[0] , dims[1] , dims[2] ); grad_x = 0;
4008  grad_y.dimension( dims[0] , dims[1] , dims[2] ); grad_y = 0;
4009  grad_z.dimension( dims[0] , dims[1] , dims[2] ); grad_z = 0;
4010 
4011  for (int x=2; x<dims[0]; ++x) {
4012  for (int y=2; y<dims[1]; ++y) {
4013  for (int z=2; z<dims[2]; ++z) {
4014  grad_x(x,y,z) = 0.5*(density(x+1,y,z) - density(x-1,y,z));
4015  grad_x(x,y,z) = 0.125*(density(x+1,y+1,z) - density(x-1,y+1,z));
4016  grad_x(x,y,z) = 0.125*(density(x+1,y-1,z) - density(x-1,y-1,z));
4017  grad_x(x,y,z) = 0.125*(density(x+1,y,z+1) - density(x-1,y,z+1));
4018  grad_x(x,y,z) = 0.125*(density(x+1,y,z-1) - density(x-1,y,z-1));
4019 
4020  grad_y(x,y,z) = 0.5*(density(x,y+1,z) - density(x,y-1,z));
4021  grad_y(x,y,z) = 0.125*(density(x+1,y+1,z) - density(x+1,y-1,z));
4022  grad_y(x,y,z) = 0.125*(density(x-1,y+1,z) - density(x-1,y-1,z));
4023  grad_y(x,y,z) = 0.125*(density(x,y+1,z+1) - density(x,y-1,z+1));
4024  grad_y(x,y,z) = 0.125*(density(x,y+1,z-1) - density(x,y-1,z-1));
4025 
4026  grad_z(x,y,z) = 0.5*(density(x,y,z+1) - density(x,y,z-1));
4027  grad_z(x,y,z) = 0.125*(density(x+1,y,z+1) - density(x+1,y,z-1));
4028  grad_z(x,y,z) = 0.125*(density(x-1,y,z+1) - density(x-1,y,z-1));
4029  grad_z(x,y,z) = 0.125*(density(x,y+1,z+1) - density(x,y+1,z-1));
4030  grad_z(x,y,z) = 0.125*(density(x,y-1,z+1) - density(x,y-1,z-1));
4031  }
4032  }
4033  }
4034  // spline coeff of dCOdx's
4035  spline_coeffs( grad_x , coeff_grad_x );
4036  spline_coeffs( grad_y , coeff_grad_y );
4037  spline_coeffs( grad_z , coeff_grad_z );
4038 
4039  TR << "Finished computing gradient maps" << std::endl;
4040 #endif
4041 }
4042 
4043 
4044 /////////////////////////////////////
4045 // compute map statistics
4047  core::Real sum=0, sum2=0, sumCoM=0;
4048  dens_max = -std::numeric_limits< core::Real >::max();
4049  dens_min = std::numeric_limits< core::Real >::max();
4050  centerOfMass = numeric::xyzVector<core::Real>(0,0,0);
4051 
4052  int N = density.u1()*density.u2()*density.u3();
4053  //core::Real N2 = square((core::Real)N);
4054 
4055  for (int i=1; i<=density.u1(); i++)
4056  for (int j=1; j<=density.u2(); j++)
4057  for (int k=1; k<=density.u3(); k++) {
4058  sum += density(i,j,k);
4059  sum2 += density(i,j,k)*density(i,j,k);
4060  dens_max = std::max(dens_max, (core::Real)density(i,j,k));
4061  dens_min = std::min(dens_min, (core::Real)density(i,j,k));
4062  }
4063  dens_mean = sum/N;
4064  dens_stdev = sqrt( sum2/N-dens_mean*dens_mean );
4065 
4066  for (int i=1; i<=density.u1(); i++)
4067  for (int j=1; j<=density.u2(); j++)
4068  for (int k=1; k<=density.u3(); k++) {
4069  // do we only care about nonnegative density when compuing com? think about this
4070  if (density(i,j,k) > 0) {
4071  centerOfMass[0] += i*density(i,j,k);
4072  centerOfMass[1] += j*density(i,j,k);
4073  centerOfMass[2] += k*density(i,j,k);
4074  sumCoM += density(i,j,k);
4075  }
4076  }
4077  centerOfMass /= sumCoM;
4078 
4079  TR << "Density map stats:" << std::endl;
4080  TR << " min = " << dens_min << std::endl;
4081  TR << " max = " << dens_max << std::endl;
4082  TR << " mean = " << dens_mean << std::endl;
4083  TR << " stdev = " << dens_stdev << std::endl;
4084  TR << " CoM = " << centerOfMass[0] << " , " << centerOfMass[1] << " , " << centerOfMass[2] << std::endl;
4085  numeric::xyzVector< core::Real > trans = getTransform();
4086  TR << " xform = " << trans[0] << " , " << trans[1] << " , " << trans[2] << std::endl;
4087  TR << " efforig = " << efforigin[0] << " , " << efforigin[1] << " , " << efforigin[2] << std::endl;
4088 }
4089 
4090 /////////////////////////////////////
4091 // void ElectronDensity::computeCrystParams()
4093  // recompute reciprocal cell
4094  // f2c, c2f
4095  core::Real ca = cos(d2r(cellAngles[0])), cb = cos(d2r(cellAngles[1])), cg = cos(d2r(cellAngles[2]));
4096  core::Real sa = sin(d2r(cellAngles[0])), sb = sin(d2r(cellAngles[1])), sg = sin(d2r(cellAngles[2]));
4097 
4098  // conversion from fractional cell coords to cartesian coords
4100  cellDimensions[0] , cellDimensions[1] * cg, cellDimensions[2] * cb,
4101  0.0, cellDimensions[1] * sg, cellDimensions[2] * (ca - cb*cg) / sg,
4102  0.0, 0.0 , cellDimensions[2] * sb * sqrt(1.0 - square((cb*cg - ca)/(sb*sg))) );
4103  core::Real D = this->f2c.det();
4104  if (D == 0) {
4105  TR << "[ WARNING ] Invalid crystal cell dimensions." << std::endl;
4106  return;
4107  }
4108  // c2f is inverse of f2c
4110  (f2c(2,2)*f2c(3,3)-f2c(2,3)*f2c(3,2))/D,
4111  -(f2c(1,2)*f2c(3,3)-f2c(1,3)*f2c(3,2))/D,
4112  (f2c(1,2)*f2c(2,3)-f2c(1,3)*f2c(2,2))/D,
4113  -(f2c(2,1)*f2c(3,3)-f2c(3,1)*f2c(2,3))/D,
4114  (f2c(1,1)*f2c(3,3)-f2c(1,3)*f2c(3,1))/D,
4115  -(f2c(1,1)*f2c(2,3)-f2c(1,3)*f2c(2,1))/D,
4116  (f2c(2,1)*f2c(3,2)-f2c(3,1)*f2c(2,2))/D,
4117  -(f2c(1,1)*f2c(3,2)-f2c(1,2)*f2c(3,1))/D,
4118  (f2c(1,1)*f2c(2,2)-f2c(1,2)*f2c(2,1))/D );
4119  this->V = cellDimensions[0]*cellDimensions[1]*cellDimensions[2]* sqrt(1-square(ca)-square(cb)-square(cg)+2*ca*cb*cg);
4120 
4121  // reciprocal space cell dimensions
4122  this->RcellDimensions[0] = cellDimensions[1]*cellDimensions[2]*sa/V;
4123  this->RcellDimensions[1] = cellDimensions[0]*cellDimensions[2]*sb/V;
4124  this->RcellDimensions[2] = cellDimensions[0]*cellDimensions[1]*sg/V;
4125  this->cosRcellAngles[0] = cos( asin( std::min( std::max( V/(cellDimensions[0]*cellDimensions[1]*cellDimensions[2]*sb*sg) , -1.0) , 1.0) ) );
4126  this->cosRcellAngles[1] = cos( asin( std::min( std::max( V/(cellDimensions[0]*cellDimensions[1]*cellDimensions[2]*sa*sg) , -1.0) , 1.0) ) );
4127  this->cosRcellAngles[2] = cos( asin( std::min( std::max( V/(cellDimensions[0]*cellDimensions[1]*cellDimensions[2]*sa*sb) , -1.0) , 1.0) ) );
4128  this->RV = 1.0/V;
4129 }
4130 
4131 }
4132 }
4133 }