function model=PropagateParameters(model,varargin)
%% model = SubstituteParameters(model)
% purpose: substitute parameter values or prepend parameter names with
% prefix across all model equations.
% input: DynaSim model structure
% options:
% action: {'substitute','prepend'} (default: substitute)
% prefix: string prepended to all parameter names if action is 'prepend'
% output: DynaSim model structure with updated parameter in all equations
%
% see also: PropagateFunctions, WriteDynaSimSolver
% Check inputs
model=CheckModel(model);
if ~isstruct(model.parameters)
% nothing to do
return;
end
% Check inputs
options=CheckOptions(varargin,{...
'action','substitute',{'substitute','prepend'},...
'prefix','pset.p.',[],...
},false);
parameters=model.parameters;
%% 1.0 Propagate through sub-structures
target_types={'fixed_variables','functions','monitors','ODEs','ICs'};
% loop over types of model data
for type_index=1:length(target_types)
type=target_types{type_index};
% info for this type
s=model.(type);
if isstruct(s)
update_these=fieldnames(s);
expressions=struct2cell(s);
% loop over target expressions from which to eliminate internal function calls
for i=1:length(expressions)
if isempty(expressions{i})
continue;
end
% update expressions of this type
switch options.action
case 'substitute'
expressions{i}=insert_parameters(expressions{i},parameters,[]);
case 'prepend'
expressions{i}=insert_parameters(expressions{i},parameters,options.prefix);
end
end
% update model with expressions that have parameter values in them
model.(type)=cell2struct(expressions,update_these,1);
end
end
%% 2.0 Propagate parameters through structure arrays (conditionals)
if ~isempty(model.conditionals)
target_types={'condition','action','else'};
for type_index=1:length(target_types)
type=target_types{type_index};
expressions={model.conditionals.(type)};
% loop over conditional expressions from which to eliminate internal function calls
for i=1:length(expressions)
if isempty(expressions{i})
continue;
end
% update expressions of this type
switch options.action
case 'substitute'
expressions{i}=insert_parameters(expressions{i},parameters,[]);
case 'prepend'
expressions{i}=insert_parameters(expressions{i},parameters,options.prefix);
end
end
[model.conditionals(1:length(model.conditionals)).(type)]=deal(expressions{:});
end
end
function expression=insert_parameters(expression,parameters,prefix)
if isnumeric(expression)
% convert to string and return string
expression=toString(expression);
return;
end
allwords=regexp(expression,'[a-zA-Z]+\w*','match');
words=unique(allwords);
found_parameters=words(ismember(words,fieldnames(parameters)));
if ~isempty(found_parameters)
% substitute those found into this target expression
for ff=1:length(found_parameters)
% name of found parameter
found_parameter=found_parameters{ff};
if isempty(prefix) % no prefix given, substitute value instead
% found value to replace found parameter name in target
found_value=parameters.(found_parameter);
% convert found value into string
if isnumeric(found_value)
if length(found_value)>1
found_value=sprintf('[%s]',num2str(found_value));
else
found_value=num2str(found_value);
end
elseif iscell(found_value)
if iscellstr(found_value)
tmp=cellfun(@(x)['''' x '''' ','] ,found_value,'uni',0);
else
tmp=cellfun(@(x)[num2str(x) ','] ,found_value,'uni',0);
end
tmp=[tmp{:}];
found_value=sprintf('{%s}',tmp(1:end-1));
elseif isa(found_value,'function_handle')
found_value=func2str(found_value);
end
else % prefix provided, substitute prefix_name
found_value=[prefix found_parameter];
end
if ~ischar(found_value)
warning('failed to convert parameter ''%s'' to string and substitute into model equations:',found_parameter);
found_value
else
% update expression
num_found = length(find(ismember(allwords,found_parameter)));
for iter=1:num_found
expression=dynasim_strrep(expression,found_parameter,found_value);
end
end
end
end