/******************************************************* * * DESCRIPTION: Electrical circuit to Bond Graph mapper * * AUTHOR: Mariana C. D'Abreu * * EMAIL: mdabreu@dc.uba.ar * ********************************************************/ #include "bgmapper.h" /******************************************************************* * Function Name: *******************************************************************/ BondGraph *EC_BG_Mapper::mappToBondGraph( const ECircuit & circuit ) { BondGraph *bg = new BondGraph(); assert( bg != NULL ); if( !mappStructures( circuit, *bg ) ) { return NULL; } else if( !insertCeroJunctions( circuit, *bg ) ) { return NULL; } else if( !deleteGroundPotential( circuit, *bg ) ) { return NULL; } else if( !insertOneJunctions( circuit, *bg ) ) { return NULL; } else if( !assignPowerDirections( circuit, *bg ) ) { return NULL; } else if( !simplify( *bg ) ) { return NULL; } else if( !assignCausality( *bg ) ) { return NULL; } else if( !checkSingularities( *bg ) ) { return NULL; } bg->setMarkAll( false ); return bg; } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::mappStructures( const ECircuit &circuit, BondGraph &bg ) { ECircuit::EComps::iterator cursor; for ( cursor = circuit.comps->begin(); cursor != circuit.comps->end(); cursor++ ) { bg.comps->insert( BondGraph::Comps::value_type(cursor->first, cursor->second->toBGComp() ) ); } return copyGraphStructure( circuit, bg ); } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::insertCeroJunctions( const ECircuit &circuit, BondGraph &bg ) { BondGraph::BGGraph::Iterator cursor; BGPNode node, jnode; list rlist; list::iterator iter; BGEdgeData *edgeData; BGParallelJunction *pJunc; for( cursor = bg.graph->begin(); cursor != bg.graph->end(); cursor++ ) { node = *cursor; assert( node ); if( !node->marked() ) { node->setMark(); // nodos alcanzados -> conexiones paralelas rlist.clear(); rlist.push_back( node ); reached( bg, node, rlist ); if( rlist.size() > 1 ) { // creo el junction paralelo pJunc = new BGParallelJunction(); assert( pJunc ); jnode = new BondGraph::BGGraph::Node( pJunc->getId() ); assert( jnode ); jnode->setMark(); // lo agrego al Bond Graph bg.graph->addNode( jnode ); bg.comps->insert( BondGraph::Comps::value_type( pJunc->getId(), pJunc ) ); // y lo conecto a todos los nodos alcanzados, borrando los ejes anteriores for( iter = rlist.begin(); iter != rlist.end(); iter++ ) { edgeData = new BGEdgeData(); assert( edgeData ); bg.graph->eraseAllEdges( *(*iter) ); bg.graph->addEdge( (*iter)->getValue(), pJunc->getId(), *edgeData ); } } } } return true; } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::deleteGroundPotential( const ECircuit &circuit, BondGraph &bg ) { bool del = false; list::const_iterator it = circuit.grounds.begin(); list::iterator iter; list *adjs; Id pid, nid; Ground *ground; BGComp *cmp; // borro todos los grounds for( ; it != circuit.grounds.end(); it++ ) { ground = (*it); pid = ground->accessPin( POSITIVE_ID ); // borro el junction adyacente al ground (deberia ser solo un junction cero) adjs = bg.graph->adjacentsValue( pid ); assert( adjs ); for( iter = adjs->begin(); iter != adjs->end(); iter++ ) { bg.graph->delNode( *iter ); cmp = (*bg.comps)[*iter]; if( cmp != NULL ) delete cmp; bg.comps->erase( *iter ); } // borro el ground bg.graph->delNode( pid ); cmp = (*bg.comps)[ground->getId()]; bg.comps->erase( ground->getId() ); if( cmp != NULL ) delete cmp; del = true; } if( del ) { return true; } // si no hay grounds borro los junction cero inmediatos a los pines negativos de los sources return ( deleteGroundPotentialFromSources( circuit, bg ) ); } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::insertOneJunctions( const ECircuit &circuit, BondGraph &bg ) { ECircuit::EComps::iterator cursor; EComp *ecomp; Id id; for ( cursor = circuit.comps->begin(); cursor != circuit.comps->end(); cursor++ ) { id = cursor->first; ecomp = cursor->second; if( ecomp->isPortComponent() ) { // por cada par de pines del componente agrego un junction serial conectado al mismo insertOneJunctionsInPortComponent( bg, (PortComp *)ecomp ); } } return true; } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::assignPowerDirections( const ECircuit &circuit, BondGraph &bg ) { if( circuit.sources.empty() ) throw EC_BG_MapperException( "Circuit with no sources, power direction assignment interrupted!" ); EComp *source = circuit.sources.front(); list *adjs; BGPEdge edge; Id junc1; bool forceDir = true; assert( source ); // fuerzo la direccion del flujo desde la fuente adjs = bg.graph->adjacents( source->getId() ); junc1 = adjs->front()->getValue(); edge = bg.graph->getEdge( source->getId(), junc1 ); edge->getData().setPowerDirDest( junc1 ); edge->setMark(); // y lo propago por el resto del grafo segun la direccion indicada en los ejes return ( assignPowerDirectionsFromNode( bg, junc1, forceDir ) ); } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::simplify( BondGraph &bg ) { return ( bg.simplify() ); } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::assignCausality( BondGraph &bg ) { return ( bg.assignCausality() ); } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::checkSingularities( BondGraph &bg ) { return ( !bg.containsAlgebraicLoops() ); } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::deleteGroundPotentialFromSources( const ECircuit &circuit, BondGraph &bg ) { Id id; list::const_iterator it = circuit.sources.begin(); PortComp *source; list *adjs; list::iterator iter; BGComp *comp; for( ; it != circuit.sources.end(); it++ ) { source = (*it); id = source->accessPin( NEGATIVE_ID ); adjs = bg.graph->adjacentsValue( id ); assert( adjs ); // borro el junction adyacente al pin negativo del source (deberia ser solo un junction cero) for( iter = adjs->begin(); iter != adjs->end(); iter++ ) { bg.graph->delNode( *iter ); comp = (*bg.comps)[*iter]; if( comp != NULL ) delete comp; bg.comps->erase( *iter ); } } return true; } /******************************************************************* * Function Name: *******************************************************************/ void EC_BG_Mapper::reached( BondGraph &bg, BGPNode node, list &rlist ) { assert( node ); list *listadj; list::iterator iter; BGPNode anode; listadj = bg.graph->adjacents( *node ); assert( listadj ); for( iter = listadj->begin(); iter != listadj->end(); iter++ ) { anode = *iter; assert( anode ); if( !anode->marked() ) { anode->setMark(); rlist.push_back( anode ); reached( bg, anode, rlist ); } } } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::copyGraphStructure( const ECircuit &circuit, BondGraph &bg ) { ECircuit::CircuitGraph::Iterator cursor; list::iterator iter; list *list; BGEdgeData *edgeData; for ( cursor = circuit.graph->begin(); cursor != circuit.graph->end(); cursor++ ) { bg.graph->addNode( (*cursor)->getValue() ); } for( cursor = circuit.graph->begin(); cursor != circuit.graph->end(); cursor++ ) { list = circuit.graph->adjacents( *(*cursor) ); if( list ) { for( iter = list->begin(); iter != list->end(); iter++ ) { edgeData = new BGEdgeData(); assert( edgeData ); bg.graph->addEdge( (*cursor)->getValue(), (*iter)->getValue(), *edgeData ); } } } return true; } /******************************************************************* * Function Name: *******************************************************************/ void EC_BG_Mapper::insertOneJunctionsInPortComponent( BondGraph &bg, PortComp *ecomp ) { Id jid; pId pinP, pinN; BGEdgeData *edgeData; BGSerialJunction *sJunc; list::iterator iter; list *list; assert( ecomp ); bg.graph->addNode( ecomp->getId() ); for( int i=1; i <= ecomp->ports(); i++ ) { // creo el junction serie y lo agrego al bg sJunc = new BGSerialJunction(); assert( sJunc ); jid = sJunc->getId(); bg.graph->addNode( jid ); bg.comps->insert( BondGraph::Comps::value_type( jid, sJunc ) ); pinP = ecomp->accessPortPin( PositivePin, i ); pinN = ecomp->accessPortPin( NegativePin, i ); // agrego los ejes entre el pin positivo y el junction serial list = bg.graph->adjacents( pinP ); if( list ) { for( iter = list->begin(); iter != list->end(); iter++ ) { edgeData = new BGEdgeData( POSITIVE_ID ); assert( edgeData ); bg.graph->addEdge( jid, (*iter)->getValue(), *edgeData ); } } // agrego los ejes entre el pin negativo y el junction serial list = bg.graph->adjacents( pinN ); if( list ) { for( iter = list->begin(); iter != list->end(); iter++ ) { edgeData = new BGEdgeData( NEGATIVE_ID ); assert( edgeData ); bg.graph->addEdge( jid, (*iter)->getValue(), *edgeData ); } } bg.graph->delNode( pinP ); bg.graph->delNode( pinN ); // agrego el eje del junction serial al componente edgeData = new BGEdgeData(); assert( edgeData ); bg.graph->addEdge( jid, ecomp->getId(), *edgeData ); } } /******************************************************************* * Function Name: *******************************************************************/ bool EC_BG_Mapper::assignPowerDirectionsFromNode( BondGraph &bg, const Id &node, bool forceDir ) { list *adjs; list::iterator iter; BGPNode adj; Id adjId; BGPEdge edge; BGComp *comp, *compAdj; comp = (*bg.comps)[node]; assert( comp ); adjs = bg.graph->adjacents( node ); for( iter =adjs->begin(); iter != adjs->end(); iter++ ) { adj = (*iter); adjId = adj->getValue(); edge = bg.graph->getEdge( node, adjId ); compAdj = (*bg.comps)[adj->getValue()]; assert( compAdj ); if( !edge->marked() ) { edge->setMark(); if( forceDir ) { // fuerzo la direccion del power if( edge->getData().getId() == NEGATIVE_ID ) edge->getData().setPowerDirDest( comp->getId() ); else edge->getData().setPowerDirDest( adjId ); } else { // dependiendo del componente y la direccion preestablecida asigno direccion al eje comp->setPowerDirToEdge( edge->getData(), *compAdj ); } assignPowerDirectionsFromNode( bg, adjId, false ); } } return true; }