Example #1
0
void SimulationRun(string RunParameterNames[])
{
	ifstream TraceFile;
	bool RunValid=true;
	if(PrimaryProtocol==NULL)
	{
		cerr<<"RUN ERROR: No protocol specified!"<<endl;
		RunValid=false;
	}
	if(TraceFileName=="")
	{
		cerr<<"RUN ERROR: No trace file specified!"<<endl;
		RunValid=false;
	}
	if(RunValid)
	{
		TraceFile.open(TraceFileName.c_str());
		if(!TraceFile.is_open())
		{
			cerr<<"RUN ERROR: Cannot open trace file!"<<endl;
			RunValid=false;
		}
		else if(TraceFile.bad()||TraceFile.fail())
		{
			cerr<<"RUN ERROR: Stream was corrupted!"<<endl;
			RunValid=false;
		}
	}
	if(!RunValid){return;}//Immediately break and cancel the run if there are execution errors.
	ResetGlobalVariables();
	int VehicleNum,BeginTime,EndTime;
	float x,y;
	int NextSimulationTime;
	int VehicleNumMask=1;//The modulo of the vehicle num and this value determines whether a vehicle is omitted to get a different set of vehicles in the simulation.
	int VehicleNumMaskOffset=0;
	bool MaskExists=CheckRunVariableExists("VehicleNumMask");
	bool OffsetExists=CheckRunVariableExists("VehicleNumMaskOffset");
	if(MaskExists!=OffsetExists){cerr<<"ERROR: Must specify both VehicleNumMask and VehicleNumMaskOffset for this input to be effective!"<<endl;}
	else if(MaskExists)
	{
		VehicleNumMask=GetRunVariableInteger("VehicleNumMask");
		VehicleNumMaskOffset=GetRunVariableInteger("VehicleNumMaskOffset");
	}
	while (TraceFile >> NextSimulationTime >> VehicleNum >> x >> y >> BeginTime >> EndTime)// loop through all input
	{
		TimeMax=max(NextSimulationTime+1,TimeMax);
		if((--VehicleNum)%VehicleNumMask==VehicleNumMaskOffset)
		{
			VehicleNum/=VehicleNumMask;
			VehicleMax=max(VehicleNum+1,VehicleMax);
			for(int i=Vehicles.Count();i<VehicleMax;i++){Vehicles.PushObj(new Vehicle("OBU#"+to_string((long long int)i)));}
			Vehicle* CurrentVehicle=Vehicles[VehicleNum];
			if(CurrentVehicle->v_begin_t==-1)
			{
				CurrentVehicle->v_begin_t=BeginTime;
				CurrentVehicle->v_begin_x=x;
				CurrentVehicle->v_begin_x=y;
				CurrentVehicle->v_end_t=EndTime;
			}
		}
	}
	OutputVariables.Set("VehicleMax",to_string((long long int)VehicleMax));
	OutputVariables.Set("TimeMax",to_string((long long int)TimeMax));
	OutputVariables.Set("TraceFile",TraceFileName);
	OutputVariables.Set("ProtocolName",ProtocolName);
	
	TraceFile.clear();
	TraceFile.seekg(0, TraceFile.beg);  // reposition to beginning of input file
	if(TraceFile.bad()||TraceFile.fail())
	{
		cerr<<"RUN ERROR: Could not reset stream!"<<endl;
		RunValid=false;
	}
	
	int PeakAnonymitySetSize=0;//Used to calculate one of our metrics later.
	float PeakAnonymityDistance=0;
	if(CheckRunVariableExists("GlobalMessageLimit")){NetworkObject::GlobalMessageLimit=GetRunVariableInteger("GlobalMessageLimit");}
	SetGlobalVehicleMaxMessagePerTick(CheckRunVariableExists("VehicleMessageLimit")?GetRunVariableInteger("VehicleMessageLimit"):0);
	time_t SimulationBeginTime=time(NULL);
	RunValid=RunValid&&PrimaryProtocol->SimulationBegin();
	bool TraceFileEOF=false;
	while(!TraceFileEOF)
	{
		TraceFile>>NextSimulationTime>>VehicleNum>>x>>y>>BeginTime>>EndTime;
		TraceFileEOF=TraceFile.eof();
		if(!TraceFileEOF&&(TraceFile.bad()||TraceFile.fail()))
		{
			cerr<<"RUN ERROR: Stream became corrupted during simulation!"<<endl;
			RunValid=false;
			break;
		}
		if(SimulationTime==-1){SimulationTime=NextSimulationTime;}//This prevents a logic error that causes a simulation tick before the first batch of tracefile data has been processed.
		if(TraceFileEOF||SimulationTime!=NextSimulationTime)
		{
			RunValid=RunValid&&PrimaryProtocol->SimulationTick();
			if(!RunValid){break;}//This short-circuits the execution if a critical error as occurred.
			//This loop adds to the average counters in each vehicle.
			//Average counters are processed after the simulation to get various anonymity statistics.
			//As such, these values are not menaingful until they have been finalized later.
			for(int i=0;i<VehicleMax;i++)
			{
				Vehicle* CurrentVehicle=Vehicles[i];
				if(!CurrentVehicle->CurrentlyWithinSimulation()){continue;}
				if(CurrentVehicle->AssignedSet!=NULL)
				{
					AnonymitySet* CurrentSet=CurrentVehicle->AssignedSet;
					int SetSize=CurrentSet->Count();
					CurrentVehicle->AverageAnonymitySetSizeCounter+=SetSize;
					PeakAnonymitySetSize=max(PeakAnonymitySetSize,SetSize);
					ArrayList<Vehicle*>* VehiclesInSet=&(CurrentSet->AnonymousVehicles);
					float SetDistance=0.0;
					for(int io=0;io<VehiclesInSet->Count();io++)
					{
						Vehicle* OtherVehicle=(*VehiclesInSet)[io];
						if(CurrentVehicle==OtherVehicle){continue;}
						float XDist=CurrentVehicle->x-OtherVehicle->x;
						float YDist=CurrentVehicle->y-OtherVehicle->y;
						float Dist=sqrt(XDist*XDist+YDist*YDist);
						SetDistance+=Dist;
						PeakAnonymityDistance=max(PeakAnonymityDistance,Dist);
					}
					CurrentVehicle->AverageAnonymityDistanceCounter+=SetDistance/SetSize;
				}
				else{CurrentVehicle->AverageAnonymitySetSizeCounter++;}
			}
			for(int i=0;i<VehicleMax;i++)
			{
				Vehicle* CurrentVehicle=Vehicles[i];
				if(SimulationTime==CurrentVehicle->v_end_t)
				{
					CurrentVehicle->v_end_x=CurrentVehicle->x;
					CurrentVehicle->v_end_y=CurrentVehicle->y;
					CurrentVehicle->v_terminated=SimulationTime;
					//We set ending data AFTER the protocol text so the set isn't prematurely decremented.
					if(CurrentVehicle->AssignedSet!=NULL){CurrentVehicle->AssignedSet->RemoveVehicle(CurrentVehicle);}
				}
			}
			if(TraceFileEOF){break;}
			SimulationTime=NextSimulationTime;
		}
		if((--VehicleNum)%VehicleNumMask==VehicleNumMaskOffset)
		{
			VehicleNum=VehicleNum/VehicleNumMask;
			Vehicle* CurrentVehicle=Vehicles[VehicleNum];//We decrement VehicleNum because trace files base their lists with 1 as the first index.
			CurrentVehicle->x=x;
			CurrentVehicle->y=y;
		}
	}
	if(RunValid)
	{
		PrimaryProtocol->SimulationEnd();
		time_t SimulationRunTime=time(NULL)-SimulationBeginTime;
		OutputVariables.Set("RunTime",to_string(((long double)SimulationRunTime)/60.0));
		
		//This loop adds inputs as outputs, so the resulting printed line can also reference parameters used in the run.
		for(int i=0;i<RunVariables.Count();i++){OutputVariables.Set(RunVariables.GetKey(i),RunVariables.Get(i));}
		
		//This loop calculates various averages.
		int AnonymousVehicleCount=0;
		int AverageAnonymitySamples=0;
		float AverageAnonymitySetSize=0.0;
		float AverageAnonymityDistance=0.0;
		float AverageAnonymityTime=0.0;
		float PeakAnonymityTime=0.0;
		for(int i=0;i<Vehicles.Count();i++)
		{
			Vehicle* CurrentVehicle=Vehicles[i];
			if(CurrentVehicle->v_terminated==-1)
			{
				cerr<<"TERMINATE ERROR: Vehicle#"<<i<<" was supposed to terminate at "<<CurrentVehicle->v_end_t<<"/"<<SimulationTime<<endl;
				CurrentVehicle->v_terminated=CurrentVehicle->v_end_t;
			}
			AverageAnonymitySamples+=(CurrentVehicle->v_terminated-CurrentVehicle->v_begin_t)+1;
			AverageAnonymitySetSize+=CurrentVehicle->AverageAnonymitySetSizeCounter;
			AverageAnonymityDistance+=CurrentVehicle->AverageAnonymityDistanceCounter;
			if(CurrentVehicle->v_k_assign_t!=-1)
			{
				AnonymousVehicleCount++;
				float AnonTime=CurrentVehicle->v_terminated-CurrentVehicle->v_k_silent_t;
				AverageAnonymityTime+=AnonTime;
				PeakAnonymityTime=max(PeakAnonymityTime,AnonTime);
			}
		}
		if(AnonymousVehicleCount>0){AverageAnonymityTime/=AnonymousVehicleCount;}
		if(AverageAnonymitySamples==0)
		{
			AverageAnonymitySetSize=0.0f;
			AverageAnonymityDistance=0.0f;
		}
		else
		{
			AverageAnonymitySetSize/=AverageAnonymitySamples;
			AverageAnonymityDistance/=AverageAnonymitySamples;
		}
		OutputVariables.Set("AverageAnonymitySetSize",to_string((long double)AverageAnonymitySetSize));
		OutputVariables.Set("PeakAnonymitySetSize",to_string((long long int)PeakAnonymitySetSize));
		OutputVariables.Set("AverageAnonymityDistance",to_string((long double)AverageAnonymityDistance));
		OutputVariables.Set("PeakAnonymityDistance",to_string((long double)PeakAnonymityDistance));
		OutputVariables.Set("AverageAnonymityTime",to_string((long double)AverageAnonymityTime));
		OutputVariables.Set("PeakAnonymityTime",to_string((long double)PeakAnonymityTime));
		OutputVariables.Set("AnonymousVehicleCount",to_string((long long int)AnonymousVehicleCount));
		OutputVariables.Set("TotalAnonymitySets",to_string((long long int)AnonymitySets.Count()));
		
		//This loop calculates the most congested networked unit.
		int CongestionCount=0;
		NetworkObject* CongestedUnit=NULL;
		for(int i=0;i<NetworkObjects.Count();i++)
		{
			NetworkObject* CurrentCounter=NetworkObjects[i];
			int MaxPackets=CurrentCounter->NetworkMessages.GetMostPacketsTransmitted();
			if(MaxPackets>CongestionCount)
			{
				CongestedUnit=CurrentCounter;
				CongestionCount=MaxPackets;
			}
		}
		if(CongestedUnit==NULL){OutputVariables.Set("PeakTrafficUnit","None");}
		else{OutputVariables.Set("PeakTrafficUnit",CongestedUnit->Title);}
		OutputVariables.Set("PeakTrafficAmount",to_string((long long int)CongestionCount));
		
		//This loop adds the traffic counters to the list of OutputVariables.
		for(int i=0;i<=TOTAL_TRAFFIC_TYPES;i++){OutputVariables.Set(string("Packet Count: ")+GetEnumName((TrafficType)i),to_string((long long int)GlobalTraffic[i]));}
		OutputVariables.Set(string("Packet Count: Overhead"),to_string((long long int)GlobalTraffic.Overhead()));
		OutputVariables.Set(string("Packet Count: Overhead Ratio"),to_string((long double)GlobalTraffic.OverheadRatio()));
		OutputVariables.Set(string("Packet Count: Successful"),to_string((long long int)GlobalTraffic.TotalTransmitted()));
		OutputVariables.Set(string("Packet Count: Lost"),to_string((long long int)GlobalTraffic.TotalLost()));
		OutputVariables.Set(string("PacketLoss"),to_string((long double)GlobalTraffic.PacketLoss()));
		OutputVariables.Set(string("Throughput"),to_string((long double)GlobalTraffic.TotalTransmitted()/TimeMax));
		
		//OUTPUT
		if(LegacyOutput)
		{
			cout<<"RUN:";
			for(int i=0;i<MAX_PARAMETERS_PER_LINE&&RunParameterNames[i].length()>0;i++)
			{
				if(i>0){cout<<",";}
				cout<<RunParameterNames[i]<<"="<<setw(3)<<RunVariables.Get(RunParameterNames[i]);
			}
			cout<<": ";
			cout<<fixed<<
				"K="<<setw(5)<<setprecision(2)<<AverageAnonymitySetSize<<"("<<AnonymitySets.Count()<<"), "<<
				"D="<<setw(6)<<setprecision(2)<<AverageAnonymityDistance<<", "<<
				"T="<<setw(5)<<setprecision(2)<<AverageAnonymityTime<<", "<<
				"Anonymous="<<setw(4)<<AnonymousVehicleCount<<"/"<<setw(4)<<VehicleMax;
			for(int i=0;i<=TOTAL_TRAFFIC_TYPES;i++){cout<<", "<<GetEnumName((TrafficType)i)<<":"<<GlobalTraffic[i];}
			if(CongestedUnit!=NULL){cout<<", Congested: "<<CongestedUnit->Title<<"("<<CongestionCount<<")";}
			cout<<endl;
		}
		else if(VerboseOutput)
		{
			for(int i=0;i<OutputVariables.Count();i++)
			{
				if(i!=0){cout<<", ";}
				cout<<OutputVariables.GetKey(i)<<"="<<OutputVariables.Get(i);
			}
			cout<<endl;
		}
		else
		{
			//TODO: Get the output to interpret different variable types.
			int FormatNeedle=0;//This advances through the format string as we process each section.
			while(FormatNeedle<OutputFormat->size())
			{
				//These first few lines find the next special character, or the end of the string, and OutputVariables any part of the string which was passed over.
				size_t FoundIndex=OutputFormat->find(OUTPUT_FORMAT_DELIMITER,FormatNeedle);
				if(FoundIndex==string::npos){FoundIndex=OutputFormat->size();}
				cout<<OutputFormat->substr(FormatNeedle,FoundIndex-FormatNeedle);
				FormatNeedle=FoundIndex+1;
				//If the end of the string was not reached, we then try to parse the next block of characters, which are special notation.
				if(FoundIndex<OutputFormat->size())
				{
					FoundIndex=OutputFormat->find(OUTPUT_FORMAT_DELIMITER,FormatNeedle);
					if(FoundIndex==string::npos)
					{
						cerr<<"ERROR: Misformatted Output String: No Closing '"<<OUTPUT_FORMAT_DELIMITER<<"'!"<<endl;
						break;
					}
					string FormatSpecifierArguments("s");
					size_t FoundSubIndex=OutputFormat->find(OUTPUT_FORMAT_SUB_DELIMITER,FormatNeedle);
					if(FoundSubIndex!=string::npos)
					{
						FormatSpecifierArguments=OutputFormat->substr(FormatNeedle,FoundSubIndex-FormatNeedle);
						FormatNeedle=FoundSubIndex+1;
					}
					string OutputValue("Unspecified");
					string VariableName=OutputFormat->substr(FormatNeedle,FoundIndex-FormatNeedle);
					if(OutputVariables.HasKey(VariableName)){OutputValue=OutputVariables.Get(VariableName);}
					string FormatSpecifier("%");
					FormatSpecifier=FormatSpecifier+FormatSpecifierArguments;
					char VariableTypeSpecifier=FormatSpecifier.at(FormatSpecifier.size()-1);
					switch(VariableTypeSpecifier)
					{
					case 'd': case 'i': case 'u':
						printf(FormatSpecifier.c_str(),atoi(OutputValue.c_str()));
						break;
					case 'f': case 'F':
						printf(FormatSpecifier.c_str(),atof(OutputValue.c_str()));
						break;
					default:
						printf(FormatSpecifier.c_str(),OutputValue.c_str());
						break;
					}
					FormatNeedle=FoundIndex+1;
				}
			}
			cout<<endl<<flush;//We have to use this operator to push a newline to cout, or the Cloud9 interface will cache it in a strange way.
		}
	}
	//CLEANUP
	fflush(NULL);
	TraceFile.close();
	while(AnonymitySets.Count()>0){delete AnonymitySets.PopObj();}
	while(Vehicles.Count()>0){delete Vehicles.PopObj();}
}