12 #ifndef IMPSAXS_WEIGHTED_PROFILE_FITTER_H
13 #define IMPSAXS_WEIGHTED_PROFILE_FITTER_H
19 #include <Eigen/Dense>
21 IMPSAXS_BEGIN_NAMESPACE
27 template <
typename ScoringFunctionT = ChiScore>
37 W_(exp_profile->size(), 1),
38 Wb_(exp_profile->size()),
39 A_(exp_profile->size(), 2) {
41 Eigen::VectorXf b(exp_profile->
size());
42 for (
unsigned int i = 0; i < exp_profile->
size(); i++) {
43 Wb_(i) = exp_profile->get_intensity(i);
44 W_(i) = 1.0 / (exp_profile->get_error(i));
46 Wb_ = W_.asDiagonal() * Wb_;
52 %typemap(in, numinputs=0)
Vector<
double>& weights (
Vector<
double> temp) {
55 %typemap(argout)
Vector<
double>& weights {
56 PyObject *obj = ConvertSequence<Vector<double>, Convert<double>>::create_python_object(ValueOrObject<
Vector<double>>::
get(*$1), $descriptor(
double*), SWIG_POINTER_OWN);
57 $result = SWIG_AppendOutput($result, obj);
68 double compute_score(
const ProfilesTemp& profiles, Vector<double>& weights,
69 bool use_offset =
false,
bool NNLS =
true)
const;
72 %clear Vector<double>& weights;
80 WeightedFitParameters fit_profile(
ProfilesTemp partial_profiles,
81 double min_c1 = 0.95,
double max_c1 = 1.05,
82 double min_c2 = -2.0,
double max_c2 = 4.0,
83 bool use_offset =
false)
const;
87 const WeightedFitParameters& fp,
88 const std::string fit_file_name,
89 bool use_offset =
false)
const;
92 WeightedFitParameters search_fit_parameters(
93 ProfilesTemp& partial_profiles,
double min_c1,
double max_c1,
double min_c2,
94 double max_c2,
double old_chi, Vector<double>& weights,
bool use_offset)
const;
106 template <
typename ScoringFunctionT>
110 bool use_offset,
bool nnls)
const {
113 if (profiles.size() == 1) {
118 profiles[0], use_offset);
122 int m = profiles.size();
129 if (A_.cols() != m) non_const_this->A_.resize(n, m);
130 for (
int j = 0; j < m; j++) {
131 for (
int i = 0; i < n; i++) {
132 (non_const_this->A_)(i, j) = profiles[j]->get_intensity(i);
138 Eigen::JacobiSVD<Eigen::MatrixXf> svd(W_.asDiagonal() * A_,
140 | Eigen::ComputeThinV);
143 for (
int i = 0; i < w.size(); i++)
144 if (w(i) < 0) w(i) = 0;
146 w =
NNLS(W_.asDiagonal() * A_, Wb_);
155 Eigen::VectorXf wp = A_ * w;
156 weighted_profile->set_qs(profiles[0]->get_qs());
157 weighted_profile->set_intensities(wp);
158 weights.resize(w.size());
159 for (
int i = 0; i < w.size(); i++) weights[i] = w[i];
163 weighted_profile, use_offset);
166 template <
typename ScoringFunctionT>
169 double min_c1,
double max_c1,
170 double min_c2,
double max_c2,
171 bool use_offset)
const {
174 search_fit_parameters(partial_profiles, min_c1, max_c1, min_c2, max_c2,
175 std::numeric_limits<double>::max(), weights, use_offset);
179 template <
typename ScoringFunctionT>
183 const std::string fit_file_name,
184 bool use_offset)
const {
185 double best_c1 = fp.get_c1();
186 double best_c2 = fp.get_c2();
189 for (
unsigned int i = 0; i < partial_profiles.size(); i++)
190 partial_profiles[i]->sum_partial_profiles(best_c1, best_c2);
192 if (partial_profiles.size() == 1) {
199 partial_profiles[0]);
204 partial_profiles[0], offset);
206 fit_file_name, partial_profiles[0], fp.get_chi_square(), c, offset);
216 for (
unsigned int i = 0; i < weights.size(); i++)
217 weighted_profile->add(partial_profiles[i], weights[i]);
229 weighted_profile, offset);
232 fit_file_name, weighted_profile,
233 fp.get_chi_square(), c, offset);
237 template <
typename ScoringFunctionT>
240 double min_c1,
double max_c1,
241 double min_c2,
double max_c2,
243 bool use_offset)
const {
246 if (old_chi < (std::numeric_limits<double>::max() - 1)) {
251 double delta_c1 = (max_c1 - min_c1) / c1_cells;
252 double delta_c2 = (max_c2 - min_c2) / c2_cells;
254 bool last_c1 =
false;
255 bool last_c2 =
false;
256 if (delta_c1 < 0.0001) {
258 delta_c1 = max_c1 - min_c1;
261 if (delta_c2 < 0.001) {
263 delta_c2 = max_c2 - min_c2;
266 double best_c1(1.0), best_c2(0.0), best_chi(old_chi);
267 bool best_set =
false;
271 for (
int i = 0; i <= c1_cells; i++, c1 += delta_c1) {
274 for (
int j = 0; j <= c2_cells; j++, c2 += delta_c2) {
276 for (
unsigned int k = 0; k < partial_profiles.size(); k++)
277 partial_profiles[k]->sum_partial_profiles(c1, c2);
278 Vector<double> curr_weights;
279 double curr_chi = compute_score(partial_profiles, curr_weights, use_offset);
280 if (!best_set || curr_chi < best_chi) {
285 weights = curr_weights;
290 if (std::fabs(best_chi - old_chi) > 0.005 &&
291 (!(last_c1 && last_c2))) {
292 min_c1 = std::max(best_c1 - delta_c1, min_c1);
293 max_c1 = std::min(best_c1 + delta_c1, max_c1);
294 min_c2 = std::max(best_c2 - delta_c2, min_c2);
295 max_c2 = std::min(best_c2 + delta_c2, max_c2);
296 return search_fit_parameters(partial_profiles, min_c1, max_c1, min_c2,
297 max_c2, best_chi, weights, use_offset);
299 return WeightedFitParameters(best_chi, best_c1, best_c2, weights);
302 IMPSAXS_END_NAMESPACE
unsigned int size() const
return number of entries in SAXS profile
Basic chi score implementation.
WeightedProfileFitter(const Profile *exp_profile)
Constructor.
Eigen::VectorXf NNLS(const Eigen::MatrixXf &A, const Eigen::VectorXf &b)
non-negative least square fitting for profile weight solving problem
a class for fitting two profiles
A more IMP-like version of the std::vector.
#define IMP_NEW(Typename, varname, args)
Declare a ref counted pointer to a new object.
Fitting of multiple profiles to the experimental one.
IMP::Vector< IMP::WeakPointer< Profile > > ProfilesTemp
double compute_offset(const Profile *model_profile) const
computes offset for fitting for fitting the modeled profile
Parameters of a weighted fit, from WeightedProfileFitter.
Fit two profiles with user-defined scoring function as a template parameter.
double compute_score(const Profile *model_profile, bool use_offset=false, const std::string fit_file_name="") const
compute fit score
double compute_scale_factor(const Profile *model_profile, double offset=0.0) const
computes the scaling factor needed for fitting the modeled profile