Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.Serialization/SoMat.md
2026-04-17 14:55:32 -04:00

132 lines
8.5 KiB
Markdown

---
source_files:
- Common/DTS.Common.Serialization/SoMat/SoMat.File.cs
- Common/DTS.Common.Serialization/SoMat/SoMatTestHeader.cs
- Common/DTS.Common.Serialization/SoMat/SoMatChannel.cs
- Common/DTS.Common.Serialization/SoMat/SoMat.File.Writer.cs
generated_at: "2026-04-16T03:38:52.973808+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "75e43dc7ec17e504"
---
# SoMat
## SoMat Serialization Module Documentation
---
### 1. Purpose
This module implements serialization of `Test` objects (from `DTS.Serialization.Test`) into a proprietary text-based format compatible with Diadem (a data analysis and reporting tool from National Instruments). It generates a single `.txt` file containing structured metadata (test header, channel definitions) followed by tab-delimited numeric data arrays. The module is part of the `DTS.Serialization.SoMat` namespace and serves as a concrete implementation of a file writer for SoMat-formatted output, primarily used for exporting test data for post-processing or reporting.
---
### 2. Public Interface
#### `DTS.Serialization.SoMat.File`
- **`File()`**
Parameterless constructor. Initializes the base `Serialization.File` with the string `"SoMat"` as the format name.
- **`static string Extension`**
Returns the file extension for SoMat files: `".txt"`.
- **`IWriter<Test> Exporter`**
Lazily-initialized property that returns an `IWriter<Test>` instance (`SoMat.File.Writer`) using `DefaultEncoding`. Throws an `Exception` with inner exception if writer instantiation fails.
#### `DTS.Serialization.SoMat.File.Writer`
- **`internal Writer(File fileType, int encoding)`**
Internal constructor; initializes the base `Writer<File>` with the provided `fileType` and `encoding`.
- **`void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)`**
**Throws `NotSupportedException`** — this overload is explicitly unsupported.
- **`void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`**
Writes a SoMat file to `pathname`.
- Constructs a `SoMatTestHeader` using `test` and `FilteredData[]` (from `FilteredData` property).
- Serializes header and channel metadata to the file.
- Writes `"DM_Start=\r\n"` as a data section marker.
- Iterates over sample indices up to `maxSamples` (max across all modules), writing one row per sample with tab-separated values (formatted as `"0.00000E+00"`), one column per channel.
- Invokes event handlers (`beginEventHandler`, `tickEventHandler`, `endEventHandler`, `errorEventHandler`) for progress and error reporting.
- Logs exceptions via `APILogger.Log`.
- Throws exceptions if no `errorEventHandler` is provided.
- **`FilteredData[] FilteredData`**
Property to set/get the `FilteredData[]` array used during serialization. Required before calling the multi-parameter `Write` method.
#### `DTS.Serialization.SoMat.SoMatTestHeader`
- **`SoMatTestHeader(Test test, FilteredData[] filteredData)`**
Constructor that populates header fields from `test` and `filteredData`.
- `TestTitle``test.Id`
- `RunDateTime` ← formatted `test.InceptionDate`
- `Operator` ← current Windows user name (falls back to empty string on failure)
- `NumLogChannels``test.Channels.Count` (capped by `filteredData.Length`)
- `NumDataModes``1` (hardcoded)
- Populates `_channels` list by constructing `SoMatChannel` objects.
- **`void Serialize(StreamWriter sw)`**
Writes header fields in `DM_`-prefixed key=value format to `sw`, followed by a blank line.
#### `DTS.Serialization.SoMat.SoMatChannel`
- **`SoMatChannel(Test.Module.Channel channel, int logicalChannel, FilteredData filteredData, int moduleArrayIndex, int numChannelsPerModule, DateTime inceptionDateTime)`**
Constructor that initializes channel metadata from `channel`, `filteredData`, and test context.
- `LogicalChannel``logicalChannel`
- `ChanName``channel.ChannelDescriptionString` (via `AnalogInputChannel`)
- `NumDataPoints``channel.ParentModule.NumberOfSamples`
- `SampleRate`, `TimeBase`, `MaxValue`, `MinValue`, `UserMax`, `UserMin`, `ElapsedTime`, `AcquisitionRate`, `RTCStart`, `RTCEnd`, `PhysicalChannelNumber` computed from module/channel/test data.
- `AxisUnitsDim2``engineeringUnits.TrimEnd()`
- `AxisLabelDim2`, `DescDim2``channel.SerialNumber`
- **`void Serialize(StreamWriter sw)`**
Writes channel metadata in `DM_`-prefixed key=value format (plus legacy `2100_` and `HDWParams`/`CALParams`/`DGParams` keys) to `sw`, followed by a blank line.
---
### 3. Invariants
- **File extension**: All output files use `.txt`.
- **Data format**: Data section begins with `"DM_Start=\r\n"` and consists of rows of tab-separated floating-point values in scientific notation (`"0.00000E+00"`).
- **Channel ordering**: Channels are serialized in the order of `test.Channels`, with index `i` mapped to `filteredData[i]`.
- **Physical channel numbering**: `PhysicalChannelNumber = 1 + moduleArrayIndex * numChannelsPerModule + aic.Number`, where `numChannelsPerModule = 3` (hardcoded in `SoMatChannel` constructor).
- **Header consistency**: `NumLogChannels` in `SoMatTestHeader` matches the number of `SoMatChannel` objects serialized.
- **Time base**: If `TimeOfFirstSampleValid` is false, `TimeBase` is computed as `(StartRecordSampleNumber - TriggerSampleNumbers[0]) / SampleRateHz`.
- **Data mode**: `NumDataModes` is always `1`; `DataModeType` is always `"TIMHIS"`.
---
### 4. Dependencies
#### Internal Dependencies (from source):
- `DTS.Serialization.Test` (namespace `DTS.Serialization`) — core test model.
- `DTS.Serialization.SoMat.FilteredData` — assumed to be a type with a `double[] Data` property (used in `SoMatChannel` and `Writer.Write`).
- `DTS.Serialization.SoMat.Test.Module.Channel`, `Test.Module.AnalogInputChannel`, `Test.Module` — test model subtypes.
- `DTS.Common.Utilities.Logging.APILogger` — for logging exceptions.
- `System.IO.StreamWriter`, `System.Text.Encoding`, `System.Security.Principal.WindowsIdentity`, `System.Linq`, `System.Windows.Forms.Application` (for `DoEvents()`).
#### External Dependencies:
- **Diadem compatibility**: Output format is designed for consumption by Diadem (per `Writer` summary).
- **Windows-specific**: Uses `WindowsIdentity.GetCurrent()` for operator name.
#### Dependencies on this module:
- `DTS.Serialization.Test` consumers (e.g., test export pipelines) likely depend on `SoMat.File.Exporter` to generate `.txt` files.
---
### 5. Gotchas
- **Unsupported `Write` overload**: The 7-parameter `Write` method throws `NotSupportedException`. Only the 17-parameter overload is functional.
- **Hardcoded `numChannelsPerModule = 3`**: In `SoMatChannel` constructor, `numChannelsPerModule` is passed as `3`. This may be incorrect if modules have varying channel counts.
- **`FilteredData` must be set manually**: The `Writer.FilteredData` property must be assigned before calling `Write`; otherwise, `FilteredData` is `null`, causing a `NullReferenceException` during header construction.
- **`TimeBase` fallback logic**: When `TimeOfFirstSampleValid` is false, `TriggerSampleNumbers[0]` is used. If `TriggerSampleNumbers` is empty or `StartRecordSampleNumber` is invalid, this may produce incorrect or NaN values.
- **Encoding**: Uses `Encoding.Default` (ANSI code page) for file writing — may cause issues with non-ASCII characters.
- **Event handler requirements**: If `errorEventHandler` is `null` and an exception occurs, the exception is rethrown. Otherwise, it is suppressed and only passed to `errorEventHandler`.
- **`DM_Start` marker**: The `"DM_Start=\r\n"` line is written *before* data rows, but no corresponding `"DM_Stop"` or end marker is present.
- **`NumDataModes` hardcoded**: Always `1`, regardless of actual data modes in the test.
- **`PhysicalChannelNumber` assumes fixed `numChannelsPerModule`**: Calculation may be incorrect if `numChannelsPerModule` differs from 3 in practice.
- **No validation of `filteredData.Length` vs `test.Channels.Count`**: The `SoMatTestHeader` constructor silently truncates to the smaller of the two counts.
None identified beyond these.