5#ifndef GEMMI_SCALING_HPP_
6#define GEMMI_SCALING_HPP_
16using Vec6 = std::array<double, 6>;
19 return a[0] * s.u11 + a[1] * s.u22 + a[2] * s.u33
20 + a[3] * s.u12 + a[4] * s.u13 + a[5] * s.u23;
28 auto constraints = [](
const std::initializer_list<int>&
l) {
29 constexpr double K2 = 0.70710678118654752440;
30 constexpr double K3 = 0.57735026918962576451;
31 static const Vec6 vv[10] = {
39 {2/3., 2/3., 0, 1/3., 0, 0},
55 return constraints({0, 1, 2, 3 +
'c' -
sg->monoclinic_unique_axis()});
71template<
typename Real>
114 fail(
"scale_data(): mask data not prepared");
120 fail(
"scale_data(): data arrays don't match");
139 std::vector<double>
ret;
162 b_star = {0, 0, 0, 0, 0, 0};
183 fail(
"prepare_points(): mask data not prepared");
184 std::complex<Real> fmask;
186 auto c =
calc.v.begin();
188 if (c->hkl !=
o.
hkl) {
191 if (c ==
calc.v.end())
200 fail(
"prepare_points(): unexpected data");
204 if (!std::isnan(
o.
value.value) && !std::isnan(
o.
value.sigma))
207 if (c ==
calc.v.end())
232 if (
p.fobs < 1 ||
p.fobs <
p.sigma)
236 double y = std::log(
static_cast<float>(
p.fobs /
fcalc));
246 double intercept = (
sy - slope *
sx) / n;
247 double b_iso = -slope;
256 if (
p.fobs < 1 ||
p.fobs <
p.sigma)
281 double V[6] = {
h.x *
h.x,
h.y *
h.y,
h.z *
h.z,
282 2 *
h.x *
h.y, 2 *
h.x *
h.z, 2 *
h.y *
h.z};
285 for (
size_t i = 0;
i < 6; ++
i) {
286 for (
size_t j = 0;
j < 6; ++
j)
343 -0.25 * y * (
h.x *
h.x),
344 -0.25 * y * (
h.y *
h.y),
345 -0.25 * y * (
h.z *
h.z),
346 -0.5 * y * (
h.x *
h.y),
347 -0.5 * y * (
h.x *
h.z),
348 -0.5 * y * (
h.y *
h.z),
360template<
typename Real>
361double calculate_for_nlopt(
unsigned n,
const double* x,
double* grad,
void* data) {
362 auto scaling =
static_cast<Scaling<Real>*
>(data);
363 scaling->set_parameters(x);
370inline const char* nlresult_to_string(nlopt_result r) {
372 case NLOPT_FAILURE:
return "failure";
373 case NLOPT_INVALID_ARGS:
return "invalid arguments";
374 case NLOPT_OUT_OF_MEMORY:
return "out of memory";
375 case NLOPT_ROUNDOFF_LIMITED:
return "roundoff errors limit progress";
376 case NLOPT_FORCED_STOP:
return "interrupted";
377 case NLOPT_SUCCESS:
return "success";
378 case NLOPT_STOPVAL_REACHED:
return "stop-value reached";
379 case NLOPT_FTOL_REACHED:
return "ftol-value reached";
380 case NLOPT_XTOL_REACHED:
return "xtol-value reached";
381 case NLOPT_MAXEVAL_REACHED:
return "max. evaluation number reached";
382 case NLOPT_MAXTIME_REACHED:
return "max. time reached";
383 default:
return "<unknown result>";
390template<
typename Real>
391double fit_parameters_with_nlopt(Scaling<Real>& scaling,
const char* optimizer) {
392 std::vector<double> params = scaling.get_parameters();
393 nlopt_opt opt = nlopt_create(nlopt_algorithm_from_string(optimizer), params.size());
395 std::vector<double> lb(params.size());
396 std::vector<double> ub(params.size());
397 lb[0] = 0.7 * params[0];
398 ub[0] = 1.2 * params[0];
400 if (scaling.use_solvent) {
401 if (!scaling.fix_k_sol) {
406 if (!scaling.fix_b_sol) {
412 for (; n < params.size(); ++n) {
416 nlopt_set_lower_bounds(opt, lb.data());
417 nlopt_set_upper_bounds(opt, ub.data());
419 nlopt_set_min_objective(opt, impl::calculate_for_nlopt<Real>, &scaling);
420 nlopt_set_maxeval(opt, 100);
422 nlopt_result r = nlopt_optimize(opt, ¶ms[0], &minf);
429 scaling.set_parameters(params);
AsuData for storing reflection data.
Least-squares fitting - Levenberg-Marquardt method.
double vec6_dot(const Vec6 &a, const SMat33< double > &s)
double compute_gradients(const Target &target, unsigned n, double *grad)
std::array< double, 6 > Vec6
std::array< int, 3 > Miller
A synonym for convenient passing of hkl.
double compute_wssr(const Target &target)
std::vector< Vec6 > adp_symmetry_constraints(const SpaceGroup *sg)
Symmetry constraints of ADP.
void fail(const std::string &msg)
void jordan_solve(double *a, double *b, int n)
This function solves a set of linear algebraic equations using Gauss-Jordan elimination with partial ...
SMat33< Real > transformed_by(const Mat33 &m) const
auto r_u_r(const Vec3_< VT > &r) const -> decltype(r.x+u11)
std::complex< Real > fmask
double get_weight() const
std::complex< Real > fcmol
double compute_value_and_derivatives(const Point &p, std::vector< double > &dy_da) const
Scaling(const UnitCell &cell_, const SpaceGroup *sg)
void set_b_overall(const SMat33< double > &b_overall)
void set_parameters(const double *p)
set k_overall, k_sol, b_sol, b_star
void fit_isotropic_b_approximately()
double get_overall_scale_factor(const Miller &hkl) const
SMat33< double > get_b_overall() const
std::complex< Real > get_fcalc(const Point &p) const
double calculate_r_factor() const
std::complex< Real > scale_value(const Miller &hkl, std::complex< Real > f_value, std::complex< Real > mask_value)
void scale_data(AsuData< std::complex< Real > > &asu_data, const AsuData< std::complex< Real > > *mask_data) const
void fit_b_star_approximately()
double compute_value(const Point &p) const
std::vector< double > get_parameters() const
double lsq_k_overall() const
void prepare_points(const AsuData< std::complex< Real > > &calc, const AsuData< ValueSigma< Real > > &obs, const AsuData< std::complex< Real > > *mask_data)
std::vector< Vec6 > constraint_matrix
double get_solvent_scale(double stol2) const
std::vector< Point > points
void set_parameters(const std::vector< double > &p)
double calculate_stol_sq(const Miller &hkl) const
Calculate (sin(theta)/lambda)^2 = d*^2/4.