Match TFS Changeset 303348

This commit is contained in:
2022-02-01 18:02:51 -07:00
parent d9057d2071
commit 0cfcb46ee7
118 changed files with 17934 additions and 13 deletions

View File

@ -0,0 +1,316 @@
using Adaptation.Shared;
using Adaptation.Shared.Methods;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
namespace Adaptation.FileHandlers.RsM
{
public class Description : IDescription
{
public int Test { get; set; }
public int Count { get; set; }
public int Index { get; set; }
//
public string EventName { get; set; }
public string NullData { get; set; }
public string JobID { get; set; }
public string Sequence { get; set; }
public string MesEntity { get; set; }
public string ReportFullPath { get; set; }
public string ProcessJobID { get; set; }
public string MID { get; set; }
//
public string Date { get; set; }
public string Employee { get; set; }
public string Lot { get; set; }
public string PSN { get; set; }
public string Reactor { get; set; }
public string Recipe { get; set; }
//
public string AutoOptimizeGain { get; set; }
public string AutoProbeHeightSet { get; set; }
public string Avg { get; set; }
public string DataReject { get; set; }
public string DLRatio { get; set; }
public string Merit { get; set; }
public string Pt { get; set; }
public string R { get; set; }
public string ResistivitySpec { get; set; }
public string Rs { get; set; }
public string SemiRadial { get; set; }
public string StdDev { get; set; }
public string T { get; set; }
public string Temp { get; set; }
//
public string Engineer { get; set; }
public string EquipId { get; set; }
public string FileName { get; set; }
public string HeaderUniqueId { get; set; }
public string Id { get; set; }
public string Layer { get; set; }
public string RDS { get; set; }
public string Run { get; set; }
public string UniqueId { get; set; }
public string Zone { get; set; }
string IDescription.GetEventDescription()
{
return "File Has been read and parsed";
}
List<string> IDescription.GetNames(IFileRead fileRead, Logistics logistics)
{
List<string> results = new();
IDescription description = GetDefault(fileRead, logistics);
string json = JsonSerializer.Serialize(description, description.GetType());
object @object = JsonSerializer.Deserialize<object>(json);
if (@object is not JsonElement jsonElement)
throw new Exception();
foreach (JsonProperty jsonProperty in jsonElement.EnumerateObject())
results.Add(jsonProperty.Name);
return results;
}
List<string> IDescription.GetDetailNames()
{
List<string> results = new()
{
nameof(AutoOptimizeGain),
nameof(AutoProbeHeightSet),
nameof(Avg),
nameof(DataReject),
nameof(DLRatio),
nameof(Merit),
nameof(Pt),
nameof(R),
nameof(ResistivitySpec),
nameof(Rs),
nameof(SemiRadial),
nameof(StdDev),
nameof(T),
nameof(Temp)
};
return results;
}
List<string> IDescription.GetHeaderNames()
{
List<string> results = new()
{
nameof(Date),
nameof(Employee),
nameof(Lot),
nameof(PSN),
nameof(Reactor),
nameof(Recipe)
};
return results;
}
IDescription IDescription.GetDisplayNames()
{
Description result = GetDisplayNames();
return result;
}
List<string> IDescription.GetParameterNames()
{
List<string> results = new()
{
nameof(Engineer),
nameof(EquipId),
nameof(FileName),
nameof(HeaderUniqueId),
nameof(Id),
nameof(Layer),
nameof(RDS),
nameof(Run),
nameof(UniqueId),
nameof(Zone)
};
return results;
}
JsonProperty[] IDescription.GetDefault(IFileRead fileRead, Logistics logistics)
{
JsonProperty[] results;
IDescription description = GetDefault(fileRead, logistics);
string json = JsonSerializer.Serialize(description, description.GetType());
object @object = JsonSerializer.Deserialize<object>(json);
results = ((JsonElement)@object).EnumerateObject().ToArray();
return results;
}
List<string> IDescription.GetPairedParameterNames()
{
List<string> results = new();
return results;
}
List<string> IDescription.GetIgnoreParameterNames(Test test)
{
List<string> results = new();
return results;
}
IDescription IDescription.GetDefaultDescription(IFileRead fileRead, Logistics logistics)
{
Description result = GetDefault(fileRead, logistics);
return result;
}
Dictionary<string, string> IDescription.GetDisplayNamesJsonElement(IFileRead fileRead)
{
Dictionary<string, string> results = new();
IDescription description = GetDisplayNames();
string json = JsonSerializer.Serialize(description, description.GetType());
JsonElement jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
foreach (JsonProperty jsonProperty in jsonElement.EnumerateObject())
{
if (!results.ContainsKey(jsonProperty.Name))
results.Add(jsonProperty.Name, string.Empty);
if (jsonProperty.Value is JsonElement jsonPropertyValue)
results[jsonProperty.Name] = jsonPropertyValue.ToString();
}
return results;
}
List<IDescription> IDescription.GetDescriptions(IFileRead fileRead, Logistics logistics, List<Test> tests, IProcessData iProcessData)
{
List<IDescription> results = new();
if (iProcessData is null || !iProcessData.Details.Any() || iProcessData is not ProcessData processData)
results.Add(GetDefault(fileRead, logistics));
else
{
string nullData;
Description description;
object configDataNullData = fileRead.NullData;
if (configDataNullData is null)
nullData = string.Empty;
else
nullData = configDataNullData.ToString();
for (int i = 0; i < iProcessData.Details.Count; i++)
{
if (iProcessData.Details[i] is not Detail detail)
continue;
description = new Description
{
Test = (int)tests[i],
Count = tests.Count,
Index = i,
//
EventName = fileRead.EventName,
NullData = nullData,
JobID = fileRead.CellInstanceName,
Sequence = logistics.Sequence.ToString(),
MesEntity = logistics.MesEntity,
ReportFullPath = logistics.ReportFullPath,
ProcessJobID = logistics.ProcessJobID,
MID = logistics.MID,
//
Date = processData.Date,
Employee = processData.Engineer,
Lot = processData.Lot,
PSN = processData.PSN,
Reactor = processData.Reactor,
Recipe = processData.Recipe,
//
AutoOptimizeGain = processData.AutoOptimizeGain,
AutoProbeHeightSet = processData.AutoProbeHeightSet,
Avg = processData.Avg,
DataReject = processData.DataReject,
DLRatio = processData.DLRatio,
Merit = detail.Merit,
Pt = detail.Pt,
R = detail.R,
ResistivitySpec = processData.ResistivitySpec,
Rs = detail.Rs,
SemiRadial = processData.SemiRadial,
StdDev = processData.StandardDeviationPercentage,
T = detail.T,
Temp = processData.Temp,
//
Engineer = processData.Engineer,
EquipId = processData.EquipId,
FileName = processData.FileName,
HeaderUniqueId = detail.HeaderUniqueId,
Id = processData.UniqueId,
Layer = processData.Layer,
RDS = processData.RDS,
Run = processData.Run,
UniqueId = detail.UniqueId,
Zone = processData.Zone
};
results.Add(description);
}
}
return results;
}
private Description GetDisplayNames()
{
Description result = new();
return result;
}
private Description GetDefault(IFileRead fileRead, Logistics logistics)
{
Description result = new()
{
Test = -1,
Count = 0,
Index = -1,
//
EventName = fileRead.EventName,
NullData = fileRead.NullData,
JobID = fileRead.CellInstanceName,
Sequence = logistics.Sequence.ToString(),
MesEntity = fileRead.MesEntity,
ReportFullPath = logistics.ReportFullPath,
ProcessJobID = logistics.ProcessJobID,
MID = logistics.MID,
//
Date = nameof(Date),
Employee = nameof(Employee),
Lot = nameof(Lot),
PSN = nameof(PSN),
Reactor = nameof(Reactor),
Recipe = nameof(Recipe),
//
AutoOptimizeGain = nameof(AutoOptimizeGain),
AutoProbeHeightSet = nameof(AutoProbeHeightSet),
Avg = nameof(Avg),
DataReject = nameof(DataReject),
DLRatio = nameof(DLRatio),
Merit = nameof(Merit),
Pt = nameof(Pt),
R = nameof(R),
ResistivitySpec = nameof(ResistivitySpec),
Rs = nameof(Rs),
SemiRadial = nameof(SemiRadial),
StdDev = nameof(StdDev),
T = nameof(T),
Temp = nameof(Temp),
//
Engineer = nameof(Engineer),
EquipId = nameof(EquipId),
FileName = nameof(FileName),
HeaderUniqueId = nameof(HeaderUniqueId),
Id = nameof(Id),
Layer = nameof(Layer),
RDS = nameof(RDS),
Run = nameof(Run),
UniqueId = nameof(UniqueId),
Zone = nameof(Zone),
};
return result;
}
}
}

