1 /*! \file lib/resol_targetfn.h 2 Header file for resolution function generator 3 */ 4 //C Copyright (C) 2000-2006 Kevin Cowtan and University of York 5 //L 6 //L This library is free software and is distributed under the terms 7 //L and conditions of version 2.1 of the GNU Lesser General Public 8 //L Licence (LGPL) with the following additional clause: 9 //L 10 //L `You may also combine or link a "work that uses the Library" to 11 //L produce a work containing portions of the Library, and distribute 12 //L that work under terms of your choice, provided that you give 13 //L prominent notice with each copy of the work that the specified 14 //L version of the Library is used in it, and that you include or 15 //L provide public access to the complete corresponding 16 //L machine-readable source code for the Library including whatever 17 //L changes were used in the work. (i.e. If you make changes to the 18 //L Library you must distribute those, but you do not need to 19 //L distribute source or object code to those portions of the work 20 //L not covered by this licence.)' 21 //L 22 //L Note that this clause grants an additional right and does not impose 23 //L any additional restriction, and so does not affect compatibility 24 //L with the GNU General Public Licence (GPL). If you wish to negotiate 25 //L other terms, please contact the maintainer. 26 //L 27 //L You can redistribute it and/or modify the library under the terms of 28 //L the GNU Lesser General Public License as published by the Free Software 29 //L Foundation; either version 2.1 of the License, or (at your option) any 30 //L later version. 31 //L 32 //L This library is distributed in the hope that it will be useful, but 33 //L WITHOUT ANY WARRANTY; without even the implied warranty of 34 //L MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 35 //L Lesser General Public License for more details. 36 //L 37 //L You should have received a copy of the CCP4 licence and/or GNU 38 //L Lesser General Public License along with this library; if not, write 39 //L to the CCP4 Secretary, Daresbury Laboratory, Warrington WA4 4AD, UK. 40 //L The GNU Lesser General Public can also be obtained by writing to the 41 //L Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 42 //L MA 02111-1307 USA 43 44 45 #ifndef CLIPPER_RESOL_TARGETFN 46 #define CLIPPER_RESOL_TARGETFN 47 48 #include "resol_basisfn.h" 49 #include "hkl_datatypes.h" 50 51 52 namespace clipper { 53 54 55 //! simple mean |F|<sup>n</sup> target 56 /*! This class implements the target function for calculating mean 57 |F|<sup>n</sup> as a function of position in reciprocal space. It 58 includes the appropriate multiplicity correction, and so can be 59 applied to any type with an 'f' member with the same dimensions as 60 an |F| or |U| (or an uncorrected |E|). 61 62 \Note This function should not be used to scale F's to E's. 63 See TargetFn_scaleEsq. */ 64 template<class T> class TargetFn_meanFnth : public TargetFn_base 65 { 66 public: 67 //! constructor: takes the datalist against which to calc target, and power 68 TargetFn_meanFnth( const HKL_data<T>& hkl_data_, const ftype& n ); 69 //! return the value and derivatives of the target function 70 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const; 71 //! the type of the function: optionally used to improve convergence type()72 FNtype type() const { return QUADRATIC; } 73 private: 74 ftype power; 75 const HKL_data<T>* hkl_data; 76 }; 77 78 79 //! simple mean |E|<sup>n</sup> target 80 /*! This class implements the target function for calculating mean 81 |E|<sup>n</sup> as a function of position in reciprocal space. It 82 includes the appropriate multiplicity correction, and so can be 83 applied to any type with an 'E' member with the same dimensions as 84 an |E| (or corrected |F| or |U|). 85 86 \Note This function should not be used to scale F's to E's. 87 See TargetFn_scaleEsq. */ 88 template<class T> class TargetFn_meanEnth : public TargetFn_base 89 { 90 public: 91 //! constructor: takes the datalist against which to calc target, and power 92 TargetFn_meanEnth( const HKL_data<T>& hkl_data_, const ftype& n ); 93 //! return the value and derivatives of the target function 94 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const; 95 //! the type of the function: optionally used to improve convergence type()96 FNtype type() const { return QUADRATIC; } 97 private: 98 ftype power; 99 const HKL_data<T>* hkl_data; 100 }; 101 102 103 //! |F|<sup>2</sup> scaling target 104 /*! This class implements the target function for calculating the 105 scale factor to scale one set of F's to another. The resulting 106 scale is the square of the factor that scales the first set of 107 data to match the second. */ 108 template<class T1, class T2> class TargetFn_scaleF1F2 : public TargetFn_base 109 { 110 public: 111 //! constructor: takes the datalist against which to calc target 112 TargetFn_scaleF1F2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ ); 113 //! return the value and derivatives of the target function 114 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const; 115 //! the type of the function: optionally used to improve convergence type()116 FNtype type() const { return QUADRATIC; } 117 private: 118 const HKL_data<T1>* hkl_data1; 119 const HKL_data<T2>* hkl_data2; 120 }; 121 122 123 //! log |F|<sup>2</sup> scaling target 124 /*! This class implements the target function for calculating the 125 scale factor to scale the weighted log of one set of F's to 126 another. The resulting scale is the square of the factor that 127 scales the first set of data to match the second. The log scaling 128 target is used in conjunction with the log-Gaussian basis 129 functions for a fast and robust approximation to iso/aniso 130 Gaussian scaling. 131 */ 132 template<class T1, class T2> class TargetFn_scaleLogF1F2 : public TargetFn_base 133 { 134 public: 135 //! constructor: takes the datalist against which to calc target 136 TargetFn_scaleLogF1F2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ ); 137 //! return the value and derivatives of the target function 138 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const; 139 //! the type of the function: optionally used to improve convergence type()140 FNtype type() const { return QUADRATIC; } 141 private: 142 const HKL_data<T1>* hkl_data1; 143 const HKL_data<T2>* hkl_data2; 144 }; 145 146 147 /*! This class implements the target function for calculating the 148 scale factor to scale one set of I's to another. The resulting 149 scale is the square of the factor that scales the first set of 150 data to match the second. */ 151 template<class T1, class T2> class TargetFn_scaleI1I2 : public TargetFn_base 152 { 153 public: 154 //! constructor: takes the datalist against which to calc target 155 TargetFn_scaleI1I2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ ); 156 //! return the value and derivatives of the target function 157 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const; 158 //! the type of the function: optionally used to improve convergence type()159 FNtype type() const { return QUADRATIC; } 160 private: 161 const HKL_data<T1>* hkl_data1; 162 const HKL_data<T2>* hkl_data2; 163 }; 164 165 166 //! log |I| scaling target 167 /*! This class implements the target function for calculating the 168 scale factor to scale the weighted log of one set of I's to 169 another. The resulting scale is the square of the factor that 170 scales the first set of data to match the second. The log scaling 171 target is used in conjunction with the log-Gaussian basis 172 functions for a fast and robust approximation to iso/aniso 173 Gaussian scaling. 174 */ 175 template<class T1, class T2> class TargetFn_scaleLogI1I2 : public TargetFn_base 176 { 177 public: 178 //! constructor: takes the datalist against which to calc target 179 TargetFn_scaleLogI1I2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ ); 180 //! return the value and derivatives of the target function 181 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const; 182 //! the type of the function: optionally used to improve convergence type()183 FNtype type() const { return QUADRATIC; } 184 private: 185 const HKL_data<T1>* hkl_data1; 186 const HKL_data<T2>* hkl_data2; 187 }; 188 189 190 //! |E|<sup>2</sup> scaling target 191 /*! This class implements the target function for calculating the 192 scale factor to normalise to <|E|<sup>2</sup>> = 1. Note that this 193 is not the same as dividing by <|E|<sup>2</sup>>, except in a few 194 special cases, e.g. a simple resolution bins calculation. The 195 resulting targen function is the square of the value by which |E| 196 should be multiplied to acheive the correct normalisation. */ 197 template<class T> class TargetFn_scaleEsq : public TargetFn_base 198 { 199 public: 200 //! constructor: takes the datalist against which to calc target 201 TargetFn_scaleEsq( const HKL_data<T>& hkl_data_ ); 202 //! return the value and derivatives of the target function 203 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const; 204 //! the type of the function: optionally used to improve convergence type()205 FNtype type() const { return QUADRATIC; } 206 private: 207 const HKL_data<T>* hkl_data; 208 }; 209 210 211 //! \deprecated simple sigma_a target function 212 /*! This class implements the target function for calculating sigma_a. 213 Required is a datalist containing Eo, Ec. 214 215 It actually refines omegaa = sigmaa/(1-sigmaa^2). This has better 216 proerties for refinement. To get sigmaa use 217 \code sigmaa = ( sqrt( 4*omegaa^2 + 1 ) - 1 ) / ( 2*omegaa ) \endcode 218 This is available as a static function: 219 \code sigmaa = targetfn.sigmaa( omegaa ) \endcode 220 221 This version simplifies terms in |Eo|^2 and |Ec|^2 which should 222 average out to 1 if the normalisation scheme is consistent with 223 the sigmaa calc. 224 225 Convergence is good for calculations using the 'binner' basis 226 function, however the smooth basis function have convergence 227 problems. This is still under investigation. 228 */ 229 template<class T> class TargetFn_sigmaa_omegaa : public TargetFn_base 230 { 231 public: 232 //! constructor: takes the datalist against which to calc target 233 TargetFn_sigmaa_omegaa( const HKL_data<T>& eo, const HKL_data<T>& ec ); 234 //! return the value and derivatives of the target function 235 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& omegaa ) const; 236 //! convert omegaa to sigmaa sigmaa(const ftype & omegaa)237 static ftype sigmaa( const ftype& omegaa ) 238 { 239 ftype omeg = (omegaa>0.05) ? omegaa : (0.05*exp(omegaa/0.05-1.0)); 240 return 0.5 * ( sqrt( 4.0*omeg*omeg + 1.0 ) - 1.0 ) / omeg; 241 } 242 private: 243 const HKL_data<T>* eo_data; 244 const HKL_data<T>* ec_data; 245 }; 246 247 248 //! \deprecated simple sigma_a target function 249 /*! \par Warning: Convergence of this basis-function can be 250 unreliable under some circumstances. Use 251 clipper::TargetFn_sigmaa_omegaa instead, except for development 252 purposes. 253 254 This class implements the target function for calculating sigma_a. 255 Required is a datalist containing Eo, Ec. 256 257 This version simplifies terms in |Eo|^2 and |Ec|^2 which should 258 average out to 1 if the normalisation scheme is consistent with 259 the sigmaa calc. 260 */ 261 template<class T> class TargetFn_sigmaa : public TargetFn_base 262 { 263 public: 264 //! constructor: takes the datalist against which to calc target 265 TargetFn_sigmaa( const HKL_data<T>& eo, const HKL_data<T>& ec ); 266 //! return the value and derivatives of the target function 267 Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& sigmaa0 ) const; 268 //! convert function to sigmaa sigmaa(const ftype & sigm)269 static ftype sigmaa( const ftype& sigm ) { return sigm; } 270 private: 271 const HKL_data<T>* eo_data; 272 const HKL_data<T>* ec_data; 273 }; 274 275 276 277 // implementations for template functions 278 279 // mean F^nth 280 TargetFn_meanFnth(const HKL_data<T> & hkl_data_,const ftype & n)281 template<class T> TargetFn_meanFnth<T>::TargetFn_meanFnth( const HKL_data<T>& hkl_data_, const ftype& n ) 282 { 283 power = n; 284 hkl_data = &hkl_data_; 285 } 286 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & fh)287 template<class T> TargetFn_base::Rderiv TargetFn_meanFnth<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const 288 { 289 Rderiv result; 290 const HKL_data<T>& data = *hkl_data; 291 if ( !data[ih].missing() ) { 292 ftype d = fh - pow( ftype(data[ih].f()) / sqrt(ih.hkl_class().epsilon()), 293 power ); 294 result.r = d * d; 295 result.dr = 2.0 * d; 296 result.dr2 = 2.0; 297 } else { 298 result.r = result.dr = result.dr2 = 0.0; 299 } 300 return result; 301 } 302 303 // mean E^nth 304 TargetFn_meanEnth(const HKL_data<T> & hkl_data_,const ftype & n)305 template<class T> TargetFn_meanEnth<T>::TargetFn_meanEnth( const HKL_data<T>& hkl_data_, const ftype& n ) 306 { 307 power = n; 308 hkl_data = &hkl_data_; 309 } 310 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & fh)311 template<class T> TargetFn_base::Rderiv TargetFn_meanEnth<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const 312 { 313 Rderiv result; 314 const HKL_data<T>& data = *hkl_data; 315 if ( !data[ih].missing() ) { 316 ftype d = fh - pow( ftype(data[ih].E()), power ); 317 result.r = d * d; 318 result.dr = 2.0 * d; 319 result.dr2 = 2.0; 320 } else { 321 result.r = result.dr = result.dr2 = 0.0; 322 } 323 return result; 324 } 325 326 // F1-F2 scaling 327 TargetFn_scaleF1F2(const HKL_data<T1> & hkl_data1_,const HKL_data<T2> & hkl_data2_)328 template<class T1, class T2> TargetFn_scaleF1F2<T1,T2>::TargetFn_scaleF1F2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ ) 329 { 330 hkl_data1 = &hkl_data1_; 331 hkl_data2 = &hkl_data2_; 332 } 333 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & fh)334 template<class T1, class T2> TargetFn_base::Rderiv TargetFn_scaleF1F2<T1,T2>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const 335 { 336 Rderiv result; 337 const T1& ft1 = (*hkl_data1)[ih]; 338 const T2& ft2 = (*hkl_data2)[ih]; 339 if ( !ft1.missing() && !ft2.missing() ) { 340 const ftype eps = ih.hkl_class().epsilon(); 341 const ftype f1 = pow( ft1.f(), 2 ) / eps; 342 const ftype f2 = pow( ft2.f(), 2 ) / eps; 343 const ftype d = fh*f1 - f2; 344 result.r = d * d / f1; 345 result.dr = 2.0 * d; 346 result.dr2 = 2.0 * f1; 347 } else { 348 result.r = result.dr = result.dr2 = 0.0; 349 } 350 return result; 351 } 352 353 // Log F1-F2 scaling 354 TargetFn_scaleLogF1F2(const HKL_data<T1> & hkl_data1_,const HKL_data<T2> & hkl_data2_)355 template<class T1, class T2> TargetFn_scaleLogF1F2<T1,T2>::TargetFn_scaleLogF1F2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ ) 356 { 357 hkl_data1 = &hkl_data1_; 358 hkl_data2 = &hkl_data2_; 359 } 360 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & fh)361 template<class T1, class T2> TargetFn_base::Rderiv TargetFn_scaleLogF1F2<T1,T2>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const 362 { 363 Rderiv result; 364 result.r = result.dr = result.dr2 = 0.0; 365 const T1& ft1 = (*hkl_data1)[ih]; 366 const T2& ft2 = (*hkl_data2)[ih]; 367 if ( !ft1.missing() && !ft2.missing() ) 368 if ( ft1.f() > 1.0e-6 && ft2.f() > 1.0e-6 ) { 369 const ftype eps = ih.hkl_class().epsilon(); 370 const ftype f1 = pow( ft1.f(), 2 ) / eps; 371 const ftype f2 = pow( ft2.f(), 2 ) / eps; 372 const ftype w = 1.0; // f1 * f2; 373 const ftype d = fh + log(f1) - log(f2); 374 result.r = w * d * d; 375 result.dr = 2.0 * w * d; 376 result.dr2 = 2.0 * w; 377 } 378 return result; 379 } 380 381 // I1-I2 scaling 382 TargetFn_scaleI1I2(const HKL_data<T1> & hkl_data1_,const HKL_data<T2> & hkl_data2_)383 template<class T1, class T2> TargetFn_scaleI1I2<T1,T2>::TargetFn_scaleI1I2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ ) 384 { 385 hkl_data1 = &hkl_data1_; 386 hkl_data2 = &hkl_data2_; 387 } 388 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & fh)389 template<class T1, class T2> TargetFn_base::Rderiv TargetFn_scaleI1I2<T1,T2>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const 390 { 391 Rderiv result; 392 const T1& ft1 = (*hkl_data1)[ih]; 393 const T2& ft2 = (*hkl_data2)[ih]; 394 if ( !ft1.missing() && !ft2.missing() ) { 395 const ftype eps = ih.hkl_class().epsilon(); 396 const ftype f1 = ft1.I() / eps; 397 const ftype f2 = ft2.I() / eps; 398 const ftype d = fh*f1 - f2; 399 result.r = d * d / f1; 400 result.dr = 2.0 * d; 401 result.dr2 = 2.0 * f1; 402 } else { 403 result.r = result.dr = result.dr2 = 0.0; 404 } 405 return result; 406 } 407 408 // Log I1-I2 scaling 409 TargetFn_scaleLogI1I2(const HKL_data<T1> & hkl_data1_,const HKL_data<T2> & hkl_data2_)410 template<class T1, class T2> TargetFn_scaleLogI1I2<T1,T2>::TargetFn_scaleLogI1I2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ ) 411 { 412 hkl_data1 = &hkl_data1_; 413 hkl_data2 = &hkl_data2_; 414 } 415 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & fh)416 template<class T1, class T2> TargetFn_base::Rderiv TargetFn_scaleLogI1I2<T1,T2>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const 417 { 418 Rderiv result; 419 result.r = result.dr = result.dr2 = 0.0; 420 const T1& ft1 = (*hkl_data1)[ih]; 421 const T2& ft2 = (*hkl_data2)[ih]; 422 if ( !ft1.missing() && !ft2.missing() ) 423 if ( ft1.I() > 1.0e-6 && ft2.I() > 1.0e-6 ) { 424 const ftype eps = ih.hkl_class().epsilon(); 425 const ftype f1 = ft1.I() / eps; 426 const ftype f2 = ft2.I() / eps; 427 const ftype w = 1.0; // f1 * f2; 428 const ftype d = fh + log(f1) - log(f2); 429 result.r = w * d * d; 430 result.dr = 2.0 * w * d; 431 result.dr2 = 2.0 * w; 432 } 433 return result; 434 } 435 436 // E^2 scaling 437 TargetFn_scaleEsq(const HKL_data<T> & hkl_data_)438 template<class T> TargetFn_scaleEsq<T>::TargetFn_scaleEsq( const HKL_data<T>& hkl_data_ ) 439 { 440 hkl_data = &hkl_data_; 441 } 442 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & fh)443 template<class T> TargetFn_base::Rderiv TargetFn_scaleEsq<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const 444 { 445 Rderiv result; 446 const HKL_data<T>& data = *hkl_data; 447 const ftype two(2.0); 448 if ( !data[ih].missing() ) { 449 ftype fsq = pow( ftype(data[ih].E()), two ); 450 ftype d = fsq * fh - 1.0; 451 result.r = d * d / fsq; 452 result.dr = two * d; 453 result.dr2 = two * fsq; 454 } else { 455 result.r = result.dr = result.dr2 = 0.0; 456 } 457 return result; 458 } 459 460 461 // sigmaa (omegaa) 462 TargetFn_sigmaa_omegaa(const HKL_data<T> & eo,const HKL_data<T> & ec)463 template<class T> TargetFn_sigmaa_omegaa<T>::TargetFn_sigmaa_omegaa( const HKL_data<T>& eo, const HKL_data<T>& ec ) 464 { 465 eo_data = &eo; 466 ec_data = &ec; 467 } 468 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & omegaa)469 template<class T> TargetFn_base::Rderiv TargetFn_sigmaa_omegaa<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& omegaa ) const 470 { 471 Rderiv result; 472 473 const HKL_data<T>& eodata = *eo_data; 474 const HKL_data<T>& ecdata = *ec_data; 475 if ( eodata[ih].missing() || ecdata[ih].missing() ) { 476 result.r = result.dr = result.dr2 = 0.0; 477 } else { 478 ftype eo = eodata[ih].E(); 479 ftype ec = ecdata[ih].E(); 480 ftype omeg = (omegaa>0.05) ? omegaa : (0.05*exp(omegaa/0.05-1.0)); 481 ftype sigmaa = 0.5*(sqrt(4*omeg*omeg+1)-1)/omeg; 482 ftype dx = 2.0 * eo * ec; 483 ftype x = dx * omeg; 484 ftype t0 = 1.0/(1-sigmaa*sigmaa) + 0.5*log((1-sigmaa*sigmaa)); 485 ftype t1 = sigmaa; 486 ftype t2 = pow(1-sigmaa*sigmaa,2)/(1+sigmaa*sigmaa); 487 if ( ih.hkl_class().centric() ) { 488 result.r = 1.0*t0 - log( cosh( x/2 ) ); 489 result.dr = 1.0*t1 - dx*0.5*tanh( x/2 ); 490 result.dr2 = 1.0*t2 - dx*dx*0.25*(1.0 - pow(tanh(x/2),2) ); 491 } else { 492 result.r = 2.0*t0 - Util::sim_integ( x ); 493 result.dr = 2.0*t1 - dx*Util::sim( x ); 494 result.dr2 = 2.0*t2 - dx*dx*Util::sim_deriv( x ); 495 } 496 if ( omegaa < 0.05 ) { 497 ftype dy = exp( omegaa/0.05 ) / exp( 1.0 ); 498 ftype dy2 = exp( omegaa/0.05 ) / ( 0.05*exp( 1.0 ) ); 499 result.dr2 = result.dr*dy2 + result.dr2*dy*dy; 500 result.dr = result.dr*dy; 501 } 502 } 503 return result; 504 } 505 506 507 // sigmaa (norm) 508 TargetFn_sigmaa(const HKL_data<T> & eo,const HKL_data<T> & ec)509 template<class T> TargetFn_sigmaa<T>::TargetFn_sigmaa( const HKL_data<T>& eo, const HKL_data<T>& ec ) 510 { 511 eo_data = &eo; 512 ec_data = &ec; 513 } 514 rderiv(const HKL_info::HKL_reference_index & ih,const ftype & sigmaa0)515 template<class T> TargetFn_base::Rderiv TargetFn_sigmaa<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& sigmaa0 ) const 516 { 517 Rderiv result; 518 519 const HKL_data<T>& eodata = *eo_data; 520 const HKL_data<T>& ecdata = *ec_data; 521 if ( eodata[ih].missing() || ecdata[ih].missing() ) { 522 result.r = result.dr = result.dr2 = 0.0; 523 } else { 524 ftype eo = eodata[ih].E(); 525 ftype ec = ecdata[ih].E(); 526 ftype sigmaa = (sigmaa0>0.99)?(0.99):((sigmaa0<0.01)?0.01:sigmaa0); 527 ftype dx = 2.0 * eo * ec; 528 ftype x = dx * sigmaa/(1-sigmaa*sigmaa); 529 ftype t0 = 1.0/(1-sigmaa*sigmaa) + 0.5*log((1-sigmaa*sigmaa)); 530 ftype t1 = sigmaa; 531 ftype t2 = pow(1-sigmaa*sigmaa,2)/(1+sigmaa*sigmaa); 532 if ( ih.hkl_class().centric() ) { 533 result.r = 1.0*t0 - log( cosh( x/2 ) ); 534 result.dr = 1.0*t1 - dx*0.5*tanh( x/2 ); 535 result.dr2 = 1.0*t2 - dx*dx*0.25*(1.0 - pow(tanh(x/2),2) ); 536 } else { 537 result.r = 2.0*t0 - Util::sim_integ( x ); 538 result.dr = 2.0*t1 - dx*Util::sim( x ); 539 result.dr2 = 2.0*t2 - dx*dx*Util::sim_deriv( x ); 540 } 541 ftype ds = (1+sigmaa*sigmaa)/pow(1-sigmaa*sigmaa,2); 542 ftype ds2 = 2*sigmaa*(3+sigmaa*sigmaa)/pow(1-sigmaa*sigmaa,3); 543 result.dr2 = result.dr*ds2 + result.dr2*ds*ds; 544 result.dr = result.dr*ds; 545 } 546 return result; 547 } 548 549 550 } // namespace clipper 551 552 #endif 553