function [S, meta] = tdcs_scenario_data(scenario) %TDCS_SCENARIO_DATA Build one merge/window scenario from the curated tDCS data. % [S, META] = TDCS_SCENARIO_DATA(SCENARIO) loads the curated 12-animal % table via TDCS_LOAD_DATA, applies the requested group-merge map from % TDCS_CONFIG, restricts to day <= maxDay per the scenario's window % suffix, adds mean-centered day covariates DAY_C / DAY_C2, and recodes % GROUP as a categorical with CFG.REF ('Electrode-Box-B2') as the FIRST % (reference) category via REORDERCATS. S is also written to % analysis/matlab/derived/.csv via WRITETABLE (the derived/ % folder is created if it does not already exist). % % SCENARIO must be one of: % unmerged_full, unmerged_d0_10, mergeA2_full, mergeA2_d0_10, % mergeB2_full, mergeB2_d0_10 % % The scenario name is split into: % - a merge key: 'unmerged' | 'mergeA2' | 'mergeB2', selecting which % containers.Map from TDCS_CONFIG (if any) to apply to relabel % GROUP. 'unmerged' applies no relabeling (identity) -- it is not % backed by a config map at all, since only the two "unknown" % conditions (Electrode-Box-A, Right-Electrode) are ever merge % targets, and the unmerged scenario reports them unmerged/as-is. % - a day window: '_full' -> maxDay = 26, '_d0_10' -> maxDay = 10. % % META is a struct with fields: % .mergeKey 'unmerged' | 'mergeA2' | 'mergeB2' % .maxDay 26 or 10 % .isUnmerged true only when mergeKey == 'unmerged' [mergeKey, maxDay] = localParseScenario(scenario); cfg = tdcs_config(); T = tdcs_load_data(); switch mergeKey case 'unmerged' % Identity: no relabeling. An empty map means isKey(...) is % always false below, so every group passes through unchanged. mergeMap = containers.Map('KeyType', 'char', 'ValueType', 'char'); case 'mergeA2' mergeMap = cfg.mergeA2; case 'mergeB2' mergeMap = cfg.mergeB2; otherwise error('tdcs_scenario_data:badScenario', ... 'Unrecognized scenario "%s".', scenario); end % Relabel GROUP per the merge map. Groups that are not a key in the map % (e.g. Naive, Electrode-Box-A2, Electrode-Box-B2 under mergeA2/mergeB2, % or every group under the empty 'unmerged' map) are left unchanged -- % only the two "unknown" conditions are ever merge-map keys. groupCell = cellstr(T.group); for i = 1:numel(groupCell) if isKey(mergeMap, groupCell{i}) groupCell{i} = mergeMap(groupCell{i}); end end % Day window (applied after relabeling, before centering, per the plan). dayMask = T.day <= maxDay; S = T(dayMask, :); groupCell = groupCell(dayMask); % Recode GROUP as categorical with cfg.ref first (the GLME reference % level). Only categories actually present after merge+window survive. S.group = categorical(groupCell); allCats = categories(S.group); otherCats = allCats(~strcmp(allCats, cfg.ref)); S.group = reordercats(S.group, [{cfg.ref}; otherCats]); % Mean-centered day covariates, computed on the post-window data. S.day_c = S.day - mean(S.day); S.day_c2 = S.day_c .^ 2; % Persist the derived scenario table. thisDir = fileparts(mfilename('fullpath')); derivedDir = fullfile(thisDir, 'derived'); if ~exist(derivedDir, 'dir') mkdir(derivedDir); end outFile = fullfile(derivedDir, [char(scenario) '.csv']); writetable(S, outFile); meta = struct(); meta.mergeKey = mergeKey; meta.maxDay = maxDay; meta.isUnmerged = strcmp(mergeKey, 'unmerged'); end function [mergeKey, maxDay] = localParseScenario(scenario) %LOCALPARSESCENARIO Split "_full" / "_d0_10" apart. scenario = char(scenario); if endsWith(scenario, '_full') maxDay = 26; mergeKey = scenario(1:end - numel('_full')); elseif endsWith(scenario, '_d0_10') maxDay = 10; mergeKey = scenario(1:end - numel('_d0_10')); else error('tdcs_scenario_data:badScenario', ... 'Scenario "%s" does not end in "_full" or "_d0_10".', scenario); end if ~ismember(mergeKey, {'unmerged', 'mergeA2', 'mergeB2'}) error('tdcs_scenario_data:badScenario', ... 'Scenario "%s" has unrecognized merge key "%s".', scenario, mergeKey); end end