source: sasview/realSpaceModeling/pointsmodelpy/libpointsmodelpy/points_model.cc @ abf6771

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since abf6771 was 0be5c81, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Normalize output P(r)

  • Property mode set to 100644
File size: 11.8 KB
Line 
1/** \file points_model.cc */
2
3#include <vector>
4#include <algorithm>
5#include <fstream>
6#include <stdio.h>
7//#include <exception>
8#include <stdexcept>
9#include "points_model.h"
10#include "Point3D.h"
11
12PointsModel::PointsModel()
13{
14  r_grids_num_ = 2000;
15  rmax_ = 0;
16  cormax_ = 0;
17  rstep_ = 0;
18}
19
20void PointsModel::CalculateIQ(IQ *iq)
21{
22  //fourier transform of the returned Array2D<double> from ddFunction()
23  int nIpoints = iq->GetNumI();
24  double qstep = (iq->GetQmax()) / (nIpoints-1);
25  vector<double> fint(nIpoints, 0);
26
27  //I(0) is calculated seperately
28  int num_rstep = pr_.dim1();
29
30  for (int k = 1; k<nIpoints; k++){
31
32    double q = k * qstep;
33
34    double r =0;
35    double debeye = 0;
36    double fadd =0;
37
38
39    for (int i = 1; i < num_rstep; ++i){
40      r = i*rstep_;  //r should start from 1* rstep
41      double qr = q*r;
42      debeye = sin(qr)/qr;
43      fadd = pr_[i][1]*debeye;
44      fint[k] = fint[k] + fadd;
45    }
46  }
47
48  //I(0)
49  double Izero = 0;
50  for (int i = 0; i < num_rstep; ++i)
51    Izero += pr_[i][1];
52  fint[0] = Izero;
53
54  //assign I(Q) with normalization
55  for(int j = 0; j < nIpoints; ++j){
56    (*iq).iq_data[j][0] = j * qstep;
57    (*iq).iq_data[j][1] = fint[j];
58    // remove normalization Izero;
59  }
60}
61
62//return I with a single q value
63double PointsModel::CalculateIQ(double q)
64{
65  //fourier transform of the returned Array2D<double> from ddFunction()
66  int num_rstep = pr_.dim1();
67
68  double r =0;
69  double debeye = 0;
70  double fadd = 0;
71  double Irelative = 0;
72
73  //I(0) is calculated seperately
74  if (q == 0){
75    //I(0)
76    double Izero = 0;
77    for (int i = 0; i < num_rstep; ++i)
78      Izero += pr_[i][1];
79    Irelative = Izero;
80  }
81  else {
82    for (int i = 1; i < num_rstep; ++i){
83      r = i*rstep_;  //r should start from 1* rstep
84      double qr = q*r;
85      debeye = sin(qr)/qr;
86      fadd = pr_[i][1]*debeye;
87      Irelative = Irelative + fadd;
88    }
89  }
90  return Irelative;
91}
92
93double PointsModel::CalculateIQError(double q)
94{
95  //fourier transform of the returned Array2D<double> from ddFunction()
96  int num_rstep = pr_.dim1();
97
98  double r =0;
99  double debeye = 0;
100  double fadd = 0;
101  double Irelative = 0;
102
103  //I(0) is calculated seperately
104  for (int i = 1; i < num_rstep; ++i){
105          r = i*rstep_;  //r should start from 1* rstep
106          double qr = q*r;
107          debeye = sin(qr)/qr;
108          fadd = fabs(pr_[i][2])*debeye*debeye
109                + rstep_*rstep_/4.0/r/r*(cos(qr)*cos(qr) + debeye*debeye);
110          Irelative = Irelative + fadd;
111  }
112  return sqrt(Irelative);
113}
114
115//pass in a vector of points, and calculate the P(r)
116double PointsModel::DistDistribution(const vector<Point3D> &vp)
117{
118  //get r axis:0,rstep,2rstep,3rstep......d_bound
119  int sizeofpr = r_grids_num_ + 1; //+1 just for overflow prevention
120
121  double d_bound = GetDimBound();
122  rstep_ = CalculateRstep(r_grids_num_,d_bound);
123
124  Array2D<double> pr(sizeofpr, 3); //third column is left for error for the future
125  pr = 0;
126
127  for (int i = 1; i != sizeofpr; ++i)
128    pr[i][0] = pr[i-1][0] + rstep_ ;  //column 1:  distance
129
130  int size = vp.size();
131
132  for (int i1 = 0; i1 < size - 1; ++i1) {
133    for (int i2 = i1 + 1; i2 < size; ++i2) {
134      //dist_.push_back(vp[i1].distanceToPoint(vp[i2]));
135      //product_sld_.push_back(vp[i1].getSLD() * vp[i2].getSLD());
136      double a_dist = vp[i1].distanceToPoint(vp[i2]);
137      double its_sld = vp[i1].getSLD() * vp[i2].getSLD();
138
139      //save maximum distance
140      if (a_dist>rmax_) {
141        rmax_ = a_dist;
142      }
143      //insert into pr array
144      int l = int(floor(a_dist/rstep_));
145
146      //cout << "i1,i2,l,a_dist"<<vp[i1]<<" "<<vp[i2]<<" "<<l<<" "<<a_dist<<endl;     
147      //overflow check
148      if (l >= sizeofpr) {
149        cerr << "one distance is out of range: " << l <<endl;
150        //throw "Out of range";
151      }
152      else {
153        pr[l][1] += its_sld;  //column 2 intermediate: sum of SLD of the points with specific distance     
154        // Estimate uncertainty (squared)
155        pr[l][2] += its_sld*its_sld; 
156        //keep maxium Pr absolute number, in order to normalize
157        //if (pr[l][1] > cormax_)         cormax_ = pr[l][1];
158      }
159    }
160  }
161 
162  //normalize Pr
163  for (int j = 0; j != sizeofpr; ++j){           //final column2 for P(r)
164    //pr[j][1] = pr[j][1]/cormax_;
165
166    // 'Size' is the number of space points, without double counting (excluding
167    // overlapping regions between shapes). The volume of the combined shape
168    // is given by  V = size * (sum of all sub-volumes) / (Total number of points)
169    //              V = size / (lores_density)
170   
171    // - To transform the integral to a sum, we need to give a weight
172    // to each entry equal to the average space volume of a point (w = V/N = 1/lores_density).
173    // The final output, I(q), should therefore be multiplied by V*V/N*N.
174    // Since we will be interested in P(r)/V, we only need to multiply by 1/N*(V/N) = 1/N/lores_density.
175    // We don't have access to lores_density from this class; we will therefore apply
176    // this correction externally.
177    //
178    // - Since the loop goes through half the points, multiply by 2.
179    // TODO: have access to lores_density from this class.
180    //
181    pr[j][1] = 2.0*pr[j][1]/size;
182    pr[j][2] = 4.0*pr[j][2]/size/size;
183  }
184  pr_ = pr;
185
186  return rmax_;
187}
188
189Array2D<double> PointsModel::GetPr()
190{
191  return pr_;
192}
193
194
195double PointsModel::CalculateRstep(int num_grids, double rmax)
196{
197  assert(num_grids > 0);
198
199  double rstep;
200  rstep = rmax / num_grids;
201
202  return rstep;
203}
204
205void PointsModel::OutputPR(const string &fpr){
206  ofstream outfile(fpr.c_str());
207  if (!outfile) {
208    cerr << "error: unable to open output file: "
209         << outfile << endl;
210    exit(1);
211  }
212 
213  double sum = 0.0;
214  double r_stepsize = 1.0;
215  if (pr_.dim1()>2) r_stepsize = pr_[1][0] - pr_[0][0];
216 
217  for (int i = 0;  i < pr_.dim1(); ++i){
218          sum += pr_[i][1]*r_stepsize;
219  }
220 
221  for (int i = 0;  i < pr_.dim1(); ++i){
222          if (pr_[i][1]==0) continue;
223          outfile << pr_[i][0] << "       " << (pr_[i][1]/sum) << endl;
224  }
225}
226
227void PointsModel::OutputPDB(const vector<Point3D> &vp,const char *fpr){
228  FILE *outfile=NULL;
229  outfile = fopen(fpr,"w+");
230  if (!outfile) {
231    cerr << "error: unable to open output file: "
232         << outfile << endl;
233    exit(1);
234  }
235  int size = vp.size();
236  int index = 0;
237  for (int i = 0;  i < size; ++i){
238    ++index;
239    fprintf(outfile,"ATOM%7d  C%24.3lf%8.3lf%8.3lf%6.3lf\n", \
240           index,vp[i].getX(),vp[i].getY(),vp[i].getZ(),vp[i].getSLD());
241  }
242  fclose(outfile);
243}
244
245PointsModel::~PointsModel()
246{
247}
248
249void PointsModel::DistDistributionXY(const vector<Point3D> &vp)
250{
251  //the max box get from 3D should be more than enough for 2D,but doesn't hurt
252  double d_bound = GetDimBound();
253
254  //using 1A for rstep, so the total bins is the max distance for the object
255  int sizeofpr = ceil(d_bound) + 1; //+1 just for overflow prevention
256  rstep_ = 1;
257
258  Array2D<double> pr_xy(sizeofpr,sizeofpr); //2D histogram
259
260  //the max frequency in the correlation histogram
261  double cormax_xy_ = 0;
262
263  //initialization
264  pr_xy = 0;
265
266  for (int i = 1; i != sizeofpr; ++i){
267    pr_xy[i][0] = pr_xy[i-1][0] + rstep_ ;  //column 1:  distance
268  }
269
270  int size = vp.size();
271
272  for (int i1 = 0; i1 < size - 1; ++i1) {
273    for (int i2 = i1 + 1; i2 < size; ++i2) {
274      int jx = int(floor(fabs(vp[i1].getX()-vp[i2].getX())/rstep_));
275      int jy = int(floor(fabs(vp[i1].getY()-vp[i2].getY())/rstep_));
276      //the sld for the pair of points
277      double its_sld = vp[i1].getSLD()*vp[i2].getSLD();
278
279      //overflow check
280      if ((jx >= sizeofpr) || (jy >= sizeofpr))
281      {
282        cerr << "one distance is out of range: " <<endl;
283        //throw "Out of range";
284      }
285      else{
286        pr_xy[jx][jy] += its_sld;
287        if (pr_xy[jx][jy] > cormax_xy_ ) cormax_xy_ = pr_xy[jx][jy];
288      }
289    }
290  }
291
292  //normalize Pr_xy
293  for (int m = 0; m != sizeofpr; ++m){           //final column2 for P(r)
294    for (int n = 0; n != sizeofpr; ++n){
295      pr_xy[m][n] = pr_xy[m][n]/cormax_xy_;
296      //cout << "m n:"<<m<<" "<<n<<" "<<pr_xy[m][n]<<endl;
297    }
298  }
299
300  pr_xy_ = pr_xy;
301}
302
303void PointsModel::OutputPR_XY(const std::string &fpr)
304{
305  ofstream outfile(fpr.c_str());
306  if (!outfile) {
307    cerr << "error: unable to open output file: "
308         << outfile << endl;
309    exit(1);
310  }
311  int size = pr_xy_.dim1();
312  //pr_xy_ is a N x N array
313  for (int i = 0;  i != size; ++i){
314    for (int j = 0; j != size; ++j)
315    {
316      outfile << i << "    " << j <<"    "<< pr_xy_[i][j] << endl;
317    }
318  }
319}
320
321void PointsModel::CalculateIQ_2D(IQ *iq,double phi)
322{
323  int nIpoints = iq->GetNumI();
324  double qstep = (iq->GetQmax()) / (nIpoints-1);
325  vector<double> fint(nIpoints, 0);
326  double Izero = 0;
327
328  //number of bins on x and y axis
329  int size_r = pr_xy_.dim1();
330  //rstep is set to one, otherwise should be cos(phi)*rstep
331  double cosphi = cos(phi);
332  double sinphi = sin(phi);
333
334  for(int k = 1; k != nIpoints; ++k){
335    double q = k * qstep;
336    double tmp = cos(q*(cosphi+sinphi));
337
338    for(int i=0; i!=size_r; ++i){
339      for(int j = 0; j!=size_r; ++j){
340        fint[k] += pr_xy_[i][j]*tmp;
341      }
342    }
343  }
344
345  for(int i=0; i!=size_r; ++i){
346    for(int j = 0; j!=size_r; ++j){
347      Izero += pr_xy_[i][j];
348    }
349  }
350  fint[0] = Izero;
351
352  //assign I(Q) with normalization
353  for(int j = 0; j < nIpoints; ++j){
354    (*iq).iq_data[j][0] = j * qstep;
355    (*iq).iq_data[j][1] = fint[j] / Izero;
356  }
357}
358
359vector<double> PointsModel::GetCenter()
360{
361  vector<double> vp(3,0);
362  return vp;
363}
364
365double PointsModel::CalculateIQ_2D(double qx, double qy)
366{
367  //for each (Qx,Qy) on 2D detector, calculate I
368  double q = sqrt(qx*qx+qy*qy);
369  double I = 0;
370
371  double cosphi = qx/q;
372  double sinphi = qy/q;
373  double tmp = cos(q*(cosphi+sinphi));
374
375  //loop through P(r) on xy plane
376  int size_r = pr_xy_.dim1();
377  for(int i=-size_r+1; i!=size_r; ++i){
378    for(int j = -size_r+1; j!=size_r; ++j){
379      //rstep is set to one, left out from calculation
380      I += pr_xy_[abs(i)][abs(j)]*cos(q*(cosphi*i+sinphi*j));
381    }
382  }
383
384  //return I, without normalization
385  return I;
386}
387
388/*
389 * 2D simulation for oriented systems
390 * The beam direction is assumed to be in the z direction.
391 *
392 * @param points: vector of space points
393 * @param qx: qx [A-1]
394 * @param qy: qy [A-1]
395 * @return: I(qx, qy) for the system described by the space points [cm-1]
396 *
397 */
398double PointsModel::CalculateIQ_2D(const vector<Point3D>&points, double qx, double qy){
399        /*
400         * TODO: the vector of points should really be part of the class
401         *           This is a design flaw inherited from the original programmer.
402         */
403       
404        int size = points.size();
405
406        double cos_term = 0;
407        double sin_term = 0;
408        for (int i = 0; i < size; i++) {
409                //the sld for the pair of points
410       
411                double phase = qx*points[i].getX() + qy*points[i].getY();
412                               
413                cos_term += cos(phase) * points[i].getSLD();
414                sin_term += sin(phase) * points[i].getSLD();
415       
416        }                       
417
418        // P(q) = 1/V I(q) = (V/N)^2 (1/V) (cos_term^2 + sin_term^2)
419        // We divide by N here and we will multiply by the density later.
420
421        return (cos_term*cos_term + sin_term*sin_term)/size;   
422}
423
424double PointsModel::CalculateIQ_2D_Error(const vector<Point3D>&points, double qx, double qy){
425       
426        int size = points.size();
427
428        double delta_x, delta_y;
429        double q_t2 = qx*qx + qy*qy;
430        double cos_term = 0;
431        double sin_term = 0;
432        double cos_err = 0;
433        double sin_err = 0;
434       
435        // Estimate the error on the position of each point
436        // in x or y as V^(1/3)/N
437       
438        for (int i = 0; i < size; i++) {
439               
440               
441                //the sld for the pair of points
442       
443                double phase = qx*points[i].getX() + qy*points[i].getY();
444                double sld_fac = points[i].getSLD() * points[i].getSLD();
445               
446                cos_term += cos(phase) * points[i].getSLD();
447                sin_term += sin(phase) * points[i].getSLD();
448
449                sin_err += cos(phase) * cos(phase) * sld_fac;
450                cos_err += sin(phase) * sin(phase) * sld_fac;
451       
452        }                       
453
454        // P(q) = 1/V I(q) = (V/N)^2 (1/V) (cos_term^2 + sin_term^2)
455        // We divide by N here and we will multiply by the density later.
456
457        // We will need to multiply this error by V^(1/3)/N.
458        // We don't have access to V from within this class.
459        return 2*sqrt(cos_term*cos_term*cos_err*cos_err + sin_term*sin_term*sin_err*sin_err)/size;     
460}
461
Note: See TracBrowser for help on using the repository browser.