123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 |
- function model = mttFetchBondgraph(filename)
- mttAssert(mttFileExists(filename),...
- ['File "',filename,'" not found']) ;
- mttNotify([' ...processing ',filename]) ;
- mttWriteNewLine ;
- model.bondgraph = filename ;
- content = mttReadFile(filename) ;
- L = length(content) ;
- N = 1 ;
- processing = (N<=L) ;
- while processing
- jump = 1 ;
- line = mttClipText(content{N}) ;
-
- if ~isempty(line)
- no_string_terminator = isempty(findstr('\001',line)) ;
-
- if no_string_terminator
- if mttIsNumericText(line)
- numbers = round(str2num(line)) ; % only interested in integer values
-
- if numbers(1)==2 % ... line definition
- forward_arrow = numbers(14)~=0 ;
- reverse_arrow = numbers(15)~=0 ;
- arrow = (forward_arrow | reverse_arrow) ;
-
- depth = numbers(7) ;
- is_visible = rem(depth,10)==0 ;
-
- if is_visible
- mttAssert(~arrow,...
- ['Line ',num2str(N),': Arrows are not recognised in bond graphs']) ;
-
- number_of_points = numbers(16) ;
- coordinate_string = [] ;
- M = 0 ;
-
- matching = 1 ;
- while matching
- M = M + 1 ;
- if isempty(coordinate_string)
- coordinate_string = content{N+M} ;
- else
- coordinate_string = [coordinate_string,' ',content{N+M}] ;
- end
-
- mttAssert(mttIsNumericText(coordinate_string),...
- ['Line ',num2str(N+M),': Coordinates not recognised']) ;
-
- coordinates = str2num(coordinate_string) ;
-
- matching = length(coordinates)<2*number_of_points ;
- end
-
- mttAssert(length(coordinates)==2*number_of_points,...
- ['Line ',num2str(N+1),': Wrong number of coordinates']) ;
-
- jump = jump + M ;
-
- if number_of_points==2
- model = create_line(model,coordinates) ;
- elseif number_of_points>2
- model = create_bond(model,coordinates) ;
- end
- else
- jump = jump + forward_arrow + reverse_arrow ;
- end
- end
- end
- else
- [last_word,first_part] = mttDetachText(line,' ') ;
-
- if mttIsNumericText(first_part)
- numbers = round(str2num(first_part)) ; % only interested in integer values
- if numbers(1)==4 % ... text definition
- depth = numbers(4) ;
- is_visible = rem(depth,10)==0 ;
-
- if is_visible
- coordinates = numbers(12:13) ;
- text = mttCompressText(mttCutText(last_word,'\001')) ;
-
- identifier = mttCutText(text,'[') ;
- qualifier = mttExtractText(text,'[',']') ;
-
- name.label = [] ;
- name.domain = [] ;
- name.domain_item = [] ;
- name.class = [] ;
- name.object = [] ;
-
- if isempty(identifier)
- name.label = qualifier ;
- model = create_label(model,name,coordinates) ;
- else
- [name.domain,name.domain_item] = mttCutText(qualifier,'::') ;
- [name.class,name.object] = mttCutText(identifier,':') ;
- model = create_object(model,name,coordinates) ;
- end
- end
- end
- end
- end
- end
-
- N = N + jump ;
- processing = (N<=L) ;
- end
- model = incorporate_anonymous_objects(model) ;
- model = identify_causal_assignments(model) ;
- model = identify_object_binding(model) ;
- model = identify_object_interfaces(model) ;
- model = associate_external_domains(model) ;
- model = tidy_up(model) ;
- function model = create_line(model,coordinates)
- next = 1 + mttGetFieldLength(model,'line') ;
- model.line(next).xy1 = coordinates(1:2) ;
- model.line(next).xy2 = coordinates(3:4) ;
- model.line(next).mid = (coordinates(1:2)+coordinates(3:4))/2 ;
-
- function model = create_bond(model,coordinates)
- next = 1 + mttGetFieldLength(model,'bond') ;
-
- N = length(coordinates) ;
-
- q1 = coordinates(N-1:N) ; p1 = coordinates(1:2) ;
- p2 = coordinates(3:4) ; q2 = coordinates(N-3:N-2) ;
- p3 = coordinates(5:6) ; q3 = coordinates(N-5:N-4) ;
- ps = norm(p2-p1) ; qs = norm(q2-q1) ;
-
- orientation = sign(ps-qs) ;
-
- switch orientation
- case 1, % harpoon points forward
- xy1 = p1 ; xy2 = q2 ; v1 = p2-p1 ; v2 = q2-q3 ; harpoon = q1-q2 ;
- case -1, % harpoon points backward
- xy1 = p2 ; xy2 = q1 ; v1 = q2-q1 ; v2 = p2-p3 ; harpoon = p1-p2 ;
- end
-
- harpoon_side = sign_cross_product(v2,harpoon) ;
-
- mttAssert(~(orientation==0 | harpoon_side==0),...
- ['Ambiguous bond orientation between[',num2str(xy1),'] and [',num2str(xy2),']']) ;
-
- model.bond(next).xy1 = xy1 ;
- model.bond(next).xy2 = xy2 ;
- model.bond(next).v1 = v1 ;
- model.bond(next).v2 = v2 ;
- model.bond(next).harpoon = harpoon ;
- model.bond(next).harpoon_side = harpoon_side ;
-
- model.bond(next).from.obj = [] ;
- model.bond(next).from.interface = [] ;
- model.bond(next).to.obj = [] ;
- model.bond(next).to.interface = [] ;
- model.bond(next).flow = [] ;
- model.bond(next).effort = [] ;
- model.bond(next).unicausal = [] ;
- model.bond(next).domain = [] ;
- model.bond(next).domain_item = [] ;
-
- function model = create_label(model,name,coordinates)
- inner_name = mttExtractText(name.label,'<','>') ;
- if isempty(inner_name)
- label_name = name.label ;
- is_inline = 0 ;
- else
- label_name = inner_name ;
- is_inline = 1 ;
- end
- mttValidateName(label_name) ;
- next = 1 + mttGetFieldLength(model,'label') ;
- model.label(next).name = label_name ;
- model.label(next).is_inline = is_inline ;
- model.label(next).xy = coordinates ;
- function model = create_object(model,name,coordinates)
- global mtt_environment
-
- domain_names = mttGetFieldNames(mtt_environment,'domain') ;
-
- is_anonymous = 0 ;
- if isempty(name.object)
- switch name.class
- case {'0','1'},
- is_anonymous = 1 ;
- case 'SS',
- mttAssert(~isempty(name.object),...
- 'Anonymous "SS" object') ;
- otherwise,
- name.object = name.class ;
- end
- end
-
- if is_anonymous
- next = 1 + mttGetFieldLength(model,'anonymous') ;
- model.anonymous(next).class = name.class ;
- model.anonymous(next).xy = coordinates ;
- else
- object_names = mttGetFieldNames(model,'obj') ;
- if ~isempty(object_names)
- mttAssert(~ismember(name.object,object_names),...
- ['Repeated object: "',name.object,'"']) ;
- end
-
- switch name.class
- case {'0','1'},
- mttValidateName(name.object) ;
- mttAssert(~ismember(name.object,{'in','out'}),...
- 'Junctions cannot use reserved port names') ;
-
- case {'SS','Se','Sf','De','Df'},
- mttValidateName(name.object) ;
-
- if isempty(name.domain) | isempty(mtt_environment)
- model = setfield(model,'obj',name.object,'domain',[]) ;
- model = setfield(model,'obj',name.object,'domain_item',[]) ;
- else
- mttAssert(ismember(name.domain,domain_names),...
- ['Unrecognised domain "',name.domain,'"']) ;
- dom = getfield(mtt_environment,'domain',name.domain,'dom') ;
- item = getfield(mtt_environment,'domain',name.domain,'item') ;
-
- if isempty(item)
- public_domain = getfield(mtt_environment,'public_domain',{dom}) ;
- item_names = mttGetFieldNames(public_domain,'item') ;
-
- mttAssert(ismember(name.domain_item,item_names),...
- ['Item "',name.domain_item,'" not found in public domain "',name.domain,'"']) ;
- item_name = name.domain_item ;
- else
- mttAssert(isempty(name.domain_item),...
- ['Item unspecified in public domain "',name.domain,'"']) ;
- item_name = item ;
- end
-
- model = setfield(model,'obj',name.object,'domain',dom) ;
- model = setfield(model,'obj',name.object,'domain_item',item_name) ;
- end
-
- otherwise,
- mttValidateName(name.class) ;
- mttValidateName(name.object) ;
-
- mttAssert(~ismember(name.object,{'in','out'}),...
- 'Objects cannot use reserved port names') ;
- end
- model = setfield(model,'obj',name.object,'class',name.class) ;
- model = setfield(model,'obj',name.object,'xy',coordinates) ;
- end
- function model = incorporate_anonymous_objects(model)
- number_of_objects = mttGetFieldLength(model,'anonymous') ;
- last = length(num2str(number_of_objects)) ;
- for i = 1:last
- object_number(i) = '0' ;
- end
-
- for i = 1:number_of_objects
- anonymous_object = getfield(model,'anonymous',{i}) ;
-
- current_number = num2str(i) ;
- width = length(current_number) ;
- first = last-width+1 ;
- object_number(first:last) = current_number ;
-
- object_name = ['mtt_obj',object_number] ;
- model = setfield(model,'obj',object_name,model.anonymous(i)) ;
- end
- function r = sign_cross_product(v1,v2)
- r = sign(v1(1)*v2(2) - v1(2)*v2(1)) ;
-
- function model = identify_causal_assignments(model)
- L = mttGetFieldLength(model,'line') ;
-
- if L>0
- N = mttGetFieldLength(model,'bond') ;
-
- for j = 1:L
- for i = 1:N
- s(i,j) = norm(model.line(j).mid - model.bond(i).xy1) ;
- f(i,j) = norm(model.line(j).mid - model.bond(i).xy2) ;
- end
- end
-
- [min_range_start,nearest_bond_start] = min(s) ;
- [min_range_finish,nearest_bond_finish] = min(f) ;
-
- equidistant = min_range_start==min_range_finish ;
- at_harpoon = min_range_start>min_range_finish ;
-
- for j = 1:L
- fulcrum = num2str(model.line(j).mid) ;
-
- mttAssert(~equidistant(j),...
- ['Ambiguous causal line at [',num2str(model.line(j).mid),']']) ;
-
- if at_harpoon(j)
- index = nearest_bond_finish(j) ;
- bond = model.bond(index) ;
- terminal = bond.xy2 ;
- terminal_vector = bond.v2 ;
- else
- index = nearest_bond_start(j) ;
- bond = model.bond(index) ;
- terminal = bond.xy1 ;
- terminal_vector = bond.v1 ;
- end
-
- to_lhs = norm(model.line(j).xy1 - terminal) ;
- to_mid = norm(model.line(j).mid - terminal) ;
- to_rhs = norm(model.line(j).xy2 - terminal) ;
-
- mttAssert(to_mid<norm(bond.harpoon),...
- ['Cannot assign causality at [',num2str(fulcrum),']']) ;
-
- causality_ok = 0 ;
-
- is_unicausal = to_mid<min(to_lhs,to_rhs) ;
- if is_unicausal
- [bond.flow,causality_ok] = mttAssign(bond.flow,at_harpoon(j)) ;
- [bond.effort,causality_ok] = mttAssign(bond.effort,at_harpoon(j)) ;
- else
- causal_vector = (right-left) * sign(to_mid>to_left) ;
- causal_assignment = sign_cross_product(terminal_vector,causal_vector) ;
- mttAssert(causal_assignment~=0,...
- ['Cannot determine causality near [',num2str(fulcrum),']']) ;
-
- if causal_assignment==bond.harpoon_side
- [bond.flow,causality_ok] = mttAssign(bond.flow,at_harpoon(j)) ;
- else
- [bond.effort,causality_ok] = mttAssign(bond.effort,at_harpoon(j)) ;
- end
- end
- mttAssert(causality_ok,...
- ['Ambiguous causal assignment near [',num2str(fulcrum),']']) ;
-
- bond.unicausal = mttCompare(bond.flow,bond.effort) ;
-
- model.bond(index) = bond ;
- end
- end
-
-
- function model = identify_object_binding(model)
- object_names = mttGetFieldNames(model,'obj') ;
- number_of_objects = length(object_names) ;
- number_of_bonds = mttGetFieldLength(model,'bond') ;
-
- for j = 1:number_of_bonds
- bond = model.bond(j) ;
- for i = 1:number_of_objects
- object = getfield(model,'obj',object_names{i}) ;
- origin_proximity(i) = norm(object.xy - bond.xy1) ;
- target_proximity(i) = norm(object.xy - bond.xy2) ;
- end
-
- [range,index] = min(origin_proximity) ;
- origin_name = object_names{index} ;
- bond.from.obj = origin_name ;
- bond.from.interface = [] ;
-
- [range,index] = min(target_proximity) ;
- target_name = object_names{index} ;
- bond.to.obj = target_name ;
- bond.to.interface = [] ;
-
- model = setfield(model,'bond',{j},bond) ;
-
- origin = getfield(model,'obj',origin_name) ;
- next = 1 + mttGetFieldLength(origin,'bond') ;
- origin.bond(next).number = j ;
- origin.bond(next).is_inbond = 0 ;
- model = setfield(model,'obj',origin_name,origin) ;
-
- target = getfield(model,'obj',target_name) ;
- next = 1 + mttGetFieldLength(target,'bond') ;
- target.bond(next).number = j ;
- target.bond(next).is_inbond = 1 ;
- model = setfield(model,'obj',target_name,target) ;
- end
-
-
- function model = identify_object_interfaces(model)
- object_names = mttGetFieldNames(model,'obj') ;
- number_of_objects = length(object_names) ;
- number_of_labels = mttGetFieldLength(model,'label') ;
- number_of_bonds = mttGetFieldLength(model,'bond') ;
-
- for j = 1:number_of_labels
- label = model.label(j) ;
- for i = 1:number_of_objects
- object_name = object_names{i} ;
- object = getfield(model,'obj',object_names{i}) ;
- proximity(i) = norm(object.xy - label.xy) ;
- end
- [range,index] = min(proximity) ;
- associated_object = object_names{index} ;
- object = getfield(model,'obj',associated_object) ;
-
- switch object.class
- case {'0','1'},
- mttAssert(~label.is_inline,...
- ['Inline ports not valid for "0" and "1" junctions']) ;
- end
-
- next = 1 + mttGetFieldLength(object,'interface') ;
- object = setfield(object,'interface',{next},'name',label.name) ;
- object = setfield(object,'interface',{next},'class',[]) ;
- object = setfield(object,'interface',{next},'is_inline',label.is_inline) ;
- object = setfield(object,'interface',{next},'xy',label.xy) ;
- object = setfield(object,'interface',{next},'in',[]) ;
- object = setfield(object,'interface',{next},'out',[]) ;
- object = setfield(object,'interface',{next},'map',[]) ;
- model = setfield(model,'obj',associated_object,object) ;
- end
-
- for j = 1:number_of_objects
- object_name = object_names{j} ;
- object = getfield(model,'obj',object_name) ;
-
- number_of_attached_bonds = mttGetFieldLength(object,'bond') ;
- number_of_interfaces = mttGetFieldLength(object,'interface') ;
-
- for k = 1:number_of_interfaces
- interface = object.interface(k) ;
-
- inbond_proximity = [] ; inbond_counter = [] ;
- outbond_proximity = [] ; outbond_counter = [] ;
-
- in_counter = 0 ;
- out_counter = 0 ;
-
- for i = 1:number_of_attached_bonds
- bond_number = object.bond(i).number ;
- bond = model.bond(bond_number) ;
-
- if object.bond(i).is_inbond
- if isempty(bond.to.interface)
- in_counter = in_counter + 1 ;
- inbond_proximity(in_counter) = norm(interface.xy - bond.xy2) ;
- inbond_counter(in_counter) = bond_number ;
- end
- else
- if isempty(bond.from.interface)
- out_counter = out_counter + 1 ;
- outbond_proximity(out_counter) = norm(interface.xy - bond.xy1) ;
- outbond_counter(out_counter) = bond_number ;
- end
- end
- end
-
- [in_range,inbond_index] = min(inbond_proximity) ;
- [out_range,outbond_index] = min(outbond_proximity) ;
- inbond = inbond_counter(inbond_index) ;
- outbond = outbond_counter(outbond_index) ;
-
- if interface.is_inline
- mttAssert(~isempty(inbond_proximity),...
- ['No in-bond for interface "',object_name,'[',interface.name,']"']) ;
- mttAssert(~isempty(outbond_proximity),...
- ['No out-bond for interface "',object_name,'[',interface.name,']"']) ;
-
- interface.in = inbond ;
- interface.out = outbond ;
-
- model = setfield(model,'bond',{outbond},'from','interface',k) ;
- model = setfield(model,'bond',{inbond},'to','interface',k) ;
- else
- mttAssert(~(isempty(inbond_proximity) & isempty(outbond_proximity)),...
- ['No bond for interface "',object_name,'[',interface.name,']"']) ;
-
- if isempty(inbond_proximity)
- interface.out = outbond ;
- model = setfield(model,'bond',{outbond},'from','interface',k) ;
- elseif isempty(outbond_proximity)
- interface.in = inbond ;
- model = setfield(model,'bond',{inbond},'to','interface',k) ;
- else
- mttAssert(in_range~=out_range,...
- ['Ambiguous interface "',object_name,'[',interface.name,']"']) ;
-
- if out_range<in_range
- interface.out = outbond ;
- model = setfield(model,'bond',{outbond},'from','interface',k) ;
- else
- interface.in = inbond ;
- model = setfield(model,'bond',{inbond},'to','interface',k) ;
- end
- end
- end
- object.interface(k) = interface ;
- end
- model = setfield(model,'obj',object_name,object) ;
- end
-
-
- for i = 1:number_of_objects
- object_name = object_names{i} ;
- object = getfield(model,'obj',object_name) ;
-
- number_of_interfaces = mttGetFieldLength(object,'interface') ;
- for k = 1:number_of_interfaces;
- interface = object.interface(k) ;
-
- if interface.is_inline
- mttAssert(~(isempty(interface.in) | isempty(interface.out)),...
- ['Unbound interface: ',object_name,'[',interface.name,']']) ;
- else
- mttAssert(~(isempty(interface.in) & isempty(interface.out)),...
- ['Unbound interface: ',object_name,'[',interface.name,']']) ;
- end
- end
- end
-
- objects_with_in = [] ;
- objects_with_out = [] ;
-
- for j = 1:number_of_bonds
- bond = model.bond(j) ;
-
- if isempty(bond.from.interface)
- object_name = bond.from.obj ;
- object = getfield(model,'obj',object_name) ;
-
- if ~ismember(object.class,{'0','1'})
- mttAssert(~ismember(object_name,objects_with_out),...
- ['Object "',object_name,'" has more than one implicit out-bond']) ;
- if isempty(objects_with_out)
- objects_with_out = {object_name} ;
- else
- objects_with_out = [objects_with_out,{object_name}] ;
- end
- end
-
- next = 1 + mttGetFieldLength(object,'interface') ;
- model = setfield(model,'obj',object_name,'interface',{next},'name','out') ;
- model = setfield(model,'obj',object_name,'interface',{next},'in',[]) ;
- model = setfield(model,'obj',object_name,'interface',{next},'out',j) ;
- model = setfield(model,'bond',{j},'from','interface',next) ;
- end
-
- if isempty(bond.to.interface)
- object_name = bond.to.obj ;
- object = getfield(model,'obj',object_name) ;
-
- if ~ismember(object.class,{'0','1'})
- mttAssert(~ismember(object_name,objects_with_in),...
- ['Object "',object_name,'" has more than one implicit in-bond']) ;
- if isempty(objects_with_in)
- objects_with_in = {object_name} ;
- else
- objects_with_in = [objects_with_in,{object_name}] ;
- end
- end
-
- next = 1 + mttGetFieldLength(object,'interface') ;
- model = setfield(model,'obj',object_name,'interface',{next},'name','in') ;
- model = setfield(model,'obj',object_name,'interface',{next},'in',j) ;
- model = setfield(model,'obj',object_name,'interface',{next},'out',[]) ;
- model = setfield(model,'bond',{j},'to','interface',next) ;
- end
- end
-
-
- function model = associate_external_domains(model)
- object_names = mttGetFieldNames(model,'obj') ;
- number_of_objects = length(object_names) ;
-
- for i = 1:number_of_objects
- object_name = object_names{i} ;
- object = getfield(model,'obj',object_name) ;
-
- switch object.class
- case {'SS','Se','Sf','De','Df'},
- mttAssert(mttGetFieldLength(object,'interface')==1,...
- ['Object "',object_name,'" must have a unique bond interface']) ;
-
- bond_number = [] ;
-
- if ~isempty(object.interface.in)
- bond_number = object.interface.in ;
- end
- if ~isempty(object.interface.out)
- bond_number = object.interface.out ;
- end
-
- [model,ok] = mttUpdateBondDomain(model,bond_number,object.domain,object.domain_item) ;
- mttAssert(ok,['Domain conflict on bond connected to object "',object_name,'"']) ;
- end
- end
-
-
- function model = tidy_up(model)
- % remove temperory data and xfig geometry from model structure
- object_names = mttGetFieldNames(model,'obj') ;
- number_of_objects = length(object_names) ;
-
- for i = 1:number_of_objects
- object_name = object_names{i} ;
- object = getfield(model,'obj',object_name) ;
-
- object = mttDeleteField(object,'bond') ;
-
- object_interfaces = getfield(object,'interface') ;
- object_interfaces = mttDeleteField(object_interfaces,'is_inline') ;
- object_interfaces = mttDeleteField(object_interfaces,'xy') ;
- object = setfield(object,'interface',object_interfaces) ;
- object = mttDeleteField(object,'xy') ;
- model = setfield(model,'obj',object_name,object) ;
- end
-
- all_bonds = getfield(model,'bond') ;
- all_bonds = mttDeleteField(all_bonds,'xy1') ;
- all_bonds = mttDeleteField(all_bonds,'xy2') ;
- all_bonds = mttDeleteField(all_bonds,'v1') ;
- all_bonds = mttDeleteField(all_bonds,'v2') ;
- all_bonds = mttDeleteField(all_bonds,'harpoon') ;
- all_bonds = mttDeleteField(all_bonds,'harpoon_side') ;
- model = setfield(model,'bond',all_bonds) ;
-
- model = mttDeleteField(model,'anonymous') ;
- model = mttDeleteField(model,'line') ;
- model = mttDeleteField(model,'label') ;
|