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
    