public static async Task ExecuteAsync( IRootFolder root, IFileWriter writer, bool deleteProcessedFiles, int parallelism, ChannelDataColumns channelDataColumns) { foreach (var simType in channelDataColumns.SimTypes) { var columns = channelDataColumns.GetColumns(simType); var folderGroups = columns.GroupBy(v => v.File.RelativePathToFile); foreach (var folderGroup in folderGroups) { var relativePathToFile = folderGroup.Key; var metadata = await GetSimTypeMetadataAsync(root, relativePathToFile, simType); var xDomainGroups = folderGroup.GroupBy(v => metadata.GetChannelXDomain(v.Metadata.ChannelName)); foreach (var xDomainGroup in xDomainGroups) { var xDomain = xDomainGroup.Key.Trim(); var fileSuffix = "_" + (string.IsNullOrWhiteSpace(xDomain) ? "Unspecified" : xDomain); var resolvedData = new ConcurrentQueue <ResolvedCsvColumn>(); await xDomainGroup.ForEachAsync( parallelism, async column => { try { var pointsInChannel = metadata.GetPointsInChannel(column.Metadata.ChannelName); var buffer = await column.File.GetContentAsBytesAsync(); if (buffer.Length == pointsInChannel * 4) { var floatValues = new float[buffer.Length / sizeof(float)]; Buffer.BlockCopy(buffer, 0, floatValues, 0, buffer.Length); var values = new double[floatValues.Length]; for (int i = 0; i < floatValues.Length; i++) { values[i] = (double)floatValues[i]; } resolvedData.Enqueue( new ResolvedCsvColumn(column.File, column.Metadata.ChannelName, values)); } else { var values = new double[buffer.Length / sizeof(double)]; Buffer.BlockCopy(buffer, 0, values, 0, buffer.Length); resolvedData.Enqueue( new ResolvedCsvColumn(column.File, column.Metadata.ChannelName, values)); } } catch (Exception t) { writer.ReportError( "Failed to parse file: " + column.File.FullPath, t); } }); var data = resolvedData.ToList(); if (data.Count > 0) { // Always put sLap at the start for ATLAS compatibility. const string AtlasPrimaryChannel = "tRun"; data.Sort((a, b) => { if (a == b) { return(0); } if (a.ChannelName == AtlasPrimaryChannel) { return(-1); } if (b.ChannelName == AtlasPrimaryChannel) { return(1); } return(String.Compare(a.ChannelName, b.ChannelName, StringComparison.OrdinalIgnoreCase)); }); var maxDataLength = data.Select(v => v.Data.Length).Max(); var csv = new StringBuilder(); csv.AppendLine(relativePathToFile + simType); csv.AppendLine(string.Join(",", data.Select(v => v.ChannelName))); csv.AppendLine(string.Join(",", data.Select(v => { var units = metadata.GetChannelUnits(v.ChannelName); if (string.IsNullOrWhiteSpace(units)) { return("\"()\""); } return("\"" + units + "\""); }))); for (int i = 0; i < maxDataLength; i++) { csv.AppendLine( string.Join( ",", data.Select(v => v.Data.Length > i ? v.Data[i].NumericOrNaN().ToString(CultureInfo.InvariantCulture) : "").ToList())); } var bytes = Encoding.UTF8.GetBytes(csv.ToString()); var fileName = simType + "_VectorResults" + fileSuffix + ".csv"; if (string.IsNullOrWhiteSpace(relativePathToFile)) { Console.WriteLine($"Writing '{fileName}'."); } else { Console.WriteLine($"Writing '{fileName}' to '{relativePathToFile}'."); } await writer.WriteNewFile(root, relativePathToFile, simType + "_VectorResults" + fileSuffix + ".csv", bytes); if (deleteProcessedFiles) { foreach (var column in data) { await writer.DeleteProcessedFile(root, column.File); } } } } } } }