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)
692bool FittedParametersAvailable(
const Distribution* fitted,
694 const string& element_name,
695 const string& group_name)
697 if (fitted !=
nullptr && fitted->
parameters.size() >= needed)
700 std::cerr <<
"InitializeParametersAndObservations: no fitted distribution for '"
701 << element_name <<
"' in group '" << group_name
702 <<
"'. Build the distributions with PopulateElementDistributions() "
703 "and AssignAllDistributions() before initializing." << std::endl;
710 const string& targetsamplename,
720 std::cerr <<
"Data has not been loaded!" << std::endl;
736 for (
auto& [group_name, profile_set] : *
this)
741 p.
SetName(group_name +
"_contribution");
754 for (
auto& [group_name, profile_set] : *
this)
770 if (elem_info.include_in_analysis)
788 for (
auto& [group_name, profile_set] : *
this)
793 *profile_set.GetEstimatedDistribution(element_name) =
794 *profile_set.GetFittedDistribution(element_name);
805 for (
auto& [group_name, profile_set] : *
this)
809 *profile_set.GetEstimatedDistribution(element_name) =
810 *profile_set.GetFittedDistribution(element_name);
825 for (
auto& [group_name, profile_set] : *
this)
830 p.
SetName(group_name +
"_" + element_name +
"_mu");
837 Distribution* estimated = profile_set.GetEstimatedDistribution(element_name);
838 const Distribution* fitted = profile_set.GetFittedDistribution(element_name);
840 if (estimated ==
nullptr ||
841 !FittedParametersAvailable(fitted, 1, element_name, group_name))
863 for (
auto& [group_name, profile_set] : *
this)
868 p.
SetName(group_name +
"_" + element_name +
"_mu");
871 Distribution* estimated = profile_set.GetEstimatedDistribution(element_name);
872 const Distribution* fitted = profile_set.GetFittedDistribution(element_name);
874 if (estimated ==
nullptr ||
875 !FittedParametersAvailable(fitted, 1, element_name, group_name))
897 for (
auto& [group_name, profile_set] : *
this)
902 p.
SetName(group_name +
"_" + element_name +
"_sigma");
906 const Distribution* fitted = profile_set.GetFittedDistribution(element_name);
908 if (!FittedParametersAvailable(fitted, 2, element_name, group_name))
911 double lower = std::max(fitted->
parameters[1] * 0.8, 0.001);
912 double upper = std::max(fitted->
parameters[1] / 0.8, 2.0);
926 for (
auto& [group_name, profile_set] : *
this)
931 p.
SetName(group_name +
"_" + element_name +
"_sigma");
935 const Distribution* fitted = profile_set.GetFittedDistribution(element_name);
937 if (!FittedParametersAvailable(fitted, 2, element_name, group_name))
940 double lower = std::max(fitted->
parameters[1] * 0.8, 0.001);
941 double upper = std::max(fitted->
parameters[1] / 0.8, 2.0);
957 error_param.
SetName(
"Error STDev");
968 obs.
SetName(targetsamplename +
"_" + element_name);
976 error_param_isotope.
SetName(
"Error STDev for isotopes");
978 error_param_isotope.
SetRange(0.01, 0.1);
987 obs.
SetName(targetsamplename +
"_" + element_name);
1000 CVector contributions(size()-1);
1001 for (
unsigned long int i=0; i<size()-2; i++)
1005 contributions[size()-2] = 1 - contributions.sum();
1006 return contributions;
1020 double logLikelihood = 0;
1021 for (
unsigned int element_counter=0; element_counter<
element_order_.size(); element_counter++)
1028 for (map<string,Elemental_Profile>::iterator sample = this_source_group->begin(); sample!=this_source_group->end(); sample++)
1035 return logLikelihood;
1047 return observed_data;
1060 return observed_data;
1073 return observed_data;
1085 CVector predicted_concentrations =
PredictTarget(param_mode);
1089 if (predicted_concentrations.min() <= 0)
1096 const double num_elements = predicted_concentrations.num;
1099 CVector log_residuals = predicted_concentrations.Log() - observed_concentrations.Log();
1100 const double sum_squared_residuals = pow(log_residuals.norm2(), 2);
1101 const double variance_term = 2.0 * pow(
error_stdev_, 2);
1103 double log_likelihood = -normalization_term - (sum_squared_residuals / variance_term);
1105 return log_likelihood;
1121 const double num_isotopes = predicted_deltas.num;
1124 CVector residuals = predicted_deltas - observed_deltas;
1125 const double sum_squared_residuals = pow(residuals.norm2(), 2);
1128 double log_likelihood = -normalization_term - (sum_squared_residuals / variance_term);
1130 return log_likelihood;
1141 if (!predicted_concentrations.is_finite())
1143 qDebug() <<
"Warning: Non-finite predicted concentrations detected in ResidualVector()";
1152 CVector elemental_residuals = predicted_concentrations.Log() - observed_concentrations.Log();
1155 CVector isotopic_residuals = predicted_deltas - observed_deltas;
1158 CVector combined_residuals = elemental_residuals;
1159 combined_residuals.append(isotopic_residuals);
1169 return combined_residuals;
1175 CVector_arma predicted_concentrations =
PredictTarget().vec;
1184 CVector_arma elemental_residuals = predicted_concentrations.Log() - observed_concentrations.Log();
1187 CVector_arma isotopic_residuals = predicted_deltas - observed_deltas;
1190 CVector_arma combined_residuals = elemental_residuals;
1191 combined_residuals.append(isotopic_residuals);
1193 return combined_residuals;
1200 const size_t num_parameters = num_sources - 1;
1203 CMatrix_arma jacobian(num_parameters, num_residuals);
1210 for (
unsigned int i = 0; i < num_parameters; i++)
1213 const double epsilon = (0.5 - base_contributions[i]) * 1e-6;
1220 jacobian.setcol(i, (perturbed_residuals - base_residuals) / epsilon);
1232 const size_t num_parameters = num_sources - 1;
1235 CMatrix jacobian(num_parameters, num_residuals);
1242 for (
unsigned int i = 0; i < num_parameters; i++)
1245 const double epsilon = (0.5 - base_contributions[i]) * 1e-3;
1252 jacobian.setrow(i, (perturbed_residuals - base_residuals) / epsilon);
1266 CMatrix jacobian(num_sources, num_residuals);
1273 for (
unsigned int i = 0; i < num_sources; i++)
1276 const double epsilon = -sign(base_softmax_params[i]) * 1e-3;
1279 CVector perturbed_params = base_softmax_params;
1280 perturbed_params[i] += epsilon;
1286 jacobian.setrow(i, (perturbed_residuals - base_residuals) / epsilon);
1302 CMatrix jacobian_transpose_jacobian = jacobian * Transpose(jacobian);
1305 jacobian_transpose_jacobian.ScaleDiagonal(1.0 + lambda);
1308 CVector jacobian_times_residuals = jacobian * residuals;
1311 if (det(jacobian_transpose_jacobian) <= 1e-6)
1314 const size_t matrix_size = jacobian_transpose_jacobian.getnumcols();
1315 CMatrix identity = CMatrix::Diag(matrix_size);
1316 jacobian_transpose_jacobian += lambda * identity;
1320 CVector parameter_update = jacobian_times_residuals / jacobian_transpose_jacobian;
1322 return parameter_update;
1332 CMatrix jacobian_transpose_jacobian = jacobian * Transpose(jacobian);
1335 jacobian_transpose_jacobian.ScaleDiagonal(1.0 + lambda);
1338 CVector jacobian_times_residuals = jacobian * residuals;
1341 if (det(jacobian_transpose_jacobian) <= 1e-6)
1344 const size_t matrix_size = jacobian_transpose_jacobian.getnumcols();
1345 CMatrix identity = CMatrix::Diag(matrix_size);
1346 jacobian_transpose_jacobian += lambda * identity;
1350 CVector parameter_update = jacobian_times_residuals / jacobian_transpose_jacobian;
1352 return parameter_update;
1364 const double tolerance = 1e-10;
1365 const int max_iterations = 1000;
1366 const double improvement_threshold = 0.8;
1367 const double lambda_decrease_factor = 1.2;
1368 const double lambda_increase_factor = 1.2;
1369 const double lambda_no_update_factor = 5.0;
1372 double lambda = 1.0;
1374 double previous_error = 1000.0;
1375 double initial_param_change = 10000.0;
1376 double current_param_change = 10000.0;
1380 while (current_error > tolerance &&
1381 current_param_change > tolerance &&
1382 iteration < max_iterations)
1385 CVector current_params;
1391 previous_error = current_error;
1394 CVector parameter_update;
1401 if (parameter_update.num == 0)
1403 lambda *= lambda_no_update_factor;
1408 current_param_change = parameter_update.norm2();
1410 initial_param_change = current_param_change;
1413 CVector updated_params = current_params - parameter_update;
1421 current_error = residuals.norm2();
1424 if (current_error < previous_error * improvement_threshold)
1427 lambda /= lambda_decrease_factor;
1429 else if (current_error > previous_error)
1432 lambda *= lambda_increase_factor;
1440 current_error = previous_error;
1472 CVector predicted_concentrations = source_mean_matrix * contribution_vector;
1480 return predicted_concentrations;
1488 CVector predicted_isotope_concentrations = source_isotope_matrix * contribution_vector;
1490 return predicted_isotope_concentrations;
1502 double predicted_corresponding_element_concentration = C_elements[lookup(
element_order_,corresponding_element)];
1503 double ratio = C[i]/predicted_corresponding_element_concentration;
1505 C[i] = (ratio/standard_ratio-1.0)*1000.0;
1523 double source_data_log_likelihood = 0.0;
1524 double element_observation_log_likelihood = 0.0;
1525 double isotope_observation_log_likelihood = 0.0;
1548 double total_log_likelihood = source_data_log_likelihood +
1549 element_observation_log_likelihood +
1550 isotope_observation_log_likelihood +
1551 contribution_log_prior;
1553 return total_log_likelihood;
1563 CMatrix source_means(num_elements, num_sources);
1566 for (
size_t element_idx = 0; element_idx < num_elements; element_idx++)
1570 for (
size_t source_idx = 0; source_idx < num_sources; source_idx++)
1582 source_means[element_idx][source_idx] = element_dist->
Mean();
1586 source_means[element_idx][source_idx] = element_dist->
DataMean();
1591 return source_means;
1601 CMatrix source_isotope_means(num_isotopes, num_sources);
1604 for (
size_t isotope_idx = 0; isotope_idx < num_isotopes; isotope_idx++)
1608 const string& base_element = isotope_info.
base_element;
1611 for (
size_t source_idx = 0; source_idx < num_sources; source_idx++)
1622 double mean_base_concentration;
1626 mean_delta = isotope_dist->
Mean();
1627 mean_base_concentration = base_element_dist->
Mean();
1631 mean_delta = isotope_dist->
DataMean();
1632 mean_base_concentration = base_element_dist->
DataMean();
1637 double delta_ratio = (mean_delta / 1000.0) + 1.0;
1638 double absolute_isotope_concentration = delta_ratio * standard_ratio * mean_base_concentration;
1640 source_isotope_means[isotope_idx][source_idx] = absolute_isotope_concentration;
1644 return source_isotope_means;
1650 const size_t num_contributions = include_all ?
1654 CVector contributions(num_contributions);
1657 for (
size_t source_idx = 0; source_idx < num_contributions; source_idx++)
1664 return contributions;
1670 CVector softmax_parameters(num_sources);
1673 for (
size_t source_idx = 0; source_idx < num_sources; source_idx++)
1680 return softmax_parameters;
1698 double constrained_contribution = 1.0 - sum_of_independent;
1713 for (
size_t i = 0; i < static_cast<size_t>(contributions.num); i++)
1719 if (contributions.min() < 0.0) {
1720 std::cerr <<
"Warning: Negative contribution detected in SetContribution()" << std::endl;
1721 std::cerr <<
" Min value: " << contributions.min() << std::endl;
1728 double denominator = 0.0;
1729 for (
size_t i = 0; i < static_cast<size_t>(softmax_params.num); i++)
1731 denominator += exp(softmax_params[i]);
1735 for (
size_t i = 0; i < static_cast<size_t>(softmax_params.num); i++)
1737 double softmax_param = softmax_params.at(i);
1738 double contribution = exp(softmax_param) / denominator;
1747 if (resulting_contributions.min() < 0.0) {
1748 std::cerr <<
"Warning: Invalid contributions after softmax transformation" << std::endl;
1749 std::cerr <<
" Min contribution: " << resulting_contributions.min() << std::endl;
1750 std::cerr <<
" This should not happen with softmax - check for numerical issues" << std::endl;
1755 size_t element_index,
1756 size_t source_index)
1762 const size_t num_contribution_params = size() - 1;
1763 const size_t element_mu_base_index = num_contribution_params;
1767 const size_t parameter_index = element_mu_base_index +
1773 std::cerr <<
"Error: Parameter index out of bounds in GetElementDistributionMuParameter" << std::endl;
1781 size_t element_index,
1782 size_t source_index)
1789 const size_t num_contribution_params = size() - 1;
1791 const size_t element_sigma_base_index = num_contribution_params + num_element_mu_params;
1794 const size_t parameter_index = element_sigma_base_index +
1800 std::cerr <<
"Error: Parameter index out of bounds in GetElementDistributionSigmaParameter" << std::endl;
1808 size_t element_index,
1809 size_t source_index)
1813 if (mu_param ==
nullptr) {
1814 std::cerr <<
"Warning: Unable to retrieve μ parameter for element "
1815 << element_index <<
", source " << source_index << std::endl;
1819 return mu_param->
Value();
1823 size_t element_index,
1824 size_t source_index)
1828 if (sigma_param ==
nullptr) {
1829 std::cerr <<
"Warning: Unable to retrieve σ parameter for element "
1830 << element_index <<
", source " << source_index << std::endl;
1834 return sigma_param->
Value();
1845 const bool estimating_contributions =
1847 const bool estimating_profiles =
1854 const size_t num_element_sigma_params = num_element_mu_params;
1855 const size_t num_isotope_sigma_params = num_isotope_mu_params;
1861 if (estimating_contributions && index < num_contribution_params)
1875 size_t element_mu_start = num_contribution_params;
1876 size_t element_mu_end = element_mu_start + num_element_mu_params;
1878 if (estimating_profiles &&
1880 index >= element_mu_start && index < element_mu_end)
1882 size_t offset = index - element_mu_start;
1893 size_t isotope_mu_start = element_mu_end;
1894 size_t isotope_mu_end = isotope_mu_start + num_isotope_mu_params;
1896 if (estimating_profiles &&
1898 index >= isotope_mu_start && index < isotope_mu_end)
1900 size_t offset = index - isotope_mu_start;
1911 size_t element_sigma_start = isotope_mu_end;
1912 size_t element_sigma_end = element_sigma_start + num_element_sigma_params;
1914 if (estimating_profiles &&
1916 index >= element_sigma_start && index < element_sigma_end)
1919 std::cerr <<
"Error: Element σ parameter cannot be negative (value = "
1920 << value <<
")" << std::endl;
1924 size_t offset = index - element_sigma_start;
1935 size_t isotope_sigma_start = element_sigma_end;
1936 size_t isotope_sigma_end = isotope_sigma_start + num_isotope_sigma_params;
1938 if (estimating_profiles &&
1940 index >= isotope_sigma_start && index < isotope_sigma_end)
1943 std::cerr <<
"Error: Isotope σ parameter cannot be negative (value = "
1944 << value <<
")" << std::endl;
1948 size_t offset = index - isotope_sigma_start;
1959 size_t error_element_index = isotope_sigma_end;
1961 if (estimating_contributions && index == error_element_index)
1964 std::cerr <<
"Error: Element error std dev cannot be negative (value = "
1965 << value <<
")" << std::endl;
1974 size_t error_isotope_index = error_element_index + 1;
1976 if (estimating_contributions && index == error_isotope_index)
1979 std::cerr <<
"Error: Isotope error std dev cannot be negative (value = "
1980 << value <<
")" << std::endl;
1989 std::cerr <<
"Warning: Parameter index " << index <<
" not recognized" << std::endl;
2000 bool all_successful =
true;
2003 for (
size_t i = 0; i < static_cast<size_t>(values.num); i++)
2006 all_successful &= success;
2011 return all_successful;
2024 return parameter_values;
2029 CVector gradient(parameters.num);
2030 CVector perturbed_params = parameters;
2037 for (
size_t i = 0; i < static_cast<size_t>(parameters.num); i++)
2047 gradient[i] = (perturbed_log_likelihood - baseline_log_likelihood) /
epsilon_;
2050 perturbed_params[i] = parameters[i];
2054 return gradient / gradient.norm2();
2064 CVector gradient_direction =
Gradient(current_params, est_mode);
2067 CVector candidate_step1 = current_params +
distance_coeff_ * gradient_direction;
2071 CVector candidate_step2 = current_params + 2.0 *
distance_coeff_ * gradient_direction;
2076 std::cout <<
"Distance Coefficient: " <<
distance_coeff_ << std::endl;
2084 if (likelihood_step2 > likelihood_step1 && likelihood_step2 > baseline_likelihood)
2088 return candidate_step2;
2092 else if (likelihood_step1 > likelihood_step2 && likelihood_step1 > baseline_likelihood)
2096 return candidate_step1;
2102 const int max_backtrack_iterations = 5;
2103 int backtrack_count = 0;
2106 while (baseline_likelihood >= likelihood_step1 && backtrack_count < max_backtrack_iterations)
2110 candidate_step1 = current_params +
distance_coeff_ * gradient_direction;
2117 if (backtrack_count < max_backtrack_iterations)
2121 return candidate_step1;
2126 std::cerr <<
"Warning: No improvement found after " << max_backtrack_iterations
2127 <<
" backtracking iterations" << std::endl;
2129 return current_params;
2163 elem_info.include_in_analysis)
2192 elem_info.include_in_analysis)
2202 elem_info.include_in_analysis)
2228 vector<string> source_names;
2231 for (
const auto& [group_name, profile_set] : *
this)
2235 source_names.push_back(group_name);
2239 return source_names;
2245 for (
auto& [group_name, profile_set] : *
this)
2248 for (
const auto& [profile_name, profile] : profile_set)
2250 if (profile_name == sample_name)
2253 return profile_set.GetProfile(profile_name);
2271 for (
size_t i = 0; i < source_order.size(); i++)
2273 (*contributions)[source_order[i]] = contribution_values[i];
2277 result.
SetName(
"Contributions");
2290 CVector predicted_concentrations =
PredictTarget(param_mode);
2294 for (
size_t i = 0; i < element_names.size(); i++)
2296 predicted_profile->
AppendElement(element_names[i], predicted_concentrations[i]);
2300 result.
SetName(
"Modeled Elemental Profile");
2310 CVector predicted_values(num_observations);
2313 for (
size_t i = 0; i < num_observations; i++)
2318 return predicted_values;
2331 for (
size_t i = 0; i < isotope_names.size(); i++)
2333 predicted_isotopes->
AppendElement(isotope_names[i], predicted_delta_values[i]);
2337 result.
SetName(
"Modeled Elemental Profile for Isotopes");
2362 result.
SetName(
"Observed vs Modeled Elemental Profile");
2371 vector<ResultItem> mlr_results;
2374 for (
auto& [group_name, profile_set] : *
this)
2377 ResultItem regression_result = profile_set.GetRegressionsAsResult();
2381 regression_result.
SetName(
"OM & Size MLR for " + group_name);
2383 mlr_results.push_back(regression_result);
2407 result.
SetName(
"Observed vs Modeled Elemental Profile for Isotopes");
2424 for (
size_t i = 0; i < element_names.size(); i++)
2426 observed_profile->
AppendElement(element_names[i], observed_concentrations[i]);
2430 result.
SetName(
"Observed Elemental Profile");
2447 for (
size_t i = 0; i < isotope_names.size(); i++)
2449 observed_isotopes->
AppendElement(isotope_names[i], observed_delta_values[i]);
2453 result.
SetName(
"Observed Elemental Profile for Isotopes");
2464 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2469 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2478 resitem.
SetName(
"Calculated mean elemental contents");
2488 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2493 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2505 resitem.
SetName(
"Calculated elemental contents standard deviations");
2514 vector<ResultItem> source_profile_results;
2517 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2524 result_item.
SetName(
"Elemental Profiles for " + it->first);
2532 *profile_set = it->second;
2535 source_profile_results.push_back(result_item);
2539 return source_profile_results;
2547 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2552 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2561 resitem.
SetName(
"Calculated mu parameter of elemental contents");
2571 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2576 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2585 resitem.
SetName(
"Infered mu parameter elemental contents");
2595 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2600 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2602 double sigma = it->second.GetElementDistribution(
element_order_[element_counter])->GetEstimatedSigma();
2603 double mu = it->second.GetElementDistribution(
element_order_[element_counter])->GetEstimatedMu();
2611 resitem.
SetName(
"Infered mean of elemental contents");
2621 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2626 for (
unsigned int element_counter = 0; element_counter <
element_order_.size(); element_counter++)
2628 double sigma = it->second.GetElementDistribution(
element_order_[element_counter])->GetEstimatedSigma();
2636 resitem.
SetName(
"Infered sigma parameter");
2646 QJsonArray tools_used_json_array;
2651 tools_used_json_array.append(QString::fromStdString(*it));
2654 return tools_used_json_array;
2659 QJsonObject json_object;
2662 for (QMap<QString, double>::const_iterator it =
options_.cbegin(); it !=
options_.cend(); it++)
2664 json_object[it.key()] = it.value();
2682 foreach (
const QJsonValue& value, jsonarray)
2696 for (QString key : jsonobject.keys())
2699 elem_info.
Role =
Role(jsonobject[key].toObject()[
"Role"].toString());
2700 elem_info.
standard_ratio = jsonobject[key].toObject()[
"Standard Ratio"].toDouble();
2701 elem_info.
base_element = jsonobject[key].toObject()[
"Base Element"].toString().toStdString();
2716 for (QString key : jsonobject.keys())
2729 for (QString key : jsonobject.keys())
2731 options_[key] = jsonobject[key].toDouble();
2739 QJsonObject json_object;
2742 for (map<string, Elemental_Profile_Set>::const_iterator it = cbegin(); it != cend(); it++)
2744 json_object[QString::fromStdString(it->first)] = it->second.toJsonObject();
2753 file->write(
"***\n");
2754 file->write(
"Elemental Profiles\n");
2757 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2759 file->write(
"**\n");
2760 file->write(QString::fromStdString(it->first +
"\n").toUtf8());
2761 it->second.writetofile(file);
2778 QJsonObject jsondoc = QJsonDocument().fromJson(fil->readAll()).object();
2785 target_group_ = jsondoc[
"Target Group"].toString().toStdString();
2792 QJsonObject json_object;
2797 QJsonObject elem_info_json_obj;
2798 elem_info_json_obj[
"Role"] =
Role(it->second.Role);
2799 elem_info_json_obj[
"Standard Ratio"] = it->second.standard_ratio;
2800 elem_info_json_obj[
"Base Element"] = QString::fromStdString(it->second.base_element);
2801 elem_info_json_obj[
"Include"] = it->second.include_in_analysis;
2803 json_object[QString::fromStdString(it->first)] = elem_info_json_obj;
2813 return "DoNotInclude";
2819 return "ParticleSize";
2824 return "DoNotInclude";
2830 if (role_string ==
"DoNotInclude")
2832 else if (role_string ==
"Element")
2834 else if (role_string ==
"Isotope")
2836 else if (role_string ==
"ParticleSize")
2838 else if (role_string ==
"OM")
2847 const string& particle_size,
2849 const double& p_value_threshold)
2857 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2859 it->second.SetRegressionModels(om, particle_size, form, p_value_threshold);
2868 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
2873 it->second.DetectOutliers(lower_threshold, upper_threshold);
2883 const size_t num_sources = size() - 1;
2890 for (map<string, Elemental_Profile_Set>::iterator source = begin(); source != end(); source++)
2932 if (eigen_vector.
size() == 0)
2999 for (map<string, Elemental_Profile_Set>::const_iterator source_group = cbegin(); source_group != cend(); source_group++)
3004 count += source_group->second.size();
3014 CMBVector discriminant_scores(
operator[](source_group).size());
3017 size_t sample_index = 0;
3018 for (map<string, Elemental_Profile>::iterator sample =
operator[](source_group).begin();
3019 sample != operator[](source_group).end();
3023 discriminant_scores[sample_index] = sample->second.CalculateDotProduct(eigenvector);
3024 discriminant_scores.
SetLabel(sample_index, sample->first);
3029 return discriminant_scores;
3037 for (map<string, Elemental_Profile_Set>::iterator profile_set = begin();
3038 profile_set != end();
3042 if (profile_set->first != excluded_source && profile_set->first !=
target_group_)
3045 for (map<string, Elemental_Profile>::iterator profile = profile_set->second.begin();
3046 profile != profile_set->second.end();
3049 combined_sources.
AppendProfile(profile->first, profile->second);
3054 return combined_sources;
3061 const size_t num_elements = element_names.size();
3064 CMBVector bracket_test_results(num_elements);
3065 CVector exceeds_max(num_elements);
3066 CVector below_min(num_elements);
3068 exceeds_max.SetAllValues(1.0);
3069 below_min.SetAllValues(1.0);
3073 false,
false, correct_based_on_om_n_size, target_sample);
3076 for (map<string, Elemental_Profile_Set>::iterator it = corrected_data.begin();
3077 it != corrected_data.end();
3084 for (
size_t i = 0; i < num_elements; i++)
3086 bracket_test_results.
SetLabel(i, element_names[i]);
3088 double target_concentration = corrected_data.at(
target_group_)
3089 .GetProfile(target_sample)->at(element_names[i]);
3092 double source_minimum = it->second.GetElementDistribution(element_names[i])
3096 if (target_concentration <= source_maximum)
3100 if (target_concentration >= source_minimum)
3109 for (
size_t i = 0; i < num_elements; i++)
3112 bracket_test_results[i] = max(exceeds_max[i], below_min[i]);
3115 if (exceeds_max[i] > 0.5)
3118 element_names[i] +
" value is higher than the maximum of the sources");
3120 else if (below_min[i] > 0.5)
3123 element_names[i] +
" value is lower than the minimum of the sources");
3127 return bracket_test_results;
3132 bool correct_based_on_om_n_size,
3133 bool exclude_elements,
3134 bool exclude_samples)
3139 const size_t num_elements =
CountElements(exclude_elements);
3140 CMBMatrix bracket_results(num_target_samples, num_elements);
3143 size_t sample_index = 0;
3144 for (map<string, Elemental_Profile>::iterator sample = at(
target_group_).begin();
3150 if (correct_based_on_om_n_size)
3153 exclude_samples, exclude_elements,
true, sample->first);
3158 exclude_samples, exclude_elements,
false);
3166 for (
size_t element_index = 0; element_index < element_names.size(); element_index++)
3168 bracket_results[element_index][sample_index] = bracket_vector.
valueAt(element_index);
3169 bracket_results.
SetRowLabel(element_index, element_names[element_index]);
3176 return bracket_results;
3190 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
3195 if (calculate_optimal_lambda)
3198 transformed_data[it->first] = it->second.ApplyBoxCoxTransform(&lambda_parameters);
3203 transformed_data[it->first] = it->second.ApplyBoxCoxTransform();
3212 return transformed_data;
3217 map<string, ConcentrationSet> element_concentrations;
3221 for (
size_t i = 0; i < element_names.size(); i++)
3226 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != end(); it++)
3232 for (map<string, Elemental_Profile>::iterator sample = it->second.begin();
3233 sample != it->second.end();
3236 concentration_set.
AppendValue(sample->second[element_names[i]]);
3241 element_concentrations[element_names[i]] = concentration_set;
3244 return element_concentrations;
3254 CMBVector lambda_parameters(element_names.size());
3256 for (
size_t i = 0; i < element_names.size(); i++)
3260 lambda_parameters[i] = concentration_sets[element_names[i]].FindOptimalBoxCoxParameter(-5, 5, 10);
3264 lambda_parameters.
SetLabels(element_names);
3266 return lambda_parameters;
3274 for (
size_t i = 0; i < element_names.size(); i++)
3277 ConcentrationSet concentration_set1 = *at(source1).GetElementDistribution(element_names[i]);
3278 ConcentrationSet concentration_set2 = *at(source2).GetElementDistribution(element_names[i]);
3281 double std1, std2, mean1, mean2;
3300 double standard_error = sqrt(pow(std1, 2) / concentration_set1.size() +
3301 pow(std2, 2) / concentration_set2.size());
3302 double t_statistic = (mean1 - mean2) / standard_error;
3305 size_t degrees_of_freedom = concentration_set1.size() + concentration_set2.size() - 2;
3306 double p_value_upper = gsl_cdf_tdist_Q(t_statistic, degrees_of_freedom);
3307 double p_value_lower = gsl_cdf_tdist_P(t_statistic, degrees_of_freedom);
3310 p_value_upper = min(p_value_upper, 1.0 - p_value_upper);
3311 p_value_lower = min(p_value_lower, 1.0 - p_value_lower);
3312 double p_value = p_value_upper + p_value_lower;
3326 for (
size_t i = 0; i < element_names.size(); i++)
3329 ConcentrationSet concentration_set1 = *at(source1).GetElementDistribution(element_names[i]);
3330 ConcentrationSet concentration_set2 = *at(source2).GetElementDistribution(element_names[i]);
3333 double std1, std2, mean1, mean2;
3352 double diff_power = 2.0 * fabs(mean1 - mean2) / (std1 + std2);
3354 differentiation_powers.
AppendElement(element_names[i], diff_power);
3357 return differentiation_powers;
3365 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3369 for (map<string, Elemental_Profile_Set>::iterator it2 = next(it); it2 != end(); it2++)
3374 all_pairs.
AppendProfile(it->first +
" and " + it2->first, diff_power);
3389 for (
size_t i = 0; i < element_names.size(); i++)
3392 ConcentrationSet concentration_set1 = *at(source1).GetElementDistribution(element_names[i]);
3393 ConcentrationSet concentration_set2 = *at(source2).GetElementDistribution(element_names[i]);
3397 combined_set.
AppendSet(concentration_set2);
3401 size_t n1 = concentration_set1.size();
3402 int set1_below_limit = aquiutils::CountLessThan(ranks, n1, n1,
false);
3403 int set1_above_limit = aquiutils::CountGreaterThan(ranks, n1, n1,
false);
3404 int set2_below_limit = aquiutils::CountLessThan(ranks, n1, n1,
true);
3405 int set2_above_limit = aquiutils::CountGreaterThan(ranks, n1, n1,
true);
3408 double set1_fraction = double(set1_below_limit + set2_above_limit) / double(combined_set.size());
3409 double set2_fraction = double(set1_above_limit + set2_below_limit) / double(combined_set.size());
3412 double classification_percentage = max(set1_fraction, set2_fraction);
3414 classification_percentages.
AppendElement(element_names[i], classification_percentage);
3417 return classification_percentages;
3425 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3429 for (map<string, Elemental_Profile_Set>::iterator it2 = next(it); it2 != end(); it2++)
3434 all_pairs.
AppendProfile(it->first +
" and " + it2->first, diff_power_pct);
3448 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3452 for (map<string, Elemental_Profile_Set>::iterator it2 = next(it); it2 != end(); it2++)
3457 all_pairs.
AppendProfile(it->first +
" and " + it2->first, p_values);
3468 vector<string> error_messages;
3474 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3476 vector<string> negative_elements = it->second.CheckForNegativeValues(
element_order_);
3479 for (
size_t i = 0; i < negative_elements.size(); i++)
3481 error_messages.push_back(
"There are zero or negative values for element '" +
3482 negative_elements[i] +
"' in sample group '" +
3487 return error_messages;
3497 it->second.include_in_analysis = include_in_analysis;
3503 double weighted_sum = 0.0;
3504 double total_count = 0.0;
3507 for (map<string, Elemental_Profile_Set>::iterator it = begin(); it != prev(end()); it++)
3512 ConcentrationSet* element_dist = it->second.GetElementDistribution(element);
3513 size_t sample_count = element_dist->size();
3518 weighted_sum += element_dist->
CalculateMean() * sample_count;
3526 total_count += sample_count;
3531 return weighted_sum / total_count;
3539 for (map<string, Elemental_Profile_Set>::const_iterator it = begin(); it != prev(end()); it++)
3551 return combined_sources;
3557 CMBVector p_values(element_names.size());
3561 for (
size_t i = 0; i < element_names.size(); i++)
3564 p_values[i] = anova_result.
p_value;
3587 double sum_between = 0.0;
3588 double sum_within = 0.0;
3590 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
3591 source_group != end();
3596 ConcentrationSet* group_data = source_group->second.GetElementDistribution(element);
3598 size_t group_size = group_data->size();
3601 sum_between += pow(group_mean - grand_mean, 2) * group_size;
3608 anova.
SSB = sum_between;
3609 anova.
SSW = sum_within;
3617 size_t total_size = all_element_data->size();
3618 anova.
SST = pow(total_std_log, 2) * (total_size - 1);
3622 double sum_between = 0.0;
3623 double sum_within = 0.0;
3625 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
3626 source_group != end();
3631 ConcentrationSet* group_data = source_group->second.GetElementDistribution(element);
3633 size_t group_size = group_data->size();
3636 sum_between += pow(group_mean_log - grand_mean_log, 2) * group_size;
3643 anova.
SSB = sum_between;
3644 anova.
SSW = sum_within;
3648 size_t num_groups = this->size() - 1;
3649 size_t total_samples = all_element_data->size();
3652 size_t df_between = num_groups - 1;
3653 size_t df_within = total_samples - num_groups;
3656 anova.
MSB = anova.
SSB / double(df_between);
3657 anova.
MSW = anova.
SSW / double(df_within);
3660 anova.
F = anova.
MSB / anova.
MSW;
3663 anova.
p_value = gsl_cdf_fdist_Q(anova.
F, df_between, total_samples);
3674 element->second.include_in_analysis =
false;
3678 for (
size_t i = 0; i < elements.size(); i++)
3695 for (map<string, Elemental_Profile_Set>::const_iterator it = cbegin(); it != cend(); it++)
3700 reduced_dataset[it->first] = it->second.EliminateSamples(
3706 reduced_dataset[it->first] = it->second;
3720 return reduced_dataset;
3726 for (map<string, Elemental_Profile_Set>::const_iterator it = cbegin(); it != cend(); it++)
3728 if (it->second.count(sample_name) == 1)
3730 return it->second.at(sample_name);
3747 new_target_group.
AppendProfile(source_sample_name, target_profile);
3760 return modified_dataset;
3764 const double& percentage,
3765 unsigned int num_iterations,
3766 string target_sample,
3775 contribution_time_series.setname(source_idx,
samplesetsorder_[source_idx]);
3779 for (
size_t iteration = 0; iteration < num_iterations; iteration++)
3805 return contribution_time_series;
3810 const double& percentage,
3811 unsigned int num_iterations,
3812 string target_sample,
3825 for (
size_t iteration = 0; iteration < num_iterations; iteration++)
3853 results->
SetName(
"Error Analysis for target sample '" + target_sample +
"'");
3854 contributions_result.
SetName(
"Error Analysis");
3855 contributions_result.
SetResult(contributions);
3861 if (num_iterations < 101)
3875 results->
Append(contributions_result);
3879 *distributions = contributions->distribution(100, 0, 0);
3882 distributions_result.
SetName(
"Posterior Distributions");
3886 distributions_result.
SetResult(distributions);
3887 results->
Append(distributions_result);
3897 double percentile_2_5 = contributions->at(i).percentile(0.025);
3898 double percentile_97_5 = contributions->at(i).percentile(0.975);
3899 double mean_contribution = contributions->at(i).mean();
3900 double median_contribution = contributions->at(i).percentile(0.5);
3905 interval.
SetMean(mean_contribution);
3906 interval.
SetMedian(median_contribution);
3908 (*credible_intervals)[contributions->getSeriesName(i)] = interval;
3912 intervals_result.
SetName(
"Source Contribution Credible Intervals");
3916 intervals_result.
SetResult(credible_intervals);
3920 results->
Append(intervals_result);
3926 const string& source_group,
3928 bool apply_om_size_correction)
3943 size_t valid_sample_count = 0;
3944 for (map<string, Elemental_Profile>::iterator sample = at(source_group).begin();
3945 sample != at(source_group).end();
3959 if (negative_elements.size() == 0)
3967 rtw_->
SetProgress(
double(valid_sample_count) /
double(at(source_group).size()));
3982 validation_results.
SetLabel(valid_sample_count, sample->first);
3983 valid_sample_count++;
3988 for (
size_t i = 0; i < negative_elements.size(); i++)
3990 qDebug() << QString::fromStdString(negative_elements[i]);
3995 return validation_results;
4000 bool apply_om_size_correction,
4001 map<
string, vector<string>>& negative_elements)
4016 size_t valid_sample_count = 0;
4017 for (map<string, Elemental_Profile>::iterator sample = at(
target_group_).begin();
4022 if (sample->first !=
"")
4031 if (negative_elements[sample->first].size() == 0)
4048 contribution_results.
SetLabel(valid_sample_count, sample->first);
4049 valid_sample_count++;
4060 return contribution_results;
4066 vector<string> all_sample_names;
4069 for (map<string, Elemental_Profile_Set>::const_iterator profile_set = cbegin();
4070 profile_set != cend();
4077 for (map<string, Elemental_Profile>::const_iterator profile = profile_set->second.cbegin();
4078 profile != profile_set->second.cend();
4081 all_sample_names.push_back(profile->first);
4086 return all_sample_names;
4093 vector<string> selected_samples;
4096 for (
size_t i = 0; i < all_samples.size(); i++)
4102 if (random_value < percentage)
4104 selected_samples.push_back(all_samples[i]);
4108 return selected_samples;
4112 const string& target_sample,
4113 map<string, string> arguments,
4116 const string& working_folder)
4122 if (progress_window ==
nullptr)
4123 progress_window = &discarded_progress;
4127 results.
SetName(
"MCMC results for '" + target_sample +
"'");
4130 bool apply_om_size_correction = (arguments[
"Apply size and organic matter correction"] ==
"true");
4137 if (negative_elements.size() > 0)
4140 results.
SetError(
"Negative elemental content in ");
4141 for (
size_t i = 0; i < negative_elements.size(); i++)
4152 mcmc->
Model = &corrected_data;
4155 progress_window->
SetTitle(
"Acceptance Rate", 0);
4156 progress_window->
SetTitle(
"Purturbation Factor", 1);
4157 progress_window->
SetTitle(
"Log posterior value", 2);
4161 progress_window->
Start();
4167 mcmc->
SetProperty(
"number_of_samples", arguments[
"Number of samples"]);
4168 mcmc->
SetProperty(
"number_of_chains", arguments[
"Number of chains"]);
4169 mcmc->
SetProperty(
"number_of_burnout_samples", arguments[
"Samples to be discarded (burnout)"]);
4170 mcmc->
SetProperty(
"dissolve_chains", arguments[
"Dissolve Chains"]);
4178 if (!QString::fromStdString(arguments[
"Samples File Name"]).contains(
"/"))
4180 output_path = working_folder +
"/";
4184 int num_chains = QString::fromStdString(arguments[
"Number of chains"]).toInt();
4185 int num_samples = QString::fromStdString(arguments[
"Number of samples"]).toInt();
4186 mcmc->
step(num_chains, num_samples, output_path + arguments[
"Samples File Name"],
4191 size_t last_source_idx = source_names.size() - 1;
4193 source_names[last_source_idx] +
"_contribution");
4199 mcmc_samples_result.
SetName(
"MCMC samples");
4201 results.
Append(mcmc_samples_result);
4204 int burnin_samples = QString::fromStdString(arguments[
"Samples to be discarded (burnout)"]).toInt();
4209 *posterior_distributions =
mcmc_samples->distribution(100, burnin_samples);
4211 posterior_distributions_result.
SetName(
"Posterior Distributions");
4215 posterior_distributions_result.
SetResult(posterior_distributions);
4216 results.
Append(posterior_distributions_result);
4221 for (
size_t i = 0; i < corrected_data.
GetSourceOrder().size(); i++)
4226 double percentile_2_5 =
mcmc_samples->at(i).percentile(0.025, burnin_samples);
4227 double percentile_97_5 =
mcmc_samples->at(i).percentile(0.975, burnin_samples);
4229 double median_contribution =
mcmc_samples->at(i).percentile(0.5, burnin_samples);
4233 interval.
SetMean(mean_contribution);
4234 interval.
SetMedian(median_contribution);
4236 (*contribution_credible_intervals)[
mcmc_samples->getSeriesName(i)] = interval;
4240 contribution_intervals_result.
SetName(
"Source Contribution Credible Intervals");
4244 contribution_intervals_result.
SetResult(contribution_credible_intervals);
4247 results.
Append(contribution_intervals_result);
4251 vector<string> element_names = corrected_data.
ElementOrder();
4252 vector<string> isotope_names = corrected_data.
IsotopeOrder();
4253 vector<string> all_constituent_names = element_names;
4254 all_constituent_names.insert(all_constituent_names.end(), isotope_names.begin(), isotope_names.end());
4257 for (
size_t i = 0; i < predicted_samples.size(); i++)
4259 predicted_samples.setname(i, all_constituent_names[i]);
4264 for (
size_t i = 0; i < predicted_samples.size(); i++)
4269 predicted_elements.append(predicted_samples[i], predicted_samples.getSeriesName(i));
4275 *predicted_element_distributions = predicted_elements.distribution(100, burnin_samples);
4278 for (
size_t i = 0; i < predicted_elements.size(); i++)
4284 predicted_elements_result.
SetName(
"Posterior Predicted Constituents");
4288 predicted_elements_result.
SetResult(predicted_element_distributions);
4289 results.
Append(predicted_elements_result);
4295 vector<double> percentile_2_5_all = predicted_samples.percentile(0.025, burnin_samples);
4296 vector<double> percentile_97_5_all = predicted_samples.percentile(0.975, burnin_samples);
4297 vector<double> mean_all = predicted_samples.mean(burnin_samples);
4298 vector<double> median_all = predicted_samples.percentile(0.5, burnin_samples);
4300 for (
size_t i = 0; i < predicted_element_distributions->size(); i++)
4305 interval.
SetMean(mean_all[i]);
4308 (*predicted_element_intervals)[predicted_element_distributions->getSeriesName(i)] = interval;
4309 (*predicted_element_intervals)[predicted_element_distributions->getSeriesName(i)].
SetValue(
4313 ResultItem predicted_element_intervals_result;
4314 predicted_element_intervals_result.
SetName(
"Predicted Samples Credible Intervals");
4318 predicted_element_intervals_result.
SetResult(predicted_element_intervals);
4320 results.
Append(predicted_element_intervals_result);
4325 for (
size_t i = 0; i < predicted_samples.size(); i++)
4330 predicted_isotopes.append(predicted_samples[i], predicted_samples.getSeriesName(i));
4335 *predicted_isotope_distributions = predicted_isotopes.distribution(100, burnin_samples);
4338 for (
size_t i = 0; i < predicted_isotopes.size(); i++)
4345 predicted_isotopes_result.
SetName(
"Posterior Predicted Isotopes");
4349 predicted_isotopes_result.
SetResult(predicted_isotope_distributions);
4350 results.
Append(predicted_isotopes_result);
4354 size_t element_offset = corrected_data.
ElementOrder().size();
4356 for (
size_t i = 0; i < predicted_isotope_distributions->size(); i++)
4359 interval.
Set(
_range::low, percentile_2_5_all[i + element_offset]);
4361 interval.
SetMean(mean_all[i + element_offset]);
4362 interval.
SetMedian(median_all[i + element_offset]);
4364 (*predicted_isotope_intervals)[predicted_isotope_distributions->getSeriesName(i)] = interval;
4365 (*predicted_isotope_intervals)[predicted_isotope_distributions->getSeriesName(i)].
SetValue(
4369 ResultItem predicted_isotope_intervals_result;
4370 predicted_isotope_intervals_result.
SetName(
"Predicted Samples Credible Intervals for Isotopes");
4374 predicted_isotope_intervals_result.
SetResult(predicted_isotope_intervals);
4376 results.
Append(predicted_isotope_intervals_result);
4390 QString safe =
name;
4391 for (QChar& c : safe)
4393 if (c.unicode() < 32 || QStringLiteral(
"\\/:*?\"<>|").contains(c))
4394 c = QLatin1Char(
'_');
4396 while (safe.endsWith(QLatin1Char(
'.')) || safe.endsWith(QLatin1Char(
' ')))
4398 return safe.isEmpty() ? QStringLiteral(
"_") : safe;
4402 map<string, string> arguments,
4405 const string& working_folder,
4406 vector<string>* failed_writes)
4412 if (progress_window ==
nullptr)
4413 progress_window = &discarded_progress;
4421 CMBMatrix contribution_statistics(num_columns, num_target_samples);
4427 contribution_statistics.
SetColumnLabel(source_idx * 4, source_name +
"-low");
4428 contribution_statistics.
SetColumnLabel(source_idx * 4 + 1, source_name +
"-high");
4429 contribution_statistics.
SetColumnLabel(source_idx * 4 + 2, source_name +
"-median");
4430 contribution_statistics.
SetColumnLabel(source_idx * 4 + 3, source_name +
"-mean");
4434 size_t sample_counter = 0;
4435 for (map<string, Elemental_Profile>::iterator sample = at(
target_group_).begin();
4439 const string& sample_name = sample->first;
4442 QDir sample_dir(QString::fromStdString(working_folder) +
"/" +
4444 const bool sample_dir_ok = sample_dir.exists() || sample_dir.mkpath(
".");
4445 if (!sample_dir_ok && failed_writes !=
nullptr)
4447 failed_writes->push_back(
"could not create folder " +
4448 sample_dir.absolutePath().toStdString());
4452 contribution_statistics.
SetRowLabel(sample_counter, sample_name);
4455 progress_window->
SetLabel(QString::fromStdString(sample_name));
4461 const string sample_folder = sample_dir_ok ? sample_dir.absolutePath().toStdString() : working_folder;
4462 Results mcmc_results =
MCMC(sample_name, arguments, mcmc, progress_window, sample_folder);
4467 for (map<string, ResultItem>::iterator result_item = mcmc_results.begin();
4468 sample_dir_ok && result_item != mcmc_results.end();
4471 QString file_path = sample_dir.absolutePath() +
"/" +
4472 SafeFileName(QString::fromStdString(result_item->first)) +
".txt";
4473 QFile output_file(file_path);
4474 if (!output_file.open(QIODevice::WriteOnly | QIODevice::Text))
4476 if (failed_writes !=
nullptr)
4477 failed_writes->push_back(file_path.toStdString() +
": " +
4478 output_file.errorString().toStdString());
4481 result_item->second.Result()->writetofile(&output_file);
4482 output_file.close();
4483 if (output_file.error() != QFileDevice::NoError && failed_writes !=
nullptr)
4485 failed_writes->push_back(file_path.toStdString() +
": " +
4486 output_file.errorString().toStdString());
4492 mcmc_results.at(
"3:Source Contribution Credible Intervals").Result());
4496 const string contribution_name =
samplesetsorder_[source_idx] +
"_contribution";
4497 const Range& contribution_interval = credible_intervals->at(contribution_name);
4500 contribution_statistics[sample_counter][4 * source_idx] = contribution_interval.
Get(
_range::low);
4501 contribution_statistics[sample_counter][4 * source_idx + 1] = contribution_interval.
Get(
_range::high);
4502 contribution_statistics[sample_counter][4 * source_idx + 2] = contribution_interval.
Median();
4503 contribution_statistics[sample_counter][4 * source_idx + 3] = contribution_interval.
Mean();
4509 progress_window->
SetProgress2(
double(sample_counter) / double(num_target_samples));
4520 return contribution_statistics;
4540 return element->first;
4557 return element->first;
4568 CMatrix within_group_covariance(element_names.size());
4571 int total_degrees_of_freedom = 0;
4572 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4573 source_group != end();
4579 int group_df = source_group->second.size() - 1;
4580 within_group_covariance += group_df * source_group->second.CalculateCovarianceMatrix();
4581 total_degrees_of_freedom += group_df;
4586 return within_group_covariance / double(total_degrees_of_freedom);
4592 CMatrix between_group_covariance(element_names.size());
4598 double total_samples = 0.0;
4599 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4600 source_group != end();
4607 CMBVector deviation = overall_mean - group_mean;
4610 size_t group_size = source_group->second.
size();
4611 for (
size_t i = 0; i < element_names.size(); i++)
4613 for (
size_t j = 0; j < element_names.size(); j++)
4615 between_group_covariance[i][j] += deviation[i] * deviation[j] * group_size;
4619 total_samples += group_size;
4624 return between_group_covariance / total_samples;
4630 CMatrix total_scatter(element_names.size());
4636 double total_samples = 0.0;
4637 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4638 source_group != end();
4644 for (map<string, Elemental_Profile>::iterator sample = source_group->second.begin();
4645 sample != source_group->second.end();
4649 for (
size_t i = 0; i < element_names.size(); i++)
4651 for (
size_t j = 0; j < element_names.size(); j++)
4653 double deviation_i = overall_mean[i] - sample->second.at(element_names[i]);
4654 double deviation_j = overall_mean[j] - sample->second.at(element_names[j]);
4655 total_scatter[i][j] += deviation_i * deviation_j;
4660 total_samples += source_group->second.
size();
4665 return total_scatter / total_samples;
4673 CMatrix_arma total_cov = within_group_cov + between_group_cov;
4676 double numerator = within_group_cov.det();
4677 double denominator = total_cov.det();
4680 return fabs(numerator) / fabs(denominator);
4693 double chi_squared = -(sample_size - 1.0 - correction_factor) *
log(wilks_lambda);
4696 double degrees_of_freedom;
4709 double p_value = gsl_cdf_chisq_Q(chi_squared, degrees_of_freedom);
4722 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4723 source_group != end();
4727 CMBVector group_scores = source_group->second.CalculateDotProduct(discriminant_function);
4728 projected_scores.
Append(source_group->first, group_scores);
4731 return projected_scores;
4743 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4744 source_group != end();
4748 CMBVector group_scores = source_group->second.CalculateDotProduct(discriminant_function);
4749 projected_scores.
Append(source_group->first, group_scores);
4752 return projected_scores;
4763 for (map<string, Elemental_Profile_Set>::iterator source_group = original->begin();
4764 source_group != original->end();
4771 CMBVector group_scores = source_group->second.CalculateDotProduct(discriminant_function);
4772 projected_scores.
Append(source_group->first, group_scores);
4776 return projected_scores;
4786 CMatrix_arma inv_within_cov = inv(within_group_cov);
4789 if (inv_within_cov.getnumrows() == 0)
4795 CMatrix_arma product_matrix = inv_within_cov * between_group_cov;
4798 arma::cx_vec eigenvalues;
4799 arma::cx_mat eigenvectors;
4800 eig_gen(eigenvalues, eigenvectors, product_matrix);
4803 CVector_arma real_eigenvalues = GetReal(eigenvalues);
4804 CMatrix_arma real_eigenvectors = GetReal(eigenvectors);
4807 size_t max_eigenvalue_index = real_eigenvalues.abs_max_elems();
4808 CMBVector discriminant_function = CVector_arma(real_eigenvectors.getcol(max_eigenvalue_index));
4812 discriminant_function.
SetLabels(element_names);
4814 return discriminant_function;
4820 CMatrix_arma cov_matrix1 = at(source1).CalculateCovarianceMatrix();
4821 CMatrix_arma cov_matrix2 = at(source2).CalculateCovarianceMatrix();
4824 CVector mean_vector1 = at(source1).CalculateElementMeans();
4825 CVector mean_vector2 = at(source2).CalculateElementMeans();
4826 CVector_arma mean1 = mean_vector1;
4827 CVector_arma mean2 = mean_vector2;
4830 CMatrix_arma pooled_cov = cov_matrix1 + cov_matrix2;
4831 CVector weight_vector_arma = (mean2 - mean1) / pooled_cov;
4834 CMBVector weight_vector = weight_vector_arma;
4835 weight_vector = weight_vector / weight_vector.norm2();
4840 return weight_vector;
4846 if (count(group_name) == 0)
4853 CMBVector group_mean = at(group_name).CalculateElementMeans();
4862 CMBVector weighted_mean(element_names.size());
4865 double total_samples = 0.0;
4866 for (map<string, Elemental_Profile_Set>::iterator source_group = begin();
4867 source_group != end();
4874 size_t group_size = source_group->second.size();
4877 weighted_mean += double(group_size) * group_mean;
4878 total_samples += double(group_size);
4885 return weighted_mean / total_samples;
4889 const string& source1,
4890 const string& source2)
4893 vector<CMBVector> stepwise_results(3);
4896 vector<string> selected_elements;
4899 for (
size_t step = 0; step < element_names.size(); step++)
4908 double best_p_value = 100.0;
4909 string best_element;
4910 double best_wilks_lambda;
4911 double best_f_test_p_value;
4914 for (
size_t j = 0; j < element_names.size(); j++)
4917 if (lookup(selected_elements, element_names[j]) == -1)
4920 vector<string> candidate_elements = selected_elements;
4921 candidate_elements.push_back(element_names[j]);
4932 return stepwise_results;
4936 if (candidate_dfa.
p_values[0] < best_p_value)
4938 best_element = element_names[j];
4939 best_p_value = candidate_dfa.
p_values[0];
4947 stepwise_results[0].
append(best_element, best_p_value);
4948 stepwise_results[1].append(best_element, best_wilks_lambda);
4949 stepwise_results[2].append(best_element, best_f_test_p_value);
4952 selected_elements.push_back(best_element);
4955 return stepwise_results;
4961 vector<CMBVector> stepwise_results(3);
4964 vector<string> selected_elements;
4967 for (
size_t step = 0; step < element_names.size(); step++)
4976 double best_p_value = 100.0;
4977 string best_element;
4978 double best_wilks_lambda;
4979 double best_f_test_p_value;
4982 for (
size_t j = 0; j < element_names.size(); j++)
4985 if (lookup(selected_elements, element_names[j]) == -1)
4988 vector<string> candidate_elements = selected_elements;
4989 candidate_elements.push_back(element_names[j]);
4998 if (p_value < best_p_value)
5000 best_element = element_names[j];
5001 best_p_value = p_value;
5002 best_wilks_lambda = candidate_dataset.
WilksLambda();
5012 stepwise_results[0].append(best_element, best_p_value);
5013 stepwise_results[1].append(best_element, best_wilks_lambda);
5014 stepwise_results[2].append(best_element, best_f_test_p_value);
5017 selected_elements.push_back(best_element);
5020 return stepwise_results;
5026 vector<CMBVector> stepwise_results(3);
5029 vector<string> selected_elements;
5032 for (
size_t step = 0; step < element_names.size(); step++)
5041 double best_p_value = 100.0;
5042 string best_element;
5043 double best_wilks_lambda;
5044 double best_f_test_p_value;
5047 for (
size_t j = 0; j < element_names.size(); j++)
5050 if (lookup(selected_elements, element_names[j]) == -1)
5053 vector<string> candidate_elements = selected_elements;
5054 candidate_elements.push_back(element_names[j]);
5063 if (candidate_dfa.
p_values[0] < best_p_value)
5065 best_element = element_names[j];
5066 best_p_value = candidate_dfa.
p_values[0];
5074 stepwise_results[0].
append(best_element, best_p_value);
5075 stepwise_results[1].append(best_element, best_wilks_lambda);
5076 stepwise_results[2].append(best_element, best_f_test_p_value);
5079 selected_elements.push_back(best_element);
5082 return stepwise_results;
5182 cout <<
"Sample Group '" + sample_group +
"' does not exist!" << std::endl;
5187 cout <<
"Element '" + element_name +
"' does not exist!" << std::endl;
5235 if (_omsizeconstituents.size() == 0)
5237 else if (_omsizeconstituents.size() == 1)
5239 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.
void SetType(const distribution_type &typ)
Set the distribution type and resize parameters vector.
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)
ProgressReporter that discards everything reported to it.
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.
Abstract sink for progress information produced by a running analysis.
virtual void SetLabel(const QString &label)=0
Sets the free-text status label.
virtual void SetProgress2(const double &prog)=0
Sets the secondary progress fraction, where one is displayed.
virtual void Start()
Makes the reporter visible or otherwise begins reporting.
virtual void SetXRange(const double &x0, const double &x1, int chart=0)=0
Sets the horizontal range of a chart.
virtual void SetYAxisTitle(const QString &title, int chart=0)=0
Sets the vertical axis title of a chart.
virtual void SetProgress(const double &prog)=0
Sets the primary progress fraction.
virtual void ClearGraph(int chart=0)=0
Discards the points accumulated in a chart.
virtual void SetTitle(const QString &title, int chart=0)=0
Sets the title of a chart.
virtual void AppendPoint(const double &x, const double &y, int chart=0)=0
Adds a point to one of the progress charts.
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.
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.
CMBMatrix MCMC_Batch(map< string, string > arguments, CMCMC< SourceSinkData > *mcmc, ProgressReporter *progress_window, const string &working_folder, vector< string > *failed_writes=nullptr)
Performs batch MCMC analysis on all target samples.
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_
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.
Results MCMC(const string &target_sample, map< string, string > arguments, CMCMC< SourceSinkData > *mcmc, ProgressReporter *progress_window, const string &working_folder)
Performs Markov Chain Monte Carlo analysis for Bayesian source apportionment.
ResultItem GetCalculatedElementMeans()
Computes estimated mean concentrations for all source elements.
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.
void SetProgressReporter(ProgressReporter *_rtw)
Sets the progress window for displaying optimization progress.
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
static QString SafeFileName(const QString &name)
@ 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