CSV like PDSF ready to test

This commit is contained in:
2025-01-13 12:46:35 -07:00
parent 865357bbc8
commit bc6810cf4f
15 changed files with 379 additions and 231 deletions

View File

@ -1,5 +1,3 @@
using System.Collections.Generic;
namespace Adaptation.FileHandlers.QS408M;
#nullable enable
@ -7,15 +5,13 @@ namespace Adaptation.FileHandlers.QS408M;
public class Body
{
public Body(List<Site> sites, string waferMeanThickness, string stdDev, string passFail)
public Body(string waferMeanThickness, string stdDev, string passFail)
{
Sites = sites;
WaferMeanThickness = waferMeanThickness;
StdDev = stdDev;
PassFail = passFail;
}
public List<Site> Sites { get; }
public string WaferMeanThickness { get; }
public string StdDev { get; }
public string PassFail { get; }
@ -44,7 +40,7 @@ public class Body
return flag;
}
private static string GetToken(string text, int[] i)
internal static string GetToken(string text, int[] i)
{
while (true)
{
@ -71,25 +67,11 @@ public class Body
internal static Body? Get(string text, int[] i)
{
Body? result;
Site site;
string thickness;
List<Site> sites = new();
string position = GetToken(text, i);
while (true)
{
if (string.IsNullOrEmpty(position) || !char.IsDigit(position[0]))
break;
thickness = GetToken(text, i);
site = new(position, thickness);
sites.Add(site);
position = GetToken(text, i);
}
i[0] = Complete.ScanPast(text, i, "mean thickness =");
string meanThickness = Complete.GetBefore(text, i, ", std. dev =");
i[0] = Run.ScanPast(text, i, "mean thickness =");
string meanThickness = Run.GetBefore(text, i, ", std. dev =");
string stdDev = GetToken(text, i);
string passFail = Complete.GetToEOL(text, i);
result = new(sites,
meanThickness,
string passFail = Run.GetToEOL(text, i);
result = new(meanThickness,
stdDev,
passFail);
return result;

View File

@ -1,120 +0,0 @@
using Adaptation.Shared;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Adaptation.FileHandlers.QS408M;
#nullable enable
internal class Complete
{
public Complete(Header header, Body body, Footer footer)
{
Header = header;
Body = body;
Footer = footer;
}
public Header Header { get; }
public Body Body { get; }
public Footer Footer { get; }
internal static string GetBefore(string text, int[] i, string search)
{
string str;
string str1;
int num = text.IndexOf(search, i[0]);
if (num <= -1)
{
str = text.Substring(i[0]);
i[0] = text.Length;
str1 = str.Trim();
}
else
{
str = text.Substring(i[0], num - i[0]);
i[0] = num + search.Length;
str1 = str.Trim();
}
return str1;
}
internal static string GetToEOL(string text, int[] i)
{
string result;
if (text.IndexOf("\n", i[0]) > -1)
result = GetBefore(text, i, "\n");
else
result = GetBefore(text, i, Environment.NewLine);
return result;
}
internal static int ScanPast(string text, int[] i, string search)
{
int result;
int num = text.IndexOf(search, i[0]);
if (num <= -1)
result = text.Length;
else
result = num + search.Length;
return result;
}
internal static Complete? Get(Logistics logistics, List<FileInfo> fileInfoCollection, Header[] lastHeader)
{
Complete? result;
int[] i = new int[] { 0 };
string text = File.ReadAllText(logistics.ReportFullPath);
Header? header = Header.Get(lastHeader, text, i);
if (header is null)
result = null;
else
{
Body? body = Body.Get(text, i);
if (body is null)
result = null;
else
{
Footer? footer = Footer.Get(text, i);
if (footer is null)
result = null;
else
{
result = new(header, body, footer);
FileInfo fileInfo = new($"{logistics.ReportFullPath}.json");
string json = JsonSerializer.Serialize(result, CompleteSourceGenerationContext.Default.Complete);
File.WriteAllText(fileInfo.FullName, json);
File.SetLastWriteTime(fileInfo.FullName, logistics.DateTimeFromSequence);
fileInfoCollection.Add(fileInfo);
}
}
}
return result;
}
}
// Bio-Rad QS400MEPI Recipe: EP_8IN9PT Thu Apr 30 11:29:10 1970
// operator: J batch: BIORAD#2
// cassette: wafer: 52-589368-4445
// --------------------------------------------------------------------------------
// position thickness position thickness position thickness
// 1 45.735 2 46.536 3 46.742
// 4 46.015 5 46.648 6 45.366
// 7 46.263 8 46.512 9 46.373
// wafer mean thickness = 46.2433, std. dev = 0.4564 PASS
// ================================================================================
// Radial variation (computation B) PASS:
// thickness -2.7474
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Complete))]
internal partial class CompleteSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -112,9 +112,9 @@ public class FileRead : Shared.FileRead, IFileRead
results.Item4.Add(_Logistics.FileInfo);
else
{
Complete? complete = Complete.Get(_Logistics, results.Item4, lastHeader: _LastHeader);
IProcessData iProcessData = new ProcessData(this, _Logistics, results.Item4, _OriginalDataBioRad, _TickOffset.Value, complete);
if (complete is null)
Run? run = Run.Get(_Logistics, results.Item4, lastHeader: _LastHeader);
IProcessData iProcessData = new ProcessData(this, _Logistics, results.Item4, _OriginalDataBioRad, _TickOffset.Value, run);
if (run is null)
throw new Exception(string.Concat("A) No Data - ", dateTime.Ticks));
if (iProcessData is not ProcessData processData)
throw new Exception(string.Concat("B) No Data - ", dateTime.Ticks));
@ -133,7 +133,7 @@ public class FileRead : Shared.FileRead, IFileRead
if (iProcessData.Details.Count == 0)
throw new Exception(string.Concat("C) No Data - ", dateTime.Ticks));
results = iProcessData.GetResults(this, _Logistics, results.Item4);
_LastHeader[0] = complete.Header;
_LastHeader[0] = run.Header;
}
return results;
}

