8 #ifndef IMPISD_UNIVARIATE_FUNCTIONS_H
9 #define IMPISD_UNIVARIATE_FUNCTIONS_H
11 #include <IMP/isd/isd_config.h>
17 #include <Eigen/Dense>
19 #define IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM 1e-7
21 IMPISD_BEGIN_NAMESPACE
35 virtual Eigen::VectorXd operator() (
40 bool stupid)
const = 0;
43 virtual bool has_changed()
const = 0;
46 virtual void update() = 0;
52 virtual void add_to_derivatives(
const Floats& x,
60 virtual void add_to_particle_derivative(
unsigned particle_no,
69 virtual Eigen::VectorXd get_derivative_vector(
70 unsigned particle_no,
const FloatsList& xlist)
const = 0;
75 bool stupid)
const = 0;
78 virtual Eigen::VectorXd get_second_derivative_vector(
79 unsigned particle_a,
unsigned particle_b,
83 virtual FloatsList get_second_derivative_vector(
84 unsigned particle_a,
unsigned particle_b,
85 const FloatsList& xlist,
bool stupid)
const = 0;
88 virtual unsigned get_ndims_x()
const = 0;
91 virtual unsigned get_ndims_y()
const = 0;
94 virtual unsigned get_number_of_particles()
const = 0;
97 virtual bool get_particle_is_optimized(
unsigned particle_no)
const = 0;
100 virtual unsigned get_number_of_optimized_particles()
const = 0;
118 IMP_LOG_TERSE(
"Linear1DFunction: constructor" << std::endl);
121 a_val_ =
Nuisance(a).get_nuisance();
122 b_val_ =
Nuisance(b).get_nuisance();
127 double tmpa =
Nuisance(a_).get_nuisance();
128 double tmpb =
Nuisance(b_).get_nuisance();
129 if ((std::abs(tmpa - a_val_) >
130 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
131 || (std::abs(tmpb - b_val_) >
132 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM))
143 a_val_ =
Nuisance(a_).get_nuisance();
144 b_val_ =
Nuisance(b_).get_nuisance();
146 << a_val_ <<
" b:=" << b_val_ << std::endl);
151 Floats ret(1,a_val_*x[0]+b_val_);
157 unsigned M = xlist.size();
158 Eigen::VectorXd retlist(M);
159 for (
unsigned i = 0; i < M; i++)
162 "expecting a 1-D vector");
163 retlist(i) = a_val_*xlist[i][0]+b_val_;
170 Eigen::VectorXd vec((*
this)(xlist));
172 for (
unsigned i=0; i<xlist.size(); i++)
173 ret.push_back(
Floats(1,vec(i)));
181 Nuisance(a_).add_to_nuisance_derivative(x[0], accum);
183 Nuisance(b_).add_to_nuisance_derivative(1, accum);
192 Nuisance(a_).add_to_nuisance_derivative(value, accum);
195 Nuisance(b_).add_to_nuisance_derivative(value, accum);
198 IMP_THROW(
"Invalid particle number", ModelException);
203 unsigned particle_no,
const FloatsList& xlist)
const
205 unsigned N=xlist.size();
206 Eigen::VectorXd ret(N);
210 for (
unsigned i=0; i<N; i++)
211 ret(i) = xlist[i][0];
217 IMP_THROW(
"Invalid particle number", ModelException);
225 Eigen::MatrixXd mat(xlist.size(),2);
229 for (
int i=0; i<mat.rows(); i++)
232 for (
int j=0; j<mat.cols(); j++)
233 line.push_back(mat(i,j));
240 unsigned,
unsigned,
const FloatsList& xlist)
const
243 unsigned N=xlist.size();
244 Eigen::VectorXd H(Eigen::VectorXd::Zero(N));
249 unsigned particle_a,
unsigned particle_b,
253 particle_a, particle_b, xlist));
255 for (
int i=0; i<mat.rows(); i++)
258 for (
int j=0; j<mat.cols(); j++)
259 line.push_back(mat(i,j));
275 return Nuisance(a_).get_nuisance_is_optimized();
277 return Nuisance(b_).get_nuisance_is_optimized();
279 IMP_THROW(
"Invalid particle number", ModelException);
286 if (
Nuisance(a_).get_nuisance_is_optimized()) count++;
287 if (
Nuisance(b_).get_nuisance_is_optimized()) count++;
311 double a_val_, b_val_;
332 G_(G), Rg_(Rg), d_(d), s_(s), A_(A)
334 IMP_LOG_TERSE(
"GeneralizedGuinierPorodFunction: constructor"
345 double tmpG =
Scale(G_).get_scale();
346 double tmpRg =
Scale(Rg_).get_scale();
347 double tmpd =
Scale(d_).get_scale();
348 double tmps =
Scale(s_).get_scale();
349 double tmpA =
Nuisance(A_).get_nuisance();
350 if ((std::abs(tmpG - G_val_) > IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
351 || (std::abs(tmpRg - Rg_val_) >
352 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
353 || (std::abs(tmpd - d_val_) >
354 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
355 || (std::abs(tmps - s_val_) >
356 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
357 || (std::abs(tmpA - A_val_) >
358 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM))
361 "GeneralizedGuinierPorodFunction: has_changed():");
370 G_val_ =
Scale(G_).get_scale();
371 Rg_val_ =
Scale(Rg_).get_scale();
372 d_val_ =
Scale(d_).get_scale();
373 s_val_ =
Scale(s_).get_scale();
374 if (d_val_ == s_val_) {
376 if (s_val_ > 0.001) {
383 A_val_ =
Nuisance(A_).get_nuisance();
384 q1_param_ = std::sqrt((d_val_-s_val_)*(3-s_val_)/2.);
385 D_param_ = G_val_ *std::exp(-IMP::square(q1_param_)/(3-s_val_));
386 q1_param_ = q1_param_ / Rg_val_;
387 D_param_ *= std::pow(q1_param_,d_val_-s_val_);
388 IMP_LOG_TERSE(
"GeneralizedGuinierPorodFunction: update() G:= "
390 <<
" Rg:=" << Rg_val_
394 <<
" Q1.Rg =" << q1_param_*Rg_val_
395 <<
" D =" << D_param_
410 Floats ret(1,get_value(x[0]));
416 unsigned M=xlist.size();
417 Eigen::VectorXd retlist(M);
418 for (
unsigned i = 0; i < M; i++)
421 "expecting a 1-D vector");
422 retlist(i) = get_value(xlist[i][0]);
429 Eigen::VectorXd vec((*
this)(xlist));
431 for (
unsigned i=0; i<xlist.size(); i++)
432 ret.push_back(
Floats(1,vec(i)));
440 double value = get_value(qval) - A_val_;
443 deriv = value/G_val_;
445 "derivative for G is nan.");
446 Scale(G_).add_to_nuisance_derivative(deriv, accum);
447 if (qval <= q1_param_)
450 deriv = - value * 2*IMP::square(qval)*Rg_val_/(3-s_val_);
452 "derivative for Rg is nan.");
453 Scale(Rg_).add_to_nuisance_derivative(deriv, accum);
458 * (IMP::square((qval*Rg_val_)/(3-s_val_)) + std::log(qval));
460 "derivative for s is nan.");
461 Scale(s_).add_to_nuisance_derivative(deriv, accum);
464 deriv = value * (s_val_-d_val_)/Rg_val_;
466 "derivative for Rg is nan.");
467 Scale(Rg_).add_to_nuisance_derivative(deriv, accum);
469 deriv = value * std::log(q1_param_/qval);
471 "derivative for d is nan.");
472 Scale(d_).add_to_nuisance_derivative(deriv, accum);
474 deriv = - value * ( (d_val_-s_val_)/(2*(3-s_val_))
475 + std::log(q1_param_) );
477 "derivative for d is nan.");
478 Scale(s_).add_to_nuisance_derivative(deriv, accum);
482 Nuisance(A_).add_to_nuisance_derivative(deriv, accum);
492 "derivative for G is nan.");
493 Scale(G_).add_to_scale_derivative(value, accum);
497 "derivative for Rg is nan.");
498 Scale(Rg_).add_to_scale_derivative(value, accum);
502 "derivative for d is nan.");
503 Scale(d_).add_to_scale_derivative(value, accum);
507 "derivative for s is nan.");
508 Scale(s_).add_to_scale_derivative(value, accum);
512 "derivative for A is nan.");
513 Nuisance(A_).add_to_nuisance_derivative(value, accum);
516 IMP_THROW(
"Invalid particle number", ModelException);
521 unsigned particle_no,
const FloatsList& xlist)
const
523 unsigned N=xlist.size();
524 Eigen::VectorXd ret(N);
529 ret = ((*this)(xlist)
530 -Eigen::VectorXd::Constant(N,A_val_))/G_val_;
533 for (
unsigned i=0; i<N; i++)
535 double qval = xlist[i][0];
536 if (qval <= q1_param_)
539 ret(i) = - (get_value(qval) - A_val_)
540 * 2*IMP::square(qval)*Rg_val_/(3-s_val_);
543 ret(i) = (get_value(qval)-A_val_)
544 * (s_val_-d_val_)/Rg_val_;
549 for (
unsigned i=0; i<N; i++)
551 double qval = xlist[i][0];
552 if (qval <= q1_param_)
558 ret(i) = (get_value(qval)-A_val_)
559 * std::log(q1_param_/qval);
564 for (
unsigned i=0; i<N; i++)
566 double qval = xlist[i][0];
567 if (qval <= q1_param_)
571 ret(i) = - (get_value(qval) - A_val_)
572 * (IMP::square((qval*Rg_val_)
577 ret(i) = - (get_value(qval) - A_val_)
578 * ( (d_val_-s_val_)/(2*(3-s_val_))
579 + std::log(q1_param_) );
584 ret = Eigen::VectorXd::Constant(N,1);
587 IMP_THROW(
"Invalid particle number", ModelException);
595 Eigen::MatrixXd mat(xlist.size(),5);
602 for (
int i=0; i<mat.rows(); i++)
605 for (
int j=0; j<mat.cols(); j++)
606 line.push_back(mat(i,j));
613 unsigned particle_a,
unsigned particle_b,
617 IMP_THROW(
"Invalid particle 1 number", ModelException);
619 IMP_THROW(
"Invalid particle 2 number", ModelException);
620 unsigned N=xlist.size();
622 if (particle_a == 4 || particle_b == 4)
623 return Eigen::VectorXd::Zero(N);
624 unsigned pa = std::min(particle_a,particle_b);
625 unsigned pb = std::max(particle_a,particle_b);
626 Eigen::VectorXd ret(N);
634 ret.noalias() = Eigen::VectorXd::Zero(N);
666 for (
unsigned i=0; i<N; i++)
668 double qval = xlist[i][0];
669 if (qval <= q1_param_)
674 ret(i) = (get_value(qval) - A_val_)
675 * 2*IMP::square(qval)/(3-s_val_)
676 * (2*IMP::square(qval*Rg_val_)/(3-s_val_) -1);
679 ret(i) = (get_value(qval) - A_val_)
680 * (d_val_-s_val_)/IMP::square(Rg_val_)
687 for (
unsigned i=0; i<N; i++)
689 double qval = xlist[i][0];
690 if (qval <= q1_param_)
697 double val=(get_value(qval)-A_val_);
698 ret(i) = -val/Rg_val_
699 - (val*std::log(q1_param_/qval)
700 * (d_val_-s_val_)/Rg_val_);
706 for (
unsigned i=0; i<N; i++)
708 double qval = xlist[i][0];
709 double val=(get_value(qval)-A_val_);
710 if (qval <= q1_param_)
715 * (IMP::square((qval*Rg_val_)
719 -2*IMP::square(qval)*Rg_val_/(3-s_val_)
720 *(deriv + val/(3-s_val_));
725 * ( (d_val_-s_val_)/(2*(3-s_val_))
726 + std::log(q1_param_) );
727 ret(i) = (val - (d_val_-s_val_)*deriv)
744 for (
unsigned i=0; i<N; i++)
746 double qval = xlist[i][0];
747 if (qval <= q1_param_)
754 double val=(get_value(qval)-A_val_);
756 IMP::square(std::log(q1_param_/qval))
757 +1/(2*(d_val_-s_val_)));
764 double lterm=(d_val_-s_val_)/(2*(3-s_val_))
765 + std::log(q1_param_);
766 double rterm=0.5*(1/(3-s_val_) + 1/(d_val_-s_val_));
767 for (
unsigned i=0; i<N; i++)
769 double qval = xlist[i][0];
770 if (qval <= q1_param_)
778 double val=(get_value(qval)-A_val_);
780 std::log(q1_param_/qval)*lterm + rterm);
799 IMP::square( 0.5*(d_val_-s_val_)/(3-s_val_)
800 + std::log(q1_param_) )
801 + 0.5*((6 - s_val_ - d_val_)/IMP::square(3-s_val_)
802 + 1./(d_val_-s_val_));
803 for (
unsigned i=0; i<N; i++)
805 double qval = xlist[i][0];
806 double val=(get_value(qval)-A_val_);
807 if (qval <= q1_param_)
813 IMP::square((qval*Rg_val_)/(3-s_val_));
815 (IMP::square(factor + std::log(qval))
816 - 2*factor/(3-s_val_));
822 ret(i) = val * cterm;
844 unsigned particle_a,
unsigned particle_b,
848 particle_a, particle_b, xlist));
850 for (
int i=0; i<mat.rows(); i++)
853 for (
int j=0; j<mat.cols(); j++)
854 line.push_back(mat(i,j));
870 return Scale(G_).get_scale_is_optimized();
872 return Scale(Rg_).get_scale_is_optimized();
874 return Scale(d_).get_scale_is_optimized();
876 return Scale(s_).get_scale_is_optimized();
878 return Nuisance(A_).get_nuisance_is_optimized();
880 IMP_THROW(
"Invalid particle number", ModelException);
887 if (
Scale(G_).get_scale_is_optimized()) count++;
888 if (
Scale(Rg_).get_scale_is_optimized()) count++;
889 if (
Scale(d_).get_scale_is_optimized()) count++;
890 if (
Scale(s_).get_scale_is_optimized()) count++;
891 if (
Nuisance(A_).get_nuisance_is_optimized()) count++;
924 inline double get_value(
double q)
const
929 value = A_val_ + G_val_/std::pow(q,s_val_)
930 * std::exp(- IMP::square(q*Rg_val_)/(3-s_val_));
932 value = A_val_ + D_param_/std::pow(q,d_val_);
937 base::Pointer<kernel::Particle> G_,Rg_,d_,s_,A_;
938 double G_val_,Rg_val_,d_val_,s_val_,A_val_,q1_param_,D_param_;
bool has_changed() const
return true if internal parameters have changed.
Eigen::VectorXd get_derivative_vector(unsigned particle_no, const FloatsList &xlist) const
return derivative vector
Base class for functions of one variable.
virtual Eigen::VectorXd get_second_derivative_vector(unsigned particle_a, unsigned particle_b, const FloatsList &xlist) const =0
return second derivative vector
Class for adding derivatives from restraints to the model.
Floats operator()(const Floats &x) const
evaluate the function at a certain point
Eigen::VectorXd get_second_derivative_vector(unsigned particle_a, unsigned particle_b, const FloatsList &xlist) const
return second derivative vector
FloatsList get_second_derivative_vector(unsigned particle_a, unsigned particle_b, const FloatsList &xlist, bool) const
for testing purposes
FloatsList operator()(const FloatsList &xlist, bool) const
used for testing only
unsigned get_ndims_y() const
returns the number of output dimensions
unsigned get_ndims_x() const
returns the number of input dimensions
A decorator for switching parameters particles.
A decorator for scale parameters particles.
#define IMP_REF_COUNTED_DESTRUCTOR(Name)
Ref counted objects should have private destructors.
A smart pointer to a reference counted object.
ParticlesTemp get_input_particles(const ModelObjectsTemp &mos)
A decorator for nuisance parameters particles.
void add_to_derivatives(const Floats &x, DerivativeAccumulator &accum) const
update derivatives of particles
Add scale parameter to particle.
bool get_particle_is_optimized(unsigned particle_no) const
returns true if the particle whose index is provided is optimized
1D mean function for SAS data
unsigned get_number_of_particles() const
returns the number of particles that this function uses
static Scale decorate_particle(::IMP::kernel::Particle *p)
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
void add_to_particle_derivative(unsigned particle_no, double value, DerivativeAccumulator &accum) const
update derivatives of particles
Eigen::VectorXd get_second_derivative_vector(unsigned, unsigned, const FloatsList &xlist) const
return second derivative vector
#define IMP_LOG_TERSE(expr)
Linear one-dimensional function.
virtual Eigen::VectorXd get_derivative_vector(unsigned particle_no, const FloatsList &xlist) const =0
return derivative vector
FloatsList get_derivative_matrix(const FloatsList &xlist, bool) const
for testing purposes
ContainersTemp get_input_containers(const ModelObjectsTemp &mos)
unsigned get_number_of_particles() const
returns the number of particles that this function uses
void add_to_particle_derivative(unsigned particle_no, double value, DerivativeAccumulator &accum) const
update derivatives of particles
FloatsList get_second_derivative_vector(unsigned particle_a, unsigned particle_b, const FloatsList &xlist, bool) const
for testing purposes
#define IMP_INTERNAL_CHECK(expr, message)
An assertion to check for internal errors in IMP. An IMP::ErrorException will be thrown.
Add nuisance parameter to particle.
IMP::base::Vector< IMP::base::WeakPointer< Container > > ContainersTemp
Eigen::VectorXd get_derivative_vector(unsigned particle_no, const FloatsList &xlist) const
return derivative vector
bool get_particle_is_optimized(unsigned particle_no) const
returns true if the particle whose index is provided is optimized
static Nuisance decorate_particle(::IMP::kernel::Particle *p)
void update()
update internal parameters
#define IMP_IF_CHECK(level)
Execute the code block if a certain level checks are on.
unsigned get_number_of_optimized_particles() const
returns the number of particles that are optimized
#define IMP_OBJECT_METHODS(Name)
Define the basic things needed by any Object.
unsigned get_number_of_optimized_particles() const
returns the number of particles that are optimized
Class to handle individual model particles.
FloatsList operator()(const FloatsList &xlist, bool) const
used for testing only
Common base class for heavy weight IMP objects.
Classes to handle individual model particles.
Floats operator()(const Floats &x) const
evaluate the function at a certain point
kernel::ParticlesTemp get_input_particles() const
particle manipulation
void add_to_derivatives(const Floats &x, DerivativeAccumulator &accum) const
update derivatives of particles
virtual void update()=0
update internal parameters
bool isnan(const T &a)
Return true if a number is NaN.
#define IMP_THROW(message, exception_name)
Throw an exception with a message.
Eigen::VectorXd operator()(const FloatsList &xlist) const
evaluate the function at a list of points
unsigned get_ndims_y() const
returns the number of output dimensions
A shared base class to help in debugging and things.
bool has_changed() const
return true if internal parameters have changed.
unsigned get_ndims_x() const
returns the number of input dimensions
FloatsList get_derivative_matrix(const FloatsList &xlist, bool) const
for testing purposes
Eigen::VectorXd operator()(const FloatsList &xlist) const
evaluate the function at a list of points
kernel::ParticlesTemp get_input_particles() const
particle manipulation
void update()
update internal parameters