int main() { //double simTime = 1e6; double simTime = 30; // Run time set to 30 years // let the system run for a max length of time int simNum = 30; // number of runs //Edited by Kiat Boon on 5/3/2016 to simulate M/M/1 queue unsigned int N = 1; // number of servers char outputFileName[] = "N100gamma1LogNormal2.txt"; // double mu = 1.0; int I=1, J=1, K=1; RngBase *arr[1], *ser[1], *abd[1]; //for deciding to go urgent queue or non-urgent queue RngBase *decide[1]; double decideValue; int countUrgent, countNonUrgent; int totalArr = 0; int totalAbd = 0; int totalRej = 0; int totalSer = 0; int totalUrgSer = 0; int totalNonUrgSer = 0; int totalUrgQueue = 0; //amount of patients still in urgent queue at end of run int totalNonUrgQueue = 0; //amount of patients still in non urgent queue at end of run int totalInServer = 0; //amount of patients still in server at end of run double privHospCost = 49891.82; //cost of surgery in private hospital: source from health-tourism.com, raffles hosp is 36700 USD double pubHospCost = 4978.85; //cost of surgery in public hospital = (4729*272+5760*87)/(272+87) //****Note: All subsidies are assumed 10% co-insurance, so govt pays 90%****// double waitingCostInNonUrgQueue = .9*200*12; //cost of waiting in non-urgent queue per yr //MediShield organ transplant for immunosuppressant subsidy is $200/mth double waitingCostInUrgQueue = .9*700*365; //inpatient: 700/day double averageNonUrgSubsidy = .9*(650.0+1*1200+5.4*700); //estimated average cost of subsidy per patient served from mediShield double averageUrgSubsidy = .9*(1550.0+2*1200+7.2*700); //Non-urg: 25th percentile of range, 200 to 2000 //Urg: 75th percentile of range, 200 to 2000 //Assume 10% of the time post-op in ICU //For overflow policy //double arrRate = 269.28; //int queueLength = 66; //queue length to be set for overflow policy //double incentiveProportion = 0; //percentage of incentive to be given to reduce arr rate //For incentive policy int queueLength = INT_MAX; double incentiveProportion = 0.22; double arrRate = 269.28*(1-seekPrivProportion(incentiveProportion)); //no need to remove this section for overflow policy double incentive = (privHospCost-pubHospCost)*incentiveProportion; //incentive to be given to each patient seeking private hospital double totalIncentive = (269.28 - arrRate)*incentive*simTime; //expected total amount of incentive given to reduce queue length double serRate = 272; double lifeTime = 0.288; //mean of 180.76 weeks //double lifeTime = 12; //double lifeTime = 1e8; double nonUrgentProportion = 0.231; //proportion of patients in non-urgent queue: 1920/8325, table 1, sobolev double upgradeProportion = 0.513; //proportion of patients to be upgraded vector<double> cs2(2); arr[0] = new ExpGen(arrRate); //arr[0] = new DetGen(0.1); double ca2 = 1; /*NOTE: By default, ser[0] is exponential, but if ser[0] is not exponential, please change the service time generator in MS_Queue_Abd init()*/ ser[0] = new ExpGen(serRate); //ser[0] = new DetGen(0.1); cs2[0] = 2.0; // ser[0] = new ErlangGen(2*mu, 2); // cs2[0] = 0.5; // ser[1] = new DetGen(1.0); // cs2[1] = 0.0; //ser[1] = new ErlangGen(2*mu, 2); //cs2[1] = 0.5; //ser[2] = new ExpGen(mu); //cs2[2] = 1; //ser[3] = new HyperExp2Gen(1/0.169, 1/2.20327, .5915); //cs2[3] = 3.0; //ser[4] = new LogNormalGen(1/mu, 3); //cs2[4] = 3.0; abd[0] = new ExpGen(lifeTime); //abd[0] = new DetGen(1e8); //so that patients will not abandon queue // abd[0] = new ErlangGen(3*alpha,3); // abd[0] = new HyperExp2Gen(1.0, 200.0, 0.9); //abd[0] = new HyperExp2Gen(0.2, 6.0, 0.9); // abd[0] = new HyperExp2Gen(1, 1/3.0, .5); // abd[0] = new HyperExp2Gen(alpha*0.3, 79*alpha/30, 0.7); // abd[1] = new ExpGen(2.0/3); // abd[0] = new UniformGen(0, 10); // abd[1] = new ExpGen(.25); decide[0] = new UniformGen(0,1); int sysSize; double depWaitTime; double depSoujournTime; int startTime = time(NULL); srand (time(NULL)); //i is for arr, j is for ser, k is for abd for(int k=0;k<K;k++){ for(int j=0;j<J;j++){ for(int i=0;i<I;i++){ /* ------ Start Simulation ----- */ SampleStat bSize, bSizeL, sSize; bSize.reset(); bSizeL.reset(); sSize.reset(); SampleStat bSizeU, bSizeLU; bSizeU.reset(); bSizeLU.reset(); SampleStat bTime, bTimeU; bTime.reset(); bTimeU.reset(); SampleStat bTimeSouj, bTimeSoujU; bTimeSouj.reset(); bTimeSoujU.reset(); SampleStat probAbd; probAbd.reset(); Counter bSizeOne, sSizeOne; Counter bSizeOneL; Counter bSizeOneU; Counter bSizeOneLU; Counter bSizeSquareOne; Counter bSizeSquareOneU; Counter bTimeOne; Counter bTimeOneU; Counter bTimeOneSouj; Counter bTimeOneSoujU; Counter bTimeSquareOne; Counter bTimeSquareOneU; Counter probAbdOne; double totalNonUrgWaitingTime = 0.0; //calculates total time of customers spent waiting in non-urgent queue double totalUrgWaitingTime = 0.0; //calculates total time of customers spent waiting in urgent queue int id; //running simulation for 30 times for(int run=0; run<simNum; run++) { id = 1; //number of servers = N MS_Queue_Abd q(N); q.initSystemClock(); q.init(upgradeProportion,queueLength, serRate); Event event; bSizeOne.reset(); bSizeOneL.reset(); bSizeOneU.reset(); bSizeOneLU.reset(); sSizeOne.reset(); bSizeSquareOne.reset(); bSizeSquareOneU.reset(); bTimeOne.reset(); bTimeOneSouj.reset(); bTimeOneU.reset(); bTimeOneSoujU.reset(); bTimeSquareOne.reset(); bTimeSquareOneU.reset(); probAbdOne.reset(); countUrgent=0; countNonUrgent=0; cout<<"Run number: "<<run+1<<endl; q.setRunNumber(run+1); //each run: run for simTime units //run+1 required since getClock will not reset to 0, so have to increase length of new run while(q.getClock()<simTime) { //find next event happening along with its maturity time event=q.nextEvent(); //get nonUrgentQueue size - regBufAdj plus server size sysSize = q.getSize(); //increases bSizeOne by nonUrgentQueue size*tm of event //meant for taking the average of the nonUrgentQueueSize later bSizeOne.update(q.getnonUrgentQueueSize(), event.tm); bSizeSquareOne.update(q.getnonUrgentQueueSize()*q.getnonUrgentQueueSize(), event.tm); //increases bSizeOne by nonUrgentQueue size*tm of event //meant for taking the average of the nonUrgentQueueSize later bSizeOneU.update(q.getUrgentQueueSize(), event.tm); bSizeSquareOneU.update(q.getUrgentQueueSize()*q.getUrgentQueueSize(), event.tm); //increases sSizeOne by server size*tm of event //meant for taking the average of the serverSize later sSizeOne.update(q.getServerSize(), event.tm); //new //don't need to include event.tm since alr included earlier bSizeOneL.update(q.getNumOfNonUrgentInServer(), event.tm); bSizeOneLU.update(q.getNumOfUrgentInServer(), event.tm); //amends server and queue based on event(arrival/depart/renege) //for arrival, customer will join server, or join queue along with regList //for departure, customer leaves server, and customer in queue joins server //for reneging, customer leaves regList, while modifying regBufAdj to account for customer left q.actOn(event); //checks if nonUrgentQueue size is correct, particularly regBufAdj q.checkStatus(); if(event.tp==arrival) { decideValue = decide[0]->genNext(); if (decideValue > nonUrgentProportion) { q.schNextArr(arr[i]->genNext(),ser[j]->genNext(), abd[k]->genNext(), run+1, urgent, id); countUrgent++; id++; } else { q.schNextArr(arr[i]->genNext(),ser[j]->genNext(), abd[k]->genNext(), run+1, nonUrgent, id); countNonUrgent++; id++; } } else if(event.tp==departure) { //get customer's waiting time in queue before entering server depWaitTime = q.getDepWaitTime(); depSoujournTime = q.getDepRespTime(); //soujourn time if (q.getDepStatus() == nonUrgent) { bTimeOne.update(depWaitTime); bTimeSquareOne.update(depWaitTime*depWaitTime); bTimeOneSouj.update(depSoujournTime); if (q.getDepAbandoned() == false) { totalNonUrgWaitingTime += q.getDepWaitTime(); } else { totalNonUrgWaitingTime += q.getDepRegTime(); } } else if (q.getDepStatus() == urgent) { bTimeOneU.update(depWaitTime); bTimeSquareOneU.update(depWaitTime*depWaitTime); bTimeOneSoujU.update(depSoujournTime); totalUrgWaitingTime += q.getDepWaitTime(); } // if(!q.getDepReneged()) // probAbdOne.update(0); } else { //probAbdOne.update(1); // bTimeOne.update(q.getRegWaitTime()); /// Use this line when computing the nonUrgentQueue time } } totalNonUrgWaitingTime += q.getStillInNonUrgQueueWaitTime(); totalUrgWaitingTime += q.getStillInUrgQueueWaitTime(); // q.printIds(); int serverSize = q.checkServerSizeAndRemove(); // cout<<"Number arrived: "<<q.getNumArrived()<<endl; // cout<<"Number abandoned: "<<q.getNumAbandoned()<<endl; // cout<<"Number served: "<<q.getNumServed()<<endl; // cout<<"Number rejected: "<<q.getNumRejected()<<endl; // cout<<"Number currently in server: "<<serverSize<<endl; // cout<<"Number in urg queue: "<<q.getUrgentQueueSize()<<endl; // cout<<"Number in non-urg queue: "<<q.getnonUrgentQueueSize()<<endl; cout<<"Unaccounted str: "<<q.getNumArrived()-q.getNumAbandoned()-q.getNumServed()-serverSize-q.getUrgentQueueSize()-q.getnonUrgentQueueSize()<<endl; probAbdOne.update2(q.getNumAbandoned(),q.getNumArrived()+q.getNumRejected()); totalArr += q.getNumArrived(); totalAbd += q.getNumAbandoned(); totalRej += q.getNumRejected(); totalSer += q.getNumServed(); totalUrgSer += q.getUrgServed(); totalNonUrgSer += q.getNonUrgServed(); totalUrgQueue += q.getUrgentQueueSize(); totalNonUrgQueue += q.getnonUrgentQueueSize(); totalInServer += serverSize; q.initNumArrived(); q.initNumAbandoned(); q.initNumRejected(); q.initNumServed(); q.initUrgServed(); q.initNonUrgServed(); //end of single run here// // cout<<"No. of urgent: "<<countUrgent<<endl; // cout<<"No. of non-urgent: "<<countNonUrgent<<endl; cout<<run+1<<" out of "<<simNum<<" runs done ..."<<endl; cout<<"Clock: "<<q.getClock()<<endl; //for subsequent runs beyond the first, the following is done if(run+1){ bSize.update(bSizeOne.average()); bSizeU.update(bSizeOneU.average());//new sSize.update(sSizeOne.average()); bTime.update(bTimeOne.average()); bTimeU.update(bTimeOneU.average());//new bTimeSouj.update(bTimeOneSouj.average()); bTimeSoujU.update(bTimeOneSoujU.average()); bSizeL.update(bSizeOneL.average()); bSizeLU.update(bSizeOneLU.average()); probAbd.update(probAbdOne.average()); } } //additional stuff done ends here ofstream outputFile; outputFile.open (outputFileName, ios::out | ios::app); //cout.setf(ios::fixed); //cout.precision(4); cout<<"________________________________\nNumber of servers = "<<N<<", Arrival rate = "<<arrRate <<", Service rate = "<<serRate<<", Lifetime rate = "; if (lifeTime == 1e8) { cout<<"No deaths"<<". \n"<<endl; } else { cout<<lifeTime<<". \n"<<endl; } outputFile<<"\n\n\nNumber of servers = "<<N<<", Arrival rate = "<<arrRate <<", Service rate = "<<serRate<<", Lifetime rate = "; if (lifeTime == 1e8) { outputFile<<"No deaths"<<". \n"<<endl; } else { outputFile<<lifeTime<<". \n"<<endl; }; cout<<"Max queue length set to: "; if (queueLength==INT_MAX) { cout<<"Max integer value"<<endl; } else { cout<<queueLength<<endl; } outputFile<<"Max queue length set to: "; if (queueLength==INT_MAX) { outputFile<<"Max integer value"<<endl; } else { outputFile<<queueLength<<endl; } //Percentage of difference between private hospital and public hospital bill cout<<"Percentage incentive given to patients to seek private treatment: "<<incentiveProportion*100<<"%"<<endl; outputFile<<"Percentage incentive given to patients to seek private treatment: "<<incentiveProportion*100<<"%"<<endl; cout<<"Arrival time is "<<arr[i]->getName() <<"; Service time is "<<ser[j]->getName() <<"; Patient time is "<<abd[k]->getName()<<"\n"<<endl; outputFile<<"Arrival time is "<<arr[i]->getName() <<"; Service time is "<<ser[j]->getName() <<"; Patient time is "<<abd[k]->getName()<<"\n"<<endl; cout<<"Proportion of non-urgent patients: "<<nonUrgentProportion*100<<"%"<<endl; cout<<"Probability of upgrading upon expiration of lifetime: "<<upgradeProportion*100<<"%"<<endl; cout<<endl; outputFile<<"Proportion of non-urgent patients: "<<nonUrgentProportion*100<<"%"<<endl; outputFile<<"Probability of upgrading upon expiration of lifetime: "<<upgradeProportion*100<<"%"<<endl; outputFile<<endl; cout<<"Estimated waiting cost of patient in non-urgent queue per year = $"<<waitingCostInNonUrgQueue<<endl; cout<<"Estimated waiting cost of patient in urgent queue per year = $"<<waitingCostInUrgQueue<<endl; cout<<"Estimated subsidies per non-urgent patient served = $"<<averageNonUrgSubsidy<<endl; cout<<"Estimated subsidies per urgent patient served = $"<<averageUrgSubsidy<<endl; cout<<endl; outputFile<<"Estimated waiting cost of patient in non-urgent queue per year = $"<<waitingCostInNonUrgQueue<<endl; outputFile<<"Estimated waiting cost of patient in urgent queue per year = $"<<waitingCostInUrgQueue<<endl; outputFile<<"Estimated subsidies per non-urgent patient served = $"<<averageNonUrgSubsidy<<endl; outputFile<<"Estimated subsidies per urgent patient served = $"<<averageUrgSubsidy<<endl; outputFile<<endl; double meanServed = double(totalSer)/simNum; double meanUrgServed = double(totalUrgSer)/simNum; double meanNonUrgServed = double(totalNonUrgSer)/simNum; double meanArrived = double(totalArr)/simNum; double meanAbandoned = double(totalAbd)/simNum; double meanRejected = double(totalRej)/simNum; double meanUrgQueue = double(totalUrgQueue)/simNum; double meanNonUrgQueue = double(totalNonUrgQueue)/simNum; double meanInServer = double(totalInServer)/simNum; double meanNonUrgWaiting = totalNonUrgWaitingTime/simNum; double meanUrgWaiting = totalUrgWaitingTime/simNum; cout<<"Mean number of patients entered system per run = "<<meanArrived<<endl; outputFile<<"Mean number of patients entered system per run = "<<meanArrived<<endl; cout<<"Mean pre-operative deaths per run = "<<meanAbandoned<<endl; outputFile<<"Mean pre-operative deaths per run = "<<meanAbandoned<<endl; cout<<"Mean number of patients still stuck in non-urgent queue at end of run = "<<meanNonUrgQueue<<endl; outputFile<<"Mean number of patients still stuck in non-urgent queue at end of run = "<<meanNonUrgQueue<<endl; cout<<"Mean number of patients still stuck in urgent queue at end of run = "<<meanUrgQueue<<endl; outputFile<<"Mean number of patients still stuck in urgent queue at end of run = "<<meanUrgQueue<<endl; cout<<"Mean number of patients still stuck in server at end of run = "<<meanInServer<<endl; outputFile<<"Mean number of patients still stuck in server at end of run = "<<meanInServer<<endl; cout<<"Mean number of customers served per run = "<<meanServed<<endl; cout<<endl; outputFile<<"Mean number of customers served per run = "<<meanServed<<endl; outputFile<<endl; cout<<"Mean number of urgent customers served per run = "<<meanUrgServed<<endl; cout<<"Mean number of non-urgent customers served per run = "<<meanNonUrgServed<<endl; cout<<endl; outputFile<<"Mean number of urgent customers served per run = "<<meanUrgServed<<endl; outputFile<<"Mean number of non-urgent customers served per run = "<<meanNonUrgServed<<endl; outputFile<<endl; cout<<"Estimated total cost of subsidies from urgent customers served = $"<<meanUrgServed*averageUrgSubsidy<<endl; cout<<endl; outputFile<<"Estimated total cost of subsidies from urgent customers served = $"<<meanUrgServed*averageUrgSubsidy<<endl; outputFile<<endl; cout<<"Estimated total cost of subsidies from non-urgent customers served = $"<<meanNonUrgServed*averageNonUrgSubsidy<<endl; cout<<endl; outputFile<<"Estimated total cost of subsidies from non-urgent customers served = $"<<meanNonUrgServed*averageNonUrgSubsidy<<endl; outputFile<<endl; cout<<"Mean patients rejected per run = "<<meanRejected<<endl; cout<<"Cost of each rejection = "<<privHospCost<<endl; cout<<"Total cost of rejections = "<<meanRejected*privHospCost<<endl; cout<<"Percentage of rejections = "<<meanRejected*100/(meanRejected+meanArrived)<<"%"<<endl; cout<<endl; outputFile<<"Mean patients rejected per run = "<<meanRejected<<endl; outputFile<<"Cost of each rejection = "<<privHospCost<<endl; outputFile<<"Total cost of rejections = "<<meanRejected*privHospCost<<endl; outputFile<<"Percentage of rejections = "<<meanRejected*100/(meanRejected+meanArrived)<<"%"<<endl; outputFile<<endl; //Probability of deaths over all arriving patients, including those rejected cout<<"Pre-operative death probability = "<<probAbd.mean()*100<<"%"<<endl; cout<<endl; outputFile<<"Pre-operative death probability = "<<probAbd.mean()*100<<"%"<<endl; outputFile<<endl; cout<<"Mean non-urgent queue length = "<<bSize.mean()<<endl; outputFile<<"Mean non-urgent queue length = "<<bSize.mean()<<endl; cout<<"Mean urgent queue length = "<<bSizeU.mean()<<endl; cout<<endl; outputFile<<"Mean urgent queue length = "<<bSizeU.mean()<<endl; outputFile<<endl; cout<<"Mean total time waited per run in non-urgent queue = "<<meanNonUrgWaiting<<endl; outputFile<<"Mean total time waited per run in non-urgent queue = "<<meanNonUrgWaiting<<endl; cout<<"Monetary cost of waiting in non-urgent queue = $"<<meanNonUrgWaiting*waitingCostInNonUrgQueue<<endl; outputFile<<"Monetary cost of waiting in non-urgent queue = $"<<meanNonUrgWaiting*waitingCostInNonUrgQueue<<endl; cout<<"Mean waiting time in non-urgent queue = "<<bTime.mean()<<endl; outputFile<<"Mean waiting time in non-urgent queue = "<<bTime.mean()<<endl; cout<<"Mean soujourn time of non-urgent patients = "<<bTimeSouj.mean()<<endl; cout<<endl; outputFile<<"Mean soujourn time of non-urgent patients = "<<bTimeSouj.mean()<<endl; outputFile<<endl; cout<<"Mean total time waited per run in urgent queue = "<<meanUrgWaiting<<endl; outputFile<<"Mean total time waited per run in urgent queue = "<<meanUrgWaiting<<endl; cout<<"Monetary cost of waiting in urgent queue = $"<<meanUrgWaiting*waitingCostInUrgQueue<<endl; outputFile<<"Monetary cost of waiting in urgent queue = $"<<meanUrgWaiting*waitingCostInUrgQueue<<endl; cout<<"Mean waiting time in urgent queue = "<<bTimeU.mean()<<endl; outputFile<<"Mean waiting time in urgent queue = "<<bTimeU.mean()<<endl; cout<<"Mean soujourn time of urgent patients = "<<bTimeSoujU.mean()<<endl; cout<<endl; outputFile<<"Mean soujourn time of urgent patients = "<<bTimeSoujU.mean()<<endl; outputFile<<endl; //bSizeL for server, bSize for queue cout<<"Mean non-urgent patients in system = "<<bSizeL.mean()+bSize.mean()<<endl; outputFile<<"Mean non-urgent patients in system = "<<bSizeL.mean()+bSize.mean()<<endl; cout<<"Mean urgent patients in system = "<<bSizeLU.mean()+bSizeU.mean()<<endl; cout<<endl; outputFile<<"Mean urgent patients in system = "<<bSizeLU.mean()+bSizeU.mean()<<endl; outputFile<<endl; cout<<"Mean number of busy servers = "<<sSize.mean()<<endl; cout<<endl; outputFile<<"Mean number of busy servers = "<<sSize.mean()<<endl; outputFile<<endl; cout<<"Estimated total cost = $"<<meanRejected*privHospCost + meanUrgServed*averageUrgSubsidy + meanNonUrgServed*averageNonUrgSubsidy + meanNonUrgWaiting*waitingCostInNonUrgQueue + meanUrgWaiting*waitingCostInUrgQueue + totalIncentive<<endl; cout<<endl; outputFile<<"Estimated total cost = $"<<meanRejected*privHospCost + meanUrgServed*averageUrgSubsidy + meanNonUrgServed*averageNonUrgSubsidy + meanNonUrgWaiting*waitingCostInNonUrgQueue + meanUrgWaiting*waitingCostInUrgQueue + totalIncentive<<endl; outputFile<<endl; outputFile<<"***********************************************************"<<endl; outputFile.close(); } } } int endTime = time(NULL); cout<<"\nCPU time: "<<(endTime-startTime)/60<<" min " <<(endTime-startTime)%60<<" seconds"<<endl; char endchar; cin >> endchar; return 0; }