2525
2626using namespace correction ;
2727
28+ // ! helper function for parsing flow behavior from string
29+ _FlowBehavior parse_flowbehavior (const rapidjson::Value& flowbehavior) {
30+ if ( flowbehavior == " clamp" ) {
31+ return _FlowBehavior::clamp;
32+ }
33+ else if ( flowbehavior == " error" ) {
34+ return _FlowBehavior::error;
35+ }
36+ else if ( flowbehavior == " wrap" ) {
37+ return _FlowBehavior::wrap;
38+ }
39+ else {
40+ return _FlowBehavior::value;
41+ }
42+ }
43+
2844class correction ::JSONObject {
2945 public:
3046 JSONObject (rapidjson::Value::ConstObject&& json) : json_(json) { }
@@ -149,20 +165,33 @@ namespace {
149165 return bins->n ; // the default value is stored at the end of the content array, after the last bin
150166 case _FlowBehavior::clamp:
151167 return value < bins->low ? 0 : bins->n - 1 ; // assuming we always have at least 1 bin
168+ case _FlowBehavior::wrap:
169+ break ;
152170 case _FlowBehavior::error:
153171 const std::string belowOrAbove = value < bins->low ? " below" : " above" ;
154172 auto msg = " Index " + belowOrAbove + " bounds in " + name + " for input argument " + std::to_string (variableIdx) + " value: " + std::to_string (value);
155173 throw std::runtime_error (std::move (msg));
156174 }
157175 }
158176
159- std::size_t binIdx = bins->n * ((value - bins->low ) / (bins->high - bins->low ));
177+ double norm_value = ((value - bins->low ) / (bins->high - bins->low ));
178+ if (flow == _FlowBehavior::wrap) {
179+ norm_value -= std::floor (norm_value);
180+ }
181+ std::size_t binIdx = bins->n * norm_value;
160182 return binIdx;
161183 }
162184
163185 // otherwise we have non-uniform binning
164186 using namespace std ::string_literals;
165187 const auto bins = std::get<_NonUniformBins>(bins_);
188+ if ( flow == _FlowBehavior::wrap ) {
189+ double low = bins[0 ];
190+ double high = bins[bins.size () - 1 ];
191+ double norm_value = (value - low) / (high - low);
192+ norm_value -= std::floor (norm_value);
193+ value = low + norm_value * (high - low);
194+ }
166195
167196 auto it = std::upper_bound (std::begin (bins), std::end (bins), value);
168197 if ( it == std::begin (bins) ) { // underflow
@@ -172,6 +201,9 @@ namespace {
172201 else if ( flow == _FlowBehavior::error ) {
173202 throw std::runtime_error (" Index below bounds in " s + name + " for input argument " + std::to_string (variableIdx) + " value: " + std::to_string (value));
174203 }
204+ else if ( flow == _FlowBehavior::wrap ) {
205+ throw std::logic_error (" I should not have ever seen an underflow" );
206+ }
175207 else { // clamp
176208 it++;
177209 }
@@ -183,6 +215,9 @@ namespace {
183215 else if ( flow == _FlowBehavior::error ) {
184216 throw std::runtime_error (" Index above bounds in " s + name + " for input argument " + std::to_string (variableIdx) + " value: " + std::to_string (value));
185217 }
218+ else if ( flow == _FlowBehavior::wrap ) {
219+ throw std::logic_error (" I should not have ever seen an overflow" );
220+ }
186221 else { // clamp
187222 it--;
188223 }
@@ -461,15 +496,9 @@ Binning::Binning(const JSONObject& json, const Correction& context)
461496 }
462497 Content default_value{0 .};
463498 const auto & flowbehavior = json.getRequiredValue (" flow" );
464- if ( flowbehavior == " clamp" ) {
465- flow_ = _FlowBehavior::clamp;
466- }
467- else if ( flowbehavior == " error" ) {
468- flow_ = _FlowBehavior::error;
469- }
470- else {
471- flow_ = _FlowBehavior::value;
472- default_value = resolve_content (flowbehavior, context);
499+ flow_ = parse_flowbehavior (flowbehavior);
500+ if (flow_ == _FlowBehavior::value) {
501+ default_value = resolve_content (flowbehavior, context);
473502 }
474503
475504 // set bin contents
@@ -540,16 +569,9 @@ MultiBinning::MultiBinning(const JSONObject& json, const Correction& context)
540569 }
541570
542571 const auto & flowbehavior = json.getRequiredValue (" flow" );
543- if ( flowbehavior == " clamp" ) {
544- flow_ = _FlowBehavior::clamp;
545- }
546- else if ( flowbehavior == " error" ) {
547- flow_ = _FlowBehavior::error;
548- }
549- else {
550- flow_ = _FlowBehavior::value;
551- // store default value at end of content array
552- content_.push_back (resolve_content (flowbehavior, context));
572+ flow_ = parse_flowbehavior (flowbehavior);
573+ if (flow_ == _FlowBehavior::value) {
574+ content_.push_back (resolve_content (flowbehavior, context));
553575 }
554576}
555577
0 commit comments