void Estimate::Build() { if (*target_ < lower_bound_) LOG_ERROR() << location() << "the initial value(" << AS_DOUBLE((*target_)) << ") on the estimate " << parameter_ << " is lower than the lower_bound(" << lower_bound_ << ")"; if (*target_ > upper_bound_) LOG_ERROR() << location() << "the initial value(" << AS_DOUBLE((*target_)) << ") on the estimate " << parameter_ << " is greater than the upper_bound(" << upper_bound_ << ")"; Reset(); }
Double DoubleNormal::GetLengthBasedResult(unsigned age, AgeLength* age_length, unsigned year, int time_step_index) { LOG_TRACE(); unsigned yearx = year == 0 ? model_->current_year() : year; unsigned time_step = time_step_index == -1 ? model_->managers().time_step()->current_time_step() : (unsigned)time_step_index; Double cv = age_length->cv(yearx, time_step, age); Double mean = age_length->mean_length(time_step, age); string dist = age_length->distribution_label(); if (dist == PARAM_NONE || n_quant_ <= 1) { if (mean < mu_) return pow(2.0, -((mean - mu_) / sigma_l_ * (mean - mu_) / sigma_l_)) * alpha_; else return pow(2.0, -((mean - mu_)/sigma_r_ * (mean - mu_) / sigma_r_)) * alpha_; } else if (dist == PARAM_NORMAL) { Double sigma = cv * mean; Double size = 0.0; Double total = 0.0; for (unsigned j = 0; j < n_quant_; ++j) { size = mean + sigma * quantiles_at_[j]; if (size < mu_) total += pow(2.0, -((size - mu_) / sigma_l_ * (size - mu_) / sigma_l_)) * alpha_; else total += pow(2.0, -((size - mu_)/sigma_r_ * (size - mu_) / sigma_r_)) * alpha_; } return total / n_quant_; } else if (dist == PARAM_LOGNORMAL) { // convert paramters to log space Double sigma = sqrt(log(1 + cv * cv)); Double mu = log(mean) - sigma * sigma * 0.5; Double size = 0.0; Double total = 0.0; boost::math::lognormal dist{AS_DOUBLE(mu), AS_DOUBLE(sigma)}; for (unsigned j = 0; j < n_quant_; ++j) { size = mu + sigma * quantile(dist, AS_DOUBLE(quantiles_[j])); if (size < mu_) total += pow(2.0, -((size - mu_) / sigma_l_ * (size - mu_) / sigma_l_)) * alpha_; else total += pow(2.0, -((size - mu_)/sigma_r_ * (size - mu_) / sigma_r_)) * alpha_; } return total / n_quant_; } LOG_CODE_ERROR() << "dist is invalid " << dist; return 0; }
/** * Validate our Mortality Constant Rate process * * - Validate the required parameters * - Assign the label from the parameters * - Assign and validate remaining parameters * - Duplicate 'm' and 'selectivities' if only 1 vale specified * - Check m is between 0.0 and 1.0 * - Check the categories are real */ void TagLoss::DoValidate() { LOG_FINEST() << "Number of categories = " << category_labels_.size() << " number of proportions given = " << tag_loss_input_.size(); if (tag_loss_input_.size() == 1) tag_loss_input_.assign(category_labels_.size(), tag_loss_input_[0]); if (selectivity_names_.size() == 1) selectivity_names_.assign(category_labels_.size(), selectivity_names_[0]); if (tag_loss_input_.size() != category_labels_.size()) { LOG_ERROR_P(PARAM_TAG_LOSS_RATE) << ": Number of tag loss values provided is not the same as the number of categories provided. Expected: " << category_labels_.size()<< " but got " << tag_loss_input_.size(); } if (selectivity_names_.size() != category_labels_.size()) { LOG_ERROR_P(PARAM_SELECTIVITIES) << ": Number of selectivities provided is not the same as the number of categories provided. Expected: " << category_labels_.size()<< " but got " << selectivity_names_.size(); } // Validate type of tag loss if (tag_loss_type_ != "single") LOG_ERROR_P(PARAM_TAG_LOSS_TYPE) << tag_loss_type_ << " Is not an expected type. Values allowed are " << PARAM_SINGLE << " and " << PARAM_DOUBLE << " is coming soon"; if (tag_loss_type_ == PARAM_DOUBLE) LOG_ERROR() << PARAM_TAG_LOSS_TYPE << " " << PARAM_DOUBLE << " is not implemented yet"; // Validate our Ms are between 1.0 and 0.0 for (Double tag_loss : tag_loss_input_) { if (tag_loss < 0.0 || tag_loss > 1.0) LOG_ERROR_P(PARAM_TAG_LOSS_RATE) << ": m value " << AS_DOUBLE(tag_loss) << " must be between 0.0 and 1.0 (inclusive)"; } for (unsigned i = 0; i < tag_loss_input_.size(); ++i) tag_loss_[category_labels_[i]] = tag_loss_input_[i]; }
/** * Validate our Survival Constant Rate process * * - Validate the required parameters * - Assign the label from the parameters * - Assign and validate remaining parameters * - Duplicate 's' and 'selectivities' if only 1 vale specified * - Check s is between 0.0 and 1.0 * - Check the categories are real */ void SurvivalConstantRate::DoValidate() { category_labels_ = model_->categories()->ExpandLabels(category_labels_, parameters_.Get(PARAM_CATEGORIES)); if (s_input_.size() == 1) s_input_.assign(category_labels_.size(), s_input_[0]); if (selectivity_names_.size() == 1) selectivity_names_.assign(category_labels_.size(), selectivity_names_[0]); if (s_input_.size() != category_labels_.size()) { LOG_ERROR_P(PARAM_S) << ": Number of Ms provided is not the same as the number of categories provided. Expected: " << category_labels_.size()<< " but got " << s_input_.size(); } if (selectivity_names_.size() != category_labels_.size()) { LOG_ERROR_P(PARAM_SELECTIVITIES) << ": Number of selectivities provided is not the same as the number of categories provided. Expected: " << category_labels_.size()<< " but got " << selectivity_names_.size(); } // Validate our Ms are between 1.0 and 0.0 for (Double s : s_input_) { if (s < 0.0 || s > 1.0) LOG_ERROR_P(PARAM_S) << ": m value " << AS_DOUBLE(s) << " must be between 0.0 and 1.0 (inclusive)"; } for (unsigned i = 0; i < s_input_.size(); ++i) m_[category_labels_[i]] = s_input_[i]; // Check categories are real for (const string& label : category_labels_) { if (!model_->categories()->IsValid(label)) LOG_ERROR_P(PARAM_CATEGORIES) << ": category " << label << " does not exist. Have you defined it?"; } }
/** * Execute this report. */ void EstimateValue::DoExecute() { LOG_TRACE(); vector<Estimate*> estimates = model_->managers().estimate()->objects(); vector<Profile*> profiles = model_->managers().profile()->objects(); if (estimates.size() > 0) { /** * if this is the first run we print the report header etc */ if (first_run_) { LOG_FINEST() << "first run of estimate_value report"; first_run_ = false; if (!skip_tags_) { cache_ << "*" << label_ << " " << "(" << type_ << ")" << "\n"; cache_ << "values " << REPORT_R_DATAFRAME << "\n"; } for (Estimate* estimate : estimates) cache_ << estimate->parameter() << " "; cache_ << "\n"; LOG_FINEST() << "Number of estimates reporting on = " << estimates.size(); for (Estimate* estimate : estimates) cache_ << AS_DOUBLE(estimate->value()) << " "; cache_ << "\n"; } else { if (model_->run_mode() == RunMode::kProfiling) { cache_ << "*" << label_ << " " << "(" << type_ << ")" << "\n"; cache_ << "values " << REPORT_R_DATAFRAME << "\n"; for (Estimate* estimate : estimates) cache_ << estimate->parameter() << " "; cache_ << "\n"; for (Estimate* estimate : estimates) cache_ << AS_DOUBLE(estimate->value()) << " "; } else { LOG_FINEST() << "Number of estimates reporting on = " << estimates.size(); for (Estimate* estimate : estimates) cache_ << AS_DOUBLE(estimate->value()) << " "; } cache_ << "\n"; } ready_for_writing_ = true; } }
/** * Simulate observed values * * @param comparisons A collection of comparisons passed by the observation */ void BinomialApprox::SimulateObserved(map<unsigned, vector<observations::Comparison> >& comparisons) { utilities::RandomNumberGenerator& rng = utilities::RandomNumberGenerator::Instance(); Double error_value = 0.0; auto iterator = comparisons.begin(); for (; iterator != comparisons.end(); ++iterator) { LOG_FINE() << "Simulating values for year: " << iterator->first; for (observations::Comparison& comparison : iterator->second) { error_value = ceil(AS_DOUBLE(AdjustErrorValue(comparison.process_error_, comparison.error_value_))); if (comparison.expected_ <= 0.0 || error_value <= 0.0) comparison.observed_ = 0.0; else comparison.observed_ = rng.binomial(AS_DOUBLE(comparison.expected_), AS_DOUBLE(error_value)) / error_value; } } }
/** * This method will execute our estimate summary report */ void EstimateSummary::DoExecute() { // Print the estimates niwa::estimates::Manager& estimate_manager = *model_->managers().estimate(); vector<Estimate*> estimates = estimate_manager.objects(); /* // Header cache_ << CONFIG_ARRAY_START << label_ << CONFIG_ARRAY_END << "\n"; // cout << PARAM_REPORT << "." << PARAM_TYPE << CONFIG_RATIO_SEPARATOR << " " << parameters_.Get(PARAM_TYPE)->GetValue<string>() << "\n"; for (EstimatePtr estimate : estimates) { cache_ << "\n"; if (estimate->label() != "") { cache_ << "Estimate: " << estimate->label() << " (" << estimate->parameter() << ")\n"; cache_ << "Parameter: " << estimate->parameter() << "\n"; } else cache_ << "Estimate: " << estimate->parameter() << "\n"; cache_ << "Lower Bound: " << estimate->lower_bound() << "\n"; cache_ << "Upper Bound: " << estimate->upper_bound() << "\n"; cache_ << "Value: " << AS_DOUBLE(estimate->value()) << "\n"; cache_ << "parameters:\n"; map<string, ParameterPtr> parameters = estimate->parameters().parameters(); for (auto iter = parameters.begin(); iter != parameters.end(); ++iter) { cache_ << iter->first << ": "; for (string parameter_value : iter->second->values()) cache_ << parameter_value << " "; cache_ << "\n"; } } cache_ << CONFIG_END_REPORT << "\n" << endl; */ cache_ << "*" << label_ << " " << "("<< type_ << ")"<<"\n"; for (Estimate* estimate : estimates) { cache_ << estimate->parameter() << " " << REPORT_R_LIST << "\n"; // cache_ << "label: " << estimate->label() << "\n"; cache_ << "lower_bound: " << estimate->lower_bound() << "\n"; cache_ << "upper_bound: " << estimate->upper_bound() << "\n"; cache_ << "value: " << AS_DOUBLE(estimate->value()) << "\n"; map<string, Parameter*> parameters = estimate->parameters().parameters(); for (auto iter = parameters.begin(); iter != parameters.end(); ++iter) { cache_ << iter->first << ": "; for (string parameter_value : iter->second->values()) cache_ << parameter_value << " "; cache_ << "\n"; } cache_ << REPORT_R_LIST_END << "\n\n"; } ready_for_writing_ = true; }
/** * Validate this selectivity. This will load the * values that were passed in from the configuration * file and assign them to the local variables. * * We'll then do some basic checks on the local * variables to ensure they are within the business * rules for the model. */ void Increasing::DoValidate() { if (alpha_ <= 0.0) LOG_ERROR_P(PARAM_ALPHA) << ": alpha (" << AS_DOUBLE(alpha_) << ") cannot be less than or equal to 0.0"; if (high_ <= low_) LOG_ERROR_P(PARAM_H) << ": 'h' (" << high_ << ") cannot be less than or the same as 'l' (" << low_ << ")"; for (unsigned i = 0; i < v_.size(); ++i) { if (v_[i] < 0.0 || v_[i] > 1.0) { LOG_ERROR_P(PARAM_V) << " 'v' element " << i + 1 << " (" << AS_DOUBLE(v_[i]) << ") is not between 0.0 and 1.0"; } } if (model_->partition_type() == PartitionType::kAge) { if (low_ < model_->min_age() || low_ > model_->max_age()) LOG_ERROR_P(PARAM_L) << ": 'l' (" << low_ << ") must be between the model min_age (" << model_->min_age() << ") and max_age (" << model_->max_age() << ")"; if (v_.size() != (high_ - low_ + 1)) { LOG_ERROR_P(PARAM_V) << " 'v' has incorrect amount of elements\n" << "Expected: " << (high_ - low_ + 1) << " but got " << v_.size(); } } else if (model_->partition_type() == PartitionType::kLength) { vector<unsigned> length_bins = model_->length_bins(); if (low_ < length_bins[0] || low_ > length_bins[length_bins.size()-1]) LOG_ERROR_P(PARAM_L) << ": 'l' (" << low_ << ") must be between the model min length (" << length_bins[0] << ") and max length (" << length_bins[length_bins.size()-1] << ")"; unsigned bins = 0; for (unsigned i = 0; i < length_bins.size(); ++i) { if (length_bins[i] >= low_ && length_bins[i] <= high_) ++bins; } if (bins != v_.size()) { LOG_ERROR_P(PARAM_V) << ": Parameter 'v' does not have the right amount of elements n = low <= length_bins <= high, " << "Expected " << bins << " but got " << v_.size(); } } }
void MortalityEventBiomass::DoExecute() { if (catch_years_[model_->current_year()] == 0) return; LOG_TRACE(); /** * Work our how much of the stock is vulnerable */ Double vulnerable = 0.0; unsigned i = 0; for (auto categories : partition_) { categories->UpdateMeanWeightData(); unsigned offset = 0; for (Double& data : categories->data_) { Double temp = data * selectivities_[i]->GetResult(categories->min_age_ + offset, categories->age_length_); vulnerable += temp * categories->mean_weight_per_[categories->min_age_ + offset]; ++offset; } ++i; } /** * Work out the exploitation rate to remove (catch/vulnerable) */ Double exploitation = catch_years_[model_->current_year()] / utilities::doublecompare::ZeroFun(vulnerable); if (exploitation > u_max_) { exploitation = u_max_; if (penalty_) penalty_->Trigger(label_, catch_years_[model_->current_year()], vulnerable * u_max_); } else if (exploitation < 0.0) { exploitation = 0.0; } LOG_FINEST() << "year: " << model_->current_year() << "; exploitation: " << AS_DOUBLE(exploitation); /** * Remove the stock now. The amount to remove is * vulnerable * exploitation */ i = 0; for (auto categories : partition_) { unsigned offset = 0; for (Double& data : categories->data_) { data -= data * selectivities_[i]->GetResult(categories->min_age_ + offset, categories->age_length_) * exploitation; ++offset; } ++i; } }
/** * Build our process proportions by category */ void ProcessProportionsByCategory::DoBuild() { ProportionsByCategory::DoBuild(); if (process_proportion_ < 0.0 || process_proportion_ > 1.0) LOG_ERROR_P(PARAM_PROCESS_PROPORTION) << ": process_proportion (" << AS_DOUBLE(process_proportion_) << ") must be between 0.0 and 1.0"; proportion_of_time_ = process_proportion_; auto time_step = model_->managers().time_step()->GetTimeStep(time_step_label_); if (!time_step) { LOG_FATAL_P(PARAM_TIME_STEP) << time_step_label_ << " could not be found. Have you defined it?"; } else { for (unsigned year : years_) time_step->SubscribeToProcess(this, year, process_label_); } }
void TimeStepAbundance::DoBuild() { Abundance::DoBuild(); if (time_step_proportion_ < 0.0 || time_step_proportion_ > 1.0) LOG_ERROR_P(PARAM_TIME_STEP_PROPORTION) << ": time_step_proportion (" << AS_DOUBLE(time_step_proportion_) << ") must be between 0.0 and 1.0"; proportion_of_time_ = time_step_proportion_; auto time_step = model_->managers().time_step()->GetTimeStep(time_step_label_); if (!time_step) { LOG_ERROR_P(PARAM_TIME_STEP) << time_step_label_ << " could not be found. Have you defined it?"; } else { for (unsigned year : years_) time_step->SubscribeToBlock(this, year); } }
void Selectivity::Validate() { parameters_.Populate(); DoValidate(); if (length_based_) { boost::math::normal dist{ }; for (unsigned i = 1; i <= n_quant_; ++i) { quantiles_.push_back((Double(i) - 0.5) / Double(n_quant_)); LOG_FINEST() << ": Quantile value = " << quantiles_[i - 1]; quantiles_at_.push_back(quantile(dist, AS_DOUBLE(quantiles_[i - 1]))); LOG_FINEST() << ": Normal quantile value = " << quantiles_at_[i - 1]; } } }
/** * Execute the report in tabular format */ void EstimateValue::DoExecuteTabular() { vector<Estimate*> estimates = model_->managers().estimate()->objects(); /** * if this is the first run we print the report header etc */ if (first_run_) { first_run_ = false; cache_ << "*" << label_ << " " << "(" << type_ << ")" << "\n"; cache_ << "values " << REPORT_R_DATAFRAME << "\n"; for (Estimate* estimate : estimates) cache_ << estimate->parameter() << " "; cache_ << "\n"; } for (Estimate* estimate : estimates) cache_ << AS_DOUBLE(estimate->value()) << " "; cache_ <<"\n" ; }
void Partition::DoExecute() { //cerr << "execute " << label_ << "\n"; // First, figure out the lowest and highest ages/length unsigned lowest = 9999; unsigned highest = 0; unsigned longest_length = 0; niwa::partition::accessors::All all_view(model_); for (auto iterator = all_view.Begin(); iterator != all_view.End(); ++iterator) { if (lowest > (*iterator)->min_age_) lowest = (*iterator)->min_age_; if (highest < (*iterator)->max_age_) highest = (*iterator)->max_age_; if (longest_length < (*iterator)->name_.length()) longest_length = (*iterator)->name_.length(); } // Print the header cache_ << "*"<< type_ << "[" << label_ << "]" << "\n"; cache_ << "year: " << model_->current_year() << "\n"; cache_ << "time_step: " << time_step_ << "\n"; cache_ << "values "<< REPORT_R_DATAFRAME<<"\n"; cache_ << "category"; for (unsigned i = lowest; i <= highest; ++i) cache_ << " " << i; cache_ << "\n"; for (auto iterator = all_view.Begin(); iterator != all_view.End(); ++iterator) { cache_ << (*iterator)->name_; unsigned age = (*iterator)->min_age_; for (auto values = (*iterator)->data_.begin(); values != (*iterator)->data_.end(); ++values, age++) { if (age >= lowest && age <= highest) { Double value = *values; cache_ << " " << std::fixed << AS_DOUBLE(value); } else cache_ << " " << "null"; } cache_ << "\n"; } ready_for_writing_ = true; }
/** * Execute this report. */ void EstimateValue::DoExecute() { vector<Estimate*> estimates = model_->managers().estimate()->objects(); vector<Profile*> profiles = model_->managers().profile()->objects(); LOG_TRACE(); // Check if estiamtes are close to bounds. flag a warning. for (Estimate* estimate : estimates) { if ((estimate->value() - estimate->lower_bound()) < 0.001 || (estimate->upper_bound() - estimate->value()) < 0.001) LOG_WARNING() << "estimated parameter '" << estimate->parameter() << "' was within 0.001 of its bound"; } if (estimates.size() > 0) { cache_ << "*"<< type_ << "[" << label_ << "]" << "\n"; cache_ << "values " << REPORT_R_DATAFRAME << "\n"; for (Estimate* estimate : estimates) cache_ << estimate->parameter() << " "; cache_ << "\n"; for (Estimate* estimate : estimates) cache_ << AS_DOUBLE(estimate->value()) << " "; cache_ << "\n"; ready_for_writing_ = true; } }
/** * Validate configuration file parameters */ void ProcessRemovalsByLength::DoValidate() { // How many elements are expected in our observed table; if (length_plus_) { number_bins_ = length_bins_.size(); } else { number_bins_ = length_bins_.size() - 1; } for (auto year : years_) { if ((year < model_->start_year()) || (year > model_->final_year())) LOG_ERROR_P(PARAM_YEARS) << "Years can't be less than start_year (" << model_->start_year() << "), or greater than final_year (" << model_->final_year() << "). Please fix this."; } map<unsigned, vector<Double>> error_values_by_year; map<unsigned, vector<Double>> obs_by_year; /** * Do some simple checks * e.g Validate that the length_bins are strictly increasing */ for (unsigned length = 0; length < length_bins_.size(); ++length) { if (length_bins_[length] < 0.0) if (length_bins_[length] > length_bins_[length + 1]) LOG_ERROR_P(PARAM_LENGTH_BINS) << ": Length bins must be strictly increasing " << length_bins_[length] << " is greater than " << length_bins_[length + 1]; } if (process_error_values_.size() != 0 && process_error_values_.size() != years_.size()) { LOG_ERROR_P(PARAM_PROCESS_ERRORS) << " number of values provied (" << process_error_values_.size() << ") does not match the number of years provided (" << years_.size() << ")"; } for (Double process_error : process_error_values_) { if (process_error < 0.0) LOG_ERROR_P(PARAM_PROCESS_ERRORS) << ": process_error (" << AS_DOUBLE(process_error) << ") cannot be less than 0.0"; } if (process_error_values_.size() != 0) process_errors_by_year_ = utilities::Map::create(years_, process_error_values_); if (delta_ < 0.0) LOG_ERROR_P(PARAM_DELTA) << ": delta (" << AS_DOUBLE(delta_) << ") cannot be less than 0.0"; /** * Validate the number of obs provided matches age spread * category_labels * years * This is because we'll have 1 set of obs per category collection provided. * categories male+female male = 2 collections */ unsigned obs_expected = number_bins_ * category_labels_.size() + 1; vector<vector<string>>& obs_data = obs_table_->data(); if (obs_data.size() != years_.size()) { LOG_ERROR_P(PARAM_OBS) << " has " << obs_data.size() << " rows defined, but we expected " << years_.size() << " to match the number of years provided"; } for (vector<string>& obs_data_line : obs_data) { if (obs_data_line.size() != obs_expected) { LOG_ERROR_P(PARAM_OBS) << " has " << obs_data_line.size() << " values defined, but we expected " << obs_expected << " to match the number bins * categories + 1 (for year)"; } unsigned year = 0; if (!utilities::To<unsigned>(obs_data_line[0], year)) LOG_ERROR_P(PARAM_OBS) << " value " << obs_data_line[0] << " could not be converted in to an unsigned integer. It should be the year for this line"; if (std::find(years_.begin(), years_.end(), year) == years_.end()) LOG_ERROR_P(PARAM_OBS) << " value " << year << " is not a valid year for this observation"; for (unsigned i = 1; i < obs_data_line.size(); ++i) { Double value = 0; if (!utilities::To<Double>(obs_data_line[i], value)) LOG_ERROR_P(PARAM_OBS) << " value (" << obs_data_line[i] << ") could not be converted to a double"; obs_by_year[year].push_back(value); } if (obs_by_year[year].size() != obs_expected - 1) LOG_FATAL_P(PARAM_OBS)<< "you supplied " << obs_by_year[year].size() << " lengths, but we expected " << obs_expected -1 << " can you please sort this out. Chairs"; } /** * Build our error value map */ vector<vector<string>>& error_values_data = error_values_table_->data(); if (error_values_data.size() != years_.size()) { LOG_FATAL_P(PARAM_ERROR_VALUES)<< " has " << error_values_data.size() << " rows defined, but we expected " << years_.size() << " to match the number of years provided"; } for (vector<string>& error_values_data_line : error_values_data) { if (error_values_data_line.size() != 2 && error_values_data_line.size() != obs_expected) { LOG_ERROR_P(PARAM_ERROR_VALUES) << " has " << error_values_data_line.size() << " values defined, but we expected " << obs_expected << " to match the number bins * categories + 1 (for year)"; } unsigned year = 0; if (!utilities::To<unsigned>(error_values_data_line[0], year)) LOG_FATAL_P(PARAM_ERROR_VALUES)<< " value " << error_values_data_line[0] << " could not be converted in to an unsigned integer. It should be the year for this line"; if (std::find(years_.begin(), years_.end(), year) == years_.end()) LOG_FATAL_P(PARAM_ERROR_VALUES)<< " value " << year << " is not a valid year for this observation"; for (unsigned i = 1; i < error_values_data_line.size(); ++i) { Double value = 0; if (!utilities::To<Double>(error_values_data_line[i], value)) LOG_FATAL_P(PARAM_ERROR_VALUES)<< " value (" << error_values_data_line[i] << ") could not be converted to a double"; if (likelihood_type_ == PARAM_LOGNORMAL && value <= 0.0) { LOG_ERROR_P(PARAM_ERROR_VALUES) << ": error_value (" << AS_DOUBLE(value) << ") cannot be equal to or less than 0.0"; } else if (likelihood_type_ == PARAM_MULTINOMIAL && value < 0.0) { LOG_ERROR_P(PARAM_ERROR_VALUES) << ": error_value (" << AS_DOUBLE(value) << ") cannot be less than 0.0"; } error_values_by_year[year].push_back(value); } if (error_values_by_year[year].size() == 1) { error_values_by_year[year].assign(obs_expected - 1, error_values_by_year[year][0]); } if (error_values_by_year[year].size() != obs_expected - 1) LOG_FATAL_P(PARAM_ERROR_VALUES)<< "We counted " << error_values_by_year[year].size() << " error values by year but expected " << obs_expected -1 << " based on the obs table"; } /** * Build our proportions and error values for use in the observation * If the proportions for a given observation do not sum to 1.0 * and is off by more than the tolerance rescale them. */ Double value = 0.0; for (auto iter = obs_by_year.begin(); iter != obs_by_year.end(); ++iter) { Double total = 0.0; for (unsigned i = 0; i < category_labels_.size(); ++i) { for (unsigned j = 0; j < number_bins_; ++j) { unsigned obs_index = i * number_bins_ + j; value = iter->second[obs_index]; Double error_value = error_values_by_year[iter->first][obs_index]; error_values_[iter->first][category_labels_[i]].push_back(error_value); proportions_[iter->first][category_labels_[i]].push_back(value); total += value; } } if (fabs(1.0 - total) > tolerance_) { LOG_ERROR_P(PARAM_OBS) << ": obs sum total (" << total << ") for year (" << iter->first << ") exceeds tolerance (" << tolerance_ << ") from 1.0"; } } }
/** * Execute our mortality event object. * */ void MortalityInitialisationEventBiomass::DoExecute() { LOG_TRACE(); unsigned time_step_index = model_->managers().time_step()->current_time_step(); // only apply if initialisation phase if (model_->state() == State::kInitialise) { /** * Work our how much of the stock is available or vulnerable to exploit */ Double vulnerable = 0.0; unsigned i = 0; for (auto categories : partition_) { unsigned j = 0; //categories->UpdateMeanWeightData(); for (Double& data : categories->data_) { Double temp = data * selectivities_[i]->GetAgeResult(categories->min_age_ + j, categories->age_length_); vulnerable += temp * categories->mean_weight_by_time_step_age_[time_step_index][categories->min_age_ + j]; ++j; } ++i; } /** * Work out the exploitation rate to remove (catch/vulnerable) */ Double exploitation = 0; LOG_FINEST() << "vulnerable biomass = " << vulnerable << " catch = " << catch_; exploitation = catch_ / utilities::doublecompare::ZeroFun(vulnerable); if (exploitation > u_max_) { exploitation = u_max_; if (penalty_) penalty_->Trigger(label_, catch_, vulnerable*u_max_); } else if (exploitation < 0.0) { exploitation = 0.0; } LOG_FINEST() << "; exploitation: " << AS_DOUBLE(exploitation); /** * Remove the stock now. The amount to remove is * vulnerable * exploitation */ // Report catches and exploitation rates for each category for each iteration /* StoreForReport("initialisation_iteration: ", init_iteration_); StoreForReport("Exploitation: ", AS_DOUBLE(exploitation)); StoreForReport("Catch: ", AS_DOUBLE(catch_)); */ Double removals =0; for (auto categories : partition_) { unsigned offset = 0; for (Double& data : categories->data_) { // report removals = vulnerable_[categories->name_][categories->min_age_ + offset] * exploitation; //StoreForReport(categories->name_ + "_Removals: ", AS_DOUBLE(removals)); data -= removals; offset++; } } ++init_iteration_; } }
/** * Validate our Mortality Event Process * * 1. Check for the required parameters * 2. Assign any remaining variables */ void MortalityInitialisationEventBiomass::DoValidate() { // Validate that the number of selectivities is the same as the number of categories if (category_labels_.size() != selectivity_names_.size()) { LOG_ERROR_P(PARAM_SELECTIVITIES) << " Number of selectivities provided does not match the number of categories provided." << " Expected " << category_labels_.size() << " but got " << selectivity_names_.size(); } // Validate u_max if (u_max_ < 0.0 || u_max_ > 1.0) LOG_ERROR_P(PARAM_U_MAX) << ": u_max must be between 0.0 and 1.0 (inclusive). Value defined was " << AS_DOUBLE(u_max_); }
/** * Validate this selectivity. This will load the * values that were passed in from the configuration * file and assign them to the local variables. * * We'll then do some basic checks on the local * variables to ensure they are within the business * rules for the model. */ void LogisticProducing::DoValidate() { if (alpha_ <= 0.0) LOG_ERROR_P(PARAM_ALPHA) << ": alpha (" << AS_DOUBLE(alpha_) << ") cannot be less than or equal to 0.0"; if (ato95_ <= 0.0) LOG_ERROR_P(PARAM_ATO95) << ": ato95 (" << AS_DOUBLE(ato95_) << ") cannot be less than or equal to 0.0"; }
/** * Validate configuration file parameters */ void ProportionsMigrating::DoValidate() { age_spread_ = (max_age_ - min_age_) + 1; map<unsigned, vector<Double>> error_values_by_year; map<unsigned, vector<Double>> obs_by_year; /** * Do some simple checks */ if (min_age_ < model_->min_age()) LOG_ERROR_P(PARAM_MIN_AGE) << ": min_age (" << min_age_ << ") is less than the model's min_age (" << model_->min_age() << ")"; if (max_age_ > model_->max_age()) LOG_ERROR_P(PARAM_MAX_AGE) << ": max_age (" << max_age_ << ") is greater than the model's max_age (" << model_->max_age() << ")"; if (process_error_values_.size() != 0 && process_error_values_.size() != years_.size()) { LOG_ERROR_P(PARAM_PROCESS_ERRORS) << " number of values provied (" << process_error_values_.size() << ") does not match the number of years provided (" << years_.size() << ")"; } for (Double process_error : process_error_values_) { if (process_error < 0.0) LOG_ERROR_P(PARAM_PROCESS_ERRORS) << ": process_error (" << AS_DOUBLE(process_error) << ") cannot be less than 0.0"; } if (process_error_values_.size() != 0) process_errors_by_year_ = utilities::Map::create(years_, process_error_values_); if (delta_ < 0.0) LOG_ERROR_P(PARAM_DELTA) << ": delta (" << AS_DOUBLE(delta_) << ") cannot be less than 0.0"; /** * Validate the number of obs provided matches age spread * category_labels * years * This is because we'll have 1 set of obs per category collection provided. * categories male+female male = 2 collections */ unsigned obs_expected = age_spread_ * category_labels_.size() + 1; vector<vector<string>>& obs_data = obs_table_->data(); if (obs_data.size() != years_.size()) { LOG_ERROR_P(PARAM_OBS) << " has " << obs_data.size() << " rows defined, but we expected " << years_.size() << " to match the number of years provided"; } for (vector<string>& obs_data_line : obs_data) { if (obs_data_line.size() != obs_expected) { LOG_ERROR_P(PARAM_OBS) << " has " << obs_data_line.size() << " values defined, but we expected " << obs_expected << " to match the age speard * categories + 1 (for year)"; } unsigned year = 0; if (!utilities::To<unsigned>(obs_data_line[0], year)) LOG_ERROR_P(PARAM_OBS) << " value " << obs_data_line[0] << " could not be converted in to an unsigned integer. It should be the year for this line"; if (std::find(years_.begin(), years_.end(), year) == years_.end()) LOG_ERROR_P(PARAM_OBS) << " value " << year << " is not a valid year for this observation"; for (unsigned i = 1; i < obs_data_line.size(); ++i) { Double value = 0; if (!utilities::To<Double>(obs_data_line[i], value)) LOG_ERROR_P(PARAM_OBS) << " value (" << obs_data_line[i] << ") could not be converted to a double"; obs_by_year[year].push_back(value); } if (obs_by_year[year].size() != obs_expected - 1) LOG_CODE_ERROR() << "obs_by_year_[year].size() (" << obs_by_year[year].size() << ") != obs_expected - 1 (" << obs_expected -1 << ")"; } /** * Build our error value map */ vector<vector<string>>& error_values_data = error_values_table_->data(); if (error_values_data.size() != years_.size()) { LOG_ERROR_P(PARAM_ERROR_VALUES) << " has " << error_values_data.size() << " rows defined, but we expected " << years_.size() << " to match the number of years provided"; } for (vector<string>& error_values_data_line : error_values_data) { if (error_values_data_line.size() != 2 && error_values_data_line.size() != obs_expected) { LOG_ERROR_P(PARAM_ERROR_VALUES) << " has " << error_values_data_line.size() << " values defined, but we expected " << obs_expected << " to match the age speard * categories + 1 (for year)"; } unsigned year = 0; if (!utilities::To<unsigned>(error_values_data_line[0], year)) LOG_ERROR_P(PARAM_ERROR_VALUES) << " value " << error_values_data_line[0] << " could not be converted in to an unsigned integer. It should be the year for this line"; if (std::find(years_.begin(), years_.end(), year) == years_.end()) LOG_ERROR_P(PARAM_ERROR_VALUES) << " value " << year << " is not a valid year for this observation"; for (unsigned i = 1; i < error_values_data_line.size(); ++i) { Double value = 0; if (!utilities::To<Double>(error_values_data_line[i], value)) LOG_ERROR_P(PARAM_ERROR_VALUES) << " value (" << error_values_data_line[i] << ") could not be converted to a double"; if (likelihood_type_ == PARAM_LOGNORMAL && value <= 0.0) { LOG_ERROR_P(PARAM_ERROR_VALUES) << ": error_value (" << AS_DOUBLE(value) << ") cannot be equal to or less than 0.0"; } else if ((likelihood_type_ == PARAM_MULTINOMIAL && value < 0.0) || (likelihood_type_ == PARAM_DIRICHLET && value < 0.0)) { LOG_ERROR_P(PARAM_ERROR_VALUES) << ": error_value (" << AS_DOUBLE(value) << ") cannot be less than 0.0"; } error_values_by_year[year].push_back(value); } if (error_values_by_year[year].size() == 1) { error_values_by_year[year].assign(obs_expected - 1, error_values_by_year[year][0]); } if (error_values_by_year[year].size() != obs_expected - 1) LOG_CODE_ERROR() << "error_values_by_year_[year].size() (" << error_values_by_year[year].size() << ") != obs_expected - 1 (" << obs_expected -1 << ")"; } /** * Validate likelihood type */ if (likelihood_type_ != PARAM_LOGNORMAL && likelihood_type_ != PARAM_MULTINOMIAL && likelihood_type_ != PARAM_DIRICHLET) LOG_ERROR_P(PARAM_LIKELIHOOD) << ": likelihood " << likelihood_type_ << " is not supported by the proportions at age observation. " << "Supported types are " << PARAM_LOGNORMAL << ", " << PARAM_MULTINOMIAL << " and " << PARAM_DIRICHLET; /** * Build our proportions and error values for use in the observation * If the proportions for a given observation do not sum to 1.0 * and is off by more than the tolerance rescale them. */ Double value = 0.0; for (auto iter = obs_by_year.begin(); iter != obs_by_year.end(); ++iter) { for (unsigned i = 0; i < category_labels_.size(); ++i) { for (unsigned j = 0; j < age_spread_; ++j) { unsigned obs_index = i * age_spread_ + j; if (!utilities::To<Double>(iter->second[obs_index], value)) LOG_ERROR_P(PARAM_OBS) << ": obs_ value (" << iter->second[obs_index] << ") at index " << obs_index + 1 << " in the definition could not be converted to a numeric double"; Double error_value = error_values_by_year[iter->first][obs_index]; error_values_[iter->first][category_labels_[i]].push_back(error_value); proportions_[iter->first][category_labels_[i]].push_back(value); } } } }
void Partition_YearCrossAgeMatrix::DoExecute() { //cerr << "execute " << label_ << "\n"; // First, figure out the lowest and highest ages/length unsigned lowest = 9999; unsigned highest = 0; unsigned longest_length = 0; niwa::partition::accessors::All all_view(model_); for (auto iterator = all_view.Begin(); iterator != all_view.End(); ++iterator) { if (lowest > (*iterator)->min_age_) lowest = (*iterator)->min_age_; if (highest < (*iterator)->max_age_) highest = (*iterator)->max_age_; if (longest_length < (*iterator)->name_.length()) longest_length = (*iterator)->name_.length(); } const char separator = ' '; //const int nameWidth = 6; const int numWidth = 13; //cache_ << std::setprecision(5); for (auto iterator = all_view.Begin(); iterator != all_view.End(); ++iterator) { //cache_ << (*iterator)->name_; cache_ << std::left << std::setw(numWidth) << std::setfill(separator) << std::setprecision(1) << std::fixed << model_->current_year(); unsigned age = (*iterator)->min_age_; //unsigned year = (*iterator)->year_; //cout << "The year at this stage is " << year << endl; for (auto values = (*iterator)->data_.begin(); values != (*iterator)->data_.end(); ++values, age++) { if (age >= lowest && age <= highest) { Double value = *values; //cache_ << "\t" << std::fixed << AS_DOUBLE(value); cache_ << std::left << std::setw(numWidth) << std::setfill(separator) << std::setprecision(0) << std::fixed << AS_DOUBLE(value); } else cache_ << " " << "null"; } cache_ << "\n"; } // ready_for_writing_ = true; ready_for_writing_ = false; }
/** * Validate our Maturation Rate process * * - Check for the required parameters * - Assign variables from our parameters * - Verify the categories are real * - If proportions or selectivities only has 1 element specified * add more elements until they match number of categories * - Verify vector lengths are all the same * - Verify categories From->To have matching age ranges * - Check all proportions are between 0.0 and 1.0 */ void TransitionCategory::DoValidate() { LOG_TRACE(); from_category_names_ = model_->categories()->ExpandLabels(from_category_names_, parameters_.Get(PARAM_FROM)); to_category_names_ = model_->categories()->ExpandLabels(to_category_names_, parameters_.Get(PARAM_TO)); if (selectivity_names_.size() == 1) selectivity_names_.assign(from_category_names_.size(), selectivity_names_[0]); // Validate Categories auto categories = model_->categories(); for (const string& label : from_category_names_) { if (!categories->IsValid(label)) LOG_ERROR_P(PARAM_FROM) << ": category " << label << " does not exist. Have you defined it?"; } for(const string& label : to_category_names_) { if (!categories->IsValid(label)) LOG_ERROR_P(PARAM_TO) << ": category " << label << " does not exist. Have you defined it?"; } // Validate the from and to vectors are the same size if (from_category_names_.size() != to_category_names_.size()) { LOG_ERROR_P(PARAM_TO) << ": Number of 'to' categories provided does not match the number of 'from' categories provided." << " Expected " << from_category_names_.size() << " but got " << to_category_names_.size(); } // Allow a one to many relationship between proportions and number of categories. if (proportions_.size() == 1) proportions_.resize(to_category_names_.size(),proportions_[0]); // Validate the to category and proportions vectors are the same size if (to_category_names_.size() != proportions_.size()) { LOG_ERROR_P(PARAM_PROPORTIONS) << ": Number of proportions provided does not match the number of 'to' categories provided." << " Expected " << to_category_names_.size() << " but got " << proportions_.size(); } // Validate the number of selectivities matches the number of proportions if (proportions_.size() != selectivity_names_.size() && proportions_.size() != 1) { LOG_ERROR_P(PARAM_SELECTIVITIES) << ": Number of selectivities provided does not match the number of proportions provided." << " Expected " << proportions_.size() << " but got " << selectivity_names_.size(); } // Validate that each from and to category have the same age range. for (unsigned i = 0; i < from_category_names_.size(); ++i) { if (categories->min_age(from_category_names_[i]) != categories->min_age(to_category_names_[i])) { LOG_ERROR_P(PARAM_FROM) << ": Category " << from_category_names_[i] << " does not" << " have the same age range as the 'to' category " << to_category_names_[i]; } if (categories->max_age(from_category_names_[i]) != categories->max_age(to_category_names_[i])) { LOG_ERROR_P(PARAM_FROM) << ": Category " << from_category_names_[i] << " does not" << " have the same age range as the 'to' category " << to_category_names_[i]; } } // Validate the proportions are between 0.0 and 1.0 for (Double proportion : proportions_) { if (proportion < 0.0 || proportion > 1.0) LOG_ERROR_P(PARAM_PROPORTIONS) << ": proportion " << AS_DOUBLE(proportion) << " must be between 0.0 and 1.0 (inclusive)"; } for (unsigned i = 0; i < from_category_names_.size(); ++i) proportions_by_category_[from_category_names_[i]] = proportions_[i]; }
/** * Execute/Run/Process the object. */ void ObjectiveFunction::Execute() { niwa::ObjectiveFunction& obj = model_->objective_function(); if (abs(AS_DOUBLE(value_) - AS_DOUBLE(obj.score())) > 1e-9) LOG_ERROR() << "Assert Failure: Objective Function had actual value " << obj.score() << " when we expected " << value_ << " with difference: " << abs(AS_DOUBLE(value_) - AS_DOUBLE(obj.score())); }
/** * Calculate our score for the current run */ void ObjectiveFunction::CalculateScore() { LOG_TRACE(); Clear(); /** * Get the scores from each of the observations/likelihoods */ vector<Observation*> observations = model_->managers().observation()->objects(); likelihoods_ = 0.0; for(auto observation : observations) { const map<unsigned, Double>& scores = observation->scores(); bool append_age = scores.size() > 1 ? true : false; for(auto iter = scores.begin(); iter != scores.end(); ++iter) { objective::Score new_score; new_score.label_ = PARAM_OBSERVATION + string("->") + observation->label(); if (append_age) new_score.label_ += string("-") + utilities::ToInline<unsigned, string>(iter->first); new_score.score_ = iter->second; score_list_.push_back(new_score); score_ += new_score.score_; likelihoods_ += AS_DOUBLE(new_score.score_); } } /** * Get the scores from each of the penalties */ penalties_ = 0.0; for (auto penalty : model_->managers().penalty()->objects()) { if (penalty->has_score()) { objective::Score new_score; new_score.label_ = PARAM_PENALTY + string("->") + penalty->label(); new_score.score_ = penalty->GetScore(); score_list_.push_back(new_score); score_ += new_score.score_; penalties_ += AS_DOUBLE(new_score.score_); } } /** * Go through the flagged penalties */ const vector<penalties::Info>& penalties = model_->managers().penalty()->flagged_penalties(); for (penalties::Info penalty : penalties) { objective::Score new_score; new_score.label_ = PARAM_PENALTY + string("->") + penalty.label_; new_score.score_ = penalty.score_; score_list_.push_back(new_score); score_ += new_score.score_; penalties_ += AS_DOUBLE(new_score.score_); } /** * Get the scores from each of the estimate priors */ model_->managers().estimate_transformation()->TransformEstimatesForObjectiveFunction(); vector<Estimate*> estimates = model_->managers().estimate()->objects(); priors_ = 0.0; for (Estimate* estimate : estimates) { if (!estimate->in_objective_function()) continue; objective::Score new_score; if (estimate->label() != "") new_score.label_ = PARAM_PRIOR + string("->") + estimate->label() + "->" + estimate->parameter(); else new_score.label_ = PARAM_PRIOR + string("->") + estimate->parameter(); new_score.score_ = estimate->GetScore(); score_list_.push_back(new_score); score_ += new_score.score_; priors_ += AS_DOUBLE(new_score.score_); } model_->managers().estimate_transformation()->RestoreEstimatesFromObjectiveFunction(); /** * Get the score from each additional prior */ vector<AdditionalPrior*> additional_priors = model_->managers().additional_prior()->objects(); additional_priors_ = 0.0; for (auto prior : additional_priors) { objective::Score new_score; new_score.label_ = PARAM_ADDITIONAL_PRIOR + string("->") + prior->label(); new_score.score_ = prior->GetScore(); score_list_.push_back(new_score); score_ += new_score.score_; additional_priors_ += AS_DOUBLE(new_score.score_); } /** * Get the Jacobian score from estimate_transformations */ auto jacobians = model_->managers().estimate_transformation()->objects(); jacobians_ = 0.0; for (auto jacobian : jacobians) { objective::Score new_score; new_score.label_ = PARAM_JACOBIAN + string("->") + jacobian->label(); new_score.score_ = jacobian->GetScore(); score_list_.push_back(new_score); score_ += new_score.score_; jacobians_ += AS_DOUBLE(new_score.score_); } LOG_MEDIUM() << "objective.score: " << score_; }