1
/*! \file lib/resol_targetfn.h
2
Header file for resolution function generator
4
//C Copyright (C) 2000-2006 Kevin Cowtan and University of York
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:
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.)'
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.
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
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.
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,
45
#ifndef CLIPPER_RESOL_TARGETFN
46
#define CLIPPER_RESOL_TARGETFN
48
#include "resol_basisfn.h"
49
#include "hkl_datatypes.h"
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|).
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
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
72
FNtype type() const { return QUADRATIC; }
75
const HKL_data<T>* hkl_data;
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|).
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
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
96
FNtype type() const { return QUADRATIC; }
99
const HKL_data<T>* hkl_data;
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
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
116
FNtype type() const { return QUADRATIC; }
118
const HKL_data<T1>* hkl_data1;
119
const HKL_data<T2>* hkl_data2;
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
132
template<class T1, class T2> class TargetFn_scaleLogF1F2 : public TargetFn_base
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
140
FNtype type() const { return QUADRATIC; }
142
const HKL_data<T1>* hkl_data1;
143
const HKL_data<T2>* hkl_data2;
147
//! |E|<sup>2</sup> scaling target
148
/*! This class implements the target function for calculating the
149
scale factor to normalise to <|E|<sup>2</sup>> = 1. Note that this
150
is not the same as dividing by <|E|<sup>2</sup>>, except in a few
151
special cases, e.g. a simple resolution bins calculation. The
152
resulting targen function is the square of the value by which |E|
153
should be multiplied to acheive the correct normalisation. */
154
template<class T> class TargetFn_scaleEsq : public TargetFn_base
157
//! constructor: takes the datalist against which to calc target
158
TargetFn_scaleEsq( const HKL_data<T>& hkl_data_ );
159
//! return the value and derivatives of the target function
160
Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const;
161
//! the type of the function: optionally used to improve convergence
162
FNtype type() const { return QUADRATIC; }
164
const HKL_data<T>* hkl_data;
168
//! \deprecated simple sigma_a target function
169
/*! This class implements the target function for calculating sigma_a.
170
Required is a datalist containing Eo, Ec.
172
It actually refines omegaa = sigmaa/(1-sigmaa^2). This has better
173
proerties for refinement. To get sigmaa use
174
\code sigmaa = ( sqrt( 4*omegaa^2 + 1 ) - 1 ) / ( 2*omegaa ) \endcode
175
This is available as a static function:
176
\code sigmaa = targetfn.sigmaa( omegaa ) \endcode
178
This version simplifies terms in |Eo|^2 and |Ec|^2 which should
179
average out to 1 if the normalisation scheme is consistent with
182
Convergence is good for calculations using the 'binner' basis
183
function, however the smooth basis function have convergence
184
problems. This is still under investigation.
186
template<class T> class TargetFn_sigmaa_omegaa : public TargetFn_base
189
//! constructor: takes the datalist against which to calc target
190
TargetFn_sigmaa_omegaa( const HKL_data<T>& eo, const HKL_data<T>& ec );
191
//! return the value and derivatives of the target function
192
Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& omegaa ) const;
193
//! convert omegaa to sigmaa
194
static ftype sigmaa( const ftype& omegaa )
196
ftype omeg = (omegaa>0.05) ? omegaa : (0.05*exp(omegaa/0.05-1.0));
197
return 0.5 * ( sqrt( 4.0*omeg*omeg + 1.0 ) - 1.0 ) / omeg;
200
const HKL_data<T>* eo_data;
201
const HKL_data<T>* ec_data;
205
//! \deprecated simple sigma_a target function
206
/*! \par Warning: Convergence of this basis-function can be
207
unreliable under some circumstances. Use
208
clipper::TargetFn_sigmaa_omegaa instead, except for development
211
This class implements the target function for calculating sigma_a.
212
Required is a datalist containing Eo, Ec.
214
This version simplifies terms in |Eo|^2 and |Ec|^2 which should
215
average out to 1 if the normalisation scheme is consistent with
218
template<class T> class TargetFn_sigmaa : public TargetFn_base
221
//! constructor: takes the datalist against which to calc target
222
TargetFn_sigmaa( const HKL_data<T>& eo, const HKL_data<T>& ec );
223
//! return the value and derivatives of the target function
224
Rderiv rderiv( const HKL_info::HKL_reference_index& ih, const ftype& sigmaa0 ) const;
225
//! convert function to sigmaa
226
static ftype sigmaa( const ftype& sigm ) { return sigm; }
228
const HKL_data<T>* eo_data;
229
const HKL_data<T>* ec_data;
234
// implementations for template functions
238
template<class T> TargetFn_meanFnth<T>::TargetFn_meanFnth( const HKL_data<T>& hkl_data_, const ftype& n )
241
hkl_data = &hkl_data_;
244
template<class T> TargetFn_base::Rderiv TargetFn_meanFnth<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const
247
const HKL_data<T>& data = *hkl_data;
248
if ( !data[ih].missing() ) {
249
ftype d = fh - pow( ftype(data[ih].f()) / sqrt(ih.hkl_class().epsilon()),
255
result.r = result.dr = result.dr2 = 0.0;
262
template<class T> TargetFn_meanEnth<T>::TargetFn_meanEnth( const HKL_data<T>& hkl_data_, const ftype& n )
265
hkl_data = &hkl_data_;
268
template<class T> TargetFn_base::Rderiv TargetFn_meanEnth<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const
271
const HKL_data<T>& data = *hkl_data;
272
if ( !data[ih].missing() ) {
273
ftype d = fh - pow( ftype(data[ih].E()), power );
278
result.r = result.dr = result.dr2 = 0.0;
285
template<class T1, class T2> TargetFn_scaleF1F2<T1,T2>::TargetFn_scaleF1F2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ )
287
hkl_data1 = &hkl_data1_;
288
hkl_data2 = &hkl_data2_;
291
template<class T1, class T2> TargetFn_base::Rderiv TargetFn_scaleF1F2<T1,T2>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const
294
const T1& ft1 = (*hkl_data1)[ih];
295
const T2& ft2 = (*hkl_data2)[ih];
296
if ( !ft1.missing() && !ft2.missing() ) {
297
const ftype eps = ih.hkl_class().epsilon();
298
const ftype f1 = pow( ft1.f(), 2 ) / eps;
299
const ftype f2 = pow( ft2.f(), 2 ) / eps;
300
const ftype d = fh*f1 - f2;
301
result.r = d * d / f1;
303
result.dr2 = 2.0 * f1;
305
result.r = result.dr = result.dr2 = 0.0;
312
template<class T1, class T2> TargetFn_scaleLogF1F2<T1,T2>::TargetFn_scaleLogF1F2( const HKL_data<T1>& hkl_data1_, const HKL_data<T2>& hkl_data2_ )
314
hkl_data1 = &hkl_data1_;
315
hkl_data2 = &hkl_data2_;
318
template<class T1, class T2> TargetFn_base::Rderiv TargetFn_scaleLogF1F2<T1,T2>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const
321
result.r = result.dr = result.dr2 = 0.0;
322
const T1& ft1 = (*hkl_data1)[ih];
323
const T2& ft2 = (*hkl_data2)[ih];
324
if ( !ft1.missing() && !ft2.missing() )
325
if ( ft1.f() > 1.0e-6 && ft2.f() > 1.0e-6 ) {
326
const ftype eps = ih.hkl_class().epsilon();
327
const ftype f1 = pow( ft1.f(), 2 ) / eps;
328
const ftype f2 = pow( ft2.f(), 2 ) / eps;
329
const ftype w = sqrt( f1 * f2 ); // f1 * f2;
330
const ftype d = fh + log(f1) - log(f2);
331
result.r = w * d * d;
332
result.dr = 2.0 * w * d;
333
result.dr2 = 2.0 * w;
340
template<class T> TargetFn_scaleEsq<T>::TargetFn_scaleEsq( const HKL_data<T>& hkl_data_ )
342
hkl_data = &hkl_data_;
345
template<class T> TargetFn_base::Rderiv TargetFn_scaleEsq<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& fh ) const
348
const HKL_data<T>& data = *hkl_data;
349
const ftype two(2.0);
350
if ( !data[ih].missing() ) {
351
ftype fsq = pow( ftype(data[ih].E()), two );
352
ftype d = fsq * fh - 1.0;
353
result.r = d * d / fsq;
355
result.dr2 = two * fsq;
357
result.r = result.dr = result.dr2 = 0.0;
365
template<class T> TargetFn_sigmaa_omegaa<T>::TargetFn_sigmaa_omegaa( const HKL_data<T>& eo, const HKL_data<T>& ec )
371
template<class T> TargetFn_base::Rderiv TargetFn_sigmaa_omegaa<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& omegaa ) const
375
const HKL_data<T>& eodata = *eo_data;
376
const HKL_data<T>& ecdata = *ec_data;
377
if ( eodata[ih].missing() || ecdata[ih].missing() ) {
378
result.r = result.dr = result.dr2 = 0.0;
380
ftype eo = eodata[ih].E();
381
ftype ec = ecdata[ih].E();
382
ftype omeg = (omegaa>0.05) ? omegaa : (0.05*exp(omegaa/0.05-1.0));
383
ftype sigmaa = 0.5*(sqrt(4*omeg*omeg+1)-1)/omeg;
384
ftype dx = 2.0 * eo * ec;
386
ftype t0 = 1.0/(1-sigmaa*sigmaa) + 0.5*log((1-sigmaa*sigmaa));
388
ftype t2 = pow(1-sigmaa*sigmaa,2)/(1+sigmaa*sigmaa);
389
if ( ih.hkl_class().centric() ) {
390
result.r = 1.0*t0 - log( cosh( x/2 ) );
391
result.dr = 1.0*t1 - dx*0.5*tanh( x/2 );
392
result.dr2 = 1.0*t2 - dx*dx*0.25*(1.0 - pow(tanh(x/2),2) );
394
result.r = 2.0*t0 - Util::sim_integ( x );
395
result.dr = 2.0*t1 - dx*Util::sim( x );
396
result.dr2 = 2.0*t2 - dx*dx*Util::sim_deriv( x );
398
if ( omegaa < 0.05 ) {
399
ftype dy = exp( omegaa/0.05 ) / exp( 1.0 );
400
ftype dy2 = exp( omegaa/0.05 ) / ( 0.05*exp( 1.0 ) );
401
result.dr2 = result.dr*dy2 + result.dr2*dy*dy;
402
result.dr = result.dr*dy;
411
template<class T> TargetFn_sigmaa<T>::TargetFn_sigmaa( const HKL_data<T>& eo, const HKL_data<T>& ec )
417
template<class T> TargetFn_base::Rderiv TargetFn_sigmaa<T>::rderiv( const HKL_info::HKL_reference_index& ih, const ftype& sigmaa0 ) const
421
const HKL_data<T>& eodata = *eo_data;
422
const HKL_data<T>& ecdata = *ec_data;
423
if ( eodata[ih].missing() || ecdata[ih].missing() ) {
424
result.r = result.dr = result.dr2 = 0.0;
426
ftype eo = eodata[ih].E();
427
ftype ec = ecdata[ih].E();
428
ftype sigmaa = Util::min( Util::max( sigmaa0, 0.01 ), 0.99 );
429
ftype dx = 2.0 * eo * ec;
430
ftype x = dx * sigmaa/(1-sigmaa*sigmaa);
431
ftype t0 = 1.0/(1-sigmaa*sigmaa) + 0.5*log((1-sigmaa*sigmaa));
433
ftype t2 = pow(1-sigmaa*sigmaa,2)/(1+sigmaa*sigmaa);
434
if ( ih.hkl_class().centric() ) {
435
result.r = 1.0*t0 - log( cosh( x/2 ) );
436
result.dr = 1.0*t1 - dx*0.5*tanh( x/2 );
437
result.dr2 = 1.0*t2 - dx*dx*0.25*(1.0 - pow(tanh(x/2),2) );
439
result.r = 2.0*t0 - Util::sim_integ( x );
440
result.dr = 2.0*t1 - dx*Util::sim( x );
441
result.dr2 = 2.0*t2 - dx*dx*Util::sim_deriv( x );
443
ftype ds = (1+sigmaa*sigmaa)/pow(1-sigmaa*sigmaa,2);
444
ftype ds2 = 2*sigmaa*(3+sigmaa*sigmaa)/pow(1-sigmaa*sigmaa,3);
445
result.dr2 = result.dr*ds2 + result.dr2*ds*ds;
446
result.dr = result.dr*ds;
452
} // namespace clipper