View File

@ -0,0 +1,22 @@
namespace Adaptation.FileHandlers.RsM
{
public class Detail
{
public string HeaderUniqueId { get; set; }
public string Merit { get; set; }
public string Pt { get; set; }
public string R { get; set; }
public string Rs { get; set; }
public string T { get; set; }
public string UniqueId { get; set; }
public override string ToString()
{
return string.Concat(Merit, ";", Pt, ";", R, ";", Rs, ";", T);
}
}
}

View File

@ -0,0 +1,149 @@
using Adaptation.Eaf.Management.ConfigurationData.CellAutomation;
using Adaptation.Ifx.Eaf.EquipmentConnector.File.Configuration;
using Adaptation.Shared;
using Adaptation.Shared.Methods;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace Adaptation.FileHandlers.RsM
{
public class FileRead : Shared.FileRead, IFileRead
{
public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, bool useCyclicalForDescription, bool isEAFHosted, int hyphenXToArchive, int hyphenIsArchive) :
base(new Description(), true, smtp, fileParameter, cellInstanceName, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, useCyclicalForDescription, isEAFHosted, hyphenXToArchive, hyphenIsArchive)
{
_MinFileLength = 10;
_NullData = string.Empty;
_Logistics = new Logistics(this);
if (_FileParameter is null)
throw new Exception(cellInstanceConnectionName);
if (_ModelObjectParameterDefinitions is null)
throw new Exception(cellInstanceConnectionName);
if (_IsDuplicator)
throw new Exception(cellInstanceConnectionName);
}
void IFileRead.Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResults, Exception exception)
{
Move(this, extractResults, exception);
}
void IFileRead.WaitForThread()
{
WaitForThread(thread: null, threadExceptions: null);
}
string IFileRead.GetEventDescription()
{
string result = _Description.GetEventDescription();
return result;
}
List<string> IFileRead.GetHeaderNames()
{
List<string> results = _Description.GetHeaderNames();
return results;
}
string[] IFileRead.Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResults, string to, string from, string resolvedFileLocation, Exception exception)
{
string[] results = Move(extractResults, to, from, resolvedFileLocation, exception);
return results;
}
JsonProperty[] IFileRead.GetDefault()
{
JsonProperty[] results = _Description.GetDefault(this, _Logistics);
return results;
}
Dictionary<string, string> IFileRead.GetDisplayNamesJsonElement()
{
Dictionary<string, string> results = _Description.GetDisplayNamesJsonElement(this);
return results;
}
List<IDescription> IFileRead.GetDescriptions(IFileRead fileRead, List<Test> tests, IProcessData processData)
{
List<IDescription> results = _Description.GetDescriptions(fileRead, _Logistics, tests, processData);
return results;
}
Tuple<string, Test[], JsonElement[], List<FileInfo>> IFileRead.GetExtractResult(string reportFullPath, string eventName)
{
Tuple<string, Test[], JsonElement[], List<FileInfo>> results;
if (string.IsNullOrEmpty(eventName))
throw new Exception();
_ReportFullPath = reportFullPath;
DateTime dateTime = DateTime.Now;
results = GetExtractResult(reportFullPath, dateTime);
if (results.Item3 is null)
results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(results.Item1, new Test[] { }, JsonSerializer.Deserialize<JsonElement[]>("[]"), results.Item4);
if (results.Item3.Length > 0 && _IsEAFHosted)
WritePDSF(this, results.Item3);
UpdateLastTicksDuration(DateTime.Now.Ticks - dateTime.Ticks);
return results;
}
Tuple<string, Test[], JsonElement[], List<FileInfo>> IFileRead.ReExtract()
{
Tuple<string, Test[], JsonElement[], List<FileInfo>> results;
List<string> headerNames = _Description.GetHeaderNames();
Dictionary<string, string> keyValuePairs = _Description.GetDisplayNamesJsonElement(this);
results = ReExtract(this, headerNames, keyValuePairs);
return results;
}
void IFileRead.CheckTests(Test[] tests, bool extra)
{
throw new Exception(string.Concat("Not ", nameof(_IsDuplicator)));
}
void IFileRead.MoveArchive()
{
throw new Exception(string.Concat("Not ", nameof(_IsDuplicator)));
}
void IFileRead.Callback(object state)
{
throw new Exception(string.Concat("Not ", nameof(_IsDuplicator)));
}
private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime)
{
Tuple<string, Test[], JsonElement[], List<FileInfo>> results = new(string.Empty, null, null, new List<FileInfo>());
_Logistics = new Logistics(this, reportFullPath, useSplitForMID: true);
SetFileParameterLotIDToLogisticsMID();
if (reportFullPath.Length < _MinFileLength)
results.Item4.Add(new FileInfo(reportFullPath));
else
{
string logBody = string.Empty;
IProcessData iProcessData = new ProcessData(this, _Logistics, results.Item4);
if (iProcessData is ProcessData processData)
{
string mid = string.Concat(processData.Reactor, "-", processData.RDS, "-", processData.PSN);
mid = Regex.Replace(mid, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
_Logistics.MID = mid;
SetFileParameterLotID(mid);
_Logistics.ProcessJobID = processData.Reactor;
logBody = processData.LogBody;
}
if (!iProcessData.Details.Any())
throw new Exception(string.Concat("No Data - ", dateTime.Ticks));
results = iProcessData.GetResults(this, _Logistics, results.Item4);
if (!_IsEAFHosted)
results = new(logBody, results.Item2, results.Item3, results.Item4);
}
return results;
}
}
}

