function model = mttApplyInterfaceCausality(model,specified_rule,branch) ;
is_root_model = (nargin==2) ;
objects = mttGetFieldNames(model,'obj') ;
for i = 1:length(objects)
object_name = objects{i} ;
object = getfield(model,'obj',object_name) ;
if isfield(object,'obj')
if is_root_model
branch = object_name ;
else
branch = [branch,'/',object_name] ;
end
object = mttApplyInterfaceCausality(object,specified_rule,branch) ;
model = setfield(model,'obj',object_name,object) ;
else
if ~isempty(object.cr)
if is_root_model
branch = mttDetachText(model.source,'/') ;
end
here = [branch,':',object_name] ;
port_names = mttGetFieldNames(object.cr.interface,'port') ;
for j = 1:length(port_names)
port_name = port_names{j} ;
port = getfield(object.cr.interface,'port',port_name) ;
inbond = port.in ;
outbond = port.out ;
for k = 1:mttGetFieldLength(port,'causality')
rule = port.causality(k).rule ;
definition = port.causality(k).def ;
association = port.causality(k).with ;
not_applied = ~port.causality(k).applied ;
switch rule
case 'assert', is_assertion = 1 ;
case 'prefer', is_assertion = 0 ;
otherwise
error(['Unrecognised rule "',port_causality.rule,'" in ',here]) ;
end
apply_rule = strcmp(specified_rule,rule) & not_applied ;
if apply_rule
switch definition
% case 'effort_state',
% mttAssert(mttIsEqual(port.is_flow_state,0),...
% ['Attempt to overwrite state assignment at port "',port_name,'" in ',here]) ;
% port.is_effort_state = 1 ;
% case 'flow_state',
% mttAssert(mttIsEqual(port.is_effort_state,0),...
% ['Attempt to overwrite state assignment at port "',port_name,'" in ',here]) ;
% port.is_flow_state = 1 ;
case {'effort_in_flow_out','flow_in_effort_out','flow_out_effort_in','effort_out_flow_in'}
mttAssert(isempty(association),...
['Over-constraint at port "',port_name,'" in ',here]) ;
switch definition
case {'effort_in_flow_out','flow_out_effort_in'},
[model,inbond_ok] = mttUpdateBondCausality(model,inbond,1,1,1) ;
[model,outbond_ok] = mttUpdateBondCausality(model,outbond,0,0,1) ;
case {'flow_in_effort_out','effort_out_flow_in'},
[model,inbond_ok] = mttUpdateBondCausality(model,inbond,0,0,1) ;
[model,outbond_ok] = mttUpdateBondCausality(model,outbond,1,1,1) ;
end
ok = inbond_ok & outbond_ok ;
if is_assertion
mttAssert(ok,['Causal conflict at port "',port_name,'" in ',here]) ;
end
case 'effort_in'
mttAssert(isempty(association),...
['Over-constraint at port "',port_name,'" in ',here]) ;
[model,inbond_ok] = mttUpdateBondCausality(model,inbond,1,[],1) ;
[model,outbond_ok] = mttUpdateBondCausality(model,outbond,0,[],1) ;
ok = inbond_ok & outbond_ok ;
if is_assertion
mttAssert(ok,['Causal conflict at port "',port_name,'" in ',here]) ;
end
case 'effort_out'
mttAssert(isempty(association),...
['Over-constraint at port "',port_name,'" in ',here]) ;
[model,inbond_ok] = mttUpdateBondCausality(model,inbond,0,[],1) ;
[model,outbond_ok] = mttUpdateBondCausality(model,outbond,1,[],1) ;
ok = inbond_ok & outbond_ok ;
if is_assertion
mttAssert(ok,['Causal conflict at port "',port_name,'" in ',here]) ;
end
case 'flow_in'
mttAssert(isempty(association),...
['Over-constraint at port "',port_name,'" in ',here]) ;
[model,inbond_ok] = mttUpdateBondCausality(model,inbond,[],0,1) ;
[model,outbond_ok] = mttUpdateBondCausality(model,outbond,[],1,1) ;
ok = inbond_ok & outbond_ok ;
if is_assertion
mttAssert(ok,['Causal conflict at port "',port_name,'" in ',here]) ;
end
case 'flow_out'
mttAssert(isempty(association),...
['Over-constraint at port "',port_name,'" in ',here]) ;
[model,inbond_ok] = mttUpdateBondCausality(model,inbond,[],1,1) ;
[model,outbond_ok] = mttUpdateBondCausality(model,outbond,[],0,1) ;
ok = inbond_ok & outbond_ok ;
if is_assertion
mttAssert(ok,['Causal conflict at port "',port_name,'" in ',here]) ;
end
case 'unicausal',
mttAssert(isempty(association),...
['Over-constraint at port "',port_name,'" in ',here]) ;
[model,inbond_ok] = mttUpdateBondCausality(model,inbond,[],[],1) ;
[model,outbond_ok] = mttUpdateBondCausality(model,outbond,[],[],1) ;
ok = inbond_ok & outbond_ok ;
if is_assertion
mttAssert(ok,['Causal conflict at port "',port_name,'" in ',here]) ;
end
case {'equicausal','anticausal'}
mttAssert(length(association)==1,...
['Incorrect constraint at port "',port_name,'" in ',here]) ;
associated_port_name = association{1} ;
associated_port = getfield(cr.interface,'port',associated_port_name) ;
associated_inbond = associated_port.in ;
associated_outbond = associated_port.out ;
mttAsert(xor(isempty(inbond),isempty(outbond)),...
['Causal rule expects unique bond at port "',port_name,'" in ',here]) ;
mttAsert(xor(isempty(associated_inbond),isempty(associated_outbond)),...
['Causal rule expects unique bond at port "',associated_port_name,'" in ',here]) ;
if isempty(associated_inbond)
a = associated_outbond ;
else
a = associated_inbond ;
end
if isempty(inbond)
b = outbond ;
else
b = inbond ;
end
switch definition
case 'equicausal',
[model,bond_ok] = mttUpdateBondCausality(model,b,...
model.bond(a).effort,model.bond(a).flow,model.bond(a).unicausal) ;
[model,associated_bond_ok] = mttUpdateBondCausality(model,a,...
model.bond(b).effort,~model.bond(b).flow,model.bond(b).unicausal) ;
case 'anticausal',
[model,bond_ok] = mttUpdateBondCausality(model,b,...
~model.bond(a).effort,model.bond(a).flow,model.bond(a).unicausal) ;
[model,associated_bond_ok] = mttUpdateBondCausality(model,a,...
~model.bond(b).effort,~model.bond(b).flow,model.bond(b).unicausal) ;
end
ok = bond_ok & associated_bond_ok ;
if is_assertion
mttAssert(ok,['Causal conflict between ports "',port_name,...
'and',associated_port_name,'" in ',here]) ;
end
otherwise,
error(['Unrecognised constraint "',definition,'" in ',here]) ;
end
port.causality(k).applied = 1 ;
object = setfield(object,'cr','interface','port',port_name,port) ;
model = setfield(model,'obj',object_name,object) ;
end
end
end
end
end
end