#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; futureValue = thisState.futureValue; recordActual = thisState.recordActual; recordTime = thisState.recordTime; recordState = thisState.recordState; vars_round0 = thisState.vars_round0; //copy the saved values of state variables at the beginning of Round 0 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) ); //Jacky: set A, flag = FALSE futureValue( out_port, value(in_port) ); //Jacky: set F, flag = FALSE //Jacky: get a copy of the current actual value, flag = FALSE setRecordActual( out_port, value(in_port) ); } holdIn( AtomicState::active, VTime::Zero); //Jacky: initialize the recordTime to 0 setRecordTime( VTime::Zero ); //Jacky: initialize the recordState to passive setRecordState( AtomicState::passive ); //save the StateVars (variables) in AtomicCellState to the StateVars (vars_round0) in TDCellState recordStateVariables() = cellStateVariables(); return *this; } /******************************************************************* * Method: externalFunction ********************************************************************/ Model &InertialDelayCell::externalFunction( const MessageBag &msgs ) { //flag to record a time change //bool timeChanged = false; //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 //1> update the RT setRecordTime( msgs.time() ); //2> update the RS for this new time setRecordState( state() ); //3> reset the flags in ActualValue to false resetValueFlags( actualMap() ); //Nov. 29, 2005 //4> update RA = A for this new time recordActualVal() = actualMap(); //save the state variables in the RV recordStateVariables() = cellStateVariables(); } //end if time change else { //No time change happens, so these are the following rounds! } //This function must be called before processing any messages! //It is this function who will set the neighborhood value correctly localTransitionConfluent( msgs ); //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() ); //Before we evaluate the transition functions, reset the state variables using the recorded one cellStateVariables() = recordStateVariables(); list tv; //////////////////////////////////////////////////////////////////////// //Right now, for this implementation, give priority to portInTransitions 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; } list::iterator pvCursor; for (pvCursor = tv.begin(); pvCursor != tv.end(); pvCursor++) { //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(calculateOutPort(pvCursor->first)) == false ){ if( ( UseQuantum().Active() || UseDynQuantum().Active() ) && ( valueWithQuantum(pvCursor->second, QuantumValue()) != valueWithQuantum(actualValue(calculateOutPort(pvCursor->first)), QuantumValue()) ) || ( !UseQuantum().Active() && (actualValue(calculateOutPort(pvCursor->first)) != pvCursor->second ) //Jacky: N != A ) ) { if( isInputPort(pvCursor->first) ){ //the value is from input port from the environment //1> Jacky: set A = N with flag = true actualValue ( calculateOutPort(pvCursor->first), pvCursor->second, true ); } else { //1> Jacky: set A = N with flag = false actualValue ( calculateOutPort(pvCursor->first), pvCursor->second ); } //end update [ActualValue] //2> Jacky: state change if( state() == AtomicState::passive ) { //a> Jacky: passive to active holdIn( AtomicState::active, delay ) ; } else { //Jacky: state() == AtomicState::active if( getRecordActual(calculateOutPort(pvCursor->first)) != pvCursor->second ) { // N != RA [==== CHANGE FURTHER ====] //b> Jacky: active & preemption // the coupled sets sigma to the reminder time until //the next internal transition if( nextChange() > VTime::Zero && futureValue(calculateOutPort(pvCursor->first)) != pvCursor->second) { //Jacky: here is the preemption!!! //Jacky: if we need to change state later && the current future //value is different from the new value (it is also the current //actual value), then schedule the state change holdIn( AtomicState::active, delay ) ; } //end preemption }//end change / change further else { // N == RA [==== CHANGE BACK ====] //c> Jacky: active & changed back if (getRecordState() == AtomicState::passive) { //originally passive at RT //change back to passive passivate(); } //end change back to passive } //end change back } //end state() == AtomicState::active //3> Jacky: set F = N futureValue( calculateOutPort(pvCursor->first), pvCursor->second); } //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 { // No state change, N = A 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 ( calculateOutPort(pvCursor->first), pvCursor->second, true ); } } } //end "result-NOT-derived-from-external-events" actualValueFlag on port is 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! } //If using DynamicQuantum, calculate the new Quantum value. if ( UseDynQuantum().Active() ) { if ( valueWithQuantum(pvCursor->second,QuantumValue()) == valueWithQuantum(actualValue(calculateOutPort(pvCursor->first)), QuantumValue())) { //Jacky: quantized new value = quantized actual value if ( UseDynQuantum().Strat() ) QuantumValue ( QuantumValue() * (1-UseDynQuantum().Ratio())); else QuantumValue ( QuantumValue() * (1+UseDynQuantum().Ratio())); } //GW // Esta es una nueva modificacion: si son distintos, lo reduzco. else { if ( !UseDynQuantum().Strat() ) QuantumValue ( QuantumValue() * (1-UseDynQuantum().Ratio())); else QuantumValue ( QuantumValue() * (1+UseDynQuantum().Ratio())); } } //end using-quantum } // for return *this ; } /******************************************************************* * Method: outputFunction ********************************************************************/ Model &InertialDelayCell::outputFunction( const CollectMessage &msg ) { PortList::iterator cursor; for (cursor = outNCPortList().begin(); cursor != outNCPortList().end(); cursor++) { string out_port(cursor->second->name()); sendOutput( msg.time(), outputPort(out_port), actualValue(out_port).value() ); } return *this; } /******************************************************************* * Method: internalFunction ********************************************************************/ Model &InertialDelayCell::internalFunction( const InternalMessage &msg ){ passivate(); return *this; } /******************************************************************* * 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; } }