Using GSF.PQDIF - running into InvalidOperationException when calling ChannelDefinition.AddNewSeriesDefinition

Hello, I am currently working to convert CSV files into PQDIFs in a .NET Framework-targeting environment. I was successful with using the IEEE provided open source libraries, but noticed that the GPA provided a friendlier library - so I have been trying to map my code/logic using the GSF components.

The logic is pretty straight forward, I create a container record, then the data source record, and then iterate to create channel definitions. From my IEEE program, each channel definition defines two SeriesDefinitions (one for time, one for the measurement data). I can instantiate a channel definition via the static ChannelDefinition Create method, and then set the Phase, Quantity Measured, and Quantity Type ID. However, a call to ChannelDefinition.AddNewSeriesDefinition throws an InvalidOperationException upon the first attempt with a message of “Sequence contains more than one matching element”.

The IEEE library provides basic examples of using their library to implement PQDIFs of waveforms and phasor data - does something exist for the GSF.PQDIF component?

IEEE component: PQDIF / PQDIFNet · GitLab

The Wiki link from the GSF repo ReadMe does not seem to be working either. See Documentation and Support.

Hello ryby,

It looks like you stumbled onto an error in the ChannelDefinition.CreateChannelDefinition() function. Internally, this function calls DataSource.AddNewChannelDefinition() which sets both Phase and QuantityMeasured to None and adds the series definitions collection with the appropriate tag to the physical structure of the new channel definition. Unfortunately, the ChannelDefinition.CreateChannelDefinition() does all the same things, which causes the series definitions collection to be added twice. Your best bet is to use DataSource.AddNewChannelDefinition() directly instead of ChannelDefinition.CreateChannelDefinition() which I plan to remove in light of this issue.

As for documentation and examples, the truth is that the library was designed to be read-only as it was written specifically to be used by openXDA. I added some features to create or edit PQDIF files when I developed the PQDIF Explorer because I often found it useful to be able to correct simple issues in the files I’d received for analysis. So the only example code I have for writing PQDIF files is in the PQDIF Explorer codebase, and it only really opens existing PQDIF files to edit them rather than creating a new file from scratch.

Also, if you do some digging into openMIC source code history, there were a couple tools that have since been removed which can be used as examples. I wouldn’t classify them as basic examples, but regardless here are the links to those.

https://github.com/GridProtectionAlliance/openMIC/tree/65e8e6871dd2b77eb79fe1eaf2abc5a0632d7beb/Source/Tools/IONDownloader
https://github.com/GridProtectionAlliance/openMIC/tree/65e8e6871dd2b77eb79fe1eaf2abc5a0632d7beb/Source/Tools/DranetzDownloader

Thanks,
Stephen

Hey @StephenCWills,

Thank you for such a prompt response, your suggestion worked and got me passed the InvalidOperationException!

I also appreciate the hooks to other source for docs. I am able to work through now to build the observation records with channel/series instances, then use the PhysicalWriter to write out each container’s PhysicalRecord. A PQDIF file is generated but gets a fatal error message “Bad state (incorrect header check)” when attempting to load it into the PQDIFExplorer - so some troubleshooting/investigation is ahead of me. Thanks for your help!

Sounds like a zlib error. I believe that a PQDIF reader would encounter that error when they try to decompress records that have not been compressed? Perhaps you are setting the compression flags in the container record, but not in the PhysicalWriter. In that case, the PhysicalWriter would write uncompressed records to the file, but the ContainerRecord would indicate that the records are compressed.

FYI, the LogicalWriter assigns these for you when writing the ContainerRecord to the file. The PhysicalWriter is unaware of the logical structure of the PQDIF file so if you choose to bypass the LogicalWriter class and use PhysicalWriter directly, you’ll have to help it along a little bit.

Thanks, solid note regarding the PhysicalWriter - I was missing the compression assignment and should have caught that. Now the Explorer will “load” my PQD but I see that each container has elements with the error “Element link is outside the bounds of the file” - so still making baby steps with progress. Going to try without compression and do a side by side of comparison with my working branch that uses the IEEE component. Maybe my channel/series instances are not “configured” properly from their definitions, may just need to step through with the debugger. Thank you!