View File

@ -0,0 +1,279 @@
using Adaptation.Shared;
using Adaptation.Shared.Methods;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace Adaptation.FileHandlers.RsM
{
public class ProcessData : IProcessData
{
private readonly List<object> _Details;
public string JobID { get; set; }
public string MesEntity { get; set; }
public string AutoOptimizeGain { get; set; }
public string AutoProbeHeightSet { get; set; }
public string Avg { get; set; }
public string DLRatio { get; set; }
public string DataReject { get; set; }
public string Date { get; set; }
public DateTime DateTime { get; set; }
public string Employee { get; set; }
public string EquipId { get; set; }
public string Engineer { get; set; }
public string FileName { get; set; }
public string Layer { get; set; }
public string Lot { get; set; }
public string LogBody { get; set; }
public string PSN { get; set; }
public string Project { get; set; }
public string RDS { get; set; }
public string Reactor { get; set; }
public string Recipe { get; set; }
public string RecipeName { get; set; }
public string ResistivitySpec { get; set; }
public string Run { get; set; }
public string SemiRadial { get; set; }
public string StandardDeviation { get; set; }
public string StandardDeviationPercentage { get; set; }
public string Temp { get; set; }
public string Title { get; set; }
public string UniqueId { get; set; }
public string Zone { get; set; }
List<object> Shared.Properties.IProcessData.Details => _Details;
public ProcessData(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection)
{
JobID = logistics.JobID;
fileInfoCollection.Clear();
_Details = new List<object>();
MesEntity = logistics.MesEntity;
Parse(fileRead, logistics, fileInfoCollection);
}
string IProcessData.GetCurrentReactor(IFileRead fileRead, Logistics logistics, Dictionary<string, string> reactors)
{
throw new Exception(string.Concat("See ", nameof(Parse)));
}
Tuple<string, Test[], JsonElement[], List<FileInfo>> IProcessData.GetResults(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection)
{
Tuple<string, Test[], JsonElement[], List<FileInfo>> results;
List<Test> tests = new();
foreach (object item in _Details)
tests.Add(Test.CDE);
List<IDescription> descriptions = fileRead.GetDescriptions(fileRead, tests, this);
if (tests.Count != descriptions.Count)
throw new Exception();
for (int i = 0; i < tests.Count; i++)
{
if (descriptions[i] is not Description description)
throw new Exception();
if (description.Test != (int)tests[i])
throw new Exception();
}
List<Description> fileReadDescriptions = (from l in descriptions select (Description)l).ToList();
string json = JsonSerializer.Serialize(fileReadDescriptions, fileReadDescriptions.GetType());
JsonElement[] jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json);
results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(logistics.Logistics1[0], tests.ToArray(), jsonElements, fileInfoCollection);
return results;
}
private void SetTitleData(string[] segments)
{
if (segments.Length > 0)
{
Title = segments[0];
// Remove illegal characters \/:*?"<>| found in the Run.
Run = Regex.Replace(segments[0], @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
string[] parsedBatch = segments[0].Split('-');
if (parsedBatch.Length > 0)
Reactor = parsedBatch[0];
if (parsedBatch.Length > 1)
RDS = parsedBatch[1];
if (parsedBatch.Length > 2)
{
string[] parsedPSN = parsedBatch[2].Split('.');
if (parsedPSN.Length > 0)
PSN = parsedPSN[0];
if (parsedPSN.Length > 1)
Layer = parsedPSN[1];
}
if (parsedBatch.Length > 3)
Zone = parsedBatch[3];
}
}
private void SetFileNameData(string[] segments)
{
if (segments.Length > 1)
FileName = segments[0];
if (segments.Length > 2)
{
Project = segments[1];
RecipeName = segments[2];
Recipe = string.Concat(segments[1], " \\ ", segments[2]);
}
}
internal static DateTime GetDateTime(Logistics logistics, string dateTimeText)
{
DateTime result;
string inputDateFormat = "HH:mm MM/dd/yy";
if (dateTimeText.Length != inputDateFormat.Length)
result = logistics.DateTimeFromSequence;
else
{
if (!DateTime.TryParseExact(dateTimeText, inputDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTimeParsed))
result = logistics.DateTimeFromSequence;
else
{
if (dateTimeParsed < logistics.DateTimeFromSequence.AddDays(1) && dateTimeParsed > logistics.DateTimeFromSequence.AddDays(-1))
result = dateTimeParsed;
else
result = logistics.DateTimeFromSequence;
}
}
return result;
}
private void SetDateTimeData(Logistics logistics, string[] segments)
{
DateTime dateTime;
if (segments.Length < 2)
dateTime = logistics.DateTimeFromSequence;
else
{
string dateTimeText = string.Concat(segments[0], ' ', segments[1]);
dateTime = GetDateTime(logistics, dateTimeText);
}
DateTime = dateTime;
Date = dateTime.ToString();
if (segments.Length > 3 && float.TryParse(segments[2], out float temp))
Temp = temp.ToString("0.0");
if (segments.Length > 7 && segments[6] == "Avg=")
Avg = segments[7];
if (segments.Length > 7 && segments[8] == "Dev=")
StandardDeviation = segments[9];
if (!string.IsNullOrEmpty(Avg) && !string.IsNullOrEmpty(StandardDeviation) && float.TryParse(Avg, out float average) && float.TryParse(StandardDeviation, out float standardDeviation))
StandardDeviationPercentage = Math.Round(standardDeviation / average, 4).ToString("0.00%");
}
private void SetOperatorData(string[] segments)
{
if (segments.Length > 1)
Employee = segments[0];
if (segments.Length > 2)
EquipId = segments[1];
}
private void SetEngineerData(string[] segments)
{
if (segments.Length > 1)
Engineer = segments[0];
}
private void SetNumProbePointsData(string[] segments)
{
if (segments.Length > 6)
DataReject = segments[6];
}
private Detail GetRData(string[] segments)
{
Detail result = new();
if (segments.Length > 0 && float.TryParse(segments[0], out float r))
result.R = r.ToString("0.0");
if (segments.Length > 1 && float.TryParse(segments[1], out float t))
result.T = t.ToString("0.0");
if (segments.Length > 2 && float.TryParse(segments[2], out float rs))
result.Rs = rs.ToString("0.0000");
if (segments.Length > 12 && float.TryParse(segments[12], out float merit))
result.Merit = merit.ToString("0.00");
result.Pt = "-1";
result.UniqueId = string.Empty;
return result;
}
private void Parse(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection)
{
if (fileRead is null)
{ }
Lot = "LotID";
Detail detail;
if (fileInfoCollection is null)
{ }
string timeFormat = "yyyyMMddHHmmss";
string[] separator = new string[] { " " };
string[] lines = File.ReadAllLines(logistics.ReportFullPath);
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains(",<Title>"))
SetTitleData(lines[i].Split(separator, StringSplitOptions.RemoveEmptyEntries));
else if (lines[i].Contains(",<FileName, Proj,Rcpe, LotID,WfrID>"))
SetFileNameData(lines[i].Split(separator, StringSplitOptions.RemoveEmptyEntries));
else if (lines[i].Contains(",<DateTime,Temp,TCR%,N|P>"))
SetDateTimeData(logistics, lines[i].Split(separator, StringSplitOptions.RemoveEmptyEntries));
else if (lines[i].Contains(",<Operator, Epuipment>"))
SetOperatorData(lines[i].Split(separator, StringSplitOptions.RemoveEmptyEntries));
else if (lines[i].Contains(",<Engineer>"))
SetEngineerData(lines[i].Split(separator, StringSplitOptions.RemoveEmptyEntries));
else if (lines[i].Contains(",<NumProbePoints, SingleOrDualProbeConfig, #ActPrbPts, Rsens,IdrvMx,VinGain, DataRejectSigma, MeritThreshold>"))
SetNumProbePointsData(lines[i].Split(separator, StringSplitOptions.RemoveEmptyEntries));
else if (lines[i].Contains(",<R,Th,Data, Rs,RsA,RsB, #Smpl, x,y, Irng,Vrng,ChiSq,merit,DataIntegrity>"))
{
for (int z = i; z < lines.Length; z++)
{
i = z;
if (string.IsNullOrEmpty(lines[z]))
continue;
detail = GetRData(lines[z].Split(separator, StringSplitOptions.RemoveEmptyEntries));
_Details.Add(detail);
}
}
}
UniqueId = string.Concat(EquipId, "_", Run, "_", logistics.DateTimeFromSequence.ToString(timeFormat));
for (int i = 0; i < _Details.Count; i++)
{
if (_Details[i] is not Detail item)
continue;
item.HeaderUniqueId = UniqueId;
item.Pt = (i + 1).ToString();
item.UniqueId = string.Concat(item, "_Point-", item.Pt);
}
// Remove illegal characters \/:*?"<>| found in the Lot.
Lot = Regex.Replace(Lot, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
StringBuilder stringBuilder = new();
string reportFileName = Path.GetFileName(logistics.ReportFullPath);
stringBuilder.AppendLine($"RUN [{Title}]");
stringBuilder.AppendLine($"Recipe {Project} \\ {RecipeName} RESISTIVITY {"####"}");
stringBuilder.AppendLine($"EQUIP# {EquipId} Engineer {Engineer}");
stringBuilder.AppendLine($"LotID {Lot} D.L.RATIO {"#.####"}");
stringBuilder.AppendLine($"OPERATOR {Employee} TEMP {Temp} {DateTime:HH:mm MM/dd/yy}");
stringBuilder.AppendLine($"AutoOptimizeGain = {"###"} AutoProbeHeightSet = {"##"}");
stringBuilder.AppendLine($"DataReject > {"#.#"}Sigma");
stringBuilder.AppendLine($"0 ..\\{Project}.prj\\{RecipeName}.rcp\\{reportFileName} {DateTime:HH:mm MM/dd/yy}");
stringBuilder.AppendLine($"pt# R Th Rs[Ohm/sq@T] Merit");
for (int i = 0; i < _Details.Count; i++)
{
if (_Details[i] is not Detail item)
continue;
stringBuilder.AppendLine($"{item.Pt} {item.R} {item.T} {item.Rs} {item.Merit}");
}
stringBuilder.AppendLine($"Avg = {Avg} {StandardDeviationPercentage} SEMI Radial= {"#.##%"}");
LogBody = stringBuilder.ToString();
}
}
}