View File

@ -19,14 +19,14 @@ public class Footer
internal static Footer? Get(string text, int[] i)
{
Footer? result;
_ = Complete.GetToEOL(text, i);
_ = Complete.GetToEOL(text, i);
string line = Complete.GetToEOL(text, i);
i[0] = Complete.ScanPast(text, i, "thickness");
string radialVariationThickness = Complete.GetToEOL(text, i);
_ = Complete.GetToEOL(text, i);
i[0] = Complete.ScanPast(text, i, "Slot:");
string slot = Complete.GetBefore(text, i, ";");
_ = Run.GetToEOL(text, i);
_ = Run.GetToEOL(text, i);
string line = Run.GetToEOL(text, i);
i[0] = Run.ScanPast(text, i, "thickness");
string radialVariationThickness = Run.GetToEOL(text, i);
_ = Run.GetToEOL(text, i);
i[0] = Run.ScanPast(text, i, "Slot:");
string slot = Run.GetBefore(text, i, ";");
result = new(line,
radialVariationThickness,
slot);

View File

@ -51,27 +51,27 @@ public class Header
{
bool usedLast;
const string twoSpaces = " ";
string title = Complete.GetBefore(text, i, "Recipe:");
string recipeAndDateTime = Complete.GetToEOL(text, i);
string title = Run.GetBefore(text, i, "Recipe:");
string recipeAndDateTime = Run.GetToEOL(text, i);
string recipe = recipeAndDateTime.Length < twoSpaces.Length ? recipeAndDateTime.Trim() : !recipeAndDateTime.Contains(twoSpaces) ? recipeAndDateTime.Substring(0, 25).Trim() : recipeAndDateTime.Split(new string[] { twoSpaces }, StringSplitOptions.None)[0].Trim();
string dateTime = recipeAndDateTime.Substring(recipe.Length).Trim();
if (dateTime.EndsWith("."))
dateTime = dateTime.Remove(dateTime.Length - 1, 1);
i[0] = Complete.ScanPast(text, i, "operator:");
string @operator = Complete.GetBefore(text, i, "batch:");
string batch = Complete.GetToEOL(text, i);
i[0] = Complete.ScanPast(text, i, "cassette:");
i[0] = Run.ScanPast(text, i, "operator:");
string @operator = Run.GetBefore(text, i, "batch:");
string batch = Run.GetToEOL(text, i);
i[0] = Run.ScanPast(text, i, "cassette:");
if (!text.Contains("cassette:"))
title = string.Empty;
string cassette = Complete.GetBefore(text, i, "wafer:");
string cassette = Run.GetBefore(text, i, "wafer:");
if (string.IsNullOrEmpty(batch))
{
i[0] = 0;
i[0] = Complete.ScanPast(text, i, "wafer:");
i[0] = Run.ScanPast(text, i, "wafer:");
}
string wafer = Complete.GetToEOL(text, i);
_ = Complete.GetToEOL(text, i);
_ = Complete.GetToEOL(text, i);
string wafer = Run.GetToEOL(text, i);
_ = Run.GetToEOL(text, i);
_ = Run.GetToEOL(text, i);
if (string.IsNullOrEmpty(wafer))
throw new Exception("Wafer field is missing.");
if (!string.IsNullOrEmpty(title))

View File

@ -57,7 +57,7 @@ public partial class ProcessData : IProcessData
#nullable enable
internal ProcessData(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, string originalDataBioRad, long tickOffset, Complete? complete)
internal ProcessData(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, string originalDataBioRad, long tickOffset, Run? run)
{
if (fileRead is null)
throw new ArgumentNullException(nameof(fileRead));
@ -72,8 +72,8 @@ public partial class ProcessData : IProcessData
foreach (string moveFile in moveFiles.Distinct())
fileInfoCollection.Add(new FileInfo(moveFile));
fileInfoCollection.Add(logistics.FileInfo);
if (complete is not null)
SetValues(logistics, tickOffset, complete);
if (run is not null)
SetValues(logistics, tickOffset, run);
}
string IProcessData.GetCurrentReactor(IFileRead fileRead, Logistics logistics, Dictionary<string, string> reactors) => throw new Exception(string.Concat("See ", nameof(ProcessData)));
@ -251,18 +251,18 @@ public partial class ProcessData : IProcessData
return result;
}
private void SetValues(Logistics logistics, long tickOffset, Complete complete)
private void SetValues(Logistics logistics, long tickOffset, Run run)
{
int slot = 0;
Detail detail;
int counter = 1;
List<Detail> details = new();
DateTime dateTime = GetDateTime(logistics, tickOffset, complete.Header.DateTime);
bool isWaferSlot = !string.IsNullOrEmpty(complete.Header.Wafer) && complete.Header.Wafer.Length is 1 or 2 && int.TryParse(complete.Header.Wafer, out slot) && slot < 27;
string batch = !isWaferSlot ? logistics.JobID : Regex.Replace(complete.Header.Batch, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
Descriptor descriptor = isWaferSlot ? GetDescriptor(complete.Header.Batch) : GetDescriptor(complete.Header.Wafer);
DateTime dateTime = GetDateTime(logistics, tickOffset, run.Header.DateTime);
bool isWaferSlot = !string.IsNullOrEmpty(run.Header.Wafer) && run.Header.Wafer.Length is 1 or 2 && int.TryParse(run.Header.Wafer, out slot) && slot < 27;
string batch = !isWaferSlot ? logistics.JobID : Regex.Replace(run.Header.Batch, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
Descriptor descriptor = isWaferSlot ? GetDescriptor(run.Header.Batch) : GetDescriptor(run.Header.Wafer);
string wafer = isWaferSlot ? slot.ToString("00") : descriptor.Wafer;
string uniqueId = string.Concat(complete.Header.Title, '_', wafer, '_', logistics.DateTimeFromSequence.ToString("yyyyMMddHHmmssffff"), '_', logistics.TotalSecondsSinceLastWriteTimeFromSequence);
string uniqueId = string.Concat(run.Header.Title, '_', wafer, '_', logistics.DateTimeFromSequence.ToString("yyyyMMddHHmmssffff"), '_', logistics.TotalSecondsSinceLastWriteTimeFromSequence);
Batch = batch;
Wafer = wafer;
Date = dateTime;
@ -273,16 +273,16 @@ public partial class ProcessData : IProcessData
JobID = logistics.JobID;
Layer = descriptor.Layer;
Reactor = descriptor.Reactor;
StdDev = complete.Body.StdDev;
Title = complete.Header.Title;
Recipe = complete.Header.Recipe;
PassFail = complete.Body.PassFail;
Cassette = complete.Header.Cassette;
RVThickness = complete.Footer.RadialVariationThickness;
Slot = string.IsNullOrEmpty(complete.Footer.Slot) ? slot.ToString("00") : complete.Footer.Slot;
Employee = string.IsNullOrEmpty(complete.Header.Operator) ? Employee : complete.Header.Operator;
MeanThickness = string.IsNullOrEmpty(complete.Body.WaferMeanThickness) && complete.Body.Sites.Count == 1 ? complete.Body.Sites.First().Thickness : complete.Body.WaferMeanThickness;
foreach (Site site in complete.Body.Sites)
StdDev = run.Body.StdDev;
Title = run.Header.Title;
Recipe = run.Header.Recipe;
PassFail = run.Body.PassFail;
Cassette = run.Header.Cassette;
RVThickness = run.Footer.RadialVariationThickness;
Slot = string.IsNullOrEmpty(run.Footer.Slot) ? slot.ToString("00") : run.Footer.Slot;
Employee = string.IsNullOrEmpty(run.Header.Operator) ? Employee : run.Header.Operator;
MeanThickness = string.IsNullOrEmpty(run.Body.WaferMeanThickness) && run.Sites.Count == 1 ? run.Sites[0].Thickness : run.Body.WaferMeanThickness;
foreach (Site site in run.Sites)
{
detail = new()
{

View File

@ -0,0 +1,59 @@
using System.Text.Json.Serialization;
namespace Adaptation.FileHandlers.QS408M;
#nullable enable
internal class Row
{
public Row(Run run, int i)
{
Title = run.Header.Title;
Recipe = run.Header.Recipe;
DateTime = run.Header.DateTime;
Operator = run.Header.Operator;
Batch = run.Header.Batch;
Cassette = run.Header.Cassette;
UsedLast = run.Header.UsedLast;
Wafer = run.Header.Wafer;
//
Position = run.Sites[i].Position;
Thickness = run.Sites[i].Thickness;
//
WaferMeanThickness = run.Body.WaferMeanThickness;
StdDev = run.Body.StdDev;
PassFail = run.Body.PassFail;
//
Line = run.Footer.Line;
RadialVariationThickness = run.Footer.RadialVariationThickness;
Slot = run.Footer.Slot;
}
public string Title { get; }
public string Recipe { get; }
public string DateTime { get; }
public string Operator { get; }
public string Batch { get; }
public string Cassette { get; }
public bool UsedLast { get; }
public string Wafer { get; }
//
public string Position { get; }
public string Thickness { get; }
//
public string WaferMeanThickness { get; }
public string StdDev { get; }
public string PassFail { get; }
//
public string Line { get; }
public string RadialVariationThickness { get; }
public string Slot { get; }
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Row))]
internal partial class RowSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,205 @@
using Adaptation.Shared;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Adaptation.FileHandlers.QS408M;
#nullable enable
internal class Run
{
public Run(Header header, ReadOnlyCollection<Site> sites, Body body, Footer footer)
{
Header = header;
Sites = sites;
Body = body;
Footer = footer;
}
public Header Header { get; }
public ReadOnlyCollection<Site> Sites { get; }
public Body Body { get; }
public Footer Footer { get; }
internal static string GetBefore(string text, int[] i, string search)
{
string str;
string str1;
int num = text.IndexOf(search, i[0]);
if (num <= -1)
{
str = text.Substring(i[0]);
i[0] = text.Length;
str1 = str.Trim();
}
else
{
str = text.Substring(i[0], num - i[0]);
i[0] = num + search.Length;
str1 = str.Trim();
}
return str1;
}
internal static string GetToEOL(string text, int[] i)
{
string result;
if (text.IndexOf("\n", i[0]) > -1)
result = GetBefore(text, i, "\n");
else
result = GetBefore(text, i, Environment.NewLine);
return result;
}
internal static int ScanPast(string text, int[] i, string search)
{
int result;
int num = text.IndexOf(search, i[0]);
if (num <= -1)
result = text.Length;
else
result = num + search.Length;
return result;
}
private static void WriteJson(Logistics logistics, List<FileInfo> fileInfoCollection, Run? result)
{
FileInfo fileInfo = new($"{logistics.ReportFullPath}.json");
string json = JsonSerializer.Serialize(result, RunSourceGenerationContext.Default.Run);
File.WriteAllText(fileInfo.FullName, json);
File.SetLastWriteTime(fileInfo.FullName, logistics.DateTimeFromSequence);
fileInfoCollection.Add(fileInfo);
}
private static ReadOnlyCollection<string> GetLines(JsonElement[]? jsonElements)
{
List<string> results = new();
int columns = 0;
StringBuilder stringBuilder = new();
for (int i = 0; i < jsonElements?.Length;)
{
foreach (JsonProperty jsonProperty in jsonElements[0].EnumerateObject())
{
columns += 1;
_ = stringBuilder.Append('"').Append(jsonProperty.Name).Append('"').Append('\t');
}
break;
}
if (jsonElements?.Length != 0)
_ = stringBuilder.Remove(stringBuilder.Length - 1, 1);
results.Add(stringBuilder.ToString());
for (int i = 0; i < jsonElements?.Length; i++)
{
_ = stringBuilder.Clear();
foreach (JsonProperty jsonProperty in jsonElements[i].EnumerateObject())
{
if (jsonProperty.Value.ValueKind == JsonValueKind.Object)
_ = stringBuilder.Append('\t');
else if (jsonProperty.Value.ValueKind != JsonValueKind.String)
_ = stringBuilder.Append(jsonProperty.Value).Append('\t');
else
_ = stringBuilder.Append('"').Append(jsonProperty.Value).Append('"').Append('\t');
}
_ = stringBuilder.Remove(stringBuilder.Length - 1, 1);
results.Add(stringBuilder.ToString());
}
return results.AsReadOnly();
}
private static ReadOnlyCollection<string> GetLines(JsonElement? jsonElement) =>
jsonElement is null ? new(Array.Empty<string>()) : GetLines(new JsonElement[] { jsonElement.Value });
private static void WriteTabSeparatedValues(Logistics logistics, List<FileInfo> fileInfoCollection, Run run)
{
List<Row> results = new();
Row row;
FileInfo fileInfo = new($"{logistics.ReportFullPath}.tsv");
for (int i = 0; i < run.Sites.Count; i++)
{
row = new(run, i);
results.Add(row);
}
string json = JsonSerializer.Serialize(results);
JsonElement[]? jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json);
ReadOnlyCollection<string> lines = GetLines(jsonElements);
File.WriteAllText(fileInfo.FullName, string.Join(Environment.NewLine, lines));
File.SetLastWriteTime(fileInfo.FullName, logistics.DateTimeFromSequence);
fileInfoCollection.Add(fileInfo);
}
private static void WriteException(Logistics logistics, Exception ex)
{
FileInfo fileInfo = new($"{logistics.ReportFullPath}.{nameof(Exception)}.txt");
File.WriteAllText(fileInfo.FullName, $"{ex.Message}{Environment.NewLine}{ex.StackTrace}");
}
internal static Run? Get(Logistics logistics, List<FileInfo> fileInfoCollection, Header[] lastHeader)
{
Run? result;
int[] i = new int[] { 0 };
string text = File.ReadAllText(logistics.ReportFullPath);
Header? header = Header.Get(lastHeader, text, i);
if (header is null)
result = null;
else
{
ReadOnlyCollection<Site> sites = Site.Get(text, i);
if (sites.Count == 0)
result = null;
else
{
Body? body = Body.Get(text, i);
if (body is null)
result = null;
else
{
Footer? footer = Footer.Get(text, i);
if (footer is null)
result = null;
else
{
result = new(header, sites, body, footer);
WriteJson(logistics, fileInfoCollection, result);
try
{
WriteTabSeparatedValues(logistics, fileInfoCollection, result);
}
catch (Exception ex)
{
WriteException(logistics, ex);
}
}
}
}
}
return result;
}
}
// Bio-Rad QS400MEPI Recipe: EP_8IN9PT Thu Apr 30 11:29:10 1970
// operator: J batch: BIORAD#2
// cassette: wafer: 52-589368-4445
// --------------------------------------------------------------------------------
// position thickness position thickness position thickness
// 1 45.735 2 46.536 3 46.742
// 4 46.015 5 46.648 6 45.366
// 7 46.263 8 46.512 9 46.373
// wafer mean thickness = 46.2433, std. dev = 0.4564 PASS
// ================================================================================
// Radial variation (computation B) PASS:
// thickness -2.7474
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Run))]
internal partial class RunSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -1,3 +1,6 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Adaptation.FileHandlers.QS408M;
public class Site
@ -12,4 +15,22 @@ public class Site
public string Position { get; }
public string Thickness { get; }
internal static ReadOnlyCollection<Site> Get(string text, int[] i)
{
List<Site> results = new();
Site site;
string thickness;
string position = Body.GetToken(text, i);
while (true)
{
if (string.IsNullOrEmpty(position) || !char.IsDigit(position[0]))
break;
thickness = Body.GetToken(text, i);
site = new(position, thickness);
results.Add(site);
position = Body.GetToken(text, i);
}
return results.AsReadOnly();
}
}