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
fractionalintegralmodel.cc
Go to the documentation of this file.
1#include <functional>
2#include <memory>
3#include <stdexcept>
4#include <vector>
5
8
15#include "lsst/gauss2d/fit/parameters.h"
17
18namespace lsst::gauss2d::fit {
19
21 std::shared_ptr<const IntegralModel> model, bool is_final)
22 : _model(std::move(model)), _parent(_find_parent(_model)), _is_final(is_final) {
23 if (_model == nullptr) throw std::invalid_argument("FractionalIntegralModel model can't be null");
24
25 const auto found = find_model(*_model);
26 if (found != nullptr) {
27 throw std::invalid_argument("FractionalIntegralModel model=" + _model->str()
28 + " already referenced by " + found->str());
29 }
30 if (data) {
31 size_t idx = 0;
32 for (const auto &datum : *data) {
33 const auto &channel = datum.first;
34 const auto &param = datum.second;
35 if (param == nullptr) {
36 throw std::runtime_error("FractionalIntegralModel data[" + channel.get().str()
37 + "] can't be null");
38 } else if (_is_final) {
39 bool is_fixed = param->get_fixed();
40 bool is_one = param->get_value() == 1;
41 std::string errmsg = "";
42 if (!is_fixed) errmsg += " is_fixed != true;";
43 if (!is_one) errmsg += " get_value()=" + std::to_string(param->get_value()) + "!=1;";
44 if (errmsg.size() > 0) {
45 throw std::invalid_argument("FractionalIntegralModel data[" + std::to_string(idx)
46 + "] is_final==true but param for " + channel.get().str()
47 + errmsg);
48 }
49 }
50 if (_map.find(channel) != _map.end()) {
51 throw std::runtime_error("FractionalIntegralModel data[" + std::to_string(idx)
52 + "] channel=" + channel.get().str() + " duplicated");
53 }
54 _data.emplace_back(datum.first, datum.second);
55 _map.insert(_data.back());
56 idx++;
57 }
58 } else {
59 auto param = std::make_shared<ProperFractionParameterD>();
60 param->set_fixed(_is_final);
61 _data.emplace_back(Channel::NONE(), param);
62 _map.insert(_data.back());
63 }
64 auto data_keys = this->get_channels();
65 auto model_keys = _model.get()->get_channels();
66 if (data_keys != model_keys) {
67 throw std::invalid_argument("FractionalIntegralModel data channels=" + str_iter_ref<true>(data_keys)
68 + " != model.get_channels()=" + str_iter_ref<true>(model_keys));
69 }
70}
71FractionalIntegralModel::~FractionalIntegralModel() {};
72
73std::shared_ptr<ProperFractionParameterD> FractionalIntegralModel::at(const Channel &channel) {
74 return _map.at(channel);
75}
76std::shared_ptr<const ProperFractionParameterD> FractionalIntegralModel::at(const Channel &channel) const {
77 return _map.at(channel);
78}
79
80// https://stackoverflow.com/questions/8147027/
81// how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const/
82// 8147213#comment58654091_25069711
84 template <typename... Args>
85 Shared_enabler(Args &&...args) : FractionalIntegralModel(std::forward<Args>(args)...) {}
86};
87
88typename FractionalIntegralModel::Data::iterator FractionalIntegralModel::begin() noexcept {
89 return _data.begin();
90}
91typename FractionalIntegralModel::Data::const_iterator FractionalIntegralModel::cbegin() const noexcept {
92 return _data.begin();
93}
94
95typename FractionalIntegralModel::Data::iterator FractionalIntegralModel::end() noexcept {
96 return _data.end();
97}
98typename FractionalIntegralModel::Data::const_iterator FractionalIntegralModel::cend() const noexcept {
99 return _data.cend();
100}
101
102std::vector<std::reference_wrapper<const Channel>> FractionalIntegralModel::get_channels() const {
104 for (auto &datum : _data) rval.emplace_back(datum.first);
105 return rval;
106}
107
108const IntegralModel &FractionalIntegralModel::get_parent_model() const { return *_model; }
109
110inline double _get_integral_remainder(const FractionalIntegralModel *frac, const IntegralModel &model,
111 const Channel &channel) {
112 return (frac == nullptr ? model.get_integral(channel) : frac->get_integral_remainder(channel));
113}
114
115double FractionalIntegralModel::get_integral(const Channel &channel) const {
116 return _map.at(channel)->get_value() * (_get_integral_remainder(_parent.get(), *_model, channel));
117}
118
120FractionalIntegralModel::get_integral_derivative_factors(const Channel &channel) const {
121 const auto &frac = *(this->_map.at(channel));
122 /*
123 For a model with no parent:
124 gauss2d will evaluate dmodel/dweight_comp
125 Fitters will want dmodel/dfrac
126
127 frac = weight_comp/weight_total
128 dfrac/dweight_comp = 1/weight_total
129 dweight_comp = dfrac*weight_total
130
131 dmodel/d_frac = weight_total*dmodel/dweight_comp
132
133 With a parent:
134
135 parent: weight_comp_parent = weight_total*frac_parent
136 child1: weight_comp_child1 = weight_total*(1 - frac_parent)
137 ...
138 childN: weight_comp_childN = weight_total*(1 - frac_parent)...*(1-frac_childNminus1)
139
140 dmodel/dfrac_parent = weight_total*(1 - frac_parent)*dmodel/dweight_comp
141 = -weight_total*dmodel/dweight_comp
142
143 i.e. there are N fraction parameters dependent on dmodel/dweight_comp for children.
144 (excluding the fixed fraction for an is_final child)
145 */
146 if (_parent == nullptr) {
147 return {{frac, {_model->get_integral(channel), 0., 0.}}};
148 }
149 auto factors = _parent->get_integral_derivative_factors(channel);
150 if (is_final()) {
151 /*
152 The last component's fraction is fixed, but it has an integral of
153 (1 - frac_previous)*integral_remaining, the derivative of which
154 w.r.t. frac_revious is -1*integral_remaining.
155 */
156 factors.back().second[0] *= -1.;
157 } else {
158 // TODO: Check this if/when it's ever enabled
159 factors.push_back({frac, {factors.back().second[0], 0., 0.}});
160 }
161 return factors;
162}
163
164double FractionalIntegralModel::get_integral_remainder(const Channel &channel) const {
165 return (1. - this->at(channel)->get_value()) * _get_integral_remainder(_parent.get(), *_model, channel);
166}
167
168ProperFractionParameterD &FractionalIntegralModel::get_parameter_frac(const Channel &channel) const {
169 return *(_map.at(channel));
170}
171
172ParamRefs &FractionalIntegralModel::get_parameters(ParamRefs &params, ParamFilter *filter) const {
173 _model->get_parameters(params, filter);
174 // Don't return the n_channels fixed frac=1 parameters at the end
175 const size_t n_p_max = _data.size() - (this->is_final() ? this->get_channels().size() : 0);
176 size_t i = 0;
177 for (auto &p : _data) {
178 if (i++ == n_p_max) break;
179 insert_param_channel(p.first, *p.second, params, filter);
180 }
181 return params;
182}
183
184ParamCRefs &FractionalIntegralModel::get_parameters_const(ParamCRefs &params, ParamFilter *filter) const {
185 _model->get_parameters_const(params, filter);
186 const size_t n_p_max = _data.size() - (this->is_final() ? this->get_channels().size() : 0);
187 size_t i = 0;
188 for (const auto &p : _data) {
189 if (i++ == n_p_max) break;
190 insert_param_channel(p.first, *p.second, params, filter);
191 }
192 return params;
193}
194
195bool FractionalIntegralModel::is_final() const { return _is_final; }
196
197size_t FractionalIntegralModel::size() const { return _data.size(); }
198
199std::string FractionalIntegralModel::repr(bool name_keywords, std::string_view namespace_separator) const {
200 std::string s = type_name_str<FractionalIntegralModel>(false, namespace_separator) + "("
201 + (name_keywords ? "data={" : "{");
202 for (const auto &datum : _data) {
203 s += datum.first.get().repr(name_keywords, namespace_separator) + ": "
204 + datum.second->repr(name_keywords, namespace_separator) + ",";
205 }
206 return s + "})";
207}
208
209std::string FractionalIntegralModel::str() const {
210 std::string s = type_name_str<FractionalIntegralModel>(true) + "(data={";
211 for (const auto &datum : _data) {
212 s += datum.first.get().str() + ": " + datum.second->str() + ",";
213 }
214 s += "}, model=" + _model->str() + ", is_final=" + std::to_string(_is_final) + ")";
215 return s;
216}
217
218// Return a pointer to a registered FractionalIntegralModel, if it is one
219// TODO: Verify if this is safe, or if dynamic_cast is better
220// TODO: Consider a second constructor (but it would likely complicate pybind11'ing)
221std::shared_ptr<const FractionalIntegralModel> FractionalIntegralModel::_find_parent(
223 if (model == nullptr) return nullptr;
224 auto parent = std::dynamic_pointer_cast<const FractionalIntegralModel>(model);
225 if (parent == nullptr) return nullptr;
226 bool found = FractionalIntegralModel::_registry.find(*parent) != _registry.end();
227 return found ? parent : nullptr;
228}
229
230std::shared_ptr<FractionalIntegralModel> FractionalIntegralModel::make(
231 std::optional<const Data> data, std::shared_ptr<const IntegralModel> model, bool is_final) {
232 std::shared_ptr<FractionalIntegralModel> ptr = std::make_shared<Shared_enabler>(data, model, is_final);
233 _registry.insert({*ptr, *model});
234 FractionalIntegralModel::_registry_rev.insert({*model, ptr});
235 return ptr;
236}
237
238const std::shared_ptr<const FractionalIntegralModel> FractionalIntegralModel::make_const(
239 std::optional<const Data> data, std::shared_ptr<const IntegralModel> model, bool is_final) {
240 return make(data, model, is_final);
241}
242
243} // namespace lsst::gauss2d::fit
char * data
Definition BaseRecord.cc:61
std::uint64_t * ptr
Definition RangeSet.cc:95
T back(T... args)
An observational channel, usually representing some range of wavelengths of light.
Definition channel.h:29
An IntegralModel that returns a Parameter-dependent fraction of the flux of another IntegralModel.
double get_integral_remainder(const Channel &channel) const
FractionalIntegralModel(const FractionalIntegralModel &)=delete
A Parametric model for the integral of a 2D distribution.
T emplace_back(T... args)
T move(T... args)
double _get_integral_remainder(const FractionalIntegralModel *frac, const IntegralModel &model, const Channel &channel)
void insert_param_channel(const lsst::gauss2d::fit::Channel &channel, g2f::ParamBase &param, t &params, ParamFilter *filter)
Same as insert_param, but only inserting if filter has a null or matching Channel.
STL namespace.
model(data, psfmodels, sources)
T size(T... args)
Options for filtering Parameter instances.
T to_string(T... args)