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);
                                }
                            }
                        }
                    }
                }
            }
        }