1 /* sfweight.cpp: structure factor weighting implementation */
2 //C Copyright (C) 2000-2006 Kevin Cowtan and University of York
3 //L
4 //L  This library is free software and is distributed under the terms
5 //L  and conditions of version 2.1 of the GNU Lesser General Public
6 //L  Licence (LGPL) with the following additional clause:
7 //L
8 //L     `You may also combine or link a "work that uses the Library" to
9 //L     produce a work containing portions of the Library, and distribute
10 //L     that work under terms of your choice, provided that you give
11 //L     prominent notice with each copy of the work that the specified
12 //L     version of the Library is used in it, and that you include or
13 //L     provide public access to the complete corresponding
14 //L     machine-readable source code for the Library including whatever
15 //L     changes were used in the work. (i.e. If you make changes to the
16 //L     Library you must distribute those, but you do not need to
17 //L     distribute source or object code to those portions of the work
18 //L     not covered by this licence.)'
19 //L
20 //L  Note that this clause grants an additional right and does not impose
21 //L  any additional restriction, and so does not affect compatibility
22 //L  with the GNU General Public Licence (GPL). If you wish to negotiate
23 //L  other terms, please contact the maintainer.
24 //L
25 //L  You can redistribute it and/or modify the library under the terms of
26 //L  the GNU Lesser General Public License as published by the Free Software
27 //L  Foundation; either version 2.1 of the License, or (at your option) any
28 //L  later version.
29 //L
30 //L  This library is distributed in the hope that it will be useful, but
31 //L  WITHOUT ANY WARRANTY; without even the implied warranty of
32 //L  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
33 //L  Lesser General Public License for more details.
34 //L
35 //L  You should have received a copy of the CCP4 licence and/or GNU
36 //L  Lesser General Public License along with this library; if not, write
37 //L  to the CCP4 Secretary, Daresbury Laboratory, Warrington WA4 4AD, UK.
38 //L  The GNU Lesser General Public can also be obtained by writing to the
39 //L  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
40 //L  MA 02111-1307 USA
41 
42 
43 #include "sfweight.h"
44 #include "../core/hkl_operators.h"
45 #include "../core/resol_targetfn.h"
46 
47 
48 namespace clipper {
49 
50 
operator ()(const HKL_class cls,const datatypes::F_sigF<T> & fo0,const datatypes::ABCD<T> & hl0,const datatypes::F_phi<T> & fc0,const ftype & s,const ftype & w,const std::vector<HLterms> & hlterms)51 template<class T> typename SFweight_spline<T>::TargetResult SFweight_spline<T>::TargetFo::operator() ( const HKL_class cls, const datatypes::F_sigF<T>& fo0, const datatypes::ABCD<T>& hl0, const datatypes::F_phi<T>& fc0, const ftype& s, const ftype& w, const std::vector<HLterms>& hlterms )
52 {
53   ftype fo(0.0), fc(0.0), phic(0.0), sfo(1.0);
54   if ( !fo0.missing() ) { fo = fo0.f(); sfo = fo0.sigf(); }
55   if ( !fc0.missing() ) { fc = fc0.f(); phic = fc0.phi(); }
56   const ftype epc = cls.epsilonc();
57   const ftype s2 = s*s;
58   const ftype fo2 = fo*fo;
59   const ftype fc2 = fc*fc;
60   const ftype d = 2.0*sfo*sfo + epc*w;
61   const ftype d2 = d*d;
62   const ftype d3 = d*d2;
63   const ftype d4 = d*d3;
64   const ftype x = 2.0*fo*fc*s/d;
65   ftype i0, di0, ddi0, cf;
66   TargetResult r;
67   if ( cls.centric() ) {
68     i0 = (fabs(x)<10.0) ? log(cosh(x)) : fabs(x)+log(0.5);
69     di0 = tanh(x);
70     ddi0 = 1.0-pow(tanh(x),2);
71     cf = 0.5;
72   } else {
73     i0 = Util::sim_integ(x);
74     di0 = Util::sim(x);
75     ddi0 = Util::sim_deriv(x);
76     cf = 1.0;
77   }
78   r.r = cf*log(d) + (fo2+s2*fc2)/d - i0;
79   r.ds = 2.0*s*fc2/d - (2.0*fo*fc/d)*di0;
80   r.dw = epc*( cf/d - (fo2+s2*fc2)/d2 + (2.0*fo*fc*s/d2)*di0 );
81   r.dss = 2.0*fc2/d - (4.0*fo2*fc2/d2)*ddi0;
82   r.dww = epc*epc*( -cf/d2 + 2.0*(fo2+s2*fc2)/d3
83       	      - (4.0*fo*fc*s/d3)*di0 - (4.0*fo2*fc2*s2/d4)*ddi0 );
84   r.dsw = epc*( -2.0*s*fc2/d2 + (2.0*fo*fc/d2)*di0
85       	  + (4.0*fo2*fc2*s/d3)*ddi0 );
86   abcd = datatypes::ABCD<T>( x*cos(phic), x*sin(phic), 0.0, 0.0 );
87   phiw = datatypes::Phi_fom<T>( phic, di0 );
88   return r;
89 }
90 
91 
operator ()(const HKL_class cls,const datatypes::F_sigF<T> & fo0,const datatypes::ABCD<T> & hl0,const datatypes::F_phi<T> & fc0,const ftype & s,const ftype & w,const std::vector<HLterms> & hlterms)92 template<class T> typename SFweight_spline<T>::TargetResult SFweight_spline<T>::TargetHL::operator() ( const HKL_class cls, const datatypes::F_sigF<T>& fo0, const datatypes::ABCD<T>& hl0, const datatypes::F_phi<T>& fc0, const ftype& s, const ftype& w, const std::vector<HLterms>& hlterms )
93 {
94   ftype fo(0.0), fc(0.0), phic(0.0), sfo(1.0);
95   ftype a0(0.0), b0(0.0), c0(0.0), d0(0.0);
96   if ( !fo0.missing() ) { fo = fo0.f(); sfo = fo0.sigf(); }
97   if ( !fc0.missing() ) { fc = fc0.f(); phic = fc0.phi(); }
98   if ( !hl0.missing() ) { a0=hl0.a(); b0=hl0.b(); c0=hl0.c(); d0=hl0.d(); }
99   const ftype epc = cls.epsilonc();
100   const ftype s2 = s*s;
101   const ftype fo2 = fo*fo;
102   const ftype fc2 = fc*fc;
103   const ftype d = 2.0*sfo*sfo + epc*w;
104   const ftype d2 = d*d;
105   const ftype d3 = d*d2;
106   //const ftype d4 = d*d3;
107   const ftype epcd = epc/d;
108   const ftype sf2 = fo2 + s2*fc2;
109   const ftype xs = 2.0*fo*fc/d;
110   const ftype cosc = cos(phic);
111   const ftype sinc = sin(phic);
112   const ftype hl_a = a0 + xs*s*cosc;
113   const ftype hl_b = b0 + xs*s*sinc;
114   const ftype hl_c = c0;
115   const ftype hl_d = d0;
116   ftype cf = 1.0;
117   int a_zero = 0;
118   int a_step = 1;
119   if ( cls.centric() ) {
120     a_step = hlterms.size()/2;
121     a_zero = Util::intr( ftype(hlterms.size())*cls.allowed()/Util::twopi() );
122     a_zero = Util::mod( a_zero, a_step );
123     cf = 0.5;
124   }
125   ftype an, asum, asum_ds, asum_dss, asum_dw, asum_dww, asum_dsw, asum_a, asum_b;
126   an = asum = asum_ds = asum_dss = asum_dw = asum_dww = asum_dsw = asum_a = asum_b = 0.0;
127   ftype q, q1, q2, e;
128   ftype qmax = sqrt( hl_a*hl_a + hl_b*hl_b );
129   for ( int a = a_zero; a < hlterms.size(); a += a_step ) {
130     const HLterms& trig = hlterms[a];
131     q = hl_a*trig.cosa + hl_b*trig.sina + hl_c*trig.cos2a + hl_d*trig.sin2a;
132     q1 = xs * ( cosc*trig.cosa + sinc*trig.sina );
133     q2 = s * q1;
134     e = exp( q - qmax );
135     an       += 1.0;
136     asum     += e;
137     asum_ds  += e * q1;
138     asum_dss += e * q1*q1;
139     asum_dw  += e * ( -q2 )*epcd;
140     asum_dww += e * ( 2.0 + q2 )*q2*epcd*epcd;
141     asum_a   += e * trig.cosa;
142     asum_b   += e * trig.sina;
143     // asum_dsw += ?;
144   }
145   asum_a   /= asum;
146   asum_b   /= asum;
147   asum     /= an;
148   asum_ds  /= an;
149   asum_dss /= an;
150   asum_dw  /= an;
151   asum_dww /= an;
152   abcd = datatypes::ABCD<T>( hl_a, hl_b, hl_c, hl_d );
153   phiw = datatypes::Phi_fom<T>( atan2( asum_b, asum_a ),
154 				sqrt( asum_a*asum_a + asum_b*asum_b ) );
155   TargetResult r;
156   r.r   =           cf*log(d) + sf2/d - log( asum ) - qmax;
157   r.ds  =               (2.0*s*fc2)/d - asum_ds/asum;
158   r.dw  =           epc*(cf/d-sf2/d2) - asum_dw/asum;
159   r.dss =                 (2.0*fc2)/d - asum_dss/asum + Util::sqr(asum_ds/asum);
160   r.dww = epc*epc*(-cf/d2+2.0*sf2/d3) - asum_dww/asum + Util::sqr(asum_dw/asum);
161   r.dsw = Util::nan();
162   return r;
163 }
164 
165 
SFweight_spline(HKL_data<datatypes::F_phi<T>> & fb,HKL_data<datatypes::F_phi<T>> & fd,HKL_data<datatypes::Phi_fom<T>> & phiw,const HKL_data<datatypes::F_sigF<T>> & fo,const HKL_data<datatypes::F_phi<T>> & fc,const HKL_data<datatypes::Flag> & usage,const int n_reflns,const int n_params)166 template<class T> SFweight_spline<T>::SFweight_spline( HKL_data<datatypes::F_phi<T> >& fb, HKL_data<datatypes::F_phi<T> >& fd, HKL_data<datatypes::Phi_fom<T> >& phiw, const HKL_data<datatypes::F_sigF<T> >& fo, const HKL_data<datatypes::F_phi<T> >& fc, const HKL_data<datatypes::Flag>& usage, const int n_reflns, const int n_params )
167 {
168   init( n_reflns, n_params );
169   (*this)( fb, fd, phiw, fo, fc, usage );
170 }
171 
172 
init(const int n_reflns,const int n_params,const int n_phases)173 template<class T> void SFweight_spline<T>::init( const int n_reflns, const int n_params, const int n_phases ) {
174   nreflns = n_reflns;
175   nparams = n_params;
176   hlterms.resize( n_phases );
177   for ( int a = 0; a < hlterms.size(); a++ ) {
178     ftype phi = ( Util::twopi() * ftype(a)/ftype(hlterms.size()) );
179     hlterms[a].cosa  = cos(phi);
180     hlterms[a].sina  = sin(phi);
181     hlterms[a].cos2a = cos(2.0*phi);
182     hlterms[a].sin2a = sin(2.0*phi);
183   }
184 }
185 
186 
operator ()(HKL_data<datatypes::F_phi<T>> & fb,HKL_data<datatypes::F_phi<T>> & fd,HKL_data<datatypes::Phi_fom<T>> & phiw,const HKL_data<datatypes::F_sigF<T>> & fo0,const HKL_data<datatypes::F_phi<T>> & fc0,const HKL_data<datatypes::Flag> & usage)187 template<class T> bool SFweight_spline<T>::operator() ( HKL_data<datatypes::F_phi<T> >& fb, HKL_data<datatypes::F_phi<T> >& fd, HKL_data<datatypes::Phi_fom<T> >& phiw, const HKL_data<datatypes::F_sigF<T> >& fo0, const HKL_data<datatypes::F_phi<T> >& fc0, const HKL_data<datatypes::Flag>& usage )
188 {
189   TargetFo tgt;
190   HKL_data<datatypes::ABCD<T> > hl0( fo0.hkl_info() ), hl( fo0.hkl_info() );
191   return evaluate( fb, fd, phiw, hl, fo0, hl0, fc0, usage, tgt );
192 }
193 
194 
operator ()(HKL_data<datatypes::F_phi<T>> & fb,HKL_data<datatypes::F_phi<T>> & fd,HKL_data<datatypes::Phi_fom<T>> & phiw,HKL_data<datatypes::ABCD<T>> & hl,const HKL_data<datatypes::F_sigF<T>> & fo0,const HKL_data<datatypes::ABCD<T>> & hl0,const HKL_data<datatypes::F_phi<T>> & fc0,const HKL_data<datatypes::Flag> & usage)195 template<class T> bool SFweight_spline<T>::operator() ( HKL_data<datatypes::F_phi<T> >& fb, HKL_data<datatypes::F_phi<T> >& fd, HKL_data<datatypes::Phi_fom<T> >& phiw, HKL_data<datatypes::ABCD<T> >& hl, const HKL_data<datatypes::F_sigF<T> >& fo0, const HKL_data<datatypes::ABCD<T> >& hl0, const HKL_data<datatypes::F_phi<T> >& fc0, const HKL_data<datatypes::Flag>& usage )
196 {
197   TargetHL tgt;
198   return evaluate( fb, fd, phiw, hl, fo0, hl0, fc0, usage, tgt );
199 }
200 
201 
evaluate(HKL_data<datatypes::F_phi<T>> & fb,HKL_data<datatypes::F_phi<T>> & fd,HKL_data<datatypes::Phi_fom<T>> & phiw,HKL_data<datatypes::ABCD<T>> & hl,const HKL_data<datatypes::F_sigF<T>> & fo0,const HKL_data<datatypes::ABCD<T>> & hl0,const HKL_data<datatypes::F_phi<T>> & fc0,const HKL_data<datatypes::Flag> & usage,F tgt)202 template<class T> template<class F> bool SFweight_spline<T>::evaluate( HKL_data<datatypes::F_phi<T> >& fb, HKL_data<datatypes::F_phi<T> >& fd, HKL_data<datatypes::Phi_fom<T> >& phiw, HKL_data<datatypes::ABCD<T> >& hl, const HKL_data<datatypes::F_sigF<T> >& fo0, const HKL_data<datatypes::ABCD<T> >& hl0, const HKL_data<datatypes::F_phi<T> >& fc0, const HKL_data<datatypes::Flag>& usage, F tgt )
203 {
204   const HKL_info& hkls = fo0.base_hkl_info();
205   typedef clipper::HKL_info::HKL_reference_index HRI;
206   bool status = false;
207 
208   // count reflections and determine number of params
209   HKL_data<datatypes::Flag_bool> flag(hkls);
210   for ( HRI ih = flag.first(); !ih.last(); ih.next() )
211     flag[ih].flag() = (!fo0[ih].missing()) && (!fc0[ih].missing()) &&
212       (usage[ih].flag()!=SFweight_base<T>::NONE);
213   int npar_sig = num_params( flag );
214   int npar_scl = npar_sig;
215   while ( npar_scl < 12 ) npar_scl *= 2;
216 
217   // prepare function
218   BasisFn_spline basisfn( flag, npar_sig, 1.0 );
219   BasisFn_spline basissc( flag, npar_scl, 1.0 );
220   BasisFn_base::Fderiv dsdp, dwdp;
221   TargetResult fn;
222   scale_fo.resize( hkls.num_reflections() );
223   scale_fc.resize( hkls.num_reflections() );
224   value_s.resize( hkls.num_reflections() );
225   value_w.resize( hkls.num_reflections() );
226 
227   // create E's for scaling
228   HKL_data<datatypes::E_sigE<T> > eo( hkls ), ec( hkls );
229   for ( HRI ih = fo0.first(); !ih.last(); ih.next() ) {
230     eo[ih].E() = fo0[ih].f() / sqrt( ih.hkl_class().epsilon() );
231     ec[ih].E() = fc0[ih].f() / sqrt( ih.hkl_class().epsilon() );
232     eo[ih].sigE() = ec[ih].sigE() = 1.0;
233   }
234   // calc scale
235   std::vector<ftype> param_fo( basissc.num_params(), 1.0 );
236   TargetFn_scaleEsq<datatypes::E_sigE<T> > tfn_fo( eo );
237   ResolutionFn rfn_fo( hkls, basissc, tfn_fo, param_fo );
238   param_fo = rfn_fo.params();
239   std::vector<ftype> param_fc( basissc.num_params(), 1.0 );
240   TargetFn_scaleEsq<datatypes::E_sigE<T> > tfn_fc( ec );
241   ResolutionFn rfn_fc( hkls, basissc, tfn_fc, param_fc );
242   param_fc = rfn_fc.params();
243 
244   // prescale Fo, Fc
245   HKL_data<datatypes::F_sigF<T> > fo = fo0;
246   HKL_data<datatypes::F_phi<T> >  fc = fc0;
247   for ( HRI ih = fo0.first(); !ih.last(); ih.next() ) {
248     scale_fo[ ih.index() ] = sqrt( basissc.f_s( ih.invresolsq(), param_fo ) );
249     scale_fc[ ih.index() ] = sqrt( basissc.f_s( ih.invresolsq(), param_fc ) );
250     fo[ih].scale( scale_fo[ ih.index() ] );
251     fc[ih].scale( scale_fc[ ih.index() ] );
252   }
253 
254   // make first estimate of s
255   param_s = std::vector<ftype>( npar_sig, 1.0 );
256 
257   // make first estimate of w
258   HKL_data<datatypes::F_sigF<T> > ftmp( hkls );
259   for ( HRI ih = flag.first(); !ih.last(); ih.next() ) if ( flag[ih].flag() )
260     ftmp[ih].f() = ftmp[ih].sigf() =
261       pow( fo[ih].f() - sqrt(basisfn.f_s(ih.invresolsq(),param_s))*fc[ih].f(), 2.0 ) / ih.hkl_class().epsilonc();
262   TargetFn_meanFnth<datatypes::F_sigF<T> > target_w( ftmp, 1.0 );
263   ResolutionFn rfn2( hkls, basisfn, target_w, param_w );
264   param_w = rfn2.params();
265   //for ( int i = 0; i < npar_sig; i++ ) std::cout << i << " " << param_s[i] << "    \t" << param_w[i] << "\n";
266 
267   // smooth the error term
268   for ( int i = 0; i < npar_sig-1; i++ )
269     param_w[i] = Util::max( param_w[i], 0.5*param_w[i+1] );
270   //for ( int i = 0; i < npar_sig; i++ ) std::cout << i << " " << param_s[i] << "    \t" << param_w[i] << "\n";
271 
272   ftype ll, ll_old = 1.0e30;
273   // now 25 cycles to refine s and w
274   int c = 0, clim = 25;
275   for ( c = 0; c < clim; c++ ) {
276     std::vector<ftype> grad_s( npar_sig, 0.0 ), shft_s( npar_sig, 0.0 );
277     std::vector<ftype> grad_w( npar_sig, 0.0 ), shft_w( npar_sig, 0.0 );
278     Matrix<ftype> curv_s( npar_sig, npar_sig, 0.0 );
279     Matrix<ftype> curv_w( npar_sig, npar_sig, 0.0 );
280     ll = 0.0;
281 
282     // build matrices
283     for ( HRI ih = flag.first(); !ih.last(); ih.next() ) if ( flag[ih].flag() ) {
284       dsdp = basisfn.fderiv_s( ih.invresolsq(), param_s );
285       dwdp = basisfn.fderiv_s( ih.invresolsq(), param_w );
286       fn = tgt( ih.hkl_class(), fo[ih], hl0[ih], fc[ih], dsdp.f, dwdp.f, hlterms );
287       //if ( Util::isnan(fn.r) ) std::cout << ih.hkl().format() << fo[ih].f() << " " << fo[ih].sigf() << " " << fc[ih].f() << " " << fc[ih].missing() << flag[ih].missing() << " " << hl0[ih].a() << " " << hl0[ih].b() << " " << hl0[ih].c() << " " << hl0[ih].d() << " " << dsdp.f << " " << dwdp.f << " \tFo,SIGo,Fc,missing\n";
288       ll += fn.r;
289       for ( int i = 0; i < npar_sig; i++ ) {
290 	grad_s[i] += fn.ds * dsdp.df[i];
291 	grad_w[i] += fn.dw * dwdp.df[i];
292 	//for ( int j = 0; j < npar_sig; j++ ) {
293 	for ( int j = Util::max(i-1,0); j <= Util::min(i+1,npar_sig-1); j++ ) {
294 	  curv_s(i,j) += dsdp.df2(i,j)*fn.ds + dsdp.df[i]*dsdp.df[j]*fn.dss;
295 	  curv_w(i,j) += dwdp.df2(i,j)*fn.dw + dwdp.df[i]*dwdp.df[j]*fn.dww;
296 	}
297       }
298     }
299     //std::cout << c << "\t" << ll << "\n";
300 
301     if ( ll > ll_old ) break;  // break on divergence
302 
303     shft_s = curv_s.solve( grad_s );
304     shft_w = curv_w.solve( grad_w );
305     for ( int i = 0; i < npar_sig; i++ ) {
306       //std::cout << i << "   \t" << param_s[i] << "   \t" << param_w[i] << "   \t" << shft_s[i] << "   \t" << shft_w[i] << "\n";
307       // soft buffers to prevent negatives
308       param_s[i] -= Util::min( shft_s[i], 0.25*param_s[i] );
309       param_w[i] -= Util::min( shft_w[i], 0.25*param_w[i] );
310     }
311 
312     if ( ll / ll_old > 0.999999 ) { status=true; break; }  // break on convergence
313     ll_old = ll;
314   }
315 
316   // store s,w
317   for ( HRI ih = fo0.first(); !ih.last(); ih.next() ) {
318     value_s[ih.index()] = basisfn.f_s( ih.invresolsq(), param_s );
319     value_w[ih.index()] = basisfn.f_s( ih.invresolsq(), param_w );
320   }
321 
322   // calculate map coeffs and FOM
323   reevaluate( fb, fd, phiw, hl, fo0, hl0, fc0, usage, tgt );
324 
325   return status;
326 }
327 
328 
reevaluate(HKL_data<datatypes::F_phi<T>> & fb,HKL_data<datatypes::F_phi<T>> & fd,HKL_data<datatypes::Phi_fom<T>> & phiw,HKL_data<datatypes::ABCD<T>> & hl,const HKL_data<datatypes::F_sigF<T>> & fo0,const HKL_data<datatypes::ABCD<T>> & hl0,const HKL_data<datatypes::F_phi<T>> & fc0,const HKL_data<datatypes::Flag> & usage,F tgt)329 template<class T> template<class F> bool SFweight_spline<T>::reevaluate( HKL_data<datatypes::F_phi<T> >& fb, HKL_data<datatypes::F_phi<T> >& fd, HKL_data<datatypes::Phi_fom<T> >& phiw, HKL_data<datatypes::ABCD<T> >& hl, const HKL_data<datatypes::F_sigF<T> >& fo0, const HKL_data<datatypes::ABCD<T> >& hl0, const HKL_data<datatypes::F_phi<T> >& fc0, const HKL_data<datatypes::Flag>& usage, F tgt )
330 {
331   typedef clipper::HKL_info::HKL_reference_index HRI;
332 
333   // prepare function
334   TargetResult fn;
335   datatypes::F_sigF<T> fo;
336   datatypes::F_phi<T> fc, twomfo, mfo, dfc, fzero(0.0,0.0);
337 
338   // calculate map coeffs and FOM
339   llw = llf = 0.0;
340   for ( HRI ih = fo0.first(); !ih.last(); ih.next() ) {
341     // prescale Fo, Fc
342     fo = fo0[ih];
343     fc = fc0[ih];
344     fo.scale( scale_fo[ih.index()] );
345     fc.scale( scale_fc[ih.index()] );
346     // get params an llk
347     const ftype s = value_s[ih.index()];
348     const ftype w = value_w[ih.index()];
349     fn = tgt( ih.hkl_class(), fo, hl0[ih], fc, s, w, hlterms );
350     hl[ih] = tgt.abcd;
351     phiw[ih] = tgt.phiw;
352     mfo    = datatypes::F_phi<T>( tgt.phiw.fom() * fo.f(), tgt.phiw.phi() );
353     twomfo = datatypes::F_phi<T>( 2.0 * mfo.f(), mfo.phi() );
354     dfc    = datatypes::F_phi<T>( s * fc.f(), fc.phi() );
355     if ( (!fo.missing()) && (!fc.missing()) ) {
356       if      ( usage[ih].flag()==SFweight_base<T>::BOTH ) llw += fn.r;
357       else if ( usage[ih].flag()==SFweight_base<T>::NONE ) llf += fn.r;
358     }
359     // deal with all possibilities of missing and non-missing
360     if ( !fc.missing() ) {
361       if ( !fo.missing() ) {
362 	fb[ih] = twomfo - dfc;
363 	fd[ih] =    mfo - dfc;
364       } else {
365 	fb[ih] = dfc;
366 	fd[ih] = fzero;
367       }
368     } else {
369       if ( !fo.missing() ) {
370 	fb[ih] = mfo;
371 	fd[ih] = fzero;
372       } else {
373 	fb[ih] = fzero;
374 	fd[ih] = fzero;
375       }
376     }
377     // undo scaling on fb, fd
378     fb[ih].scale( 1.0/scale_fo[ih.index()] );
379     fd[ih].scale( 1.0/scale_fo[ih.index()] );
380   }
381 
382   return true;
383 }
384 
385 
targetfn(const HKL_class cls,const datatypes::F_sigF<T> & fo0,const datatypes::F_phi<T> & fc0,const ftype & s,const ftype & w) const386 template<class T> typename SFweight_spline<T>::TargetResult SFweight_spline<T>::targetfn( const HKL_class cls, const datatypes::F_sigF<T>& fo0, const datatypes::F_phi<T>& fc0, const ftype& s, const ftype& w ) const
387 {
388   const datatypes::ABCD<T> hl0;
389   TargetFo tgt;
390   return tgt( cls, fo0, hl0, fc0, s, w, hlterms );
391 }
392 
393 
targethl(const HKL_class cls,const datatypes::F_sigF<T> & fo0,const datatypes::ABCD<T> & hl0,const datatypes::F_phi<T> & fc0,const ftype & s,const ftype & w) const394 template<class T> typename SFweight_spline<T>::TargetResult SFweight_spline<T>::targethl( const HKL_class cls, const datatypes::F_sigF<T>& fo0, const datatypes::ABCD<T>& hl0, const datatypes::F_phi<T>& fc0, const ftype& s, const ftype& w ) const
395 {
396   TargetHL tgt;
397   return tgt( cls, fo0, hl0, fc0, s, w, hlterms );
398 }
399 
400 
num_params(const HKL_data<datatypes::Flag_bool> & flag) const401 template<class T> int SFweight_spline<T>::num_params( const HKL_data<datatypes::Flag_bool>& flag ) const
402 {
403   int npar;
404   int n_use = flag.num_obs();
405   if ( nparams == 0 ) {
406     npar = Util::max( n_use / nreflns, 2 );
407   } else if ( nreflns == 0 ) {
408     npar = nparams;
409   } else {
410     ftype np1 = ftype(nparams+0.499);
411     ftype np2 = ftype(n_use) / ftype(nreflns);
412     ftype np = sqrt( np1*np1*np2*np2 / ( np1*np1+np2*np2 ) );
413     npar = Util::max( int(np), 2 );
414   }
415   return npar;
416 }
417 
418 
debug() const419 template<class T> void SFweight_spline<T>::debug() const
420 {
421   TargetResult r00, r01, r10, r11, rxx;
422   Spacegroup p1( Spacegroup::P1 );
423   HKL_class cls;
424   datatypes::F_sigF<T> fo;
425   datatypes::F_phi<T>  fc;
426   fo.f() = 10.0; fo.sigf() = 2.0;
427   fc.f() = 15.0; fc.phi() = 0.0;
428   fo.sigf() = 0.0; //!!!!!
429   ftype ds = 0.000001;
430   ftype dw = 0.000001;
431   datatypes::ABCD<T> hl( 0.0, 0.0, 0.0, 0.0 );
432   for ( int h = 0; h < 2; h++ ) {
433     cls = HKL_class( p1, HKL( h, 0, 0 ) );
434     std::cout << "\nCentric? " << cls.centric() << " epsc " << cls.epsilonc() << "\n";
435     for ( ftype w = 10.0; w < 1000.0; w *= 3.0 )
436       for ( ftype s = 0.4; s < 2.0; s *= 2.0 ) {
437 
438         rxx = targethl( cls, fo, hl, fc, s, w );
439         r00 = targetfn( cls, fo, fc, s, w );
440         r01 = targetfn( cls, fo, fc, s, w+dw );
441         r10 = targetfn( cls, fo, fc, s+ds, w );
442         r11 = targetfn( cls, fo, fc, s+ds, w+dw );
443 
444         std::cout << w << " " << s << "\t" << r00.r << " " << r01.r << " " << r10.r << " " << r11.r << " " << rxx.r << "\n";
445         std::cout << (r10.r-r00.r)/ds << "\t" << r00.ds << "\n";
446         std::cout << (r01.r-r00.r)/dw << "\t" << r00.dw << "\n";
447         std::cout << (r10.ds-r00.ds)/ds << "\t" << r00.dss << "\n";
448         std::cout << (r01.dw-r00.dw)/dw << "\t" << r00.dww << "\n";
449         std::cout << (r01.ds-r00.ds)/dw << "\t" << r00.dsw << "\n";
450         std::cout << (r10.dw-r00.dw)/ds << "\t" << r00.dsw << "\n";
451       }
452   }
453   for ( int h = 0; h < 2; h++ ) {
454     cls = HKL_class( p1, HKL( h, 0, 0 ) );
455     std::cout << "\nCentric? " << cls.centric() << " epsc " << cls.epsilonc() << "\n";
456     for ( ftype w = 10.0; w < 1000.0; w *= 3.0 )
457       for ( ftype s = 0.4; s < 2.0; s *= 2.0 ) {
458 
459         rxx = targetfn( cls, fo, fc, s, w );
460         r00 = targethl( cls, fo, hl, fc, s, w );
461         r01 = targethl( cls, fo, hl, fc, s, w+dw );
462         r10 = targethl( cls, fo, hl, fc, s+ds, w );
463         r11 = targethl( cls, fo, hl, fc, s+ds, w+dw );
464 
465         std::cout << w << " " << s << "\t" << r00.r << " " << r01.r << " " << r10.r << " " << r11.r << " " << rxx.r << "\n";
466         std::cout << (r10.r-r00.r)/ds << "\t" << r00.ds << "\n";
467         std::cout << (r01.r-r00.r)/dw << "\t" << r00.dw << "\n";
468         std::cout << (r10.ds-r00.ds)/ds << "\t" << r00.dss << "\n";
469         std::cout << (r01.dw-r00.dw)/dw << "\t" << r00.dww << "\n";
470         std::cout << (r01.ds-r00.ds)/dw << "\t" << r00.dsw << "\n";
471         std::cout << (r10.dw-r00.dw)/ds << "\t" << r00.dsw << "\n";
472       }
473   }
474 }
475 
476 
477 // compile templates
478 
479 template class SFweight_spline<ftype32>;
480 
481 template class SFweight_spline<ftype64>;
482 
483 
484 } // namespace clipper
485