00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifndef _chemistry_qc_mbptr12_gaussianfittimpl_h
00029 #define _chemistry_qc_mbptr12_gaussianfittimpl_h
00030
00031 #include <cmath>
00032 #include <algorithm>
00033 #include <math/optimize/levmar/lm.h>
00034 #include <util/class/scexception.h>
00035 #include <chemistry/qc/mbptr12/gaussianfit.h>
00036
00037 extern "C" {
00038 void __eval_slater(double* params, double* f, int nparam, int np,
00039 void *extraparams);
00040 void __eval_slater_dfdp(double* params, double* dfdp, int nparam, int np,
00041 void *extraparams);
00042 void __eval_slater_pgauss(double* params, double* f, int nparam, int np,
00043 void *extraparams);
00044 void __eval_slater_dfdp_pgauss(double* params, double* dfdp, int nparam,
00045 int np, void *extraparams);
00046 }
00047 ;
00048
00049 namespace {
00050 extern "C" {
00051 typedef void
00052 (*eval_f_ptr)(double *p, double *hx, int m, int n, void *adata);
00053 typedef void (*eval_dfdp_ptr)(double *p, double *hx, int m, int n,
00054 void *adata);
00055 }
00056 ;
00057 }
00058
00059 namespace sc {
00060
00061 template <typename Function, typename Weight> GaussianFit<Function, Weight>::GaussianFit(
00062 unsigned int N,
00063 const Weight& W,
00064 double left,
00065 double right,
00066 unsigned int NP) :
00067 weight_(W), p_(new double[2*N]), scratch_(new double[NP]), npts_(NP),
00068 left_(left), right_(right) {
00069 if (left < 0.0 || right < 0.0 || left >= right || N < 1 || NP < 2)
00070 throw sc::ProgrammingError("GaussianFit::GaussianFit() -- invalid parameters",__FILE__,__LINE__);
00071
00072
00073 gaussians_.resize(N);
00074
00075 if (N%2) {
00076
00077 double gamma = 3.0;
00078 for (int i=N/2; i>=0; --i, gamma/=3.0)
00079 gaussians_[i] = std::make_pair(gamma, 1.0);
00080 gamma = 9.0;
00081 for (int i=N/2+1; i<N; ++i, gamma*=3.0)
00082 gaussians_[i] = std::make_pair(gamma, 1.0);
00083 } else {
00084
00085 double gamma = 3.0/sqrt(3.0);
00086 for (int i=N/2-1; i>=0; --i, gamma/=3.0)
00087 gaussians_[i] = std::make_pair(gamma, 1.0);
00088 gamma = 3.0*sqrt(3.0);
00089 for (int i=N/2; i<N; ++i, gamma*=3.0)
00090 gaussians_[i] = std::make_pair(gamma, 1.0);
00091 }
00092
00093
00094 for (unsigned int p=0; p<npts_; ++p)
00095 scratch_[p] = 0.0;
00096 }
00097
00098 template <typename Function, typename Weight> GaussianFit<Function, Weight>::~GaussianFit() {
00099 delete[] p_;
00100 delete[] scratch_;
00101 }
00102
00103 namespace {
00104
00105 template <class Function, class Weight> struct ExtraParams {
00106 const Function* f;
00107 const Weight* w;
00108 unsigned int npts;
00109 double lb;
00110 double ub;
00111 int k;
00112 };
00113
00114 template <class Function, class Weight> void eval_f(double* params,
00115 double* f, int nparam,
00116 int np,
00117 void *extraparams) {
00118 typedef ExtraParams<Function,Weight> XPS;
00119 typedef GaussianFit<Function,Weight> GaussFit;
00120 XPS* XParams = static_cast<XPS*>(extraparams);
00121 const double lb = XParams->lb;
00122 const double ub = XParams->ub;
00123 const double dx = (ub - lb)/(np - 1);
00124 const double npts = XParams->npts;
00125 const Function& F = *(XParams->f);
00126 const Weight& W = *(XParams->w);
00127 const int k = XParams->k;
00128
00129 double x = 0.0;
00130 for (unsigned int p=0; p<npts; ++p, x+=dx) {
00131 double fitvalue = 0.0;
00132 for (unsigned int i=0; i<nparam;) {
00133 const double gamma = params[i++];
00134 const double coef = params[i++];
00135 fitvalue += coef * std::pow(x, k) * std::exp(-gamma*x*x);
00136 }
00137
00138 if (GaussFit::weigh_F) {
00139 const double df = fitvalue - W(x) * F(x);
00140 f[p] = df;
00141 } else {
00142 const double df = fitvalue - F(x);
00143
00144
00145 f[p] = df * std::sqrt(W(x));
00146 }
00147 }
00148 }
00149 template <class Function, class Weight> void eval_dfdp(double* params,
00150 double* dfdp,
00151 int nparam, int np,
00152 void *extraparams) {
00153 typedef ExtraParams<Function,Weight> XPS;
00154 typedef GaussianFit<Function,Weight> GaussFit;
00155 XPS* XParams = static_cast<XPS*>(extraparams);
00156 const double lb = XParams->lb;
00157 const double ub = XParams->ub;
00158 const double dx = (ub - lb)/(np - 1);
00159 const double npts = XParams->npts;
00160 const Function& F = *(XParams->f);
00161 const Weight& W = *(XParams->w);
00162 const int k = XParams->k;
00163
00164 double x = 0.0;
00165 unsigned int j = 0;
00166 for (unsigned int p=0, j=0; p<npts; ++p, x+=dx) {
00167 const double sqrt_W = std::sqrt(W(x));
00168 for (unsigned int i=0; i<nparam;) {
00169 const unsigned int p1 = i++;
00170 const unsigned int p2 = i++;
00171 const double gamma = params[p1];
00172 const double coef = params[p2];
00173 const double expgxx = std::pow(x, k) * std::exp(-gamma*x*x);
00174 if (GaussFit::weigh_F) {
00175 dfdp[j++] = - (x * x * coef * expgxx);
00176 dfdp[j++] = expgxx;
00177 } else {
00178 dfdp[j++] = -sqrt_W * (x * x * coef * expgxx);
00179 dfdp[j++] = sqrt_W * expgxx;
00180 }
00181 }
00182 }
00183 }
00184 }
00185
00186 namespace mbptr12 {
00187 template <class Function, class Weight> struct __to_extern_C_eval {
00188 static eval_f_ptr f_ptr;
00189 static eval_dfdp_ptr dfdp_ptr;
00190 };
00191
00192 }
00193
00194 template <typename Function, typename Weight> const typename GaussianFit<Function,Weight>::Gaussians& GaussianFit<
00195 Function, Weight>::operator()(const Function& F) const
00196 {
00197 ExtraParams<Function,Weight> xp;
00198 xp.f = &F;
00199 xp.w = &weight_;
00200 xp.npts = npts_;
00201 xp.lb = left_;
00202 xp.ub = right_;
00203 xp.k = k_;
00204 const int ngaussians = gaussians_.size();
00205
00206 extract_params();
00207
00208 const int niter = dlevmar_der(mbptr12::__to_extern_C_eval<Function,Weight>::f_ptr,
00209 mbptr12::__to_extern_C_eval<Function,Weight>::dfdp_ptr,
00210 p_, scratch_, 2*ngaussians, npts_, 100000, NULL, NULL, NULL, NULL, static_cast<void*>(&xp));
00211 if (niter> 0) {
00212 if (classdebug_) {
00213 std::cout << "GaussianFit() -- converged in " << niter << " iterations" << std::endl;
00214 for(unsigned int g=0, p=0; g<ngaussians; ++g) {
00215 std::cout << " gamma = " << p_[p++];
00216 std::cout << " coef = " << p_[p++] << std::endl;
00217 }
00218 }
00219
00220 assign_params();
00221 }
00222 else {
00223 throw AlgorithmException("GaussianFit() -- fit failed",__FILE__,__LINE__);
00224 }
00225
00226 return gaussians_;
00227 }
00228
00229 template <typename Function,
00230 typename Weight>
00231 void
00232 GaussianFit<Function,Weight>::extract_params() const
00233 {
00234 const unsigned int ngaussians = gaussians_.size();
00235 unsigned int pp;
00236 for(unsigned int p=0, pp=0; p<ngaussians; ++p) {
00237 p_[pp++] = gaussians_[p].first;
00238 p_[pp++] = gaussians_[p].second;
00239 }
00240 }
00241
00242 template <typename Function,
00243 typename Weight>
00244 void
00245 GaussianFit<Function,Weight>::assign_params() const
00246 {
00247 const unsigned int ngaussians = gaussians_.size();
00248 unsigned int pp;
00249 for(unsigned int p=0, pp=0; p<ngaussians; ++p) {
00250 gaussians_[p].first = p_[pp++];
00251 gaussians_[p].second = p_[pp++];
00252 }
00253 }
00254 };
00255
00256 #endif // include guards
00258
00259
00260
00261
00262