feat: add ResultsExporter

move results postprocessing to separate class
fix few typos
This commit is contained in:
2026-08-12 05:42:06 +03:00
parent ec054d88c4
commit 96ca781fe7
3 changed files with 317 additions and 80 deletions
@@ -0,0 +1,122 @@
using System.Text;
using System.Globalization;
using GSS2.Core.Analysis.AmineContent.Database;
namespace GSS2.Core.Analysis.AmineContent;
public static class ResultExporter
{
public static void ExportCsv(string path, IEnumerable<ResultRecord> records)
{
NumberFormatInfo nfi = new NumberFormatInfo
{
NumberDecimalSeparator = ","
};
var rows = new List<List<string>>();
rows.Add(new List<string>
{
"ИД",
"Название пробы",
"Дата и время отбора пробы",
"Место отбора пробы",
"Дополнительная информация о пробе",
"Дата и время создания записи",
"Дата и время редактирования записи",
"Тип сепаратора",
"Марка пробы",
"Марка кондиционирующей смеси",
"Норма расхода кондиционирующей смеси, кг/т",
"Количество частиц",
"Средняя нормированная обработанная площадь",
"50-й процентиль",
"10-й процентиль",
"90-й процентиль",
"Ширина центрального диапазона",
"Межгранульное среднеквадратичное отклонение",
"Межгранульная неоднородность",
"Доля необработанных гранул",
"Средняя внутригранульная неоднородность",
"Средняя горячая площадь",
"Средний интегральный оптический показатель"
});
foreach (var record in records)
{
var results = ResultsPostProcessor.PostProcess(record);
var row = new List<string>
{
record.Id.ToString(),
record.SampleName,
record.SamplingDateTime.ToString("dd.MM.yyyy hh:mm:ss"),
record.SamplingPlace,
record.SampleComment,
record.CreateDateTime.ToString("dd.MM.yyyy hh:mm:ss"),
record.EditDateTime.ToString("dd.MM.yyyy hh:mm:ss"),
record.SeparatorType,
record.BrandName,
record.MixtureName,
record.MixtureNormalRate.ToString("F3", nfi),
results.values.Count().ToString(),
results.meanProcessedArea.ToString("F3", nfi),
results.processedAreaP50.ToString("F3", nfi),
results.processedAreaP10.ToString("F3", nfi),
results.processedAreaP90.ToString("F3", nfi),
results.processedAreaDeltaP90P10.ToString("F3", nfi),
results.processedAreaStdDev.ToString("F3", nfi),
results.interHeterogeneity.ToString("F3", nfi),
results.unprocessedFraction.ToString("F3", nfi),
results.meanInnerHeterogeneity.ToString("F3", nfi),
results.meanHotspotArea.ToString("F3", nfi),
results.meanOpticalIntegral.ToString("F3", nfi)
};
rows.Add(row);
row = new List<string>(23);
row.Add("Нормированная обработанная площадь");
foreach (var v in results.processedAreas)
row.Add(v.ToString("F3", nfi));
rows.Add(row);
row = new List<string>(23);
row.Add("Горячая площадь");
foreach (var v in results.hotspotAreas)
row.Add(v.ToString("F3", nfi));
rows.Add(row);
row = new List<string>(23);
row.Add("Оптический интегральный показатель");
foreach (var v in results.opticalIntegrals)
row.Add(v.ToString("F3", nfi));
rows.Add(row);
row = new List<string>(23);
row.Add("Нормированная обработанная площадь");
foreach (var v in results.innerStdDevs)
row.Add(v.ToString("F3", nfi));
rows.Add(row);
row = new List<string>(23);
row.Add("Внутригранульная неоднородность");
foreach (var v in results.innerHeterogeneities)
row.Add(v.ToString("F3", nfi));
rows.Add(row);
}
var sb = new StringBuilder();
foreach (var row in rows)
{
foreach (var cell in row)
{
sb.Append(cell);
sb.Append(";");
}
sb.Append("\n");
}
File.WriteAllText(path, sb.ToString());
}
}
@@ -0,0 +1,167 @@
using MathNet.Numerics.Statistics;
using GSS2.Core.Analysis.AmineContent.Database;
using GSS2.Core.Extensions;
namespace GSS2.Core.Analysis.AmineContent;
public static class ResultsPostProcessor
{
public const double UNPROCESSED_THRESHOLD = 0.5;
public const double HOTSPOT_THRESHOLD = 1.2;
public const double EPSILON = 1e-10;
public const double UNPROCESSED_FRACTION_THRESHOLD = 10;
public static (
int particlesCount,
List<float[]> values,
List<double[]> normalizedValues,
List<double> processedAreas,
List<double> unprocessedAreas,
List<double> hotspotAreas,
List<double> opticalIntegrals,
List<double> innerStdDevs,
List<double> innerHeterogeneities,
double meanProcessedArea,
double processedAreaP10,
double processedAreaP50,
double processedAreaP90,
double processedAreaStdDev,
double interHeterogeneity,
double processedAreaDeltaP90P10,
double unprocessedFraction,
double meanInnerHeterogeneity,
double meanInnerStdDev,
double meanHotspotArea,
double meanOpticalIntegral
) PostProcess(ResultRecord record) => PostProcess(record.ValueData, record.ValueCount, record.MixtureNormalRate);
public static (
int particlesCount,
List<float[]> values,
List<double[]> normalizedValues,
List<double> processedAreas,
List<double> unprocessedAreas,
List<double> hotspotAreas,
List<double> opticalIntegrals,
List<double> innerStdDevs,
List<double> innerHeterogeneities,
double meanProcessedArea,
double processedAreaP10,
double processedAreaP50,
double processedAreaP90,
double processedAreaStdDev,
double interHeterogeneity,
double processedAreaDeltaP90P10,
double unprocessedFraction,
double meanInnerHeterogeneity,
double meanInnerStdDev,
double meanHotspotArea,
double meanOpticalIntegral
) PostProcess(List<float> valueData, List<int> valueCount, double mixtureNormalRate) => PostProcess(valueData.Chunk(valueCount).Select(v => v.ToArray()).ToList(), mixtureNormalRate);
public static (
int particlesCount,
List<float[]> values,
List<double[]> normalizedValues,
List<double> processedAreas,
List<double> unprocessedAreas,
List<double> hotspotAreas,
List<double> opticalIntegrals,
List<double> innerStdDevs,
List<double> innerHeterogeneities,
double meanProcessedArea,
double processedAreaP10,
double processedAreaP50,
double processedAreaP90,
double processedAreaStdDev,
double interHeterogeneity,
double processedAreaDeltaP90P10,
double unprocessedFraction,
double meanInnerHeterogeneity,
double meanInnerStdDev,
double meanHotspotArea,
double meanOpticalIntegral
) PostProcess(List<float[]> values, double mixtureNormalRate)
{
var normalizedValues = new List<double[]>();
var processedAreas = new List<double>();
var unprocessedAreas = new List<double>();
var hotspotAreas = new List<double>();
var opticalIntegrals = new List<double>();
var innerStdDevs = new List<double>();
var innerHeterogeneities = new List<double>();
var max = values.Max(vs => vs.Max());
foreach (var value in values)
{
// Находим нормализованное значение
var normalized = new double[value.Count()];
for (int i = 0; i < value.Count(); i++)
if (value[i] <= mixtureNormalRate * UNPROCESSED_THRESHOLD)
normalized[i] = value[i] / (mixtureNormalRate * UNPROCESSED_THRESHOLD);
else if (value[i] <= mixtureNormalRate * HOTSPOT_THRESHOLD)
normalized[i] = 1 + (value[i] - (mixtureNormalRate * UNPROCESSED_THRESHOLD)) / ((mixtureNormalRate * HOTSPOT_THRESHOLD) - (mixtureNormalRate * UNPROCESSED_THRESHOLD));
else
normalized[i] = 2 + (value[i] - (mixtureNormalRate * HOTSPOT_THRESHOLD)) / (max - (mixtureNormalRate * HOTSPOT_THRESHOLD));
// Вычисляем значения
var area = normalized.Count();
var processedArea = normalized.Count(v => v > 1) / area * 100;
var unprocessedArea = normalized.Count(v => v <= 1) / area * 100;
var hotspotArea = normalized.Count(v => v > 2) / area * 100;
var opticalIntegral = normalized.Sum() / area * 100;
var innerStdDev = normalized.StdDev();
var innerHeterogeneity = innerStdDev / (opticalIntegral + EPSILON);
// Добавляем значения в списки
normalizedValues.Add(normalized);
processedAreas.Add(processedArea);
unprocessedAreas.Add(unprocessedArea);
hotspotAreas.Add(hotspotArea);
opticalIntegrals.Add(opticalIntegral);
innerStdDevs.Add(innerStdDev);
innerHeterogeneities.Add(innerHeterogeneity);
}
// Вычисляем общие значения
var meanProcessedArea = processedAreas.Mean();
var processedAreaP10 = processedAreas.Percentile(10);
var processedAreaP50 = processedAreas.Percentile(50);
var processedAreaP90 = processedAreas.Percentile(90);
var processedAreaStdDev = processedAreas.StdDev();
var interHeterogeneity = processedAreaStdDev / meanProcessedArea * 100;
var processedAreaDeltaP90P10 = processedAreaP90 - processedAreaP10;
var unprocessedFraction = (double)unprocessedAreas.Count(v => v > UNPROCESSED_FRACTION_THRESHOLD) / unprocessedAreas.Count() * 100;
var meanInnerHeterogeneity = innerHeterogeneities.Mean();
var meanInnerStdDev = innerStdDevs.Mean();
var meanHotspotArea = hotspotAreas.Mean();
var meanOpticalIntegral = opticalIntegrals.Mean();
return
(
values.Count(),
values,
normalizedValues,
processedAreas,
unprocessedAreas,
hotspotAreas,
opticalIntegrals,
innerStdDevs,
innerHeterogeneities,
meanProcessedArea,
processedAreaP10,
processedAreaP50,
processedAreaP90,
processedAreaStdDev,
interHeterogeneity,
processedAreaDeltaP90P10,
unprocessedFraction,
meanInnerHeterogeneity,
meanInnerStdDev,
meanHotspotArea,
meanOpticalIntegral
);
}
}