mttPropagateCausality.m 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. function model = mttPropagateCausality(model,branch)
  2. is_root_model = (nargin==1) ;
  3. objects = mttGetFieldNames(model,'obj') ;
  4. for i = 1:length(objects)
  5. object_name = objects{i} ;
  6. object = getfield(model,'obj',object_name) ;
  7. if is_root_model
  8. branch = mttDetachText(model.source,'/') ;
  9. end
  10. here = [branch,':',object_name] ;
  11. if isfield(object,'obj')
  12. for i = 1:mttGetFieldLength(object,'interface')
  13. port_name = object.interface(i).name ;
  14. inbond = object.interface(i).in ;
  15. outbond = object.interface(i).out ;
  16. inmap = object.interface(i).map.in ;
  17. outmap = object.interface(i).map.out ;
  18. [inbond_effort,inbond_flow,inbond_unicausal] = mttGetBondCausality(model,inbond) ;
  19. [outbond_effort,outbond_flow,outbond_unicausal] = mttGetBondCausality(model,outbond) ;
  20. [inmap_effort,inmap_flow,inmap_unicausal] = mttGetBondCausality(object,inmap) ;
  21. [outmap_effort,outmap_flow,outmap_unicausal] = mttGetBondCausality(object,outmap) ;
  22. [model,inbond_ok] = mttUpdateBondCausality(model,inbond,inmap_effort,inmap_flow,inmap_unicausal) ;
  23. [model,outbond_ok] = mttUpdateBondCausality(model,outbond,outmap_effort,outmap_flow,outmap_unicausal) ;
  24. [object,inmap_ok] = mttUpdateBondCausality(object,inmap,inbond_effort,inbond_flow,inbond_unicausal) ;
  25. [object,outmap_ok] = mttUpdateBondCausality(object,outmap,outbond_effort,outbond_flow,outbond_unicausal) ;
  26. ok = inbond_ok & outbond_ok & inmap_ok & outmap_ok ;
  27. mttAssert(ok,['Causal conflict at port "',port_name,'" in ',here]) ;
  28. end
  29. if is_root_model
  30. branch = object_name ;
  31. else
  32. branch = [branch,'/',object_name] ;
  33. end
  34. object = mttPropagateCausality(object,branch) ;
  35. model = setfield(model,'obj',object_name,object) ;
  36. else
  37. number_of_interfaces = mttGetFieldLength(object,'interface') ;
  38. switch object.class
  39. case {'Se','Sf','De','Df'}
  40. for i = 1:number_of_interfaces
  41. port_name = object.interface(i).name ;
  42. inbond = object.interface(i).in ;
  43. outbond = object.interface(i).out ;
  44. mttAssert(xor(isempty(inbond),isempty(outbond)),...
  45. ['"',object.class,'" objects must have exactly one attached bond in ',here]) ;
  46. switch object.class
  47. case {'Se','De'},
  48. [model,ok] = mttUpdateBondCausality(model,outbond,[],1,1) ; % Constraint
  49. [model] = mttUpdateBondCausality(model,outbond,1,[],1) ; % Preference
  50. case {'Sf','Df'},
  51. [model,ok] = mttUpdateBondCausality(model,outbond,0,[],1) ; % Constraint
  52. [model] = mttUpdateBondCausality(model,outbond,[],0,1) ; % Preference
  53. end
  54. mttAssert(ok,['Causal constraint violation at port "',port_name,'" in ',here])
  55. end
  56. case '0',
  57. mttAssert(number_of_interfaces>1,...
  58. ['Less than two interfaces at 0-junction ',here]) ;
  59. imposed_effort = [] ;
  60. resultant_flow = [] ;
  61. for j = 1:number_of_interfaces
  62. inbond = object.interface(j).in ;
  63. outbond = object.interface(j).out ;
  64. if isempty(inbond)
  65. bond(j) = outbond ;
  66. orientation(j) = 0 ;
  67. else
  68. bond(j) = inbond ;
  69. orientation(j) = 1 ;
  70. end
  71. [effort,flow,unicausal] = mttGetBondCausality(model,bond(j)) ;
  72. if ~isempty(effort)
  73. if effort==orientation(j)
  74. mttAssert(isempty(imposed_effort),...
  75. ['Over-determined effort at 0-junction ',here]) ;
  76. imposed_effort = bond(j) ;
  77. end
  78. end
  79. if ~isempty(flow)
  80. if flow==orientation(j)
  81. mttAssert(isempty(resultant_flow),...
  82. ['Over-determined flow at 0-junction ',here]) ;
  83. resultant_flow = bond(j) ;
  84. end
  85. end
  86. end
  87. for j = 1:number_of_interfaces
  88. if ~isempty(imposed_effort)
  89. if bond(j)~=imposed_effort
  90. model = mttUpdateBondCausality(model,bond(j),~orientation(j),[],[]) ;
  91. end
  92. end
  93. if ~isempty(resultant_flow)
  94. if bond(j)~=resultant_flow
  95. model = mttUpdateBondCausality(model,bond(j),[],~orientation(j),[]) ;
  96. end
  97. end
  98. end
  99. case '1',
  100. mttAssert(number_of_interfaces>1,...
  101. ['Less than two interfaces at 1-junction ',here]) ;
  102. imposed_flow = [] ;
  103. resultant_effort = [] ;
  104. for j = 1:number_of_interfaces
  105. inbond = object.interface(j).in ;
  106. outbond = object.interface(j).out ;
  107. if isempty(inbond)
  108. bond(j) = outbond ;
  109. orientation(j) = 0 ;
  110. else
  111. bond(j) = inbond ;
  112. orientation(j) = 1 ;
  113. end
  114. [effort,flow,unicausal] = mttGetBondCausality(model,bond(j)) ;
  115. if ~isempty(effort)
  116. if effort~=orientation(j)
  117. mttAssert(isempty(resultant_effort),...
  118. ['Over-determined effort at 1-junction ',here]) ;
  119. resultant_effort = bond(j) ;
  120. end
  121. end
  122. if ~isempty(flow)
  123. if flow~=orientation(j)
  124. mttAssert(isempty(imposed_flow),...
  125. ['Over-determined flow at 1-junction ',here]) ;
  126. imposed_flow = bond(j) ;
  127. end
  128. end
  129. end
  130. for j = 1:number_of_interfaces
  131. if ~isempty(resultant_effort)
  132. if bond(j)~=resultant_effort
  133. model = mttUpdateBondCausality(model,bond(j),orientation(j),[],[]) ;
  134. end
  135. end
  136. if ~isempty(imposed_flow)
  137. if bond(j)~=imposed_flow
  138. model = mttUpdateBondCausality(model,bond(j),[],orientation(j),[]) ;
  139. end
  140. end
  141. end
  142. end
  143. end
  144. end