3#include <gsl/gsl_statistics_double.h>
11 element_distributions_(),
14 contribution_softmax_(0.0),
22 element_distributions_(other.element_distributions_),
23 mlr_vs_om_size_(other.mlr_vs_om_size_),
24 contribution_(other.contribution_),
25 contribution_softmax_(other.contribution_softmax_),
26 outlierdone_(other.outlierdone_)
38 map<string, Elemental_Profile>::operator=(other);
54 bool exclude_elements,
56 const vector<double>& om_size,
57 const map<string, element_information>* elementinfo)
const
61 for (
const auto& [sample_name, profile] : *
this)
64 if (exclude_samples && !profile.IsIncludedInAnalysis()) {
72 profile.CreateCorrectedProfile(exclude_elements, omnsizecorrect, om_size, &
mlr_vs_om_size_, elementinfo)
78 profile.CreateCorrectedProfile(exclude_elements,
false, om_size,
nullptr, elementinfo)
88 const map<string, element_information>* elementinfo,
93 for (
const auto& [sample_name, profile] : *
this)
95 out.
AppendProfile(sample_name, profile.ExtractChemicalElements(elementinfo, isotopes));
102 const vector<string>& element_list)
const
106 for (
const auto& [sample_name, profile] : *
this)
108 out.
AppendProfile(sample_name, profile.ExtractElements(element_list));
115 bool applyomsizecorrection,
116 const vector<double>& om_size,
117 map<string, element_information>* elementinfo)
121 if (applyomsizecorrection)
127 for (
auto& [sample_name, profile] : *
this)
130 if (profile.IsIncludedInAnalysis() && !sample_name.empty())
142 vector<string> samples_to_eliminate,
143 map<string, element_information>* elementinfo)
const
147 for (
const auto& [sample_name, profile] : *
this)
150 if (profile.IsIncludedInAnalysis() && lookup(samples_to_eliminate, sample_name) == -1)
167 for (
auto& [sample_name, profile] : *
this)
170 for (
const auto& [element_name, concentration] : profile)
182 map<string, element_information>* elementinfo)
187 std::cerr <<
"Profile '" +
name +
"' already exists!" << std::endl;
195 for (
const auto& [element_name, concentration] : profile)
198 if (elementinfo ==
nullptr)
203 else if (elementinfo->count(element_name) != 0)
205 const auto& elem_info = elementinfo->at(element_name);
208 if (elem_info.include_in_analysis &&
218 return &operator[](
name);
223 map<string, element_information>* elementinfo)
226 for (
const auto& [sample_name, profile] : profiles)
237 vector<string> sample_names;
238 sample_names.reserve(size());
240 for (
const auto& [sample_name, profile] : *
this)
242 sample_names.push_back(sample_name);
260 out +=
"Element name\t";
261 for (
const auto& [sample_name, profile] : *
this)
263 out += sample_name +
"\t";
268 for (
const string& element : element_names)
271 for (
const auto& [sample_name, profile] : *
this)
273 out +=
"\t" + aquiutils::numbertostring(profile.at(element));
287 file->write(QString::fromStdString(
ToString()).toUtf8());
293 QJsonObject json_object;
299 for (
auto& [sample_name, profile] : *
this)
302 if (!sample_name.empty())
304 json_object[QString::fromStdString(sample_name)] = profile.toJsonObject();
315 for (
const QString& key : jsonobject.keys())
346 for (
const auto& [sample_name, profile] : *
this)
348 if (!profile.Contains(element_name)) {
359 return vector<string>();
363 vector<string> element_names;
365 element_names.reserve(first_profile.size());
367 for (
const auto& [element_name, concentration] : first_profile)
369 element_names.push_back(element_name);
372 return element_names;
377 if (count(
name) == 0)
379 std::cerr <<
"Sample '" +
name +
"' does not exist!" << std::endl;
383 return &operator[](
name);
388 if (index >= size()) {
394 std::advance(it, index);
401 if (count(
name) == 0)
403 std::cerr <<
"Sample '" +
name +
"' does not exist!" << std::endl;
412 if (index >= size()) {
418 std::advance(it, index);
427 vector<double> concentrations;
430 if (empty() || begin()->second.count(element_name) == 0) {
431 return concentrations;
434 concentrations.reserve(size());
436 for (
const auto& [sample_name, profile] : *
this)
438 concentrations.push_back(profile.at(element_name));
441 return concentrations;
447 if (count(sample_name) == 0) {
448 return vector<double>();
452 return at(sample_name).GetAllValues();
461 double maximum = -std::numeric_limits<double>::max();
463 for (
const auto& [sample_name, profile] : *
this)
465 double profile_max = profile.GetMaximum();
466 if (profile_max > maximum) {
467 maximum = profile_max;
480 double minimum = std::numeric_limits<double>::max();
482 for (
const auto& [sample_name, profile] : *
this)
484 double profile_min = profile.GetMinimum();
485 if (profile_min < minimum) {
486 minimum = profile_min;
498 const double& p_value_threshold)
503 for (
const string& element : element_names)
506 models[element].SetDependentVariableName(element);
513 const string& element,
517 const double& p_value_threshold)
525 vector<vector<double>> independents;
526 vector<string> independent_var_names;
530 independent_var_names.push_back(om);
535 independent_var_names.push_back(d);
542 model.
Regress(independents, dependent, independent_var_names);
551 const double& p_value_threshold)
581 CMBMatrix covariance_matrix(element_names.size());
587 for (
size_t i = 0; i < element_names.size(); i++)
590 covariance_matrix.
SetRowLabel(i, element_names[i]);
594 for (
size_t i = 0; i < data_matrix->size2; i++)
596 for (
size_t j = i; j < data_matrix->size2; j++)
598 gsl_vector_view col_i = gsl_matrix_column(data_matrix, i);
599 gsl_vector_view col_j = gsl_matrix_column(data_matrix, j);
602 double cov = gsl_stats_covariance(
603 col_i.vector.data, col_i.vector.stride,
604 col_j.vector.data, col_j.vector.stride,
609 double adjusted_cov = cov * (col_i.vector.size - 1) / col_i.vector.size;
612 covariance_matrix[i][j] = adjusted_cov;
613 covariance_matrix[j][i] = adjusted_cov;
617 gsl_matrix_free(data_matrix);
618 return covariance_matrix;
624 CMBMatrix correlation_matrix(element_names.size());
630 for (
size_t i = 0; i < element_names.size(); i++)
633 correlation_matrix.
SetRowLabel(i, element_names[i]);
637 for (
size_t i = 0; i < data_matrix->size2; i++)
639 for (
size_t j = i; j < data_matrix->size2; j++)
641 gsl_vector_view col_i = gsl_matrix_column(data_matrix, i);
642 gsl_vector_view col_j = gsl_matrix_column(data_matrix, j);
644 double corr = gsl_stats_correlation(
645 col_i.vector.data, col_i.vector.stride,
646 col_j.vector.data, col_j.vector.stride,
651 correlation_matrix[i][j] = corr;
652 correlation_matrix[j][i] = corr;
656 gsl_matrix_free(data_matrix);
657 return correlation_matrix;
665 gsl_matrix*
matrix = gsl_matrix_alloc(size(), element_names.size());
669 for (
const auto& [sample_name, profile] : *
this)
672 for (
const auto& [element_name, concentration] : profile)
674 gsl_matrix_set(
matrix, row, col, concentration);
688 CMBVector ks_statistics(element_names.size());
691 for (
size_t i = 0; i < element_names.size(); i++)
694 CalculateKolmogorovSmirnovStatistic(dist_type);
697 return ks_statistics;
701 const vector<string>& element_order)
const
704 vector<string> element_names = element_order.empty() ?
707 CVector means(element_names.size());
709 for (
size_t i = 0; i < element_names.size(); i++)
721 QTableWidget* table =
new QTableWidget();
722 table->setEditTriggers(QAbstractItemView::NoEditTriggers);
727 table->setRowCount(element_names.size());
728 table->setColumnCount(size());
731 QStringList row_headers;
732 for (
const string& element : element_names)
734 row_headers << QString::fromStdString(element);
736 table->setVerticalHeaderLabels(row_headers);
739 QStringList column_headers;
742 for (
const auto& [sample_name, profile] : *
this)
745 column_headers << QString::fromStdString(sample_name);
748 for (
size_t row = 0; row < element_names.size(); row++)
750 double concentration = profile.GetValue(element_names[row]);
751 table->setItem(row, col,
new QTableWidgetItem(QString::number(concentration)));
758 table->item(row, col)->setForeground(QColor(Qt::red));
766 table->setHorizontalHeaderLabels(column_headers);
773 const vector<double>& om_size,
774 map<string, element_information>* elementinfo)
778 for (
auto& [sample_name, profile] : *
this)
781 if (profile.IsIncludedInAnalysis() && !sample_name.empty())
786 corrected_set.
AppendProfile(sample_name, corrected_profile, elementinfo);
790 return corrected_set;
801 lambda_values[i] =
distribution.FindOptimalBoxCoxParameter(-5.0, 5.0, 10);
802 lambda_values.
SetLabel(i, element_name);
806 return lambda_values;
811 const double& lowerlimit,
812 const double& upperlimit)
818 CMBMatrix outlier_magnitude(begin()->second.size(), size());
821 vector<double> means;
836 size_t sample_idx = 0;
837 for (
auto& [sample_name, profile] : *
this)
839 profile.ClearNotes();
840 outlier_magnitude.
SetRowLabel(sample_idx, sample_name);
842 size_t element_idx = 0;
843 for (
const auto& [element_name, concentration] : profile)
848 double lambda = lambdas[element_idx];
849 double transformed_value = (pow(concentration, lambda) - 1.0) / lambda;
852 double z_score = (transformed_value - means[element_idx]) / stds[element_idx];
853 outlier_magnitude[sample_idx][element_idx] = z_score;
856 if (upperlimit != lowerlimit)
858 if (z_score > upperlimit || z_score < lowerlimit)
860 profile.
AppendtoNotes(element_name +
" was detected as outlier");
871 return outlier_magnitude;
879 CMBVector lambdas = (lambda_vals ==
nullptr) ?
894 size_t sample_idx = 0;
895 for (
auto& [sample_name, profile] : transformed)
897 profile[element_name] = transformed_values[sample_idx];
916 for (
const auto& [sample_name, profile] : *
this)
918 matrix.SetRowLabel(row, sample_name);
921 for (
const auto& [element_name, concentration] : profile)
923 matrix[row][col] = concentration;
924 matrix.SetColumnLabel(col, element_name);
937 const vector<string>& element_names)
const
939 vector<string> elements_with_negative_values;
941 for (
const string& element : element_names)
945 elements_with_negative_values.push_back(element);
949 return elements_with_negative_values;
958 for (
const auto& [sample_name, profile] : *
this)
961 CMBVector sorted = profile.SortByConcentration();
963 for (
int i = 0; i < n && i < sorted.num; i++)
965 string element_name = sorted.
Label(i);
966 double concentration = sorted[i];
969 if (aggregated.count(element_name) == 0)
975 aggregated[element_name] = std::min(concentration, aggregated[element_name]);
989 for (
const auto& [sample_name, profile] : *
this)
991 dot_products[i] = profile.CalculateDotProduct(v);
992 dot_products.
SetLabel(i, sample_name);
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.
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.
string Label(int i) const
Gets label at specified index.
Manages a collection of concentration measurements with statistical analysis.
double CalculateMean() const
Calculate arithmetic mean.
double GetMinimum() const
Get minimum value.
ConcentrationSet ApplyBoxCoxTransform(double lambda, bool normalize) const
Apply Box-Cox transformation.
double CalculateStdDev(double mean_value=-999) const
Calculate standard deviation.
Represents a parametric probability distribution for uncertainty quantification.
Manages a collection of elemental profiles (samples) for source fingerprinting analysis.
gsl_matrix * CopyToGSLMatrix() const
Convert to GSL matrix for statistical functions.
CMBMatrix ToMatrix() const
Convert to matrix format (samples × elements)
ConcentrationSet * GetElementDistribution(const string &element_name)
Get distribution for a specific element (mutable)
bool writetofile(QFile *file) override
Write object data to a file.
Elemental_Profile_Set CreateCorrectedSet(bool exclude_samples, bool exclude_elements, bool omnsizecorrect, const vector< double > &om_size, const map< string, element_information > *elementinfo=nullptr) const
Create corrected and filtered subset.
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)
CMBVector CalculateKolmogorovSmirnovStatistics(distribution_type dist_type)
Calculate Kolmogorov-Smirnov statistics for all elements.
vector< double > GetAllConcentrationsFor(const string &element_name)
Get all concentration values for a specific element across samples.
ResultItem GetRegressionsAsResult()
Get regressions wrapped in ResultItem for display.
Elemental_Profile SelectTopElementsAggregate(int n) const
Select top N elements across all samples (aggregate minimum)
void UpdateElementDistributions()
Rebuild element distributions from all profiles.
Elemental_Profile_Set & operator=(const Elemental_Profile_Set &other)
vector< string > GetElementNames() const
Get all element names (from first profile)
bool SetContributionSoftmax(const double &value)
Set softmax-transformed contribution.
MultipleLinearRegressionSet * GetRegressionModels()
Get internal regression model set.
double GetMinimum() const
Get minimum concentration across all elements and samples.
vector< double > GetConcentrationsForSample(const string &sample_name) const
Get all element concentrations for a specific sample.
CMBVector CalculateDotProduct(const CVector &v) const
Calculate dot product of each profile with weight vector.
Elemental_Profile * GetProfile(const string &name)
Get profile by sample name (mutable)
bool ReadFromJsonObject(const QJsonObject &jsonobject) override
Deserialize object from JSON format.
bool Read(const QStringList &strlist) override
Parse object data from a string list.
MultipleLinearRegression BuildRegressionModel(const string &element, const string &om, const string &d, regression_form form=regression_form::linear, const double &p_value_threshold=0.05)
Build MLR model for single element vs OM and particle size.
CMBMatrix CalculateCovarianceMatrix()
Calculate covariance matrix across elements.
bool SetContribution(const double &value)
Set contribution value for this source.
double GetMaximum() const
Get maximum concentration across all elements and samples.
Elemental_Profile_Set ExtractElements(const vector< string > &element_list) const
Create subset with only specified elements.
Elemental_Profile_Set CopyIncludedInAnalysis(bool applyomsizecorrection, const vector< double > &om_size, map< string, element_information > *elementinfo=nullptr)
Copy only samples marked for inclusion in analysis.
bool ContainsElement(const string &element_name) const
Check if an element exists in ALL profiles.
MultipleLinearRegressionSet mlr_vs_om_size_
MLR models for OM/size corrections.
QJsonObject toJsonObject() const override
Serialize object to JSON format.
string ToString() const override
Convert object to string representation.
CMBVector CalculateBoxCoxParameters()
Calculate optimal Box-Cox lambda for each element.
double contribution_softmax_
Softmax-transformed contribution.
QTableWidget * ToTable() override
Create a Qt table widget representation of the data.
CVector CalculateElementMeans(const vector< string > &element_order=vector< string >()) const
Calculate mean concentration for each element.
Distribution * GetFittedDistribution(const string &element_name)
Get fitted distribution for an element (from data, for likelihood)
Elemental_Profile_Set ApplyOrganicMatterAndSizeCorrections(const vector< double > &om_size, map< string, element_information > *elementinfo=nullptr)
Apply OM and particle size corrections to all profiles.
CMBMatrix CalculateCorrelationMatrix()
Calculate correlation matrix across elements.
map< string, ConcentrationSet > element_distributions_
Concentration distributions for each element.
CMBMatrix DetectOutliers(const double &lowerlimit=0, const double &upperlimit=0)
Detect outliers using Box-Cox transformation and standardization.
Elemental_Profile_Set EliminateSamples(vector< string > samples_to_eliminate, map< string, element_information > *elementinfo) const
Create subset excluding specified samples.
MultipleLinearRegressionSet BuildRegressionModels(const string &om, const string &d, regression_form form=regression_form::linear, const double &p_value_threshold=0.05)
Build MLR models for all elements vs OM and particle size.
void SetRegressionModels(const string &om, const string &d, regression_form form=regression_form::linear, const double &p_value_threshold=0.05)
Set regression models (build new)
bool outlierdone_
Flag indicating outlier analysis performed.
double contribution_
Source contribution (for CMB)
Elemental_Profile_Set ApplyBoxCoxTransform(CMBVector *lambda_vals=nullptr)
Apply Box-Cox transformation to all profiles.
vector< string > CheckForNegativeValues(const vector< string > &element_names) const
Check for elements with negative values.
void AppendProfiles(const Elemental_Profile_Set &profiles, map< string, element_information > *elementinfo)
Add multiple profiles from another set.
Elemental_Profile_Set ExtractChemicalElements(const map< string, element_information > *elementinfo, bool isotopes) const
Create subset with only chemical elements (and optionally isotopes)
Container for elemental concentration data of a single sediment sample.
Elemental_Profile CreateAnalysisProfile(const map< string, element_information > *elementinfo=nullptr) const
Create profile with only analyzed elements.
Elemental_Profile ApplyOrganicMatterAndSizeCorrections(const vector< double > &reference_om_size, const MultipleLinearRegressionSet *regression_models, const map< string, element_information > *elementinfo=nullptr) const
Apply organic matter and particle size corrections.
bool AppendElement(const string &name, double val=0.0)
Add new element to profile.
bool ReadFromJsonObject(const QJsonObject &json) override
Deserialize from JSON object.
Abstract base class providing common serialization and visualization interface.
double lowlimit
Lower threshold for value highlighting (when enabled)
Interface & operator=(const Interface &intf)
Assignment operator.
void AppendtoNotes(const string ¬e)
Append a note to existing notes.
bool highlightoutsideoflimit
Flag indicating whether to highlight values outside defined limits.
double highlimit
Upper threshold for value highlighting (when enabled)
void SetDependentVariableName(const string name)
void SetPValueThreshold(const double &p)
double Regress(const vector< vector< double > > &independent, const vector< double > dependent, const vector< string > &indep_vars_names)
void SetEquation(regression_form form)
void SetResult(Interface *_result)
void SetType(const result_type &_type)
distribution_type
Enumeration of probability distribution types supported in SedSat3.