/******************************************************* * * DESCRIPTION: class BondGraph * * AUTHOR: Mariana C. D'Abreu * * EMAIL: mdabreu@dc.uba.ar * ********************************************************/ #include "bg.h" /******************************************************************* * Function Name: *******************************************************************/ BondGraph::BondGraph() { this->graph = new BGGraph(); assert( graph != NULL ); this->comps = new Comps(); assert( comps != NULL ); } /******************************************************************* * Function Name: *******************************************************************/ BondGraph::~BondGraph() { if( graph ) delete graph; Comps::iterator cursor; for ( cursor = comps->begin(); cursor != comps->end(); cursor++ ) { if( cursor->second ) delete ( cursor->second ); } if( comps ) delete comps; } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::addComponent( BGComp *comp ) { assert( comp ); BGComp *pcomp; if ( findComponent( comp->getId(), pcomp ) ) { throw BondGraphException( ADD_COMPONENT_ERROR_MSG + comp->getId() ); } comps->insert( Comps::value_type(comp->id, comp) ); return ( graph->addNode( comp->id ) ); } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::delComponent( const Id &key ) { comps->erase( key ); return ( graph->delNode( key ) ); } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::addBond( const Id &key1, const Id &key2, const Id &powerDest, const Id &causalDest ) { BGComp *cmp1, *cmp2; if ( !findComponent( key1, cmp1 ) || !findComponent( key2, cmp2 ) ) { throw BondGraphException( ADD_BOND_ERROR_MSG + key1 + " and " + key2 ); } if( !cmp1->isJunction() && !cmp2->isJunction() ) { throw BondGraphException( ADD_BOND_ERROR_MSG + key1 + " and " + key2 ); } BGEdgeData *edge = new BGEdgeData( powerDest, causalDest ); return ( graph->addEdge( key1, key2, *edge ) ); } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::delBond( const Id &key1, const Id &key2 ) { return ( graph->delEdge( key1, key2 ) ); } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::findComponent( const Id &key, BGComp * &comp ) { Comps::iterator it; it = comps->find( key ); comp = it->second; return ( it != comps->end() ); } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::simplify() { if( !simplifyPowerThroughJunctions() ) { return false; } return ( simplifyEqualAdjJunctions() ); } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::assignCausality() { BGGraph::Iterator cursor; BGGraph::PNode node; BGComp *comp; Causality causality; //------------------------------------------------------------ // Algoritmo SCAP: Sequential Causality Assigment Procedure //------------------------------------------------------------ //Trato de propagar la causalidad a partir de los elementos con causalidad fija (sources) for ( cursor = graph->begin(); cursor != graph->end(); cursor++ ) { node = *cursor; comp = (*comps)[node->getValue()]; if ( comp->getCausalityType() == FixedCausality ) { graph->setMarkAllNodes( false ); assignCausalityFromComponent( *comp, *node, comp->getAllowedCausality(), false ); } } //Trato de propagar la causalidad a partir de los elementos con causalidad preferencial (storages) for ( cursor = graph->begin(); cursor != graph->end(); cursor++ ) { node = *cursor; comp = (*comps)[node->getValue()]; if ( comp->getCausalityType() == PreferredCausality ) { causality = comp->getPreferredCausality(); if( causalizationAllowed( *comp, causality ) ) { graph->setMarkAllNodes( false ); assignCausalityFromComponent( *comp, *node, causality, false ); } else { throw BondGraphException( CAUSALIZATION_ERROR_MSG + comp->getId() + ". Derivative causality not supported!" ); } } } // Trato de propagar la causalidad a partir de los elementos con causalidad variable (disipators) for ( cursor = graph->begin(); cursor != graph->end(); cursor++ ) { node = *cursor; comp = (*comps)[node->getValue()]; if ( comp->getCausalityType() == VarCausality ) { causality = EffortIn; if( causalizationAllowed( *comp, causality ) ) { graph->setMarkAllNodes( false ); assignCausalityFromComponent( *comp, *node, causality, false ); } else if( causalizationAllowed( *comp, INVERSE_CAUSALITY( causality ) ) ) { graph->setMarkAllNodes( false ); assignCausalityFromComponent( *comp, *node, INVERSE_CAUSALITY( causality ), false ); } else { throw BondGraphException( CAUSALIZATION_ERROR_MSG + comp->getId() ); } } } //cout << "\nBG: "; //this->print( cout ); if( !isFullyCausalized() ) { throw BondGraphException( "Error on causalization process. Some components were unabled to be causalized" ); } return true; } /******************************************************************* * Function Name: *******************************************************************/ void BondGraph::print( ostream &out ) { graph->print( out ); } /******************************************************************* * Function Name: *******************************************************************/ list* BondGraph::adjacents( const Id &id ) const { list *adjs; list::iterator iter; list *adjComps; Id adjId; adjs = graph->adjacentsValue( id ); assert( adjs ); adjComps = new list; for( iter = adjs->begin(); iter != adjs->end(); iter++ ) { adjId = *iter; adjComps->push_back( (*comps)[adjId] ); } return adjComps; } /******************************************************************* * Function Name: *******************************************************************/ BGEdgeData &BondGraph::getBondData( const BGComp &comp1, const BGComp &comp2 ) { Id c1, c2; BGComp *pc1, *pc2; BGGraph::Edge *edge; c1 = comp1.getId(); c2 = comp2.getId(); if ( !findComponent( c1, pc1 ) || !findComponent( c2, pc2 ) ) { throw BondGraphException( "Edge not existing between nodes: " + c1 + " and " + c2 ); } edge = graph->getEdge( c1, c2 ); assert( edge ); return ( edge->getData() ); } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::simplifyPowerThroughJunctions() { BGGraph::Iterator cursor; BGGraph::PEdge e1, e2; BGComp *comp; Id node, adj1, adj2; list *adjs; for ( cursor = graph->begin(); cursor != graph->end(); cursor++ ) { node = (*cursor)->getValue(); comp = (*comps)[node]; assert( comp ); // simplifico los junctions con power through --> 1 --> o --> 0 --> if( comp->isJunction() && ( graph->degree( node ) == 2 ) ) { adjs = graph->adjacents( node ); adj1 = adjs->front()->getValue(); adjs->pop_front(); adj2 = adjs->front()->getValue(); e1 = graph->getEdge( node, adj1 ); e2 = graph->getEdge( node, adj2 ); if ( (*comps)[adj1]->isJunction() || (*comps)[adj2]->isJunction() ) { if( e1->getData().isPowerDest( node ) && !e2->getData().isPowerDest( node ) ) { graph->addEdge( adj1, adj2, e2->getData() ); graph->eraseNode( cursor ); comps->erase( node ); delete ( comp ); } else if( !e1->getData().isPowerDest( node ) && e2->getData().isPowerDest( node ) ) { graph->addEdge( adj1, adj2, e1->getData() ); graph->eraseNode( cursor ); comps->erase( node ); delete ( comp ); } } } } return true; } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::simplifyEqualAdjJunctions() { BGGraph::Iterator cursor; BGGraph::PNode node; BGComp *comp; cursor = graph->begin(); while ( cursor != graph->end() ) { node = *cursor; comp = (*comps)[node->getValue()]; assert( comp ); // simplifico los junctions adyacentes de igual tipo -->1-->1--> => -->1--> if( comp->isJunction() ) { mergeAdjacents( comp, cursor ); } cursor++; } return true; } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::mergeAdjacents( BGComp *comp, BGGraph::Iterator &cursor ) { list *adjs; list::iterator iter; Id node, anode; BGComp *acomp; node = comp->getId(); adjs = graph->adjacentsValue( node ); assert( adjs ); for( iter = adjs->begin(); iter != adjs->end(); iter++ ) { anode = *iter; acomp = (*comps)[anode]; if( comp->className() == (*comps)[anode]->className() ) { graph->moveAdjacency( node, anode ); graph->eraseNode( cursor ); comps->erase( node ); if( comp != NULL ) delete comp; } } return true; } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::assignCausalityFromComponent( BGComp &comp, BGGraph::Node &node, Causality causality, bool forceCausalization ) { list *adjs; list::iterator iter; BGGraph::PNode anode; BGGraph::PEdge edge; BGComp *acomp; adjs = graph->adjacents( node ); assert( adjs ); for( iter = adjs->begin(); iter != adjs->end(); iter++ ) { anode = *iter; acomp = (*comps)[anode->getValue()]; // asigno causalidad solo a los elementos estructurales (restringidos) if( !anode->marked() && acomp->getCausalityType() == RestrictedCausality ) { anode->setMark(); edge = graph->getEdge( node, *anode ); // Si el eje no fue causalizado if( !edge->getData().isCausalized() ) { // chequeo que la causalizacion sea posible if( !causalizationAllowed( comp, *acomp, causality ) ) { return false; } else { // causalizo y sigo hasta donde sea posible causalizeBond( comp, *acomp, edge->getData(), causality ); assignCausalityFromComponent( *acomp, *anode, causality, forceCausalization ); } } } } return true; } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::causalizeBond( BGComp &comp, BGComp &acomp, BGEdgeData &edge, Causality causality ) { Id cdId = ( causality == EffortIn ? comp.getId() : acomp.getId() ); edge.setCausalityDest( cdId ); comp.updateAllowedCausality( causality ); acomp.updateAllowedCausality( INVERSE_CAUSALITY( causality ) ); return true; } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::causalizationAllowed( BGComp &comp, Causality causality ) { list *adjs; list::iterator it; adjs = adjacents( comp.getId() ); assert( adjs ); for ( it = adjs->begin(); it != adjs->end() && causalizationAllowed( comp, **it, causality ); it++ ); return ( it == adjs->end() ); } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::causalizationAllowed( BGComp &comp, BGComp &adjcomp, Causality causality ) { Causality c1, c2; c1 = ( comp.isJunction() ? getAllowedCausalityOnJunction( comp, adjcomp ) : comp.getAllowedCausality() ); c2 = ( adjcomp.isJunction() ? getAllowedCausalityOnJunction( adjcomp, comp ) : adjcomp.getAllowedCausality() ); return ( ( c1 == Any || ( c1 == causality ) ) && ( c2 == Any || ( c2 == INVERSE_CAUSALITY( causality ) ) ) ); } /******************************************************************* * Function Name: *******************************************************************/ Causality BondGraph::getAllowedCausalityOnJunction( BGComp &junc, BGComp &adjcomp ) { if( junc.getAllowedCausality() != Any ) { return junc.getAllowedCausality(); } // chequeo cuantos ejes adyacentes ya tienen causalidad definida list *adjs; list::iterator iter; BGGraph::PNode node; BGGraph::PEdge edge; BGComp *acomp; int causalizedBonds = 0; Causality juncCaus; juncCaus = ( junc.className() == "BGSerialJunction" ? EffortOut : EffortIn ); node = graph->getNode( junc.getId() ); assert( node ); adjs = graph->adjacents( *node ); assert( adjs ); for( iter = adjs->begin(); iter != adjs->end(); iter++ ) { edge = graph->getEdge( *node, **iter ); acomp = (*comps)[(*iter)->getValue()]; if( acomp->getAllowedCausality() == INVERSE_CAUSALITY( juncCaus ) && ( acomp->getId() != adjcomp.getId() ) && !edge->getData().isCausalized() ) { return INVERSE_CAUSALITY( juncCaus ); } if( edge->getData().isCausalized() || ( ( acomp->getAllowedCausality() == juncCaus ) && ( acomp->getId() != adjcomp.getId() ) ) ) causalizedBonds++; } // Si solo tengo una asignacion posible, retorno el valor que corresponda segun el junction if( causalizedBonds == ( graph->degree( junc.getId() ) - 1 ) ) { return( juncCaus ); } return Any; } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::isFullyCausalized() { BGGraph::Iterator cursor; list::iterator iter; list *adjs; BGGraph::PEdge edge; for ( cursor = graph->begin(); cursor != graph->end(); cursor++ ) { adjs = graph->adjacents( **cursor ); assert( adjs ); for( iter = adjs->begin(); iter != adjs->end(); iter++ ) { edge = graph->getEdge( **cursor, **iter ); if( !edge->getData().isCausalized() ) return false; } } return true; } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::getMark( const Id & id ) { BGComp *comp; if( findComponent( id, comp ) ) return comp->marked(); return false; } /******************************************************************* * Function Name: *******************************************************************/ void BondGraph::setMark( const Id &id, const bool mark ) { BGComp *comp; if( findComponent( id, comp ) ) comp->setMark( mark ); } /******************************************************************* * Function Name: *******************************************************************/ void BondGraph::setMarkAll( const bool mark ) { Comps::iterator it; BGComp *comp; for( it = comps->begin(); it != comps->end(); it++ ) { comp = it->second; comp->setMark( mark ); } } /******************************************************************* * Function Name: *******************************************************************/ bool BondGraph::containsAlgebraicLoops() { Comps::iterator it; BGComp *comp, *dcomp; // Detecto loops entre resistencias for( it = comps->begin(); it != comps->end(); it++ ) { comp = it->second; if( comp->className() == "BGResistance" ) { setMarkAll( false ); dcomp = detectAlgebraicLoopFromComp( *comp, Any ); if( dcomp != NULL ) { throw BondGraphException( "Algebraic loop detected between components " + comp->getId() + " and " + dcomp->getId() ); } } } return false; } /******************************************************************* * Function Name: *******************************************************************/ BGComp *BondGraph::detectAlgebraicLoopFromComp( BGComp &comp, const Causality & causality ) { list *adjs; list::iterator it; BGComp *adj; Causality caus; adjs = adjacents( comp.getId() ); assert( adjs ); comp.setMark(); for ( it = adjs->begin(); it != adjs->end(); it++ ) { adj = *it; if( !adj->marked() ) { adj->setMark(); caus = ( getBondData( comp, *adj ).isCausalityDest( comp.getId() ) ? EffortIn : EffortOut ); if( ( adj->className() == "BGResistance" ) && ( causality == Any || causality == caus ) ) { return adj; } else if( causality == Any || causality == caus ) { return detectAlgebraicLoopFromComp( *adj, caus ); } } } delete adjs; return NULL; }