SedSat3 1.1.6
Sediment Source Apportionment Tool - Advanced statistical methods for environmental pollution research
Loading...
Searching...
No Matches
elemental_profile_set.cpp
Go to the documentation of this file.
2#include <iostream>
3#include <gsl/gsl_statistics_double.h>
4#include <QFile>
5
6// ========== Construction and Assignment ==========
7
10 Interface(),
11 element_distributions_(),
12 mlr_vs_om_size_(),
13 contribution_(0.0),
14 contribution_softmax_(0.0),
15 outlierdone_(false)
16{
17}
18
20 : map<string, Elemental_Profile>(other),
21 Interface(other),
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_)
27{
28}
29
31{
32 // Check for self-assignment
33 if (this == &other) {
34 return *this;
35 }
36
37 // Copy base classes
38 map<string, Elemental_Profile>::operator=(other);
40
41 // Copy member variables
47
48 return *this;
49}
50// ========== Data Extraction and Filtering ==========
51
53 bool exclude_samples,
54 bool exclude_elements,
55 bool omnsizecorrect,
56 const vector<double>& om_size,
57 const map<string, element_information>* elementinfo) const
58{
60
61 for (const auto& [sample_name, profile] : *this)
62 {
63 // Skip excluded samples if requested
64 if (exclude_samples && !profile.IsIncludedInAnalysis()) {
65 continue;
66 }
67
68 // Apply corrections based on whether MLR models exist
69 if (!mlr_vs_om_size_.empty()) {
70 out.AppendProfile(
71 sample_name,
72 profile.CreateCorrectedProfile(exclude_elements, omnsizecorrect, om_size, &mlr_vs_om_size_, elementinfo)
73 );
74 }
75 else {
76 out.AppendProfile(
77 sample_name,
78 profile.CreateCorrectedProfile(exclude_elements, false, om_size, nullptr, elementinfo)
79 );
80 }
81 }
82
84 return out;
85}
86
88 const map<string, element_information>* elementinfo,
89 bool isotopes) const
90{
92
93 for (const auto& [sample_name, profile] : *this)
94 {
95 out.AppendProfile(sample_name, profile.ExtractChemicalElements(elementinfo, isotopes));
96 }
97
98 return out;
99}
100
102 const vector<string>& element_list) const
103{
105
106 for (const auto& [sample_name, profile] : *this)
107 {
108 out.AppendProfile(sample_name, profile.ExtractElements(element_list));
109 }
110
111 return out;
112}
113
115 bool applyomsizecorrection,
116 const vector<double>& om_size,
117 map<string, element_information>* elementinfo)
118{
120
121 if (applyomsizecorrection)
122 {
123 out = ApplyOrganicMatterAndSizeCorrections(om_size, elementinfo);
124 }
125 else
126 {
127 for (auto& [sample_name, profile] : *this)
128 {
129 // Include only samples marked for analysis with non-empty names
130 if (profile.IsIncludedInAnalysis() && !sample_name.empty())
131 {
132 out.AppendProfile(sample_name, profile, elementinfo);
133 }
134 }
135 }
136
138 return out;
139}
140
142 vector<string> samples_to_eliminate,
143 map<string, element_information>* elementinfo) const
144{
146
147 for (const auto& [sample_name, profile] : *this)
148 {
149 // Include sample if it's marked for analysis AND not in elimination list
150 if (profile.IsIncludedInAnalysis() && lookup(samples_to_eliminate, sample_name) == -1)
151 {
152 out.AppendProfile(sample_name, profile, elementinfo);
153 }
154 }
155
157 return out;
158}
159
160// ========== Data Management ==========
161
163{
165
166 // Iterate through each sample profile
167 for (auto& [sample_name, profile] : *this)
168 {
169 // Iterate through each element in the profile
170 for (const auto& [element_name, concentration] : profile)
171 {
172 element_distributions_[element_name].AppendValue(concentration);
173 }
174 }
175}
176
177// ========== Data Management ==========
178
180 const string& name,
181 const Elemental_Profile& profile,
182 map<string, element_information>* elementinfo)
183{
184 // Check if profile with this name already exists
185 if (count(name) > 0)
186 {
187 std::cerr << "Profile '" + name + "' already exists!" << std::endl;
188 return nullptr;
189 }
190
191 // Add the profile (filtered by elementinfo if provided)
192 operator[](name) = profile.CreateAnalysisProfile(elementinfo);
193
194 // Update element distributions
195 for (const auto& [element_name, concentration] : profile)
196 {
197 // No filtering - add all elements
198 if (elementinfo == nullptr)
199 {
200 element_distributions_[element_name].AppendValue(concentration);
201 }
202 // With filtering - only add elements that meet criteria
203 else if (elementinfo->count(element_name) != 0)
204 {
205 const auto& elem_info = elementinfo->at(element_name);
206
207 // Include if: marked for analysis AND not excluded roles
208 if (elem_info.include_in_analysis &&
212 {
213 element_distributions_[element_name].AppendValue(concentration);
214 }
215 }
216 }
217
218 return &operator[](name);
219}
220
222 const Elemental_Profile_Set& profiles,
223 map<string, element_information>* elementinfo)
224{
225 // Add each profile from the source set
226 for (const auto& [sample_name, profile] : profiles)
227 {
228 AppendProfile(sample_name, profile, elementinfo);
229 }
230
231 // Rebuild distributions after adding all profiles
233}
234
236{
237 vector<string> sample_names;
238 sample_names.reserve(size()); // Pre-allocate for efficiency
239
240 for (const auto& [sample_name, profile] : *this)
241 {
242 sample_names.push_back(sample_name);
243 }
244
245 return sample_names;
246}
247
248// ========== Serialization ==========
249
251{
252 if (empty()) {
253 return string();
254 }
255
256 string out;
257 vector<string> element_names = GetElementNames();
258
259 // Header row: "Element name" followed by sample names
260 out += "Element name\t";
261 for (const auto& [sample_name, profile] : *this)
262 {
263 out += sample_name + "\t";
264 }
265 out += "\n";
266
267 // Data rows: element name followed by concentrations for each sample
268 for (const string& element : element_names)
269 {
270 out += element;
271 for (const auto& [sample_name, profile] : *this)
272 {
273 out += "\t" + aquiutils::numbertostring(profile.at(element));
274 }
275 out += "\n";
276 }
277
278 return out;
279}
280
282{
283 if (!file) {
284 return false;
285 }
286
287 file->write(QString::fromStdString(ToString()).toUtf8());
288 return true; // Fixed: was returning 0 (false)
289}
290
292{
293 QJsonObject json_object;
294
295 if (empty()) {
296 return json_object;
297 }
298
299 for (auto& [sample_name, profile] : *this)
300 {
301 // Only include samples with non-empty names
302 if (!sample_name.empty())
303 {
304 json_object[QString::fromStdString(sample_name)] = profile.toJsonObject();
305 }
306 }
307
308 return json_object;
309}
310
311bool Elemental_Profile_Set::ReadFromJsonObject(const QJsonObject& jsonobject)
312{
313 clear();
314
315 for (const QString& key : jsonobject.keys())
316 {
317 if (key.isEmpty()) {
318 continue;
319 }
320
321 Elemental_Profile elemental_profile;
322 if (elemental_profile.ReadFromJsonObject(jsonobject[key].toObject()))
323 {
324 AppendProfile(key.toStdString(), elemental_profile);
325 }
326 }
327
328 return true;
329}
330bool Elemental_Profile_Set::Read(const QStringList &strlist)
331{
332
333
334 return true;
335}
336
337// ========== Data Access ==========
338
339bool Elemental_Profile_Set::ContainsElement(const string& element_name) const
340{
341 if (empty()) {
342 return false;
343 }
344
345 // Element must exist in all profiles
346 for (const auto& [sample_name, profile] : *this)
347 {
348 if (!profile.Contains(element_name)) {
349 return false;
350 }
351 }
352
353 return true;
354}
355
357{
358 if (empty()) {
359 return vector<string>();
360 }
361
362 // Get element names from the first profile
363 vector<string> element_names;
364 const Elemental_Profile& first_profile = begin()->second;
365 element_names.reserve(first_profile.size());
366
367 for (const auto& [element_name, concentration] : first_profile)
368 {
369 element_names.push_back(element_name);
370 }
371
372 return element_names;
373}
374
376{
377 if (count(name) == 0)
378 {
379 std::cerr << "Sample '" + name + "' does not exist!" << std::endl;
380 return nullptr;
381 }
382
383 return &operator[](name);
384}
385
387{
388 if (index >= size()) {
389 return nullptr;
390 }
391
392 // Advance iterator to the requested index
393 auto it = begin();
394 std::advance(it, index);
395
396 return &it->second;
397}
398
400{
401 if (count(name) == 0)
402 {
403 std::cerr << "Sample '" + name + "' does not exist!" << std::endl;
404 return Elemental_Profile();
405 }
406
407 return at(name);
408}
409
411{
412 if (index >= size()) {
413 return Elemental_Profile();
414 }
415
416 // Advance iterator to the requested index
417 auto it = begin();
418 std::advance(it, index);
419
420 return it->second;
421}
422
423// ========== Data Access (continued) ==========
424
425vector<double> Elemental_Profile_Set::GetAllConcentrationsFor(const string& element_name)
426{
427 vector<double> concentrations;
428
429 // Check if element exists in first profile
430 if (empty() || begin()->second.count(element_name) == 0) {
431 return concentrations;
432 }
433
434 concentrations.reserve(size());
435
436 for (const auto& [sample_name, profile] : *this)
437 {
438 concentrations.push_back(profile.at(element_name));
439 }
440
441 return concentrations;
442}
443
444vector<double> Elemental_Profile_Set::GetConcentrationsForSample(const string& sample_name) const
445{
446 // Check if sample exists
447 if (count(sample_name) == 0) {
448 return vector<double>();
449 }
450
451 // Use at() to get const reference (no copy)
452 return at(sample_name).GetAllValues();
453}
454
456{
457 if (empty()) {
458 return 0.0;
459 }
460
461 double maximum = -std::numeric_limits<double>::max();
462
463 for (const auto& [sample_name, profile] : *this)
464 {
465 double profile_max = profile.GetMaximum();
466 if (profile_max > maximum) {
467 maximum = profile_max;
468 }
469 }
470
471 return maximum;
472}
473
475{
476 if (empty()) {
477 return 0.0;
478 }
479
480 double minimum = std::numeric_limits<double>::max();
481
482 for (const auto& [sample_name, profile] : *this)
483 {
484 double profile_min = profile.GetMinimum();
485 if (profile_min < minimum) {
486 minimum = profile_min;
487 }
488 }
489
490 return minimum;
491}
492// ========== Regression Models (OM/Size Corrections) ==========
493
495 const string& om,
496 const string& d,
497 regression_form form,
498 const double& p_value_threshold)
499{
501 vector<string> element_names = GetElementNames();
502
503 for (const string& element : element_names)
504 {
505 models[element] = BuildRegressionModel(element, om, d, form, p_value_threshold);
506 models[element].SetDependentVariableName(element);
507 }
508
509 return models;
510}
511
513 const string& element,
514 const string& om,
515 const string& d,
516 regression_form form,
517 const double& p_value_threshold)
518{
520
521 // Get dependent variable (element concentrations)
522 vector<double> dependent = GetAllConcentrationsFor(element);
523
524 // Build independent variables (OM and/or particle size)
525 vector<vector<double>> independents;
526 vector<string> independent_var_names;
527
528 if (!om.empty()) {
529 independents.push_back(GetAllConcentrationsFor(om));
530 independent_var_names.push_back(om);
531 }
532
533 if (!d.empty()) {
534 independents.push_back(GetAllConcentrationsFor(d));
535 independent_var_names.push_back(d);
536 }
537
538 // Configure and run regression
539 model.SetPValueThreshold(p_value_threshold);
540 model.SetEquation(form);
541 model.SetDependentVariableName(element);
542 model.Regress(independents, dependent, independent_var_names);
543
544 return model;
545}
546
548 const string& om,
549 const string& d,
550 regression_form form,
551 const double& p_value_threshold)
552{
553 mlr_vs_om_size_ = BuildRegressionModels(om, d, form, p_value_threshold);
554}
555
562
570
575
576// ========== Statistical Analysis ==========
577
579{
580 vector<string> element_names = GetElementNames();
581 CMBMatrix covariance_matrix(element_names.size());
582
583 // Convert to GSL matrix for statistics calculations
584 gsl_matrix* data_matrix = CopyToGSLMatrix();
585
586 // Set matrix labels
587 for (size_t i = 0; i < element_names.size(); i++)
588 {
589 covariance_matrix.SetColumnLabel(i, element_names[i]);
590 covariance_matrix.SetRowLabel(i, element_names[i]);
591 }
592
593 // Calculate covariance for each element pair
594 for (size_t i = 0; i < data_matrix->size2; i++)
595 {
596 for (size_t j = i; j < data_matrix->size2; j++)
597 {
598 gsl_vector_view col_i = gsl_matrix_column(data_matrix, i);
599 gsl_vector_view col_j = gsl_matrix_column(data_matrix, j);
600
601 // GSL uses n-1 denominator, but we want n denominator for consistency
602 double cov = gsl_stats_covariance(
603 col_i.vector.data, col_i.vector.stride,
604 col_j.vector.data, col_j.vector.stride,
605 col_i.vector.size
606 );
607
608 // Adjust from n-1 to n denominator
609 double adjusted_cov = cov * (col_i.vector.size - 1) / col_i.vector.size;
610
611 // Matrix is symmetric
612 covariance_matrix[i][j] = adjusted_cov;
613 covariance_matrix[j][i] = adjusted_cov;
614 }
615 }
616
617 gsl_matrix_free(data_matrix);
618 return covariance_matrix;
619}
620
622{
623 vector<string> element_names = GetElementNames();
624 CMBMatrix correlation_matrix(element_names.size());
625
626 // Convert to GSL matrix for statistics calculations
627 gsl_matrix* data_matrix = CopyToGSLMatrix();
628
629 // Set matrix labels
630 for (size_t i = 0; i < element_names.size(); i++)
631 {
632 correlation_matrix.SetColumnLabel(i, element_names[i]);
633 correlation_matrix.SetRowLabel(i, element_names[i]);
634 }
635
636 // Calculate correlation for each element pair
637 for (size_t i = 0; i < data_matrix->size2; i++)
638 {
639 for (size_t j = i; j < data_matrix->size2; j++)
640 {
641 gsl_vector_view col_i = gsl_matrix_column(data_matrix, i);
642 gsl_vector_view col_j = gsl_matrix_column(data_matrix, j);
643
644 double corr = gsl_stats_correlation(
645 col_i.vector.data, col_i.vector.stride,
646 col_j.vector.data, col_j.vector.stride,
647 col_i.vector.size
648 );
649
650 // Matrix is symmetric
651 correlation_matrix[i][j] = corr;
652 correlation_matrix[j][i] = corr;
653 }
654 }
655
656 gsl_matrix_free(data_matrix);
657 return correlation_matrix;
658}
659
661{
662 vector<string> element_names = GetElementNames();
663
664 // Allocate matrix: rows = samples, columns = elements
665 gsl_matrix* matrix = gsl_matrix_alloc(size(), element_names.size());
666
667 // Fill matrix with concentration data
668 size_t row = 0;
669 for (const auto& [sample_name, profile] : *this)
670 {
671 size_t col = 0;
672 for (const auto& [element_name, concentration] : profile)
673 {
674 gsl_matrix_set(matrix, row, col, concentration);
675 col++;
676 }
677 row++;
678 }
679
680 return matrix;
681}
682// ========== Statistical Analysis (continued) ==========
683
685 distribution_type dist_type)
686{
687 vector<string> element_names = GetElementNames();
688 CMBVector ks_statistics(element_names.size());
689 ks_statistics.SetLabels(element_names);
690
691 for (size_t i = 0; i < element_names.size(); i++)
692 {
693 ks_statistics[i] = GetElementDistribution(element_names[i])->
694 CalculateKolmogorovSmirnovStatistic(dist_type);
695 }
696
697 return ks_statistics;
698}
699
701 const vector<string>& element_order) const
702{
703 // Use provided element order, or get all elements if not specified
704 vector<string> element_names = element_order.empty() ?
705 GetElementNames() : element_order;
706
707 CVector means(element_names.size());
708
709 for (size_t i = 0; i < element_names.size(); i++)
710 {
711 means[i] = element_distributions_.at(element_names[i]).CalculateMean();
712 }
713
714 return means;
715}
716
717// ========== Serialization (continued) ==========
718
720{
721 QTableWidget* table = new QTableWidget();
722 table->setEditTriggers(QAbstractItemView::NoEditTriggers);
723
724 vector<string> element_names = GetElementNames();
725
726 // Set table dimensions: rows = elements, columns = samples
727 table->setRowCount(element_names.size());
728 table->setColumnCount(size());
729
730 // Build row headers (element names)
731 QStringList row_headers;
732 for (const string& element : element_names)
733 {
734 row_headers << QString::fromStdString(element);
735 }
736 table->setVerticalHeaderLabels(row_headers);
737
738 // Fill table with concentration data
739 QStringList column_headers;
740 int col = 0;
741
742 for (const auto& [sample_name, profile] : *this)
743 {
744 // Add column header (sample name)
745 column_headers << QString::fromStdString(sample_name);
746
747 // Fill column with element concentrations
748 for (size_t row = 0; row < element_names.size(); row++)
749 {
750 double concentration = profile.GetValue(element_names[row]);
751 table->setItem(row, col, new QTableWidgetItem(QString::number(concentration)));
752
753 // Highlight values outside limits if enabled
755 {
756 if (concentration > highlimit || concentration < lowlimit)
757 {
758 table->item(row, col)->setForeground(QColor(Qt::red));
759 }
760 }
761 }
762
763 col++;
764 }
765
766 table->setHorizontalHeaderLabels(column_headers);
767
768 return table;
769}
770// ========== Regression Models (continued) ==========
771
773 const vector<double>& om_size,
774 map<string, element_information>* elementinfo)
775{
776 Elemental_Profile_Set corrected_set;
777
778 for (auto& [sample_name, profile] : *this)
779 {
780 // Only include samples marked for analysis with non-empty names
781 if (profile.IsIncludedInAnalysis() && !sample_name.empty())
782 {
783 Elemental_Profile corrected_profile =
784 profile.ApplyOrganicMatterAndSizeCorrections(om_size, &mlr_vs_om_size_, elementinfo);
785
786 corrected_set.AppendProfile(sample_name, corrected_profile, elementinfo);
787 }
788 }
789
790 return corrected_set;
791}
792// ========== Box-Cox Transformations ==========
793
795{
796 CMBVector lambda_values(element_distributions_.size());
797
798 size_t i = 0;
799 for (auto& [element_name, distribution] : element_distributions_)
800 {
801 lambda_values[i] = distribution.FindOptimalBoxCoxParameter(-5.0, 5.0, 10);
802 lambda_values.SetLabel(i, element_name);
803 i++;
804 }
805
806 return lambda_values;
807}
808// ========== Outlier Detection ==========
809
811 const double& lowerlimit,
812 const double& upperlimit)
813{
814 // Calculate optimal Box-Cox parameters for each element
816
817 // Initialize output matrix: rows = samples, columns = elements
818 CMBMatrix outlier_magnitude(begin()->second.size(), size());
819
820 // Calculate means and standard deviations of Box-Cox transformed distributions
821 vector<double> means;
822 vector<double> stds;
823 means.reserve(element_distributions_.size());
824 stds.reserve(element_distributions_.size());
825
826 size_t elem_idx = 0;
827 for (auto& [element_name, distribution] : element_distributions_)
828 {
829 ConcentrationSet transformed = distribution.ApplyBoxCoxTransform(lambdas[elem_idx], false);
830 means.push_back(transformed.CalculateMean());
831 stds.push_back(transformed.CalculateStdDev());
832 elem_idx++;
833 }
834
835 // Calculate standardized outlier magnitude for each sample
836 size_t sample_idx = 0;
837 for (auto& [sample_name, profile] : *this)
838 {
839 profile.ClearNotes();
840 outlier_magnitude.SetRowLabel(sample_idx, sample_name);
841
842 size_t element_idx = 0;
843 for (const auto& [element_name, concentration] : profile)
844 {
845 outlier_magnitude.SetColumnLabel(element_idx, element_name);
846
847 // Apply Box-Cox transformation
848 double lambda = lambdas[element_idx];
849 double transformed_value = (pow(concentration, lambda) - 1.0) / lambda;
850
851 // Calculate standardized score
852 double z_score = (transformed_value - means[element_idx]) / stds[element_idx];
853 outlier_magnitude[sample_idx][element_idx] = z_score;
854
855 // Flag outliers if thresholds are set
856 if (upperlimit != lowerlimit)
857 {
858 if (z_score > upperlimit || z_score < lowerlimit)
859 {
860 profile.AppendtoNotes(element_name + " was detected as outlier");
861 }
862 }
863
864 element_idx++;
865 }
866
867 sample_idx++;
868 }
869
870 outlierdone_ = true;
871 return outlier_magnitude;
872}
873
874// ========== Box-Cox Transformations (continued) ==========
875
877{
878 // Use provided lambdas or calculate optimal ones
879 CMBVector lambdas = (lambda_vals == nullptr) ?
880 CalculateBoxCoxParameters() : *lambda_vals;
881
882 // Create copy of this set to transform
883 Elemental_Profile_Set transformed(*this);
884
885 // Apply Box-Cox transformation to each element across all samples
886 size_t elem_idx = 0;
887 for (auto& [element_name, distribution] : element_distributions_)
888 {
889 // Transform all values for this element
890 ConcentrationSet transformed_values =
891 distribution.ApplyBoxCoxTransform(lambdas[elem_idx], false);
892
893 // Update each profile with transformed value
894 size_t sample_idx = 0;
895 for (auto& [sample_name, profile] : transformed)
896 {
897 profile[element_name] = transformed_values[sample_idx];
898 sample_idx++;
899 }
900
901 elem_idx++;
902 }
903
904 return transformed;
905}
906
908{
909 vector<string> element_names = GetElementNames();
910
911 // Initialize matrix: rows = samples, columns = elements
912 CMBMatrix matrix(size(), element_names.size());
913
914 // Fill matrix with concentration data
915 size_t row = 0;
916 for (const auto& [sample_name, profile] : *this)
917 {
918 matrix.SetRowLabel(row, sample_name);
919
920 size_t col = 0;
921 for (const auto& [element_name, concentration] : profile)
922 {
923 matrix[row][col] = concentration;
924 matrix.SetColumnLabel(col, element_name);
925 col++;
926 }
927
928 row++;
929 }
930
931 return matrix;
932}
933
934// ========== Outlier Detection (continued) ==========
935
937 const vector<string>& element_names) const
938{
939 vector<string> elements_with_negative_values;
940
941 for (const string& element : element_names)
942 {
943 if (GetElementDistribution(element).GetMinimum() <= 0)
944 {
945 elements_with_negative_values.push_back(element);
946 }
947 }
948
949 return elements_with_negative_values;
950}
951
952// ========== Utility Functions (continued) ==========
953
955{
956 Elemental_Profile aggregated;
957
958 for (const auto& [sample_name, profile] : *this)
959 {
960 // Get top n elements from this profile sorted by concentration
961 CMBVector sorted = profile.SortByConcentration();
962
963 for (int i = 0; i < n && i < sorted.num; i++)
964 {
965 string element_name = sorted.Label(i);
966 double concentration = sorted[i];
967
968 // Add element if not present, or keep minimum concentration if already present
969 if (aggregated.count(element_name) == 0)
970 {
971 aggregated.AppendElement(element_name, concentration);
972 }
973 else
974 {
975 aggregated[element_name] = std::min(concentration, aggregated[element_name]);
976 }
977 }
978 }
979
980 return aggregated;
981}
982// ========== Utility Functions (continued) ==========
983
985{
986 CMBVector dot_products(size());
987
988 size_t i = 0;
989 for (const auto& [sample_name, profile] : *this)
990 {
991 dot_products[i] = profile.CalculateDotProduct(v);
992 dot_products.SetLabel(i, sample_name);
993 i++;
994 }
995
996 return dot_products;
997}
998
999// Add this to elemental_profile_set.cpp
1000
1002{
1003 if (element_distributions_.count(element_name) > 0) {
1004 return &element_distributions_[element_name];
1005 }
1006 return nullptr;
1007}
1008
1010{
1011 return element_distributions_.at(element_name);
1012}
1013
1015{
1017 return true;
1018}
1019
1021{
1022 if (element_distributions_.count(element_name) > 0)
1023 return element_distributions_[element_name].GetEstimatedDistribution();
1024 else
1025 return nullptr;
1026}
1027
1029{
1030 if (element_distributions_.count(element_name) > 0)
1031 return element_distributions_[element_name].GetFittedDistribution();
1032 else
1033 return nullptr;
1034}
1035
1037{
1038 contribution_ = x;
1039 return true;
1040}
Matrix class with labeled rows and columns for Chemical Mass Balance analysis.
Definition cmbmatrix.h:19
void SetRowLabel(int i, const string &label)
Sets row label at specified index.
Definition cmbmatrix.h:118
void SetColumnLabel(int i, const string &label)
Sets column label at specified index.
Definition cmbmatrix.h:111
Vector class with string labels for Chemical Mass Balance analysis.
Definition cmbvector.h:17
void SetLabels(const vector< string > &label)
Sets all element labels at once.
Definition cmbvector.h:151
void SetLabel(int i, const string &label)
Sets label at specified index.
Definition cmbvector.h:145
string Label(int i) const
Gets label at specified index.
Definition cmbvector.h:118
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.
Definition interface.h:65
double lowlimit
Lower threshold for value highlighting (when enabled)
Definition interface.h:211
Interface & operator=(const Interface &intf)
Assignment operator.
Definition interface.cpp:14
void AppendtoNotes(const string &note)
Append a note to existing notes.
Definition interface.h:196
bool highlightoutsideoflimit
Flag indicating whether to highlight values outside defined limits.
Definition interface.h:221
double highlimit
Upper threshold for value highlighting (when enabled)
Definition interface.h:212
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)
Definition resultitem.h:18
void SetType(const result_type &_type)
Definition resultitem.h:23
distribution_type
Enumeration of probability distribution types supported in SedSat3.
@ organic_carbon
Organic carbon content.
@ particle_size
Particle size distribution parameter.
@ do_not_include
Exclude from all analyses.