function reorganize_data()
    basePath = '../';
    rawDataPath = fullfile(basePath, 'raw_data');

    % Initialize maps to track run files and transient run numbers
    runFilesMap = containers.Map('KeyType', 'char', 'ValueType', 'any');
    transientRunMap = containers.Map('KeyType', 'char', 'ValueType', 'double');

    files = dir(fullfile(rawDataPath, '**/*.mat'));

    % Process files to categorize runs and identify transient runs
    for i = 1:length(files)
        data = load(fullfile(files(i).folder, files(i).name));
        if isfield(data, 'tireid') && isfield(data, 'testid')
            tireid = data.tireid;
            testType = formatTestType(data.testid);
            runNumber = extractRunNumber(files(i).name);

            key = sprintf('%s_%s', tireid, testType);
            if ~runFilesMap.isKey(key)
                runFilesMap(key) = {};
            end
            runFiles = runFilesMap(key);
            runFiles{end+1} = struct('path', fullfile(files(i).folder, files(i).name), 'runNumber', runNumber);
            runFilesMap(key) = runFiles;

            % Identify the transient run for cornering
            if strcmpi(testType, 'cornering')
                if transientRunMap.isKey(tireid)
                    transientRunMap(tireid) = min(transientRunMap(tireid), runNumber);
                else
                    transientRunMap(tireid) = runNumber;
                end
            end
        end
    end

% Create directories for each tireid if they don't exist
    mapKeys = runFilesMap.keys();
    tireids = unique(cellfun(@(x) strtok(x, '_'), mapKeys, 'UniformOutput', false));
    for i = 1:length(tireids)
        newDir = fullfile('../sorted_data', tireids{i});
        if ~exist(newDir, 'dir')
            mkdir(newDir);
        end
    end

    % Merge files in ascending order of run number and handle transient runs
    for i = 1:length(mapKeys)
        key = mapKeys{i};
        runFiles = runFilesMap(key);
        [tireid, testType] = strtok(key, '_');
        testType = testType(2:end); % Remove leading underscore

        % Extract run numbers and sort runs by run number
        runNumbers = arrayfun(@(x) x.runNumber, [runFiles{:}]);
        [~, idx] = sort(runNumbers);
        sortedRuns = runFiles(idx);

        newDir = fullfile('../sorted_data', tireid);
        for j = 1:length(sortedRuns)
            if strcmpi(testType, 'cornering') && sortedRuns{j}.runNumber == transientRunMap(tireid)
                % Handle transient cornering run separately
                newFilePath = fullfile(newDir, 'cornering_transient.mat');
                copyfile(sortedRuns{j}.path, newFilePath);
            else
                % Regular file processing
                newFilePath = fullfile(newDir, sprintf('%s.mat', testType));
                if j == 1 || ~exist(newFilePath, 'file')
                    copyfile(sortedRuns{j}.path, newFilePath);
                else
                    mergeData(newFilePath, sortedRuns{j}.path);
                end
            end
        end
    end
end

function testType = formatTestType(testid)
    switch lower(testid)
        case 'cornering'
            testType = 'cornering';
        case 'drive/brake/combined'
            testType = 'drivebrake';
        otherwise
            error('Unknown testid: %s', testid);
    end
end

function mergeData(mergedFilePath, newFilePath)
    % Load existing and new data
    existingData = load(mergedFilePath);
    newData = load(newFilePath);

    % Merge logic with error checking for singular values
    fieldNames = fieldnames(newData);
    for i = 1:length(fieldNames)
        fieldName = fieldNames{i};
        if isnumeric(newData.(fieldName)) || islogical(newData.(fieldName))
            if numel(newData.(fieldName)) == 1 % Singular value
                if isfield(existingData, fieldName) && existingData.(fieldName) ~= newData.(fieldName)
                    error('Mismatch in singular value for field "%s" between existing and new data.', fieldName);
                end
            elseif isfield(existingData, fieldName)
                existingData.(fieldName) = [existingData.(fieldName); newData.(fieldName)];
            else
                existingData.(fieldName) = newData.(fieldName);
            end
        elseif ~strcmp(fieldName, 'tireid') && ~strcmp(fieldName, 'testid')
            if isfield(existingData, fieldName) && ~isequal(existingData.(fieldName), newData.(fieldName))
                error('Mismatch in non-array field "%s" between existing and new data.', fieldName);
            end
            existingData.(fieldName) = newData.(fieldName);
        end
    end

    % Save the merged data
    save(mergedFilePath, '-struct', 'existingData');
end

function runNumber = extractRunNumber(fileName)
    num = sscanf(fileName, 'B2356run%d');
    if isempty(num)
        runNumber = NaN; % Indicate missing or invalid run number
    else
        runNumber = num;
    end
end