4#include "qjsondocument.h"
6#include <gsl/gsl_cdf.h>
19 element_information_(),
20 element_distributions_(),
21 numberofconstituents_(0),
23 numberofsourcesamplesets_(0),
30 selected_target_sample_(),
37 regression_p_value_threshold_(0.05),
42 options_[
"Outlier deviation threshold"] = 3.0;
48 element_information_(other.element_information_),
49 element_distributions_(other.element_distributions_),
50 numberofconstituents_(other.numberofconstituents_),
51 numberofisotopes_(other.numberofisotopes_),
52 numberofsourcesamplesets_(other.numberofsourcesamplesets_),
53 observations_(other.observations_),
54 outputpath_(other.outputpath_),
55 parameters_(other.parameters_),
56 target_group_(other.target_group_),
57 samplesetsorder_(other.samplesetsorder_),
58 constituent_order_(other.constituent_order_),
59 selected_target_sample_(other.selected_target_sample_),
60 element_order_(other.element_order_),
61 isotope_order_(other.isotope_order_),
62 size_om_order_(other.size_om_order_),
63 parameter_estimation_mode_(other.parameter_estimation_mode_),
64 omconstituent_(other.omconstituent_),
65 sizeconsituent_(other.sizeconsituent_),
66 regression_p_value_threshold_(other.regression_p_value_threshold_),
67 distance_coeff_(other.distance_coeff_),
68 tools_used_(other.tools_used_),
69 options_(other.options_)
82 map<string, Elemental_Profile_Set>::operator=(other);
112 const string& target,
114 map<string, element_information>* elementinfo)
120 vector<double> om_size;
129 for (
auto& [group_name, profile_set] : *
this)
132 bool apply_corrections = (group_name !=
target_group_) && omnsizecorrect;
133 corrected[group_name] = profile_set.CopyIncludedInAnalysis(
151 if (elem_info.include_in_analysis &&
193 if (!exclude_elements) {
201 if (elem_info.include_in_analysis &&
214 bool exclude_samples,
215 bool exclude_elements,
217 const string& target)
const
223 if (!target.empty()) {
231 vector<double> om_size;
247 for (
const auto& [group_name, profile_set] : *
this)
252 corrected[group_name] = profile_set.CreateCorrectedSet(
263 corrected[group_name] = profile_set.CreateCorrectedSet(
293 for (
const auto& [group_name, profile_set] : *
this)
316 for (
const auto& [group_name, profile_set] : *
this)
320 extracted[group_name] = profile_set.ExtractElements(element_list);
375 std::cerr <<
"Sample set '" +
name +
"' already exists!" << std::endl;
382 return &operator[](
name);
388 if (count(
name) == 0) {
392 return &operator[](
name);
398 (count(group_name) > 0) ? &at(group_name) :
nullptr;
404 return vector<string>();
409 vector<string> group_names;
410 group_names.reserve(size());
412 for (
const auto& [group_name, profile_set] : *
this)
414 group_names.push_back(group_name);
423 return vector<string>();
428 if (first_group.empty()) {
429 return vector<string>();
434 vector<string> element_names;
435 element_names.reserve(first_sample.size());
437 for (
const auto& [element_name, concentration] : first_sample)
439 element_names.push_back(element_name);
442 return element_names;
446 const vector<vector<string>>& indicators)
const
450 extracted.
values.reserve(indicators.size());
453 for (
const auto& indicator : indicators)
455 const string& group_name = indicator[0];
456 const string& sample_name = indicator[1];
459 (count(group_name) > 0) ? &at(group_name) :
nullptr;
464 extracted.
values.push_back(concentrations);
473 const vector<vector<string>>& indicators)
const
477 for (
const auto& indicator : indicators)
479 const string& group_name = indicator[0];
480 const string& sample_name = indicator[1];
483 (count(group_name) > 0) ? &at(group_name) :
nullptr;
485 if (group && group->count(sample_name) > 0)
489 extracted.
AppendProfile(group_name +
"-" + sample_name, profile);
496 const string& element,
497 const string& group)
const
503 (count(group) > 0) ? &at(group) :
nullptr;
509 extracted.
values.reserve(profile_set->size());
512 for (
const auto& [sample_name, profile] : *profile_set)
514 extracted.
values.push_back(profile.GetValue(element));
527 for (
auto& [group_name, profile_set] : *
this)
530 profile_set.UpdateElementDistributions();
533 for (
const string& element : element_names)
536 profile_set.GetElementDistribution(element)
544 map<string, vector<double>> extracted;
547 for (
const string& group_name : group_names)
550 extracted[group_name] = group_data.
values;
561 for (
const string& element : element_names)
569 for (
auto& [group_name, profile_set] : *
this)
610 for (
const string& element : element_names)
612 if (ElementInfo ==
nullptr)
677 const string& targetsamplename,
687 std::cerr <<
"Data has not been loaded!" << std::endl;
703 for (
auto& [group_name, profile_set] : *
this)
708 p.
SetName(group_name +
"_contribution");
721 for (
auto& [group_name, profile_set] : *
this)
737 if (elem_info.include_in_analysis)
755 for (
auto& [group_name, profile_set] : *
this)
760 *profile_set.GetEstimatedDistribution(element_name) =
761 *profile_set.GetFittedDistribution(element_name);
772 for (
auto& [group_name, profile_set] : *
this)
776 *profile_set.GetEstimatedDistribution(element_name) =
777 *profile_set.GetFittedDistribution(element_name);
792 for (
auto& [group_name, profile_set] : *
this)
797 p.
SetName(group_name +
"_" + element_name +
"_mu");
801 profile_set.GetEstimatedDistribution(element_name)->SetType(
806 const Distribution* fitted = profile_set.GetFittedDistribution(element_name);
820 for (
auto& [group_name, profile_set] : *
this)
825 p.
SetName(group_name +
"_" + element_name +
"_mu");
829 profile_set.GetEstimatedDistribution(element_name)->SetType(
834 const Distribution* fitted = profile_set.GetFittedDistribution(element_name);
848 for (
auto& [group_name, profile_set] : *
this)
853 p.
SetName(group_name +
"_" + element_name +
"_sigma");
857 const Distribution* fitted = profile_set.GetFittedDistribution(element_name);
858 double lower = std::max(fitted->
parameters[1] * 0.8, 0.001);
859 double upper = std::max(fitted->
parameters[1] / 0.8, 2.0);
873 for (
auto& [group_name, profile_set] : *
this)
878 p.
SetName(group_name +
"_" + element_name +
"_sigma");
882 const Distribution* fitted = profile_set.GetFittedDistribution(element_name);
883 double lower = std::max(fitted->
parameters[1] * 0.8, 0.001);
884 double upper = std::max(fitted->
parameters[1] / 0.8, 2.0);
900 error_param.
SetName(
"Error STDev");
911 obs.
SetName(targetsamplename +
"_" + element_name);
919 error_param_isotope.
SetName(
"Error STDev for isotopes");
921 error_param_isotope.
SetRange(0.01, 0.1);
930 obs.
SetName(targetsamplename +
"_" + element_name);
943 CVector contributions(size()-1);
944 for (
unsigned long int i=0; i<size()-2; i++)
948 contributions[size()-2] = 1 - contributions.sum();
949 return contributions;
963 double logLikelihood = 0;
964 for (
unsigned int element_counter=0; element_counter<
element_order_.size(); element_counter++)
971 for (map<string,Elemental_Profile>::iterator sample = this_source_group->begin(); sample!=this_source_group->end(); sample++)
978 return logLikelihood;
990 return observed_data;
1003 return observed_data;
1016 return observed_data;
1028 CVector predicted_concentrations =
PredictTarget(param_mode);
1032 if (predicted_concentrations.min() <= 0)
1039 const double num_elements = predicted_concentrations.num;
1042 CVector log_residuals = predicted_concentrations.Log() - observed_concentrations.Log();
1043 const double sum_squared_residuals = pow(log_residuals.norm2(), 2);
1044 const double variance_term = 2.0 * pow(
error_stdev_, 2);
1046 double log_likelihood = -normalization_term - (sum_squared_residuals / variance_term);
1048 return log_likelihood;
1064 const double num_isotopes = predicted_deltas.num;
1067 CVector residuals = predicted_deltas - observed_deltas;
1068 const double sum_squared_residuals = pow(residuals.norm2(), 2);
1071 double log_likelihood = -normalization_term - (sum_squared_residuals / variance_term);
1073 return log_likelihood;
1084 if (!predicted_concentrations.is_finite())
1086 qDebug() <<
"Warning: Non-finite predicted concentrations detected in ResidualVector()";
1095 CVector elemental_residuals = predicted_concentrations.Log() - observed_concentrations.Log();
1098 CVector isotopic_residuals = predicted_deltas - observed_deltas;
1101 CVector combined_residuals = elemental_residuals;
1102 combined_residuals.append(isotopic_residuals);
1112 return combined_residuals;
1118 CVector_arma predicted_concentrations =
PredictTarget().vec;
1127 CVector_arma elemental_residuals = predicted_concentrations.Log() - observed_concentrations.Log();
1130 CVector_arma isotopic_residuals = predicted_deltas - observed_deltas;
1133 CVector_arma combined_residuals = elemental_residuals;
1134 combined_residuals.append(isotopic_residuals);
1136 return combined_residuals;
1143 const size_t num_parameters = num_sources - 1;
1146 CMatrix_arma jacobian(num_parameters, num_residuals);
1153 for (
unsigned int i = 0; i < num_parameters; i++)
1156 const double epsilon = (0.5 - base_contributions[i]) * 1e-6;
1163 jacobian.setcol(i, (perturbed_residuals - base_residuals) / epsilon);
1175 const size_t num_parameters = num_sources - 1;
1178 CMatrix jacobian(num_parameters, num_residuals);
1185 for (
unsigned int i = 0; i < num_parameters; i++)
1188 const double epsilon = (0.5 - base_contributions[i]) * 1e-3;
1195 jacobian.setrow(i, (perturbed_residuals - base_residuals) / epsilon);
1209 CMatrix jacobian(num_sources, num_residuals);
1216 for (
unsigned int i = 0; i < num_sources; i++)
1219 const double epsilon = -sign(base_softmax_params[i]) * 1e-3;
1222 CVector perturbed_params = base_softmax_params;
1223 perturbed_params[i] += epsilon;
1229 jacobian.setrow(i, (perturbed_residuals - base_residuals) / epsilon);
1245 CMatrix jacobian_transpose_jacobian = jacobian * Transpose(jacobian);
1248 jacobian_transpose_jacobian.ScaleDiagonal(1.0 + lambda);
1251 CVector jacobian_times_residuals = jacobian * residuals;
1254 if (det(jacobian_transpose_jacobian) <= 1e-6)
1257 const size_t matrix_size = jacobian_transpose_jacobian.getnumcols();
1258 CMatrix identity = CMatrix::Diag(matrix_size);
1259 jacobian_transpose_jacobian += lambda * identity;
1263 CVector parameter_update = jacobian_times_residuals / jacobian_transpose_jacobian;
1265 return parameter_update;
1275 CMatrix jacobian_transpose_jacobian = jacobian * Transpose(jacobian);
1278 jacobian_transpose_jacobian.ScaleDiagonal(1.0 + lambda);
1281 CVector jacobian_times_residuals = jacobian * residuals;
1284 if (det(jacobian_transpose_jacobian) <= 1e-6)
1287 const size_t matrix_size = jacobian_transpose_jacobian.getnumcols();
1288 CMatrix identity = CMatrix::Diag(matrix_size);
1289 jacobian_transpose_jacobian += lambda * identity;
1293 CVector parameter_update = jacobian_times_residuals / jacobian_transpose_jacobian;
1295 return parameter_update;
1307 const double tolerance = 1e-10;
1308 const int max_iterations = 1000;
1309 const double improvement_threshold = 0.8;
1310 const double lambda_decrease_factor = 1.2;
1311 const double lambda_increase_factor = 1.2;
1312 const double lambda_no_update_factor = 5.0;
1315 double lambda = 1.0;
1317 double previous_error = 1000.0;
1318 double initial_param_change = 10000.0;
1319 double current_param_change = 10000.0;
1323 while (current_error > tolerance &&
1324 current_param_change > tolerance &&
1325 iteration < max_iterations)
1328 CVector current_params;
1334 previous_error = current_error;
1337 CVector parameter_update;
1344 if (parameter_update.num == 0)
1346 lambda *= lambda_no_update_factor;
1351 current_param_change = parameter_update.norm2();
1353 initial_param_change = current_param_change;
1356 CVector updated_params = current_params - parameter_update;
1364 current_error = residuals.norm2();
1367 if (current_error < previous_error * improvement_threshold)
1370 lambda /= lambda_decrease_factor;
1372 else if (current_error > previous_error)
1375 lambda *= lambda_increase_factor;
1383 current_error = previous_error;
1408 CVector predicted_concentrations = source_mean_matrix * contribution_vector;
1416 return predicted_concentrations;
1424 CVector predicted_isotope_concentrations = source_isotope_matrix * contribution_vector;
1426 return predicted_isotope_concentrations;
1438 double predicted_corresponding_element_concentration = C_elements[lookup(
element_order_,corresponding_element)];
1439 double ratio = C[i]/predicted_corresponding_element_concentration;
1441 C[i] = (ratio/standard_ratio-1.0)*1000.0;
1459 double source_data_log_likelihood = 0.0;
1460 double element_observation_log_likelihood = 0.0;
1461 double isotope_observation_log_likelihood = 0.0;
1484 double total_log_likelihood = source_data_log_likelihood +
1485 element_observation_log_likelihood +
1486 isotope_observation_log_likelihood +
1487 contribution_log_prior;
1489 return total_log_likelihood;
1499 CMatrix source_means(num_elements, num_sources);
1502 for (
size_t element_idx = 0; element_idx < num_elements; element_idx++)
1506 for (
size_t source_idx = 0; source_idx < num_sources; source_idx++)
1518 source_means[element_idx][source_idx] = element_dist->
Mean();
1522 source_means[element_idx][source_idx] = element_dist->
DataMean();
1527 return source_means;
1537 CMatrix source_isotope_means(num_isotopes, num_sources);
1540 for (
size_t isotope_idx = 0; isotope_idx < num_isotopes; isotope_idx++)
1544 const string& base_element = isotope_info.
base_element;
1547 for (
size_t source_idx = 0; source_idx < num_sources; source_idx++)
1558 double mean_base_concentration;
1562 mean_delta = isotope_dist->
Mean();
1563 mean_base_concentration = base_element_dist->
Mean();
1567 mean_delta = isotope_dist->
DataMean();
1568 mean_base_concentration = base_element_dist->
DataMean();
1573 double delta_ratio = (mean_delta / 1000.0) + 1.0;
1574 double absolute_isotope_concentration = delta_ratio * standard_ratio * mean_base_concentration;
1576 source_isotope_means[isotope_idx][source_idx] = absolute_isotope_concentration;
1580 return source_isotope_means;
1586 const size_t num_contributions = include_all ?
1590 CVector contributions(num_contributions);
1593 for (
size_t source_idx = 0; source_idx < num_contributions; source_idx++)
1600 return contributions;
1606 CVector softmax_parameters(num_sources);
1609 for (
size_t source_idx = 0; source_idx < num_sources; source_idx++)
1616 return softmax_parameters;
1634 double constrained_contribution = 1.0 - sum_of_independent;
1649 for (
size_t i = 0; i < static_cast<size_t>(contributions.num); i++)
1655 if (contributions.min() < 0.0) {
1656 std::cerr <<
"Warning: Negative contribution detected in SetContribution()" << std::endl;
1657 std::cerr <<
" Min value: " << contributions.min() << std::endl;
1664 double denominator = 0.0;
1665 for (
size_t i = 0; i < static_cast<size_t>(softmax_params.num); i++)
1667 denominator += exp(softmax_params[i]);
1671 for (
size_t i = 0; i < static_cast<size_t>(softmax_params.num); i++)
1673 double softmax_param = softmax_params.at(i);
1674 double contribution = exp(softmax_param) / denominator;
1683 if (resulting_contributions.min() < 0.0) {
1684 std::cerr <<
"Warning: Invalid contributions after softmax transformation" << std::endl;
1685 std::cerr <<
" Min contribution: " << resulting_contributions.min() << std::endl;
1686 std::cerr <<
" This should not happen with softmax - check for numerical issues" << std::endl;
1691 size_t element_index,
1692 size_t source_index)
1698 const size_t num_contribution_params = size() - 1;
1699 const size_t element_mu_base_index = num_contribution_params;
1703 const size_t parameter_index = element_mu_base_index +
1709 std::cerr <<
"Error: Parameter index out of bounds in GetElementDistributionMuParameter" << std::endl;
1717 size_t element_index,
1718 size_t source_index)
1725 const size_t num_contribution_params = size() - 1;
1727 const size_t element_sigma_base_index = num_contribution_params + num_element_mu_params;
1730 const size_t parameter_index = element_sigma_base_index +
1736 std::cerr <<
"Error: Parameter index out of bounds in GetElementDistributionSigmaParameter" << std::endl;
1744 size_t element_index,
1745 size_t source_index)
1749 if (mu_param ==
nullptr) {
1750 std::cerr <<
"Warning: Unable to retrieve μ parameter for element "
1751 << element_index <<
", source " << source_index << std::endl;
1755 return mu_param->
Value();
1759 size_t element_index,
1760 size_t source_index)
1764 if (sigma_param ==
nullptr) {
1765 std::cerr <<
"Warning: Unable to retrieve σ parameter for element "
1766 << element_index <<
", source " << source_index << std::endl;
1770 return sigma_param->
Value();
1781 const bool estimating_contributions =
1783 const bool estimating_profiles =
1790 const size_t num_element_sigma_params = num_element_mu_params;
1791 const size_t num_isotope_sigma_params = num_isotope_mu_params;
1797 if (estimating_contributions && index < num_contribution_params)
1811 size_t element_mu_start = num_contribution_params;
1812 size_t element_mu_end = element_mu_start + num_element_mu_params;
1814 if (estimating_profiles &&
1816 index >= element_mu_start && index < element_mu_end)
1818 size_t offset = index - element_mu_start;
1829 size_t isotope_mu_start = element_mu_end;
1830 size_t isotope_mu_end = isotope_mu_start + num_isotope_mu_params;
1832 if (estimating_profiles &&
1834 index >= isotope_mu_start && index < isotope_mu_end)
1836 size_t offset = index - isotope_mu_start;
1847 size_t element_sigma_start = isotope_mu_end;
1848 size_t element_sigma_end = element_sigma_start + num_element_sigma_params;
1850 if (estimating_profiles &&
1852 index >= element_sigma_start && index < element_sigma_end)
1855 std::cerr <<
"Error: Element σ parameter cannot be negative (value = "
1856 << value <<
")" << std::endl;
1860 size_t offset = index - element_sigma_start;
1871 size_t isotope_sigma_start = element_sigma_end;
1872 size_t isotope_sigma_end = isotope_sigma_start + num_isotope_sigma_params;
1874 if (estimating_profiles &&
1876 index >= isotope_sigma_start && index < isotope_sigma_end)
1879 std::cerr <<
"Error: Isotope σ parameter cannot be negative (value = "
1880 << value <<
")" << std::endl;
1884 size_t offset = index - isotope_sigma_start;
1895 size_t error_element_index = isotope_sigma_end;
1897 if (estimating_contributions && index == error_element_index)
1900 std::cerr <<
"Error: Element error std dev cannot be negative (value = "
1901 << value <<
")" << std::endl;
1910 size_t error_isotope_index = error_element_index + 1;
1912 if (estimating_contributions && index == error_isotope_index)
1915 std::cerr <<
"Error: Isotope error std dev cannot be negative (value = "
1916 << value <<
")" << std::endl;
1925 std::cerr <<
"Warning: Parameter index " << index <<
" not recognized" << std::endl;
1936 bool all_successful =
true;
1939 for (
size_t i = 0; i < static_cast<size_t>(values.num); i++)
1942 all_successful &= success;
1947 return all_successful;
1960 return parameter_values;
1965 CVector gradient(parameters.num);
1966 CVector perturbed_params = parameters;
1973 for (
size_t i = 0; i < static_cast<size_t>(parameters.num); i++)
1983 gradient[i] = (perturbed_log_likelihood - baseline_log_likelihood) /
epsilon_;
1986 perturbed_params[i] = parameters[i];
1990 return gradient / gradient.norm2();
2000 CVector gradient_direction =
Gradient(current_params, est_mode);
2003 CVector candidate_step1 = current_params +
distance_coeff_ * gradient_direction;
2007 CVector candidate_step2 = current_params + 2.0 *
distance_coeff_ * gradient_direction;
2012 std::cout <<
"Distance Coefficient: " <<
distance_coeff_ << std::endl;
2020 if (likelihood_step2 > likelihood_step1 && likelihood_step2 > baseline_likelihood)
2024 return candidate_step2;
2028 else if (likelihood_step1 > likelihood_step2 && likelihood_step1 > baseline_likelihood)
2032 return candidate_step1;
2038 const int max_backtrack_iterations = 5;
2039 int backtrack_count = 0;
2042 while (baseline_likelihood >= likelihood_step1 && backtrack_count < max_backtrack_iterations)
2046 candidate_step1 = current_params +
distance_coeff_ * gradient_direction;
2053 if (backtrack_count < max_backtrack_iterations)
2057 return candidate_step1;
2062 std::cerr <<
"Warning: No improvement found after " << max_backtrack_iterations
2063 <<
" backtracking iterations" << std::endl;
2065 return current_params;
2099 elem_info.include_in_analysis)
2128 elem_info.include_in_analysis)
2138 elem_info.include_in_analysis)
2164 vector<string> source_names;
2167 for (
const auto& [group_name, profile_set] : *
this)
2171 source_names.push_back(group_name);
2175 return source_names;
2181 for (
auto& [group_name, profile_set] : *
this)
2184 for (
const auto& [profile_name, profile] : profile_set)
2186 if (profile_name == sample_name)
2189 return profile_set.GetProfile(profile_name);
2207 for (
size_t i = 0; i < source_order.size(); i++)
2209 (*contributions)[source_order[i]] = contribution_values[i];
2213 result.
SetName(
"Contributions");
2226 CVector predicted_concentrations =
PredictTarget(param_mode);
2230 for (
size_t i = 0; i < element_names.size(); i++)
2232 predicted_profile->
AppendElement(element_names[i], predicted_concentrations[i]);
2236 result.
SetName(
"Modeled Elemental Profile");
2246 CVector predicted_values(num_observations);
2249 for (
size_t i = 0; i < num_observations; i++)
2254 return predicted_values;
2267 for (
size_t i = 0; i < isotope_names.size(); i++)
2269 predicted_isotopes->
AppendElement(isotope_names[i], predicted_delta_values[i]);
2273 result.
SetName(
"Modeled Elemental Profile for Isotopes");
2298 result.
SetName(
"Observed vs Modeled Elemental Profile");
2307 vector<ResultItem> mlr_results;
2310 for (
auto& [group_name, profile_set] : *
this)
2313 ResultItem regression_result = profile_set.GetRegressionsAsResult();
2317 regression_result.
SetName(
"OM & Size MLR for " + group_name);
2319 mlr_results.push_back(regression_result);
2343 result.
SetName(
"Observed vs Modeled Elemental Profile for Isotopes");
2360 for (
size_t i = 0; i < element_names.size(); i++)
2362 observed_profile->
AppendElement(element_names[i], observed_concentrations[i]);
2366 result.
SetName(
"Observed Elemental Profile");
2383 for (
size_t i = 0; i < isotope_names.size(); i++)
2385 observed_isotopes->
AppendElement(isotope_names[i], observed_delta_values[i]);
2389 result.
SetName(
"Observed Elemental Profile for Isotopes");
2400 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2405 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2414 resitem.
SetName(
"Calculated mean elemental contents");
2424 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2429 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2441 resitem.
SetName(
"Calculated elemental contents standard deviations");
2450 vector<ResultItem> source_profile_results;
2453 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2460 result_item.
SetName(
"Elemental Profiles for " + it->first);
2468 *profile_set = it->second;
2471 source_profile_results.push_back(result_item);
2475 return source_profile_results;
2483 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2488 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2497 resitem.
SetName(
"Calculated mu parameter of elemental contents");
2507 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2512 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2521 resitem.
SetName(
"Infered mu parameter elemental contents");
2531 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2536 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2538 double sigma = it->second.GetElementDistribution(
element_order_[element_counter])->GetEstimatedSigma();
2539 double mu = it->second.GetElementDistribution(
element_order_[element_counter])->GetEstimatedMu();
2547 resitem.
SetName(
"Infered mean of elemental contents");
2557 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2562 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2564 double sigma = it->second.GetElementDistribution(
element_order_[element_counter])->GetEstimatedSigma();
2572 resitem.
SetName(
"Infered sigma parameter");
2582 QJsonArray tools_used_json_array;
2587 tools_used_json_array.append(QString::fromStdString(*it));
2590 return tools_used_json_array;
2595 QJsonObject json_object;
2598 for (QMap<QString, double>::const_iterator it =
options_.cbegin(); it !=
options_.cend(); it++)
2600 json_object[it.key()] = it.value();
2618 foreach (
const QJsonValue& value, jsonarray)
2632 for (QString key : jsonobject.keys())
2635 elem_info.
Role =
Role(jsonobject[key].toObject()[
"Role"].toString());
2636 elem_info.
standard_ratio = jsonobject[key].toObject()[
"Standard Ratio"].toDouble();
2637 elem_info.
base_element = jsonobject[key].toObject()[
"Base Element"].toString().toStdString();
2652 for (QString key : jsonobject.keys())
2665 for (QString key : jsonobject.keys())
2667 options_[key] = jsonobject[key].toDouble();
2675 QJsonObject json_object;
2678 for (map<string, Elemental_Profile_Set>::const_iterator it = cbegin(); it != cend(); it++)
2680 json_object[QString::fromStdString(it->first)] = it->second.toJsonObject();
2689 file->write(
"***\n");
2690 file->write(
"Elemental Profiles\n");
2693 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2695 file->write(
"**\n");
2696 file->write(QString::fromStdString(it->first +
"\n").toUtf8());
2697 it->second.writetofile(file);
2714 QJsonObject jsondoc = QJsonDocument().fromJson(fil->readAll()).object();
2721 target_group_ = jsondoc[
"Target Group"].toString().toStdString();
2728 QJsonObject json_object;
2733 QJsonObject elem_info_json_obj;
2734 elem_info_json_obj[
"Role"] =
Role(it->second.Role);
2735 elem_info_json_obj[
"Standard Ratio"] = it->second.standard_ratio;
2736 elem_info_json_obj[
"Base Element"] = QString::fromStdString(it->second.base_element);
2737 elem_info_json_obj[
"Include"] = it->second.include_in_analysis;
2739 json_object[QString::fromStdString(it->first)] = elem_info_json_obj;
2749 return "DoNotInclude";
2755 return "ParticleSize";
2760 return "DoNotInclude";
2766 if (role_string ==
"DoNotInclude")
2768 else if (role_string ==
"Element")
2770 else if (role_string ==
"Isotope")
2772 else if (role_string ==
"ParticleSize")
2774 else if (role_string ==
"OM")
2783 const string& particle_size,
2785 const double& p_value_threshold)
2793 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2795 it->second.SetRegressionModels(om, particle_size, form, p_value_threshold);
2804 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2809 it->second.DetectOutliers(lower_threshold, upper_threshold);
2819 const size_t num_sources = size() - 1;
2826 for (map<string, Elemental_Profile_Set>::iterator source = begin(); source != end(); source++)
2868 if (eigen_vector.
size() == 0)
2935 for (map<string, Elemental_Profile_Set>::const_iterator source_group = cbegin(); source_group != cend(); source_group++)
2940 count += source_group->second.size();
2950 CMBVector discriminant_scores(
operator[](source_group).size());
2953 size_t sample_index = 0;
2954 for (map<string, Elemental_Profile>::iterator sample =
operator[](source_group).begin();
2955 sample != operator[](source_group).end();
2959 discriminant_scores[sample_index] = sample->second.CalculateDotProduct(eigenvector);
2960 discriminant_scores.
SetLabel(sample_index, sample->first);
2965 return discriminant_scores;
2973 for (map<string, Elemental_Profile_Set>::iterator profile_set = begin();
2974 profile_set != end();
2978 if (profile_set->first != excluded_source && profile_set->first !=
target_group_)
2981 for (map<string, Elemental_Profile>::iterator profile = profile_set->second.begin();
2982 profile != profile_set->second.end();
2985 combined_sources.
AppendProfile(profile->first, profile->second);
2990 return combined_sources;
2997 const size_t num_elements = element_names.size();
3000 CMBVector bracket_test_results(num_elements);
3001 CVector exceeds_max(num_elements);
3002 CVector below_min(num_elements);
3004 exceeds_max.SetAllValues(1.0);
3005 below_min.SetAllValues(1.0);
3009 false,
false, correct_based_on_om_n_size, target_sample);
3012 for (map<string, Elemental_Profile_Set>::iterator it = corrected_data.begin();
3013 it != corrected_data.end();
3020 for (
size_t i = 0; i < num_elements; i++)
3022 bracket_test_results.
SetLabel(i, element_names[i]);
3024 double target_concentration = corrected_data.at(
target_group_)
3025 .GetProfile(target_sample)->at(element_names[i]);
3028 double source_minimum = it->second.GetElementDistribution(element_names[i])
3032 if (target_concentration <= source_maximum)
3036 if (target_concentration >= source_minimum)
3045 for (
size_t i = 0; i < num_elements; i++)
3048 bracket_test_results[i] = max(exceeds_max[i], below_min[i]);
3051 if (exceeds_max[i] > 0.5)
3054 element_names[i] +
" value is higher than the maximum of the sources");
3056 else if (below_min[i] > 0.5)
3059 element_names[i] +
" value is lower than the minimum of the sources");
3063 return bracket_test_results;
3068 bool correct_based_on_om_n_size,
3069 bool exclude_elements,
3070 bool exclude_samples)
3075 const size_t num_elements =
CountElements(exclude_elements);
3076 CMBMatrix bracket_results(num_target_samples, num_elements);
3079 size_t sample_index = 0;
3080 for (map<string, Elemental_Profile>::iterator sample = at(
target_group_).begin();
3086 if (correct_based_on_om_n_size)
3089 exclude_samples, exclude_elements,
true, sample->first);
3094 exclude_samples, exclude_elements,
false);
3102 for (
size_t element_index = 0; element_index < element_names.size(); element_index++)
3104 bracket_results[element_index][sample_index] = bracket_vector.
valueAt(element_index);
3105 bracket_results.
SetRowLabel(element_index, element_names[element_index]);
3112 return bracket_results;
3126 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
3131 if (calculate_optimal_lambda)
3134 transformed_data[it->first] = it->second.ApplyBoxCoxTransform(&lambda_parameters);
3139 transformed_data[it->first] = it->second.ApplyBoxCoxTransform();
3148 return transformed_data;
3153 map<string, ConcentrationSet> element_concentrations;
3157 for (
size_t i = 0; i < element_names.size(); i++)
3162 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
3168 for (map<string, Elemental_Profile>::iterator sample = it->second.begin();
3169 sample != it->second.end();
3172 concentration_set.
AppendValue(sample->second[element_names[i]]);
3177 element_concentrations[element_names[i]] = concentration_set;
3180 return element_concentrations;
3190 CMBVector lambda_parameters(element_names.size());
3192 for (
size_t i = 0; i < element_names.size(); i++)
3196 lambda_parameters[i] = concentration_sets[element_names[i]].FindOptimalBoxCoxParameter(-5, 5, 10);
3200 lambda_parameters.
SetLabels(element_names);
3202 return lambda_parameters;
3210 for (
size_t i = 0; i < element_names.size(); i++)
3213 ConcentrationSet concentration_set1 = *at(source1).GetElementDistribution(element_names[i]);
3214 ConcentrationSet concentration_set2 = *at(source2).GetElementDistribution(element_names[i]);
3217 double std1, std2, mean1, mean2;
3236 double standard_error = sqrt(pow(std1, 2) / concentration_set1.size() +
3237 pow(std2, 2) / concentration_set2.size());
3238 double t_statistic = (mean1 - mean2) / standard_error;
3241 size_t degrees_of_freedom = concentration_set1.size() + concentration_set2.size() - 2;
3242 double p_value_upper = gsl_cdf_tdist_Q(t_statistic, degrees_of_freedom);
3243 double p_value_lower = gsl_cdf_tdist_P(t_statistic, degrees_of_freedom);
3246 p_value_upper = min(p_value_upper, 1.0 - p_value_upper);
3247 p_value_lower = min(p_value_lower, 1.0 - p_value_lower);
3248 double p_value = p_value_upper + p_value_lower;
3262 for (
size_t i = 0; i < element_names.size(); i++)
3265 ConcentrationSet concentration_set1 = *at(source1).GetElementDistribution(element_names[i]);
3266 ConcentrationSet concentration_set2 = *at(source2).GetElementDistribution(element_names[i]);
3269 double std1, std2, mean1, mean2;
3288 double diff_power = 2.0 * fabs(mean1 - mean2) / (std1 + std2);
3290 differentiation_powers.
AppendElement(element_names[i], diff_power);
3293 return differentiation_powers;
3301 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3305 for (map<string, Elemental_Profile_Set>::iterator it2 = next(it); it2 != end(); it2++)
3310 all_pairs.
AppendProfile(it->first +
" and " + it2->first, diff_power);
3325 for (
size_t i = 0; i < element_names.size(); i++)
3328 ConcentrationSet concentration_set1 = *at(source1).GetElementDistribution(element_names[i]);
3329 ConcentrationSet concentration_set2 = *at(source2).GetElementDistribution(element_names[i]);
3333 combined_set.
AppendSet(concentration_set2);
3337 size_t n1 = concentration_set1.size();
3338 int set1_below_limit = aquiutils::CountLessThan(ranks, n1, n1,
false);
3339 int set1_above_limit = aquiutils::CountGreaterThan(ranks, n1, n1,
false);
3340 int set2_below_limit = aquiutils::CountLessThan(ranks, n1, n1,
true);
3341 int set2_above_limit = aquiutils::CountGreaterThan(ranks, n1, n1,
true);
3344 double set1_fraction = double(set1_below_limit + set2_above_limit) / double(combined_set.size());
3345 double set2_fraction = double(set1_above_limit + set2_below_limit) / double(combined_set.size());
3348 double classification_percentage = max(set1_fraction, set2_fraction);
3350 classification_percentages.
AppendElement(element_names[i], classification_percentage);
3353 return classification_percentages;
3361 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3365 for (map<string, Elemental_Profile_Set>::iterator it2 = next(it); it2 != end(); it2++)
3370 all_pairs.
AppendProfile(it->first +
" and " + it2->first, diff_power_pct);
3384 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3388 for (map<string, Elemental_Profile_Set>::iterator it2 = next(it); it2 != end(); it2++)
3393 all_pairs.
AppendProfile(it->first +
" and " + it2->first, p_values);
3404 vector<string> error_messages;
3410 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3412 vector<string> negative_elements = it->second.CheckForNegativeValues(
element_order_);
3415 for (
size_t i = 0; i < negative_elements.size(); i++)
3417 error_messages.push_back(
"There are zero or negative values for element '" +
3418 negative_elements[i] +
"' in sample group '" +
3423 return error_messages;
3433 it->second.include_in_analysis = include_in_analysis;
3439 double weighted_sum = 0.0;
3440 double total_count = 0.0;
3443 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3448 ConcentrationSet* element_dist = it->second.GetElementDistribution(element);
3449 size_t sample_count = element_dist->size();
3454 weighted_sum += element_dist->
CalculateMean() * sample_count;
3462 total_count += sample_count;
3467 return weighted_sum / total_count;
3475 for (map<string, Elemental_Profile_Set>::const_iterator it = begin(); it != prev(end()); it++)
3487 return combined_sources;
3493 CMBVector p_values(element_names.size());
3497 for (
size_t i = 0; i < element_names.size(); i++)
3500 p_values[i] = anova_result.
p_value;
3523 double sum_between = 0.0;
3524 double sum_within = 0.0;
3526 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
3527 source_group != end();
3532 ConcentrationSet* group_data = source_group->second.GetElementDistribution(element);
3534 size_t group_size = group_data->size();
3537 sum_between += pow(group_mean - grand_mean, 2) * group_size;
3544 anova.
SSB = sum_between;
3545 anova.
SSW = sum_within;
3553 size_t total_size = all_element_data->size();
3554 anova.
SST = pow(total_std_log, 2) * (total_size - 1);
3558 double sum_between = 0.0;
3559 double sum_within = 0.0;
3561 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
3562 source_group != end();
3567 ConcentrationSet* group_data = source_group->second.GetElementDistribution(element);
3569 size_t group_size = group_data->size();
3572 sum_between += pow(group_mean_log - grand_mean_log, 2) * group_size;
3579 anova.
SSB = sum_between;
3580 anova.
SSW = sum_within;
3584 size_t num_groups = this->size() - 1;
3585 size_t total_samples = all_element_data->size();
3588 size_t df_between = num_groups - 1;
3589 size_t df_within = total_samples - num_groups;
3592 anova.
MSB = anova.
SSB / double(df_between);
3593 anova.
MSW = anova.
SSW / double(df_within);
3596 anova.
F = anova.
MSB / anova.
MSW;
3599 anova.
p_value = gsl_cdf_fdist_Q(anova.
F, df_between, total_samples);
3610 element->second.include_in_analysis =
false;
3614 for (
size_t i = 0; i < elements.size(); i++)
3631 for (map<string, Elemental_Profile_Set>::const_iterator it = cbegin(); it != cend(); it++)
3636 reduced_dataset[it->first] = it->second.EliminateSamples(
3642 reduced_dataset[it->first] = it->second;
3656 return reduced_dataset;
3662 for (map<string, Elemental_Profile_Set>::const_iterator it = cbegin(); it != cend(); it++)
3664 if (it->second.count(sample_name) == 1)
3666 return it->second.at(sample_name);
3683 new_target_group.
AppendProfile(source_sample_name, target_profile);
3696 return modified_dataset;
3700 const double& percentage,
3701 unsigned int num_iterations,
3702 string target_sample,
3711 contribution_time_series.setname(source_idx,
samplesetsorder_[source_idx]);
3715 for (
size_t iteration = 0; iteration < num_iterations; iteration++)
3741 return contribution_time_series;
3746 const double& percentage,
3747 unsigned int num_iterations,
3748 string target_sample,
3761 for (
size_t iteration = 0; iteration < num_iterations; iteration++)
3789 results->
SetName(
"Error Analysis for target sample '" + target_sample +
"'");
3790 contributions_result.
SetName(
"Error Analysis");
3791 contributions_result.
SetResult(contributions);
3797 if (num_iterations < 101)
3811 results->
Append(contributions_result);
3815 *distributions = contributions->distribution(100, 0, 0);
3818 distributions_result.
SetName(
"Posterior Distributions");
3822 distributions_result.
SetResult(distributions);
3823 results->
Append(distributions_result);
3833 double percentile_2_5 = contributions->at(i).percentile(0.025);
3834 double percentile_97_5 = contributions->at(i).percentile(0.975);
3835 double mean_contribution = contributions->at(i).mean();
3836 double median_contribution = contributions->at(i).percentile(0.5);
3841 interval.
SetMean(mean_contribution);
3842 interval.
SetMedian(median_contribution);
3844 (*credible_intervals)[contributions->getSeriesName(i)] = interval;
3848 intervals_result.
SetName(
"Source Contribution Credible Intervals");
3852 intervals_result.
SetResult(credible_intervals);
3856 results->
Append(intervals_result);
3862 const string& source_group,
3864 bool apply_om_size_correction)
3879 size_t valid_sample_count = 0;
3880 for (map<string, Elemental_Profile>::iterator sample = at(source_group).begin();
3881 sample != at(source_group).end();
3895 if (negative_elements.size() == 0)
3903 rtw_->
SetProgress(
double(valid_sample_count) /
double(at(source_group).size()));
3918 validation_results.
SetLabel(valid_sample_count, sample->first);
3919 valid_sample_count++;
3924 for (
size_t i = 0; i < negative_elements.size(); i++)
3926 qDebug() << QString::fromStdString(negative_elements[i]);
3931 return validation_results;
3936 bool apply_om_size_correction,
3937 map<
string, vector<string>>& negative_elements)
3952 size_t valid_sample_count = 0;
3953 for (map<string, Elemental_Profile>::iterator sample = at(
target_group_).begin();
3958 if (sample->first !=
"")
3967 if (negative_elements[sample->first].size() == 0)
3984 contribution_results.
SetLabel(valid_sample_count, sample->first);
3985 valid_sample_count++;
3996 return contribution_results;
4002 vector<string> all_sample_names;
4005 for (map<string, Elemental_Profile_Set>::const_iterator profile_set = cbegin();
4006 profile_set != cend();
4013 for (map<string, Elemental_Profile>::const_iterator profile = profile_set->second.cbegin();
4014 profile != profile_set->second.cend();
4017 all_sample_names.push_back(profile->first);
4022 return all_sample_names;
4029 vector<string> selected_samples;
4032 for (
size_t i = 0; i < all_samples.size(); i++)
4038 if (random_value < percentage)
4040 selected_samples.push_back(all_samples[i]);
4044 return selected_samples;
4048 const string& target_sample,
4049 map<string, string> arguments,
4052 const string& working_folder)
4056 results.
SetName(
"MCMC results for '" + target_sample +
"'");
4059 bool apply_om_size_correction = (arguments[
"Apply size and organic matter correction"] ==
"true");
4066 if (negative_elements.size() > 0)
4069 results.
SetError(
"Negative elemental content in ");
4070 for (
size_t i = 0; i < negative_elements.size(); i++)
4081 mcmc->
Model = &corrected_data;
4084 progress_window->
SetTitle(
"Acceptance Rate", 0);
4085 progress_window->
SetTitle(
"Purturbation Factor", 1);
4086 progress_window->
SetTitle(
"Log posterior value", 2);
4090 progress_window->show();
4096 mcmc->
SetProperty(
"number_of_samples", arguments[
"Number of samples"]);
4097 mcmc->
SetProperty(
"number_of_chains", arguments[
"Number of chains"]);
4098 mcmc->
SetProperty(
"number_of_burnout_samples", arguments[
"Samples to be discarded (burnout)"]);
4099 mcmc->
SetProperty(
"dissolve_chains", arguments[
"Dissolve Chains"]);
4107 if (!QString::fromStdString(arguments[
"Samples File Name"]).contains(
"/"))
4109 output_path = working_folder +
"/";
4113 int num_chains = QString::fromStdString(arguments[
"Number of chains"]).toInt();
4114 int num_samples = QString::fromStdString(arguments[
"Number of samples"]).toInt();
4115 mcmc->
step(num_chains, num_samples, output_path + arguments[
"Samples File Name"],
4120 size_t last_source_idx = source_names.size() - 1;
4122 source_names[last_source_idx] +
"_contribution");
4128 mcmc_samples_result.
SetName(
"MCMC samples");
4130 results.
Append(mcmc_samples_result);
4133 int burnin_samples = QString::fromStdString(arguments[
"Samples to be discarded (burnout)"]).toInt();
4138 *posterior_distributions =
mcmc_samples->distribution(100, burnin_samples);
4140 posterior_distributions_result.
SetName(
"Posterior Distributions");
4144 posterior_distributions_result.
SetResult(posterior_distributions);
4145 results.
Append(posterior_distributions_result);
4150 for (
size_t i = 0; i < corrected_data.
GetSourceOrder().size(); i++)
4155 double percentile_2_5 =
mcmc_samples->at(i).percentile(0.025, burnin_samples);
4156 double percentile_97_5 =
mcmc_samples->at(i).percentile(0.975, burnin_samples);
4158 double median_contribution =
mcmc_samples->at(i).percentile(0.5, burnin_samples);
4162 interval.
SetMean(mean_contribution);
4163 interval.
SetMedian(median_contribution);
4165 (*contribution_credible_intervals)[
mcmc_samples->getSeriesName(i)] = interval;
4169 contribution_intervals_result.
SetName(
"Source Contribution Credible Intervals");
4173 contribution_intervals_result.
SetResult(contribution_credible_intervals);
4176 results.
Append(contribution_intervals_result);
4180 vector<string> element_names = corrected_data.
ElementOrder();
4181 vector<string> isotope_names = corrected_data.
IsotopeOrder();
4182 vector<string> all_constituent_names = element_names;
4183 all_constituent_names.insert(all_constituent_names.end(), isotope_names.begin(), isotope_names.end());
4186 for (
size_t i = 0; i < predicted_samples.size(); i++)
4188 predicted_samples.setname(i, all_constituent_names[i]);
4193 for (
size_t i = 0; i < predicted_samples.size(); i++)
4198 predicted_elements.append(predicted_samples[i], predicted_samples.getSeriesName(i));
4204 *predicted_element_distributions = predicted_elements.distribution(100, burnin_samples);
4207 for (
size_t i = 0; i < predicted_elements.size(); i++)
4213 predicted_elements_result.
SetName(
"Posterior Predicted Constituents");
4217 predicted_elements_result.
SetResult(predicted_element_distributions);
4218 results.
Append(predicted_elements_result);
4224 vector<double> percentile_2_5_all = predicted_samples.percentile(0.025, burnin_samples);
4225 vector<double> percentile_97_5_all = predicted_samples.percentile(0.975, burnin_samples);
4226 vector<double> mean_all = predicted_samples.mean(burnin_samples);
4227 vector<double> median_all = predicted_samples.percentile(0.5, burnin_samples);
4229 for (
size_t i = 0; i < predicted_element_distributions->size(); i++)
4234 interval.
SetMean(mean_all[i]);
4237 (*predicted_element_intervals)[predicted_element_distributions->getSeriesName(i)] = interval;
4238 (*predicted_element_intervals)[predicted_element_distributions->getSeriesName(i)].
SetValue(
4242 ResultItem predicted_element_intervals_result;
4243 predicted_element_intervals_result.
SetName(
"Predicted Samples Credible Intervals");
4247 predicted_element_intervals_result.
SetResult(predicted_element_intervals);
4249 results.
Append(predicted_element_intervals_result);
4254 for (
size_t i = 0; i < predicted_samples.size(); i++)
4259 predicted_isotopes.append(predicted_samples[i], predicted_samples.getSeriesName(i));
4264 *predicted_isotope_distributions = predicted_isotopes.distribution(100, burnin_samples);
4267 for (
size_t i = 0; i < predicted_isotopes.size(); i++)
4274 predicted_isotopes_result.
SetName(
"Posterior Predicted Isotopes");
4278 predicted_isotopes_result.
SetResult(predicted_isotope_distributions);
4279 results.
Append(predicted_isotopes_result);
4283 size_t element_offset = corrected_data.
ElementOrder().size();
4285 for (
size_t i = 0; i < predicted_isotope_distributions->size(); i++)
4288 interval.
Set(
_range::low, percentile_2_5_all[i + element_offset]);
4290 interval.
SetMean(mean_all[i + element_offset]);
4291 interval.
SetMedian(median_all[i + element_offset]);
4293 (*predicted_isotope_intervals)[predicted_isotope_distributions->getSeriesName(i)] = interval;
4294 (*predicted_isotope_intervals)[predicted_isotope_distributions->getSeriesName(i)].
SetValue(
4298 ResultItem predicted_isotope_intervals_result;
4299 predicted_isotope_intervals_result.
SetName(
"Predicted Samples Credible Intervals for Isotopes");
4303 predicted_isotope_intervals_result.
SetResult(predicted_isotope_intervals);
4305 results.
Append(predicted_isotope_intervals_result);
4315 map<string, string> arguments,
4318 const string& working_folder)
4326 CMBMatrix contribution_statistics(num_columns, num_target_samples);
4332 contribution_statistics.
SetColumnLabel(source_idx * 4, source_name +
"-low");
4333 contribution_statistics.
SetColumnLabel(source_idx * 4 + 1, source_name +
"-high");
4334 contribution_statistics.
SetColumnLabel(source_idx * 4 + 2, source_name +
"-median");
4335 contribution_statistics.
SetColumnLabel(source_idx * 4 + 3, source_name +
"-mean");
4339 size_t sample_counter = 0;
4340 for (map<string, Elemental_Profile>::iterator sample = at(
target_group_).begin();
4344 const string& sample_name = sample->first;
4347 QDir sample_dir(QString::fromStdString(working_folder) +
"/" + QString::fromStdString(sample_name));
4348 if (!sample_dir.exists())
4350 sample_dir.mkpath(
".");
4354 contribution_statistics.
SetRowLabel(sample_counter, sample_name);
4357 progress_window->
SetLabel(QString::fromStdString(sample_name));
4360 Results mcmc_results =
MCMC(sample_name, arguments, mcmc, progress_window, working_folder);
4363 for (map<string, ResultItem>::iterator result_item = mcmc_results.begin();
4364 result_item != mcmc_results.end();
4367 QString file_path = sample_dir.absolutePath() +
"/" +
4368 QString::fromStdString(result_item->first) +
".txt";
4369 QFile output_file(file_path);
4370 output_file.open(QIODevice::WriteOnly | QIODevice::Text);
4371 result_item->second.Result()->writetofile(&output_file);
4372 output_file.close();
4377 mcmc_results.at(
"3:Source Contribution Credible Intervals").Result());
4381 const string contribution_name =
samplesetsorder_[source_idx] +
"_contribution";
4382 const Range& contribution_interval = credible_intervals->at(contribution_name);
4385 contribution_statistics[sample_counter][4 * source_idx] = contribution_interval.
Get(
_range::low);
4386 contribution_statistics[sample_counter][4 * source_idx + 1] = contribution_interval.
Get(
_range::high);
4387 contribution_statistics[sample_counter][4 * source_idx + 2] = contribution_interval.
Median();
4388 contribution_statistics[sample_counter][4 * source_idx + 3] = contribution_interval.
Mean();
4394 progress_window->
SetProgress2(
double(sample_counter) / double(num_target_samples));
4405 return contribution_statistics;
4425 return element->first;
4442 return element->first;
4453 CMatrix within_group_covariance(element_names.size());
4456 int total_degrees_of_freedom = 0;
4457 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4458 source_group != end();
4464 int group_df = source_group->second.size() - 1;
4465 within_group_covariance += group_df * source_group->second.CalculateCovarianceMatrix();
4466 total_degrees_of_freedom += group_df;
4471 return within_group_covariance / double(total_degrees_of_freedom);
4477 CMatrix between_group_covariance(element_names.size());
4483 double total_samples = 0.0;
4484 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4485 source_group != end();
4492 CMBVector deviation = overall_mean - group_mean;
4495 size_t group_size = source_group->second.
size();
4496 for (
size_t i = 0; i < element_names.size(); i++)
4498 for (
size_t j = 0; j < element_names.size(); j++)
4500 between_group_covariance[i][j] += deviation[i] * deviation[j] * group_size;
4504 total_samples += group_size;
4509 return between_group_covariance / total_samples;
4515 CMatrix total_scatter(element_names.size());
4521 double total_samples = 0.0;
4522 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4523 source_group != end();
4529 for (map<string, Elemental_Profile>::iterator sample = source_group->second.begin();
4530 sample != source_group->second.end();
4534 for (
size_t i = 0; i < element_names.size(); i++)
4536 for (
size_t j = 0; j < element_names.size(); j++)
4538 double deviation_i = overall_mean[i] - sample->second.at(element_names[i]);
4539 double deviation_j = overall_mean[j] - sample->second.at(element_names[j]);
4540 total_scatter[i][j] += deviation_i * deviation_j;
4545 total_samples += source_group->second.
size();
4550 return total_scatter / total_samples;
4558 CMatrix_arma total_cov = within_group_cov + between_group_cov;
4561 double numerator = within_group_cov.det();
4562 double denominator = total_cov.det();
4565 return fabs(numerator) / fabs(denominator);
4578 double chi_squared = -(sample_size - 1.0 - correction_factor) *
log(wilks_lambda);
4581 double degrees_of_freedom;
4594 double p_value = gsl_cdf_chisq_Q(chi_squared, degrees_of_freedom);
4607 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4608 source_group != end();
4612 CMBVector group_scores = source_group->second.CalculateDotProduct(discriminant_function);
4613 projected_scores.
Append(source_group->first, group_scores);
4616 return projected_scores;
4628 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4629 source_group != end();
4633 CMBVector group_scores = source_group->second.CalculateDotProduct(discriminant_function);
4634 projected_scores.
Append(source_group->first, group_scores);
4637 return projected_scores;
4648 for (map<string, Elemental_Profile_Set>::iterator source_group = original->begin();
4649 source_group != original->end();
4656 CMBVector group_scores = source_group->second.CalculateDotProduct(discriminant_function);
4657 projected_scores.
Append(source_group->first, group_scores);
4661 return projected_scores;
4671 CMatrix_arma inv_within_cov = inv(within_group_cov);
4674 if (inv_within_cov.getnumrows() == 0)
4680 CMatrix_arma product_matrix = inv_within_cov * between_group_cov;
4683 arma::cx_vec eigenvalues;
4684 arma::cx_mat eigenvectors;
4685 eig_gen(eigenvalues, eigenvectors, product_matrix);
4688 CVector_arma real_eigenvalues = GetReal(eigenvalues);
4689 CMatrix_arma real_eigenvectors = GetReal(eigenvectors);
4692 size_t max_eigenvalue_index = real_eigenvalues.abs_max_elems();
4693 CMBVector discriminant_function = CVector_arma(real_eigenvectors.getcol(max_eigenvalue_index));
4697 discriminant_function.
SetLabels(element_names);
4699 return discriminant_function;
4705 CMatrix_arma cov_matrix1 = at(source1).CalculateCovarianceMatrix();
4706 CMatrix_arma cov_matrix2 = at(source2).CalculateCovarianceMatrix();
4709 CVector mean_vector1 = at(source1).CalculateElementMeans();
4710 CVector mean_vector2 = at(source2).CalculateElementMeans();
4711 CVector_arma mean1 = mean_vector1;
4712 CVector_arma mean2 = mean_vector2;
4715 CMatrix_arma pooled_cov = cov_matrix1 + cov_matrix2;
4716 CVector weight_vector_arma = (mean2 - mean1) / pooled_cov;
4719 CMBVector weight_vector = weight_vector_arma;
4720 weight_vector = weight_vector / weight_vector.norm2();
4725 return weight_vector;
4731 if (count(group_name) == 0)
4738 CMBVector group_mean = at(group_name).CalculateElementMeans();
4747 CMBVector weighted_mean(element_names.size());
4750 double total_samples = 0.0;
4751 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4752 source_group != end();
4759 size_t group_size = source_group->second.size();
4762 weighted_mean += double(group_size) * group_mean;
4763 total_samples += double(group_size);
4770 return weighted_mean / total_samples;
4774 const string& source1,
4775 const string& source2)
4778 vector<CMBVector> stepwise_results(3);
4781 vector<string> selected_elements;
4784 for (
size_t step = 0; step < element_names.size(); step++)
4793 double best_p_value = 100.0;
4794 string best_element;
4795 double best_wilks_lambda;
4796 double best_f_test_p_value;
4799 for (
size_t j = 0; j < element_names.size(); j++)
4802 if (lookup(selected_elements, element_names[j]) == -1)
4805 vector<string> candidate_elements = selected_elements;
4806 candidate_elements.push_back(element_names[j]);
4817 return stepwise_results;
4821 if (candidate_dfa.
p_values[0] < best_p_value)
4823 best_element = element_names[j];
4824 best_p_value = candidate_dfa.
p_values[0];
4832 stepwise_results[0].
append(best_element, best_p_value);
4833 stepwise_results[1].append(best_element, best_wilks_lambda);
4834 stepwise_results[2].append(best_element, best_f_test_p_value);
4837 selected_elements.push_back(best_element);
4840 return stepwise_results;
4846 vector<CMBVector> stepwise_results(3);
4849 vector<string> selected_elements;
4852 for (
size_t step = 0; step < element_names.size(); step++)
4861 double best_p_value = 100.0;
4862 string best_element;
4863 double best_wilks_lambda;
4864 double best_f_test_p_value;
4867 for (
size_t j = 0; j < element_names.size(); j++)
4870 if (lookup(selected_elements, element_names[j]) == -1)
4873 vector<string> candidate_elements = selected_elements;
4874 candidate_elements.push_back(element_names[j]);
4883 if (p_value < best_p_value)
4885 best_element = element_names[j];
4886 best_p_value = p_value;
4887 best_wilks_lambda = candidate_dataset.
WilksLambda();
4897 stepwise_results[0].append(best_element, best_p_value);
4898 stepwise_results[1].append(best_element, best_wilks_lambda);
4899 stepwise_results[2].append(best_element, best_f_test_p_value);
4902 selected_elements.push_back(best_element);
4905 return stepwise_results;
4911 vector<CMBVector> stepwise_results(3);
4914 vector<string> selected_elements;
4917 for (
size_t step = 0; step < element_names.size(); step++)
4926 double best_p_value = 100.0;
4927 string best_element;
4928 double best_wilks_lambda;
4929 double best_f_test_p_value;
4932 for (
size_t j = 0; j < element_names.size(); j++)
4935 if (lookup(selected_elements, element_names[j]) == -1)
4938 vector<string> candidate_elements = selected_elements;
4939 candidate_elements.push_back(element_names[j]);
4948 if (candidate_dfa.
p_values[0] < best_p_value)
4950 best_element = element_names[j];
4951 best_p_value = candidate_dfa.
p_values[0];
4959 stepwise_results[0].
append(best_element, best_p_value);
4960 stepwise_results[1].append(best_element, best_wilks_lambda);
4961 stepwise_results[2].append(best_element, best_f_test_p_value);
4964 selected_elements.push_back(best_element);
4967 return stepwise_results;
5067 cout <<
"Sample Group '" + sample_group +
"' does not exist!" << std::endl;
5072 cout <<
"Element '" + element_name +
"' does not exist!" << std::endl;
5120 if (_omsizeconstituents.size() == 0)
5122 else if (_omsizeconstituents.size() == 1)
5124 else if (_omsizeconstituents.size() == 2)
Matrix class with labeled rows and columns for Chemical Mass Balance analysis.
void SetRowLabel(int i, const string &label)
Sets row label at specified index.
void SetColumnLabel(int i, const string &label)
Sets column label at specified index.
Collection of time series with labels and observed values.
void SetLabel(unsigned int i, const string &label)
Sets custom label for time point.
void SetObservedValue(int i, const double &value)
Sets observed value for comparison at specified index.
void Append(const string &columnlabel, const CMBVectorSet &vectorset)
Adds or replaces a vector set in the collection.
Collection of named CMBVector objects for multi-variable analysis.
void Append(const string &columnlabel, const CMBVector &vectorset)
Adds or replaces a vector in the set.
double FTest_p_value() const
Computes F-test p-value for ANOVA.
Vector class with string labels for Chemical Mass Balance analysis.
void SetLabels(const vector< string > &label)
Sets all element labels at once.
void SetLabel(int i, const string &label)
Sets label at specified index.
int size() const
Gets number of elements in vector.
void append(const string &label, const double &val)
Appends a labeled element to the vector.
double valueAt(int i) const
Gets value at specified index.
Markov Chain Monte Carlo sampler for Bayesian parameter estimation.
CMBTimeSeriesSet predicted
Model predictions as time series set.
bool SetProperty(const string &varname, const string &value)
Set MCMC properties from string key-value pairs.
bool step(int k, int chain_counter)
Perform single MCMC step for one chain.
T * Model
Pointer to the model object being calibrated.
void initialize(CMBTimeSeriesSet *results, bool random=false)
Initialize MCMC chains with starting parameter values.
Manages a collection of concentration measurements with statistical analysis.
double CalculateSSE(double mean_value=-999) const
Calculate sum of squared errors from mean.
double CalculateMean() const
Calculate arithmetic mean.
Distribution * GetEstimatedDistribution()
Get estimated distribution (for MCMC optimization)
void SetEstimatedSigma(double value)
double CalculateStdDevLog(double mean_value=-999) const
Calculate standard deviation of log-transformed values.
vector< double > EstimateDistributionParameters(distribution_type dist_type=distribution_type::none)
Estimate distribution parameters from data.
double CalculateMeanLog() const
Calculate mean of log-transformed values.
void SetEstimatedMu(double value)
vector< unsigned int > CalculateRanks() const
Calculate ranks of values (1 = smallest)
double GetMaximum() const
Get maximum value.
void AppendSet(const ConcentrationSet &other)
Append all values from another set.
Distribution * GetFittedDistribution()
Get fitted distribution (from data)
void AppendValue(double value)
Append a single concentration value.
double CalculateSSELog(double mean_value=-999) const
Calculate sum of squared errors from log mean.
double CalculateStdDev(double mean_value=-999) const
Calculate standard deviation.
Source contribution container for Chemical Mass Balance results.
Represents a parametric probability distribution for uncertainty quantification.
vector< double > parameters
Distribution parameters vector.
double EvalLog(const double &x)
Evaluate natural logarithm of probability density.
double DataMean()
Get the stored empirical mean.
distribution_type distribution
The type of probability distribution.
double Mean(parameter_mode param_mode=parameter_mode::based_on_fitted_distribution)
Calculate the mean (expected value) of the distribution.
Manages a collection of elemental profiles (samples) for source fingerprinting analysis.
ConcentrationSet * GetElementDistribution(const string &element_name)
Get distribution for a specific element (mutable)
vector< string > GetSampleNames() const
Get all sample names in the set.
Elemental_Profile * AppendProfile(const string &name, const Elemental_Profile &profile=Elemental_Profile(), map< string, element_information > *elementinfo=nullptr)
Add a new sample profile to the set.
Distribution * GetEstimatedDistribution(const string &element_name)
Get estimated distribution for an element (for MCMC optimization)
void UpdateElementDistributions()
Rebuild element distributions from all profiles.
bool SetContributionSoftmax(const double &value)
Set softmax-transformed contribution.
vector< double > GetConcentrationsForSample(const string &sample_name) const
Get all element concentrations for a specific sample.
Elemental_Profile * GetProfile(const string &name)
Get profile by sample name (mutable)
bool ReadFromJsonObject(const QJsonObject &jsonobject) override
Deserialize object from JSON format.
bool SetContribution(const double &value)
Set contribution value for this source.
double GetContribution() const
Get contribution value.
double GetContributionSoftmax() const
Get softmax-transformed contribution.
void AppendProfiles(const Elemental_Profile_Set &profiles, map< string, element_information > *elementinfo)
Add multiple profiles from another set.
Container for elemental concentration data of a single sediment sample.
bool AppendElement(const string &name, double val=0.0)
Add new element to profile.
double GetValue(const string &name) const
Get element concentration by name.
static double GetRndUniF(double xmin, double xmax)
void SetName(const std::string &nam)
void SetPredictedValue(const double &value)
void AppendValues(const double &t, const double &val)
Represents a model parameter with prior distribution and constraints.
void SetPriorDistribution(distribution_type dist_type)
Set the type of prior probability distribution.
double Value() const
Get the current parameter value.
void SetRange(const vector< double > &rng)
Set the parameter range from a vector.
string Name() const
Get the parameter name.
void SetName(const string &nam)
Set the parameter name/identifier.
void SetProgress2(const double &prog)
void SetYAxisTitle(const QString &title, int chart=0)
void AppendPoint(const double &x, const double &y, int chart=0)
void SetXRange(const double &x0, const double &x1, int chart=0)
void SetProgress(const double &prog)
void ClearGraph(int chart=0)
void SetTitle(const QString &title, int chart=0)
void SetLabel(const QString &label)
void Set(_range lowhigh, const double &value)
void SetValue(const double value)
void SetMedian(const double &m)
void SetMean(const double &m)
double Get(_range lowhigh) const
void SetShowGraph(bool state)
void setYAxisTitle(const string &title)
void SetXAxisMode(xaxis_mode mode)
void SetYLimit(_range highlow, const double &value)
void SetName(const string &_name)
Interface * Result() const
void SetResult(Interface *_result)
void SetShowTable(bool state)
void setXAxisTitle(const string &title)
void SetYAxisMode(yaxis_mode mode)
void SetShowAsString(bool value)
void SetType(const result_type &_type)
void Append(const ResultItem &)
void SetError(const string &_error)
void AppendError(const string &_error)
void SetName(const string &_name)
Elemental_Profile * GetElementalProfile(const string &sample_name)
Finds and retrieves an elemental profile by sample name.
CMatrix BetweenGroupCovarianceMatrix()
Computes between-group covariance matrix.
vector< string > IsotopesToBeUsedInCMB()
Identifies isotopes to be used in CMB analysis.
profiles_data ExtractConcentrationData(const vector< vector< string > > &indicators) const
Extract concentration data for specified samples.
Parameter * GetElementDistributionSigmaParameter(size_t element_index, size_t source_index)
Retrieves pointer to the σ (std dev) parameter for an element distribution.
void AssignAllDistributions()
Assign distributions to all elements at both dataset and group levels.
vector< string > element_order_
string GetOutputPath() const
Get the output directory path.
bool InitializeParametersAndObservations(const string &targetsamplename, estimation_mode est_mode=estimation_mode::elemental_profile_and_contribution)
Initialize parameters and observations for MCMC optimization.
Elemental_Profile Sample(const string &sample_name) const
Retrieves an elemental profile by sample name.
QMap< QString, double > * GetOptions()
Retrieves pointer to the options map.
void SetProgressWindow(ProgressWindow *_rtw)
Sets the progress window for displaying optimization progress.
size_t ParametersCount()
Returns the number of parameters.
bool PerformRegressionVsOMAndSize(const string &om, const string &particle_size, regression_form form, const double &p_value_threshold=0.05)
Performs multiple linear regression of elements vs OM and particle size.
vector< string > size_om_order_
bool ReadFromFile(QFile *fil)
Loads complete dataset from a JSON file.
vector< Parameter > & Parameters()
Retrieves reference to the parameters vector.
ResultItem GetCalculatedElementMu()
Computes μ parameters from fitted log-normal distributions for source elements.
ResultItem GetObservedElementalProfile()
Retrieves the observed elemental concentrations for the selected target sample.
bool ReadElementInformationfromJsonObject(const QJsonObject &jsonobject)
Deserializes element information metadata from a JSON object.
map< string, vector< double > > ExtractElementDataByGroup(const string &element) const
Extract concentration data for a specific element from all groups.
Elemental_Profile_Set DifferentiationPower_Percentage(bool include_target)
Computes rank-based differentiation percentage for all source pairs.
CVector GetContributionVector(bool include_all=true)
Retrieves the current source contribution fractions.
CMBTimeSeriesSet BootStrap(const double &percentage, unsigned int num_iterations, string target_sample, bool use_softmax)
Performs bootstrap uncertainty analysis on source contributions.
double GetElementDistributionMuValue(size_t element_index, size_t source_index)
Retrieves the current value of the μ parameter for an element distribution.
vector< string > GetElementNames() const
Get all element names in the dataset.
SourceSinkData ExtractChemicalElements(bool isotopes) const
Extract only chemical elements (and optionally isotopes)
Observation * observation(size_t i)
Retrieves pointer to an observation by index.
SourceSinkData & operator=(const SourceSinkData &other)
Assignment operator.
Elemental_Profile_Set TheRest(const string &excluded_source)
Collects all source samples except those from a specified source group.
CMBVector ANOVA(bool use_log)
Performs one-way ANOVA for all elements across source groups.
CMBVector OptimalBoxCoxParameters()
Computes optimal Box-Cox transformation parameters for all elements.
CVector PredictTarget_Isotope(parameter_mode param_mode=parameter_mode::direct)
Predicts target sample isotopic compositions based on source contributions.
void OutlierAnalysisForAll(const double &lower_threshold=-3, const double &upper_threshold=3)
Performs outlier detection on all source groups.
bool SolveLevenberg_Marquardt(transformation trans=transformation::linear)
Solves for optimal source contributions using the Levenberg-Marquardt algorithm.
CMatrix_arma ResidualJacobian_arma()
Calculates the Jacobian matrix of residuals with respect to contributions (Armadillo)
CMBVectorSet DFA_Projected()
Projects all groups onto the discriminant function axis.
ConcentrationSet * GetElementDistribution(const string &element_name)
Retrieves pointer to element distribution at dataset level.
SourceSinkData BoxCoxTransformed(bool calculate_optimal_lambda=false)
Applies Box-Cox transformation to all source groups for normalization.
CVector OneStepLevenberg_Marquardt(double lambda)
Performs one iteration of the Levenberg-Marquardt optimization algorithm.
CMatrix ResidualJacobian_softmax()
Calculates the Jacobian using softmax parameterization of contributions.
void SetParameterEstimationMode(estimation_mode est_mode)
Sets the estimation mode for parameter optimization.
CMBVector DFA_weight_vector(const string &source1, const string &source2)
Computes discriminant weight vector for two-group comparison.
Elemental_Profile_Set * GetSampleSet(const string &name)
Get a sample set (source or target group) by name.
Elemental_Profile_Set * AppendSampleSet(const string &name, const Elemental_Profile_Set &elemental_profile_set=Elemental_Profile_Set())
Add a new sample set (source or target group) to the dataset.
void Clear()
Clear all data from the object.
double regression_p_value_threshold_
CMBMatrix MCMC_Batch(map< string, string > arguments, CMCMC< SourceSinkData > *mcmc, ProgressWindow *progress_window, const string &working_folder)
Performs batch MCMC analysis on all target samples.
CMatrix WithinGroupCovarianceMatrix()
Computes pooled within-group covariance matrix.
double LogLikelihoodModelvsMeasured(estimation_mode est_mode=estimation_mode::elemental_profile_and_contribution)
Calculates the log-likelihood of the model prediction versus measured data.
CVector ObservedDataforSelectedSample_Isotope_delta(const string &SelectedTargetSample="")
Retrieves the observed isotopic data in delta notation.
Elemental_Profile t_TestPValue(const string &source1, const string &source2, bool use_log)
Computes t-test p-values for element-wise differences between two sources.
vector< Observation > observations_
Distribution * GetFittedDistribution(const string &element_name)
Get the fitted distribution for a specific element at dataset level.
double WilksLambda()
Computes Wilks' Lambda statistic for multivariate group separation.
map< string, ConcentrationSet > ExtractConcentrationSet()
Extracts concentration distributions for all elements across sources.
list< string > tools_used_
bool SetParameterValue(size_t index, double value)
Sets a parameter value and updates corresponding model components.
CVector GetParameterValue() const
Retrieves all current parameter values as a vector.
vector< string > SourceGroupNames() const
Retrieves the names of all source groups (excluding target)
bool ToolsUsed(const string &tool_name)
Checks if a specific analysis tool has been used.
vector< ResultItem > GetMLRResults()
Retrieves multiple linear regression results for all sample groups.
vector< string > RandomlypickSamples(const double &percentage) const
Randomly selects a subset of source samples.
CVector ObservedDataforSelectedSample_Isotope(const string &SelectedTargetSample="")
Retrieves the observed isotopic data for a selected target sample.
estimation_mode parameter_estimation_mode_
bool SetOutputPath(const string &output_path)
Set the output directory path.
ResultItem GetPredictedElementalProfile_Isotope(parameter_mode param_mode=parameter_mode::based_on_fitted_distribution)
Generates predicted isotope delta values for the target sample.
CMBVector BracketTest(const string &target_sample, bool correct_based_on_om_n_size)
Performs bracket test to check if target concentrations fall within source ranges.
bool ReadElementDatafromJsonObject(const QJsonObject &jsonobject)
Deserializes elemental profile data from a JSON object.
Elemental_Profile_Set ExtractSamplesAsProfileSet(const vector< vector< string > > &indicators) const
Extract samples as an Elemental_Profile_Set.
vector< string > isotope_order_
CVector GetContributionVectorSoftmax()
Retrieves the softmax parameters for source contributions.
void IncludeExcludeElementsBasedOn(const vector< string > &elements)
Sets element inclusion based on a specified list.
ResultItem GetPredictedElementalProfile(parameter_mode param_mode=parameter_mode::based_on_fitted_distribution)
Generates predicted elemental concentrations for the target sample.
CVector GetPredictedValues()
Retrieves predicted values for all observations.
QJsonObject ElementInformationToJsonObject() const
Exports element information metadata to a JSON object.
ResultItem GetCalculatedElementSigma()
Computes estimated standard deviations for all source elements.
QJsonObject OptionsToJsonObject() const
Exports analysis options/settings to a JSON object.
void SetOMandSizeConstituents(const string &_omconstituent, const string &_sizeconsituent)
Sets the names of OM and particle size constituents.
Parameter * parameter(size_t i)
Retrieves pointer to a parameter by index.
bool ReadToolsUsedFromJsonObject(const QJsonArray &jsonarray)
Deserializes the list of analysis tools from a JSON array.
SourceSinkData RandomlyEliminateSourceSamples(const double &percentage)
Creates dataset with randomly excluded source samples for validation.
CVector Gradient(const CVector ¶meters, estimation_mode est_mode)
Computes the normalized gradient of the log-likelihood function.
void SetContributionSoftmax(size_t source_index, double softmax_value)
Sets a single softmax parameter value.
vector< string > constituent_order_
int numberofsourcesamplesets_
SourceSinkData ReplaceSourceAsTarget(const string &source_sample_name) const
Creates a new dataset with a source sample designated as the target.
double LogPriorContributions()
Calculates the log prior probability for source contributions.
CVector ResidualVector()
Calculates the combined residual vector for elemental and isotopic predictions.
SourceSinkData CreateCorrectedAndFilteredDataset(bool exclude_samples, bool exclude_elements, bool omnsizecorrect, const string &target="") const
Create a corrected and filtered copy of the dataset.
QJsonObject ElementDataToJsonObject() const
Exports all elemental profile data to a JSON object.
vector< string > NegativeValueCheck()
Checks for zero or negative concentration values across all sources.
CMBTimeSeriesSet VerifySource(const string &source_group, bool use_softmax, bool apply_om_size_correction)
Performs leave-one-out validation on a source group.
bool SetSelectedTargetSample(const string &sample_name)
Sets the currently selected target sample for analysis.
map< string, element_information > * GetElementInformation()
Retrieves pointer to the element information map.
void AddtoToolsUsed(const string &tool)
Adds a tool name to the list of tools used in analysis.
QMap< QString, double > options_
DFA_result DiscriminantFunctionAnalysis()
Performs discriminant function analysis for all source groups.
vector< string > ElementsToBeUsedInCMB()
Identifies chemical elements to be used in CMB analysis.
map< string, ConcentrationSet > element_distributions_
vector< string > SizeOMOrder()
Retrieves the ordering of size and OM constituents.
void PopulateConstituentOrders()
Populates all element ordering vectors used throughout CMB analysis.
vector< ResultItem > GetSourceProfiles()
Retrieves elemental profiles for all source groups.
CMatrix BuildSourceMeanMatrix_Isotopes(parameter_mode param_mode=parameter_mode::based_on_fitted_distribution)
Builds the source mean concentration matrix for isotopes.
map< string, element_information > element_information_
void PopulateElementInformation(const map< string, element_information > *ElementInfo=nullptr)
Populate element information metadata.
ResultItem GetCalculatedElementMeans()
Computes estimated mean concentrations for all source elements.
Results MCMC(const string &target_sample, map< string, string > arguments, CMCMC< SourceSinkData > *mcmc, ProgressWindow *progress_window, const string &working_folder)
Performs Markov Chain Monte Carlo analysis for Bayesian source apportionment.
Elemental_Profile_Set DifferentiationPower(bool use_log, bool include_target)
Computes differentiation power for all source pairs.
string GetParameterName(int index) const
Get the name of a parameter by its index.
double LogLikelihoodSourceElementalDistributions()
Calculates the log-likelihood of source elemental distributions.
vector< string > samplesetsorder_
bool InitializeContributionsRandomly()
Initialize source contributions randomly (linear constraint)
double LogLikelihood(estimation_mode est_mode=estimation_mode::elemental_profile_and_contribution)
Calculates the total log-likelihood for Bayesian source apportionment.
QString Role(const element_information::role &role) const
Converts element role enum to string representation.
size_t ObservationsCount()
Returns the number of observations.
CVector GradientUpdate(estimation_mode estmode=estimation_mode::elemental_profile_and_contribution)
Performs one gradient ascent step with adaptive step size.
SourceSinkData CreateCorrectedDataset(const string &target, bool omnsizecorrect, map< string, element_information > *elementinfo)
Create a corrected copy of the dataset for a specific target sample.
vector< CMBVector > StepwiseDiscriminantFunctionAnalysis()
Performs stepwise discriminant analysis across all source groups.
vector< string > GetSampleNames(const string &group_name) const
Get all sample names within a specific group.
CMBVector MeanElementalContent()
Computes weighted mean elemental concentrations across all sources.
CMatrix TotalScatterMatrix()
Computes total scatter matrix.
ResultItem GetEstimatedElementSigma()
Retrieves estimated σ parameters from Bayesian inference for source elements.
double GrandMean(const string &element, bool use_log)
Computes grand mean concentration for an element across all sources.
void IncludeExcludeAllElements(bool include_in_analysis)
Sets inclusion flag for all elements.
string FirstOMConstituent()
Retrieves the name of the first organic matter constituent.
CVector OneStepLevenberg_Marquardt_softmax(double lambda)
Performs one iteration of Levenberg-Marquardt using softmax parameterization.
CVector PredictTarget(parameter_mode param_mode=parameter_mode::direct)
Predicts target sample elemental concentrations based on source contributions.
vector< string > ElementOrder()
Retrieves the ordering of chemical elements.
vector< string > GetGroupNames() const
Get all group names in the dataset.
string SelectedTargetSample() const
Retrieves the name of the currently selected target sample.
ResultItem GetObservedvsModeledElementalProfile(parameter_mode param_mode=parameter_mode::based_on_fitted_distribution)
Creates a comparison of observed vs modeled elemental profiles.
vector< string > IsotopeOrder()
Retrieves the ordering of isotopes.
int CountElements(bool exclude_elements) const
Count the number of elements in the dataset.
SourceSinkData ExtractSpecificElements(const vector< string > &element_list) const
Extract specific elements from source groups.
bool InitializeContributionsRandomlySoftmax()
Initialize source contributions randomly (softmax transformation)
int TotalNumberofSourceSamples() const
Counts the total number of source samples across all source groups.
Parameter * GetElementDistributionMuParameter(size_t element_index, size_t source_index)
Retrieves pointer to the μ (mean) parameter for an element distribution.
estimation_mode ParameterEstimationMode()
Retrieves the current estimation mode.
int numberofconstituents_
element_data ExtractElementConcentrations(const string &element, const string &group) const
Extract concentration data for a specific element from a group.
double DFA_P_Value()
Computes p-value for discriminant function analysis.
ResultItem GetEstimatedElementMean()
Computes actual mean concentrations from estimated log-normal parameters.
string GetTargetGroup() const
Retrieves the name of the target group.
void PopulateElementDistributions()
Populate element distributions from all groups.
Elemental_Profile_Set DifferentiationPower_P_value(bool include_target)
Computes t-test p-values for all source pairs.
CVector PredictTarget_Isotope_delta(parameter_mode param_mode=parameter_mode::based_on_fitted_distribution)
Predicts target sample isotopic compositions in delta notation.
ResultItem GetContribution()
Packages source contributions into a ResultItem for output.
CVector_arma ResidualVector_arma()
Calculates the combined residual vector using Armadillo vector format.
vector< string > AllSourceSampleNames() const
Retrieves names of all samples across all source groups.
string FirstSizeConstituent()
Retrieves the name of the first particle size constituent.
bool ReadOptionsfromJsonObject(const QJsonObject &jsonobject)
Deserializes analysis options from a JSON object.
string selected_target_sample_
double GetObjectiveFunctionValue()
Returns the objective function value for optimization algorithms.
CMBVector DFATransformed(const CMBVector &eigenvector, const string &source_group)
Projects samples onto a discriminant function axis.
CMBTimeSeriesSet LM_Batch(transformation transform, bool apply_om_size_correction, map< string, vector< string > > &negative_elements)
Solves CMB model for all target samples using Levenberg-Marquardt.
vector< Parameter > parameters_
bool SetTargetGroup(const string &targroup)
Sets the target/sink group designation.
vector< string > GetSourceOrder() const
Retrieves the ordering of source groups.
vector< string > ConstituentOrder()
Retrieves the ordering of all constituents.
CVector ObservedDataforSelectedSample(const string &SelectedTargetSample="")
Retrieves the observed elemental data for a selected target sample.
ResultItem GetObservedElementalProfile_Isotope()
Retrieves the observed isotope delta values for the selected target sample.
CMatrix ResidualJacobian()
Calculates the Jacobian matrix of residuals with respect to contributions.
CMatrix BuildSourceMeanMatrix(parameter_mode param_mode=parameter_mode::based_on_fitted_distribution)
Builds the source mean concentration matrix for chemical elements.
CVector GetSourceContributions()
Retrieves the contributions from all sources.
double GetElementDistributionSigmaValue(size_t element_index, size_t source_index)
Retrieves the current value of the σ parameter for an element distribution.
QJsonArray ToolsUsedToJsonObject() const
Exports the list of analysis tools used to a JSON array.
double error_stdev_isotope_
Elemental_Profile_Set LumpAllProfileSets()
Combines all source samples into a single profile set.
double LogLikelihoodModelvsMeasured_Isotope(estimation_mode est_mode=estimation_mode::elemental_profile_and_contribution)
Calculates the log-likelihood of model versus measured isotopic data.
bool WriteDataToFile(QFile *file)
Writes elemental profile data to a text file.
bool WriteToFile(QFile *file)
Writes dataset to a text file.
vector< string > SamplesetsOrder()
Retrieves the ordering of sample sets.
void SetContribution(size_t source_index, double contribution_value)
Sets a single source contribution value.
ResultItem GetEstimatedElementMu()
Retrieves estimated μ parameters from Bayesian inference for source elements.
CMBVector DFA_eigvector()
Computes the primary discriminant function eigenvector.
ResultItem GetObservedvsModeledElementalProfile_Isotope(parameter_mode param_mode=parameter_mode::based_on_fitted_distribution)
Creates a comparison of observed vs modeled isotope delta values.
vector< string > OMandSizeConstituents()
Retrieves the names of OM and particle size constituents.
SourceSinkData()
Default constructor.
parameter_mode
Specifies whether to use direct data statistics or fitted distribution parameters.
@ based_on_fitted_distribution
Calculate from fitted distribution parameters.
@ direct
Use empirical statistics from data.
@ dirichlet
Dirichlet distribution (treated as uniform on simplex in current implementation)
@ lognormal
Lognormal distribution: ln(x) ~ N(μ, σ²), for strictly positive variables.
@ normal
Normal (Gaussian) distribution: p(x) = N(μ, σ²)
@ low
Lower bound of the parameter range.
@ high
Upper bound of the parameter range.
@ distribution_with_observed
@ predicted_concentration
@ elemental_profile_and_contribution
@ source_elemental_profiles_based_on_source_data
CMBVectorSet eigen_vectors
CMBVectorSetSet multi_projected
vector< string > sample_names
vector< vector< double > > values
vector< string > element_names
vector< string > sample_names