LSST Applications g1653933729+34a971ddd9,g1a997c3884+34a971ddd9,g2160c40384+da0d0eec6b,g28da252d5a+1236b942f7,g2bbee38e9b+e5a1bc5b38,g2bc492864f+e5a1bc5b38,g2ca4be77d2+192fe503f0,g2cdde0e794+704103fe75,g3156d2b45e+6e87dc994a,g347aa1857d+e5a1bc5b38,g35bb328faa+34a971ddd9,g3a166c0a6a+e5a1bc5b38,g3e281a1b8c+8ec26ec694,g4005a62e65+ba0306790b,g414038480c+9f5be647b3,g41af890bb2+c3a10c924f,g5065538af8+e7237db731,g5a0bb5165c+eae055db26,g717e5f8c0f+b65b5c3ae4,g80478fca09+4ce5a07937,g82479be7b0+08790af60f,g858d7b2824+b65b5c3ae4,g9125e01d80+34a971ddd9,ga5288a1d22+5df949a35e,gae0086650b+34a971ddd9,gb58c049af0+ace264a4f2,gbd397ab92a+2141afb137,gc28159a63d+e5a1bc5b38,gc805d3fbd4+b65b5c3ae4,gcf0d15dbbd+97632ccc20,gd6b7c0dfd1+de826e8718,gda6a2b7d83+97632ccc20,gdaeeff99f8+7774323b41,ge2409df99d+e6cadbf968,ge33fd446bb+b65b5c3ae4,ge79ae78c31+e5a1bc5b38,gf0baf85859+890af219f9,gf5289d68f6+a27069ed62,w.2024.37
LSST Data Management Base Package
Loading...
Searching...
No Matches
shapeprior.cc
Go to the documentation of this file.
1/*
2 * This file is part of gauss2d_fit.
3 *
4 * Developed for the LSST Data Management System.
5 * This product includes software developed by the LSST Project
6 * (https://www.lsst.org).
7 * See the COPYRIGHT file at the top-level directory of this distribution
8 * for details of code ownership.
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24#include <cmath>
25#include <string>
26
30
33
34namespace lsst::gauss2d::fit {
35ShapePriorOptions::ShapePriorOptions(double delta_jacobian, double size_maj_floor, double axrat_floor)
36 : _delta_jacobian(delta_jacobian), _size_maj_floor(size_maj_floor), _axrat_floor(axrat_floor) {
37 this->check_delta_jacobian(_delta_jacobian, true);
38 this->check_size_maj_floor(_size_maj_floor, true);
39 this->check_axrat_floor(_axrat_floor, true);
40}
41
42bool ShapePriorOptions::check_delta_jacobian(double delta_jacobian, bool do_throw) {
43 if (!std::isfinite(delta_jacobian)) {
44 if (do_throw) {
45 throw std::invalid_argument("delta_jacobian=" + std::to_string(delta_jacobian)
46 + " must be finite");
47 }
48 return false;
49 }
50 return true;
51}
52
53bool ShapePriorOptions::check_size_maj_floor(double size_maj_floor, bool do_throw) {
54 if (!(std::isfinite(size_maj_floor) && (size_maj_floor > 0))) {
55 if (do_throw) {
56 throw std::invalid_argument("size_maj_floor=" + std::to_string(size_maj_floor)
57 + " must be >0 and finite");
58 }
59 return false;
60 }
61 return true;
62}
63
64bool ShapePriorOptions::check_axrat_floor(double axrat_floor, bool do_throw) {
65 if (!(std::isfinite(axrat_floor) && (axrat_floor > 0))) {
66 if (do_throw) {
67 throw std::invalid_argument("axrat_floor=" + std::to_string(axrat_floor)
68 + " must be >0 and finite");
69 }
70 return false;
71 }
72 return true;
73}
74
75double ShapePriorOptions::get_delta_jacobian() const { return _delta_jacobian; }
76
77double ShapePriorOptions::get_size_maj_floor() const { return _size_maj_floor; }
78
79double ShapePriorOptions::get_axrat_floor() const { return _axrat_floor; }
80
81void ShapePriorOptions::set_delta_jacobian(double delta_jacobian) {
82 check_delta_jacobian(delta_jacobian, true);
83 _delta_jacobian = delta_jacobian;
84}
85
86void ShapePriorOptions::set_size_maj_floor(double size_maj_floor) {
87 check_size_maj_floor(size_maj_floor, true);
88 this->_size_maj_floor = size_maj_floor;
89}
90
91void ShapePriorOptions::set_axrat_floor(double axrat_floor) {
92 check_axrat_floor(axrat_floor, true);
93 this->_axrat_floor = axrat_floor;
94}
95
96std::string ShapePriorOptions::repr(bool name_keywords, std::string_view namespace_separator) const {
97 return type_name_str<ShapePriorOptions>(false, namespace_separator) + "("
98 + (name_keywords ? "delta_jacobian=" : "") + to_string_float(_delta_jacobian) + ", "
99 + (name_keywords ? "size_maj_floor=" : "") + to_string_float(_size_maj_floor) + ", "
100 + (name_keywords ? "axrat_floor=" : "") + to_string_float(_axrat_floor) + ")";
101}
102
104 return type_name_str<ShapePriorOptions>(true) + "(delta_jacobian=" + to_string_float(_delta_jacobian)
105 + ", size_maj_floor=" + to_string_float(_size_maj_floor)
106 + ", axrat_floor=" + to_string_float(_axrat_floor) + ")";
107}
108
113 : _ellipse(std::move(ellipse)),
114 _prior_size(std::move(prior_size)),
115 _prior_axrat(std::move(prior_axrat)),
116 _options(std::move((options == nullptr) ? std::make_shared<ShapePriorOptions>() : options)) {
117 if (_ellipse == nullptr) throw std::invalid_argument("ellipse param must not be null");
118 double loglike = this->evaluate().loglike;
119 if (!std::isfinite(loglike)) {
120 throw std::invalid_argument(this->str() + " has non-finite loglike=" + std::to_string(loglike)
121 + " on init");
122 }
123}
124
126
127PriorEvaluation ShapePrior::evaluate(bool calc_jacobians, bool normalize) const {
128 const auto ellipse = lsst::gauss2d::Ellipse(this->_ellipse->get_size_x(), this->_ellipse->get_size_y(),
129 this->_ellipse->get_rho());
130 const auto ellipse_major = lsst::gauss2d::EllipseMajor(ellipse);
131
132 double size_maj = ellipse_major.get_r_major();
133 double axrat = size_maj == 0 ? 0 : ellipse_major.get_axrat();
134
135 if (!(axrat >= 0)) {
136 throw std::runtime_error(this->str() + " got invalid axrat=" + std::to_string(axrat));
137 }
138
139 auto result = PriorEvaluation(0, {}, {}, false);
140
141 if (this->_prior_size != nullptr) {
142 double size_maj_floor = this->_options->get_size_maj_floor();
143 size_maj = sqrt(size_maj * size_maj * axrat + size_maj_floor * size_maj_floor);
144 size_maj = _prior_size->get_mean_parameter().get_transform().forward(size_maj);
145 double sigma = _prior_size->get_stddev();
146 double residual = (size_maj - _prior_size->get_mean_parameter().get_value_transformed()) / sigma;
147 if (!std::isfinite(residual)) {
148 throw std::runtime_error(this->str() + ".evaluate() got non-finite size residual="
149 + std::to_string(residual) + " from size_maj=" + std::to_string(size_maj)
150 + ", _prior_size=" + _prior_size->str());
151 }
152 result.residuals.emplace_back(residual);
153 result.loglike += normalize ? logpdf_norm(residual, 1.0) : -residual * residual / 2.;
154 }
155
156 if (this->_prior_axrat != nullptr) {
157 double axrat_floor = this->_options->get_axrat_floor();
158 axrat = sqrt(axrat_floor * axrat_floor + axrat * axrat);
159 if (axrat > 1) {
160 axrat = 1;
161 } else if (!(axrat >= 0)) {
162 throw std::runtime_error(this->str() + " got invalid axrat=" + std::to_string(axrat)
163 + " from axrat_floor=" + std::to_string(axrat_floor));
164 }
165 const auto& transform_param = _prior_axrat->get_mean_parameter().get_transform();
166 axrat = transform_param.forward(axrat);
167 double sigma = _prior_axrat->get_stddev();
168 double residual = (axrat - _prior_axrat->get_mean_parameter().get_value_transformed()) / sigma;
169 if (!std::isfinite(residual)) {
170 auto str = this->str();
171 throw std::runtime_error(str + ".evaluate() got non-finite axrat residual="
172 + std::to_string(residual) + " from axrat=" + std::to_string(axrat)
173 + ", _prior_axrat=" + _prior_axrat->str());
174 }
175 // RuntimeError('Infinite axis ratio prior residual from q={axrat} and mean, std, f
176 // 'logit stretch divisor = {self.axrat_params}')
177 result.residuals.emplace_back(residual);
178 result.loglike += normalize ? logpdf_norm(residual, 1.0) : -residual * residual / 2.;
179 }
180
181 if (calc_jacobians) {
182 ParamRefs params = nonconsecutive_unique(_ellipse->get_parameters_new());
183 for (auto& paramref : params) {
184 auto& param = paramref.get();
185 double value_init = param.get_value();
186 double value_trans = param.get_value_transformed();
187 double delta = finite_difference_param(param, _options->get_delta_jacobian());
188 double value_new = param.get_value_transformed();
189
190 std::vector<double> residuals_old;
191 std::vector<double> residuals_new;
192 try {
193 param.set_value_transformed(value_trans + delta / 2.);
194 residuals_new = this->evaluate(false, normalize).residuals;
195 param.set_value_transformed(value_trans - delta / 2.);
196 residuals_old = this->evaluate(false, normalize).residuals;
197 } catch (std::exception& e) {
198 param.set_value_transformed(value_new);
199 residuals_new = this->evaluate(false, normalize).residuals;
200 residuals_old = result.residuals;
201 }
202 // Return to the old value
203 param.set_value(value_init);
204 value_new = param.get_value();
205 if (value_new != value_init) {
206 throw std::runtime_error(this->str() + " could not return " + param.str()
207 + " to original value=" + to_string_float(value_init) + " (stuck at "
208 + to_string_float(value_new) + "); check limits");
209 }
210 std::vector<double> jacobians(result.residuals.size());
211 for (size_t idx = 0; idx < result.residuals.size(); ++idx) {
212 jacobians[idx] = (residuals_new[idx] - residuals_old[idx]) / delta;
213 }
214 result.jacobians[paramref] = jacobians;
215 }
216 }
217
218 return result;
219}
220
222
224
226 return {this->_prior_size == nullptr ? 0 : (LOG_1 - log(this->_prior_size->get_stddev() * SQRT_2_PI)),
227 this->_prior_axrat == nullptr ? 0 : (LOG_1 - log(this->_prior_axrat->get_stddev() * SQRT_2_PI))};
228}
229
231 _prior_size = prior_size;
232}
233
235 _prior_axrat = prior_axrat;
236}
237
238size_t ShapePrior::size() const { return (this->_prior_size != nullptr) + (this->_prior_axrat != nullptr); };
239
240std::string ShapePrior::repr(bool name_keywords, std::string_view namespace_separator) const {
241 return type_name_str<ShapePrior>(false, namespace_separator) + "(" + (name_keywords ? "ellipse=" : "")
242 + _ellipse->repr(name_keywords, namespace_separator) + ", " + (name_keywords ? "prior_size=" : "")
243 + repr_ptr(_prior_size.get(), name_keywords, namespace_separator) + ", "
244 + (name_keywords ? "prior_axrat=" : "")
245 + repr_ptr(_prior_axrat.get(), name_keywords, namespace_separator) + ", "
246 + (name_keywords ? "options=" : "") + _options->repr(name_keywords, namespace_separator) + ")";
247}
248
250 return type_name_str<ShapePrior>(true) + "(ellipse=" + _ellipse->str()
251 + ", prior_size=" + str_ptr(_prior_size.get()) + ", prior_axrat=" + str_ptr(_prior_axrat.get())
252 + ", options=" + _options->str() + ")";
253}
254
255} // namespace lsst::gauss2d::fit
py::object result
Definition _schema.cc:429
afw::table::Key< double > sigma
An Ellipse with sigma_x, sigma_y, and rho values.
Definition ellipse.h:283
An Ellipse with r_major, axrat and angle values.
Definition ellipse.h:337
Results from the evaluation of a prior probability function.
Definition prior.h:16
std::vector< double > residuals
Definition prior.h:21
std::string repr(bool name_keywords=false, std::string_view namespace_separator=Object::CC_NAMESPACE_SEPARATOR) const override
Return a full, callable string representation of this.
size_t size() const override
PriorEvaluation evaluate(bool calc_jacobians=false, bool normalize_loglike=false) const override
Evaluate the log likelihood and residual-dependent terms.
std::string str() const override
Return a brief, human-readable string representation of this.
std::shared_ptr< ParametricGaussian1D > get_prior_axrat() const
ShapePrior(std::shared_ptr< const ParametricEllipse > ellipse, std::shared_ptr< ParametricGaussian1D > prior_size=nullptr, std::shared_ptr< ParametricGaussian1D > prior_axrat=nullptr, std::shared_ptr< ShapePriorOptions > options=nullptr)
Construct a ShapePrior from a Parameter and mean_size/std.
void set_prior_size(std::shared_ptr< ParametricGaussian1D > prior_size)
std::shared_ptr< ParametricGaussian1D > get_prior_size() const
std::vector< double > get_loglike_const_terms() const override
Return the constant terms of the log likelihood (dependent on stddevs only)
void set_prior_axrat(std::shared_ptr< ParametricGaussian1D > prior_axrat)
Options for a ShapePrior.
Definition shapeprior.h:18
void set_size_maj_floor(double size_maj_floor)
Definition shapeprior.cc:86
bool check_axrat_floor(double axrat_floor, bool do_throw=false)
Definition shapeprior.cc:64
bool check_size_maj_floor(double size_maj_floor, bool do_throw=false)
Definition shapeprior.cc:53
std::string str() const override
Return a brief, human-readable string representation of this.
void set_delta_jacobian(double delta_jacobian)
Definition shapeprior.cc:81
void set_axrat_floor(double axrat_floor)
Definition shapeprior.cc:91
ShapePriorOptions(double delta_jacobian=delta_jacobian_default, double size_maj_floor=size_maj_floor_default, double axrat_floor=axrat_floor_default)
Construct a ShapePriorOptions from values.
Definition shapeprior.cc:35
bool check_delta_jacobian(double delta_jacobian, bool do_throw=false)
Definition shapeprior.cc:42
std::string repr(bool name_keywords=false, std::string_view namespace_separator=Object::CC_NAMESPACE_SEPARATOR) const override
Return a full, callable string representation of this.
Definition shapeprior.cc:96
T isfinite(T... args)
const double LOG_1
Definition math.h:8
double finite_difference_param(ParamBase &param, double delta)
Definition param_defs.cc:6
const double SQRT_2_PI
Definition math.h:9
double logpdf_norm(T residual, T sigma)
Definition math.h:18
@ loglike
Compute the log likelihood only.
std::vector< T > nonconsecutive_unique(const std::vector< T > &vec)
Definition util.h:92
std::string str_ptr(T ptr)
Definition object.h:132
std::string repr_ptr(T ptr, bool name_keywords, std::string_view namespace_separator)
Definition object.h:82
std::string to_string_float(const T value, const int precision=6, const bool scientific=true)
Definition to_string.h:15
STL namespace.
T to_string(T... args)