function inspect_lem_models % Read-only structural inventory and compile probe for the LEM Simulink models. rootDir = fileparts(mfilename('fullpath')); modelDir = fullfile(rootDir, 'LEM_slx'); reportDir = fullfile(rootDir, 'analysis_artifacts'); if ~exist(reportDir, 'dir') mkdir(reportDir); end models = {'Clark', 'PMLSM', 'PMLSM_ThreeNodeThermal'}; addpath(modelDir); for k = 1:numel(models) model = models{k}; modelFile = fullfile(modelDir, [model '.slx']); reportFile = fullfile(reportDir, [model '_inventory.txt']); fid = fopen(reportFile, 'w'); cleanup = onCleanup(@() fclose(fid)); fprintf(fid, 'MODEL\t%s\nFILE\t%s\n', model, modelFile); load_system(modelFile); fprintf(fid, 'MODEL_VERSION\t%s\n', get_param(model, 'ModelVersion')); fprintf(fid, 'SOLVER\t%s\n', get_param(model, 'Solver')); fprintf(fid, 'SOLVER_TYPE\t%s\n', get_param(model, 'SolverType')); fprintf(fid, 'FIXED_STEP\t%s\n', get_param(model, 'FixedStep')); fprintf(fid, 'START_TIME\t%s\n', get_param(model, 'StartTime')); fprintf(fid, 'STOP_TIME\t%s\n', get_param(model, 'StopTime')); fprintf(fid, 'SAMPLE_TIME_COLORS\t%s\n', get_param(model, 'SampleTimeColors')); refs = find_mdlrefs(model, 'MatchFilter', @Simulink.match.internal.filterOutCodeInactiveVariantSubsystemChoices); fprintf(fid, 'MODEL_REFERENCES\t%s\n', strjoin(refs, ', ')); fprintf(fid, '\nMODEL_WORKSPACE\n'); ws = get_param(model, 'ModelWorkspace'); vars = ws.whos; for n = 1:numel(vars) value = ws.getVariable(vars(n).name); fprintf(fid, '%s\t%s\t%s\n', vars(n).name, vars(n).class, valueText(value)); end fprintf(fid, '\nBLOCKS_AND_PARAMETERS\n'); blocks = find_system(model, 'LookUnderMasks', 'all', 'FollowLinks', 'off', ... 'MatchFilter', @Simulink.match.allVariants, 'Type', 'Block'); for n = 1:numel(blocks) block = blocks{n}; fprintf(fid, '\nBLOCK\t%s\n', block); fprintf(fid, 'SID\t%s\n', Simulink.ID.getSID(block)); fprintf(fid, 'TYPE\t%s\n', get_param(block, 'BlockType')); fprintf(fid, 'MASK_TYPE\t%s\n', get_param(block, 'MaskType')); fprintf(fid, 'REFERENCE\t%s\n', get_param(block, 'ReferenceBlock')); params = get_param(block, 'DialogParameters'); if isstruct(params) names = fieldnames(params); for p = 1:numel(names) name = names{p}; try value = get_param(block, name); fprintf(fid, 'PARAM\t%s\t%s\n', name, valueText(value)); catch end end end if strcmp(get_param(block, 'BlockType'), 'SubSystem') try script = get_param(block, 'Script'); if ~isempty(script) fprintf(fid, 'SCRIPT_BEGIN\n%s\nSCRIPT_END\n', script); end catch end end end fprintf(fid, '\nLINES\n'); systems = [{model}; find_system(model, 'LookUnderMasks', 'all', ... 'FollowLinks', 'off', 'MatchFilter', @Simulink.match.allVariants, ... 'BlockType', 'SubSystem')]; systems = unique(systems, 'stable'); for n = 1:numel(systems) lines = find_system(systems{n}, 'FindAll', 'on', 'SearchDepth', 1, 'Type', 'Line'); for p = 1:numel(lines) src = get_param(lines(p), 'SrcBlockHandle'); dst = get_param(lines(p), 'DstBlockHandle'); if src > 0 && ~isempty(dst) for q = 1:numel(dst) if dst(q) > 0 fprintf(fid, '%s\t%s -> %s\n', systems{n}, ... getfullname(src), getfullname(dst(q))); end end end end end clear cleanup close_system(model, 0); end compileFile = fullfile(reportDir, 'compile_probe.txt'); fid = fopen(compileFile, 'w'); cleanup = onCleanup(@() fclose(fid)); for k = 1:numel(models) model = models{k}; modelFile = fullfile(modelDir, [model '.slx']); fprintf(fid, 'MODEL\t%s\n', model); try in = Simulink.SimulationInput(model); in = in.setModelParameter('StopTime', '0'); in = in.setModelParameter('SimulationMode', 'normal'); in = in.setPreSimFcn(@(~) addpath(modelDir)); out = sim(in); fprintf(fid, 'STATUS\tPASS\n'); fprintf(fid, 'OUTPUTS\t%s\n', strjoin(who(out), ', ')); catch ME fprintf(fid, 'STATUS\tFAIL\n'); fprintf(fid, 'ERROR_ID\t%s\n', ME.identifier); fprintf(fid, 'ERROR\t%s\n', getReport(ME, 'extended', 'hyperlinks', 'off')); end fprintf(fid, '\n'); end clear cleanup end function text = valueText(value) if ischar(value) text = value; elseif isstring(value) text = strjoin(cellstr(value), ', '); elseif isnumeric(value) || islogical(value) text = mat2str(value); elseif iscell(value) pieces = cellfun(@valueText, value, 'UniformOutput', false); text = ['{' strjoin(pieces, ', ') '}']; else try text = jsonencode(value); catch text = ['<' class(value) '>']; end end text = regexprep(text, '[\r\n\t]+', ' '); end