//Jacky: This is based on the simplified Lopez's version // No FutureValue is used in this version! /******************************************************************* * * DESCRIPTION: class InertialDelayCell * * AUTHOR: Amir Barylko & Jorge Beyoglonian * Version 2: Daniel Rodriguez. * Version 3: Gabriel Wainer * Version 4: Alejandro Troccoli * Version 5: Qi (Jacky) Liu * * EMAIL: mailto://amir@dc.uba.ar * mailto://jbeyoglo@dc.uba.ar * mailto://drodrigu@dc.uba.ar * mailto://gabrielw@dc.uba.ar * mailto://liuqi@sce.carleton.ca * * DATE: 27/06/1998 * DATE: 17/09/1999 (v2) * DATE: 09/10/2005 (v5) * *******************************************************************/ // ** include files **// #include "idcell.h" // header class #include "message.h" // ExternalMessage #include "coupcell.h" // CoupledCell #include "realfunc.h" // calculateWithQuantum /*************************************** * INERTIAL DELAY CELL STATE ***************************************/ /*************************************** * Method: operator= ***************************************/ IDCellState &IDCellState::operator=(IDCellState& thisState) { (AtomicCellState &)*this = (AtomicCellState &)thisState; actualValue = thisState.actualValue; //A recordActual = thisState.recordActual; //RA recordTime = thisState.recordTime; //RT recordState = thisState.recordState; //RS //copy the saved values of state variables at R0 vars_round0 = thisState.vars_round0; //RV //record the delay of the cell at the beginning //of R0 if its phase is Active recordDelay = thisState.recordDelay; //RD return *this; } /*************************************** * Method: copyState ***************************************/ void IDCellState::copyState(BasicState *rhs){ *this = *((IDCellState*)rhs); } /*************************************** * Method: getSize() ***************************************/ int IDCellState::getSize() const { return sizeof(IDCellState); } /*************************************** * INERTIAL DELAY CELL ***************************************/ /******************************************************************* * Method: initializeCell ********************************************************************/ void InertialDelayCell::initializeCell() { AtomicCell::initializeCell(); //This function requires the cell state to be already created. if ( UseQuantum().Active() ) QuantumValue( Real(UseQuantum().Value()) ); } /******************************************************************* * Method: initFunction ********************************************************************/ Model &InertialDelayCell::initFunction() { PortList::iterator cursor; //To start the simulation, send an output message with the current //value and passivate. Model will become active on processing the //outputs from the other cells. for (cursor = outNCPortList().begin(); cursor != outNCPortList().end(); cursor++) { string out_port(cursor->second->name()); string in_port(calculateInPort(out_port)); actualValue( out_port, value(in_port) ); //set A, flag = F setRecordActual( out_port, value(in_port) ); //set RA = A, flag = F } holdIn( AtomicState::active, VTime::Zero); setRecordTime( VTime::Zero ); //RT = 0 setRecordState( AtomicState::passive ); //RS = passive #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "\t --------> IDCell::initFunction() -> " << endl << flush; jacky_os << "\t\t --- RT = " << getRecordTime().asString() << " / " << "RS = " << flush; if(getRecordState() == AtomicState::active){ jacky_os << "active" << endl << flush; } else { jacky_os << "passive" << endl << flush; } jacky_os << "\t\t --- A = " << flush; printValues(actualMap(), jacky_os); jacky_os << endl << "\t\t --- RA = " << flush; printValues(recordActualVal(), jacky_os); jacky_os << endl << flush; jacky_os << "\t\t --- RD = " << VTime::Inf.asString() << endl << flush; #endif //end JACKY_DEBUG //save the StateVars in AtomicCellState to the StateVars in TDCellState recordStateVariables() = cellStateVariables(); //RV = V #ifdef JACKY_DEBUG jacky_os << "\t[2006-01-10] StateVariables in AtomicCellState = " << cellStateVariables().asString() << endl << flush; jacky_os << "\t[2006-01-10] Recorded StateVariables in IDCellState = " << recordStateVariables().asString() << endl << flush; #endif //initialize the RD to Zero since when the cell enters externalFunction //(after outputFunction and internalFunction) the cell's delay at time 0 //will be Infinity. The internalFunction calls passivate() on this cell! setRecordDelay( VTime::Inf ); #ifdef JACKY_DEBUG //this is the number to record the number of the Round in the multiple-round message passing roundNum = 0; #endif //end JACKY_DEBUG return *this; } /******************************************************************* * Method: externalFunction ********************************************************************/ Model &InertialDelayCell::externalFunction( const MessageBag &msgs ) { #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "\t-------->IDCell::externalFunction() called() " << endl << flush; #endif //This function must be called before processing any messages! //It is this function who will set the neighborhood value correctly localTransitionConfluent( msgs ); //flag to record a time change bool timeChanged; //let's check whether there is a time change (usually time advance, but time //can go back in case of a rollback) if( getRecordTime() != msgs.time() ){ //there is a time change #ifdef JACKY_DEBUG jacky_os << "\t IDCell::externalFunction() ---> TIME CHANGED !!!!!" << endl << flush; jacky_os << "\t\t\t Before Update: RT = " << getRecordTime().asString() << " / " << "RS = " << flush; if(getRecordState() == AtomicState::active){ jacky_os << "active" << endl << flush; } else { jacky_os << "passive" << endl << flush; } jacky_os << "\t\t\t Before Update: RA = " << flush; printValues(recordActualVal(), jacky_os); jacky_os << endl << flush; #endif setRecordTime( msgs.time() ); //set RT = new time setRecordState( state() ); //set RS = current state at R0 resetValueFlags( actualMap() ); //Nov. 29, 2005 set all flags in A to False! recordActualVal() = actualMap(); //RA = A #ifdef JACKY_DEBUG jacky_os << "\t -----------------------------------------------------------------" << endl << flush; jacky_os << "\t IDCell::externalFunction() After Update: " << endl << flush; jacky_os << "\t\t --- RT = " << getRecordTime().asString() << " / " << "RS = " << flush; if(getRecordState() == AtomicState::active){ jacky_os << "active" << endl << flush; } else { jacky_os << "passive" << endl << flush; } jacky_os << "\t\t --- Current A = " << flush; printValues(actualMap(), jacky_os); jacky_os << endl << "\t\t --- RA = " << flush; printValues(recordActualVal(), jacky_os); jacky_os << endl << flush; //reset the round number to 0 roundNum = 0; jacky_os << endl << "TimeChange! [Round 0] @" << msgs.time().asString() << endl << flush; #endif //end JACKY_DEBUG recordStateVariables() = cellStateVariables(); //save the state variables in the RV //set the "time change" flag to true timeChanged = true; //if the cell enters a new time with Active phase, records its delay here if ( state() == AtomicState::active ){ //Note: //Time to the next change = absoluteNext - currentTime //Time has elapsed for a period of [currentTime - lastChange()]. //The nextChange has been updated in the ParallelSimulator before this function is called //So the time to next change is the current updated nextChange() setRecordDelay( nextChange() ); //set RD = time to next change if Active #ifdef JACKY_DEBUG jacky_os << "\t\tTimeChange & Active => [[RD = nextChange = " << nextChange().asString() << "]], msgTime = " << msgs.time().asString() << endl << flush; #endif } else { setRecordDelay( VTime::Inf ); //passive, delay = ... } #ifdef JACKY_DEBUG jacky_os << "\t\t\t Resulting RD = " << getRecordDelay().asString() << endl << flush; #endif } //end if time change else { //No time change happens, so these are the following rounds! timeChanged = false; #ifdef JACKY_DEBUG ++roundNum; //increase the number of the round jacky_os << endl << "No TimeChange! [Round " << roundNum << "]@" << msgs.time().asString() << endl << flush; #endif //end JACKY_DEBUG } //This is should be removed once the new Cell Devs definition language is //approved and considers multiple messages from external models bool executedLocal = false; VTime delay( static_cast( parent() )->defaultDelay() ) ; VTime actualTime( msgs.time() ); //always evaluate the transition functions using variables recorded at R0 cellStateVariables() = recordStateVariables(); //Variables = RV list tv; ////////////////////////////////////////////////////////////////////// //Right now, for this implementation, give priority to portInTransitions //This should be changed!! for ( MessageBag::iterator cursor = msgs.begin(); cursor != msgs.end(); cursor++) { ExternalMessage msg = *((ExternalMessage *)(*cursor)); if (!isInNCPort(msg.port().name())) { MASSERTMSG( executedLocal == false, "Current implementation can not handle multiple messages from external models!!"); string functionName = inputPortFunction()[ msg.port().name() ]; if (functionName == DEFAULT_FUNCTION_InPort) { PortValue pv(msg.port().name(), msg.value()); tv.push_back(pv); } else { // sino es un PortInTransition valido VirtualPortList *vpl = new VirtualPortList; getOutPorts(vpl); tv = SingleLocalTransAdmin::Instance().evaluate( functionName, neighborhood(), &(inputPortValues()), delay, actualTime, vpl, this, msg.port().name() ) ; delete vpl; }//if executedLocal = true; }//if }//for if ( !executedLocal ) { VirtualPortList *vpl = new VirtualPortList; getOutPorts(vpl); tv = SingleLocalTransAdmin::Instance().evaluate( localFunction(), neighborhood(), NULL, delay, actualTime, vpl, this ) ; delete vpl; } #ifdef JACKY_DEBUG jacky_os << "\t\tIDCell::externalFunction() resulting (tv) is ---------------------- " << endl << flush; list::iterator tv_it; for (tv_it = tv.begin(); tv_it != tv.end(); tv_it++){ jacky_os << "\t\t\t" << tv_it->first << " = " << (tv_it->second).value() << endl << flush; } jacky_os << "\t\tIDCell::externalFunction() BEFORE COMPARISON, [A] is ==========" << endl << flush; printValues( actualMap(), jacky_os ); #endif //cout << " Quantum : " << QuantumValue().value() << endl; //cout << " ActualValue : " << actualValue().value() << " with q " // << valueWithQuantum(actualValue(), QuantumValue()) << endl; //cout << " New value : " << tv << " with q " << valueWithQuantum(tv, QuantumValue()) << endl; list::iterator pvCursor; for (pvCursor = tv.begin(); pvCursor != tv.end(); pvCursor++) { string output_portname = calculateOutPort(pvCursor->first); #ifdef JACKY_DEBUG jacky_os << "\t\t***IDCell::externalFunction() NEW value: <" << pvCursor->first << "->[" << calculateOutPort( pvCursor->first ) << "] = " << (pvCursor->second).value() << ">" << endl << flush; jacky_os << "\t\t***IDCell::externalFunction() Actual value: <" << pvCursor->first << "->[" << calculateOutPort( pvCursor->first ) << "] = " << actualValue(output_portname).value() << flush; if( actualValueFlag(output_portname) == true ){ jacky_os << " / flag = TRUE> " << endl << flush; } else { jacky_os << " / flag = FALSE> " << endl << flush; } #endif //Nov. 29, 2005 //this condition is added to avoid offset results derived from external events //if NOT derived from event, we allow further changes // [2006-01-06] //Once an event is received: // if the event causes a state change -> change the state, and set flag=TRUE, thus no further change // if the event does not cause a change -> just set flag=TRUE, thus no further change as well // for ALL the message-passing rounds at this time. // When time changes, the flag will be reset to false. if( actualValueFlag(output_portname) == false ){ //AF = FALSE if( ( UseQuantum().Active() || UseDynQuantum().Active() ) && ( valueWithQuantum(pvCursor->second, QuantumValue()) != valueWithQuantum(actualValue(output_portname), QuantumValue()) ) || ( !UseQuantum().Active() && (actualValue(output_portname) != pvCursor->second ) //Jacky: N != A ) ) { //we have to check the "timeChanged" flag //1. if there is a time change // -> we are entering a new multiple-round message passing for this new time // i.e. we enter these multiple rounds with (A = F = RA) & (RS = Active) // Thus, we will set A = F = N, and do preemption here! //2. if there is not a time change // -> we are entering round 1 ... round N for this time. // i.e. we enter the following rounds! Thus "change back" & "change further" // will happen here! if( state() == AtomicState::passive ) { holdIn( AtomicState::active, delay ) ; //Passive => Active #ifdef JACKY_DEBUG jacky_os << "\t1> N != A & Passive => Active, delay = " << delay.asString() << endl << flush; #endif } else { //Jacky: state() == AtomicState::active #ifdef JACKY_DEBUG jacky_os << "\t2> N != A & Active -->" << endl << flush; #endif if( getRecordActual(output_portname) != pvCursor->second ) { //****** (N != A && N != RA) [==== CHANGE FURTHER ===] ****** #ifdef JACKY_DEBUG jacky_os << "\t\t2a> N != RA & Active => ChangeFurther / next = " << nextChange().asString() << endl << flush; #endif //active & preemption if( nextChange() > VTime::Zero ) { //preemption of the delay! holdIn( AtomicState::active, delay ) ; #ifdef JACKY_DEBUG jacky_os << "\t\t\tnext > 0 => preempt delay, Active & delay = " << delay.asString() << endl << flush; #endif } //end preemption }//end change / change further else { MASSERTMSG( timeChanged == false, "Change Back & timeChanged = TRUE !"); //****** (N != A && N == RA) [==== CHANGE BACK ====] ****** #ifdef JACKY_DEBUG jacky_os << "\t\t2b> N == RA & Active => ChangeBack to RS = " << flush; if (getRecordState() == AtomicState::passive) { jacky_os << "Passive!" << endl << flush; } else { jacky_os << "Active...!!" << endl << flush; } #endif if (getRecordState() == AtomicState::passive) { //RS = passive //Change back to passive passivate(); //cerr << "CB Active->Passive" << endl; } else { //RS = active //Change back to active holdIn( AtomicState::active, getRecordDelay() ); #ifdef JACKY_DEBUG jacky_os << "\t\t\tChangeBack to Active => preempt delay, Active & delay = " << getRecordDelay().asString() << endl << flush; #endif //cerr << "CB Active->Active" << endl; } } //end change back } //end state() == AtomicState::active //update A = N if( isInputPort(pvCursor->first) ){ //the value is from input port from the environment actualValue ( output_portname, pvCursor->second, true ); //event, set flag = T } else { actualValue ( output_portname, pvCursor->second ); //not event, set flag = F } //end update [ActualValue] => A = N } //end state change // [ ****************** 2006-01-06 *********************] // Note:If the external event does not cause cell's value changes, i.e. N = A // We still need to set the flag in the ActualValue to TRUE so that further messages // from neighbors will NOT cause new changes to this cell!!! // Ex: At time 04:000, cell's value is 1 (A), and an external event arrives at the cell // at the same time 04:000 with value 1. Thus, the cell's value at time 05:000 (after // a delay of 1000) should be 1 (the same as the external event based on Default-Port-In) // The resulting tv is , which is the same as the event value. In the following // rounds of message-passing, the cell gets values from its neighbors (all 1's), and the // resulting tv is based on Local-Transition. // Since in the 1st round, the event didn't cause state change, the flag in A is NOT set // to TRUE, the cell's value will be changed to 0 in the 2nd round!!! // This is NOT what we want! We need to set the flag in A to TRUE event when the external // event does not trigger a state change in the cell! // The following else clause will set the flag in A to TRUE (but do NOT change the value in A) // if the tv is derived from an event. else { // N = A, i.e. No state change //This is in the document! [No State Change] if ( isInputPort(pvCursor->first) ) { // set the flag in A to TRUE // In this case, external event's value is the same as the current cell's value // No value change! And we will NOT allow any potential urther changes derived // from neighbor's values in the later rounds of message-passing // Since N = A, setting the value of A to N means "do not change the value of A"! actualValue ( output_portname, pvCursor->second, true ); } } //end [state change] } //end AF == FALSE else { //Mov. 29, 2005 // If the flag in A is TRUE, i.e. the value of the cell has been changed //(or is the same as the external event) according to the external event, //do NOTHING! } //end [AF] //Adjust Quantum Value =============================================================================== //If using DynamicQuantum, calculate the new Quantum value. if ( UseDynQuantum().Active() ) { if ( valueWithQuantum(pvCursor->second,QuantumValue()) == valueWithQuantum(actualValue(output_portname), QuantumValue())) { //Jacky: quantized N = quantized A if ( UseDynQuantum().Strat() ) QuantumValue ( QuantumValue() * (1-UseDynQuantum().Ratio())); else QuantumValue ( QuantumValue() * (1+UseDynQuantum().Ratio())); } else { if ( !UseDynQuantum().Strat() ) QuantumValue ( QuantumValue() * (1-UseDynQuantum().Ratio())); else QuantumValue ( QuantumValue() * (1+UseDynQuantum().Ratio())); } //cout << " q act = " << QuantumValue().value() << endl; } //end using-quantum } // end for each N return *this ; } /******************************************************************* * Method: outputFunction ********************************************************************/ Model &InertialDelayCell::outputFunction( const CollectMessage &msg ) { #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "\t-------->IDCell::outputFunction() called" << endl << flush; jacky_os << "\t\t --- Current ActualValues @ (" << msg.time().asString() << ") = " << flush; printValues(actualMap(), jacky_os); jacky_os << endl << "\t\t --- RA for RT (" << getRecordTime().asString() << ") = " << flush; printValues(recordActualVal(), jacky_os); jacky_os << endl << "\t\t --- RS for RT (" << getRecordTime().asString() << ") = " << flush; if(getRecordState() == AtomicState::active){ jacky_os << "active" << endl << flush; } else { jacky_os << "passive" << endl << flush; } #endif PortList::iterator cursor; for (cursor = outNCPortList().begin(); cursor != outNCPortList().end(); cursor++) { string out_port(cursor->second->name()); #ifdef JACKY_DEBUG jacky_os << "\t\t => send output <" << msg.time().asString() << " / " << outputPort(out_port).name() << " = " << actualValue(out_port).value() << ">" << endl << flush; #endif //end JACKY_DEBUG sendOutput( msg.time(), outputPort(out_port), actualValue(out_port).value() ); } return *this; } /******************************************************************* * Method: internalFunction ********************************************************************/ Model &InertialDelayCell::internalFunction( const InternalMessage &msg ) { passivate(); #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "\t-------->IDCell::internalFunction() called, Passivate()! nextChange = " << nextChange().asString() << endl << endl << flush; #endif return *this; } #if defined(JACKY_DEBUG) || defined (JACKY_WRITER) //====================================== /******************************************************************* * Method: printValues *Description: function for printing the content of A & RA ********************************************************************/ void InertialDelayCell::printValues(const IDCellState::StateValues &toPrint , ostream &out) const{ IDCellState::StateValues::const_iterator it; for(it = toPrint.begin(); it != toPrint.end(); it++){ out << "< " << it->first //portName << " = " << (it->second).first.value() //portValue << " / flag = " << flush; if( (it->second).second == true){ //event flag out << "TRUE > " << flush; } else { out << "FALSE > " << flush; } } } #endif //end JACKY_DEBUG =================================================================== /******************************************************************* * Method: resetValueFlags *Description: reset all flags accociated with values of the given MAP (A/F/RA) to FALSE ********************************************************************/ void InertialDelayCell::resetValueFlags( IDCellState::StateValues &values ){ IDCellState::StateValues::iterator it; for(it = values.begin(); it != values.end(); it++){ (it->second).second = false; } }