Report === ## Completion - Goals - [x] Build up a flexsim model to simulate a MCLP problem instance. - [x] Complete midterm with codes instead of drag and modify only one object at a time.(So will be able to create model immediately once change the input parameters.)* - [ ] Find out the best server combination.(Define best active set of facility, use optimizer with replication 5 per scenario)*** - Details & Assumptions - [x] 1. Each hospital(service node) has only one ambulance. - [x] 2. An ambulance could only serve demand nodes within its coverage. - [x] 3. An ambulance could only serve one demand in a travel. (Consider failed request as well)** - [x] 4. An ambulance must go back to it’s base(hospital) after a service. (Consider failed request as well)** - [x] 5. An ambulance only be available when it’s in the base.(And thus can tackle requests.) - [x] 6. Once there are no any available server(ambulance) for a request of a demand node, the request failed. - [ ] 7. Assign failed requests to potential server(the server which is active and can cover the request but might be busy then), the server must tackle the failed request after it finish current works. - [x] 8. Assign requirements to the nearest server which is available.*** - [x] 9. Performance measurement is sum of failure times(次數) of all demand nodes. - [x] 10. Arrival time and service time follow exponential distribution. - Extra - [x] GUI ## Model Description 1. 我寫了一個Reset,可以讓model回到最一開始的畫面 ```cpp= while(content(model())>1) destroyobject(last(model())); ``` 2. 寫了一個for loop讓它執行80次,建立Source和Processor,並設定Processor的變數"useprocessoperators"和"usetransport"為1,同時將每一個Source和Processor連結起來。 ```cpp= for(int i=1; i<=80; i++){ treenode Source = createinstance(node("?Source",library()),model()); setnodename( Source, concat("Source",numtostring(i))); setloc( Source, gettablenum("location_Demand",i,1), gettablenum("location_Demand",i,2),0); treenode Processor = createinstance(node("?Processor",library()),model()); setnodename( Processor, concat("Processor",numtostring(i))); setloc( Processor, gettablenum("location_Demand",i,1), gettablenum("location_Demand",i,2),0); setvarnum(Processor,"useprocessoperators",1); setvarnum(Processor,"usetransport",1); contextdragconnection(Source,Processor,"A"); } ``` 3. 寫了一個for loop讓它執行13次,建立Sink和Operator,並將Operator reset position。 ```cpp= for(int i=1; i<=13; i++){ treenode Sink = createinstance(node("?Sink",library()),model()); setnodename( Sink, concat("Sink",numtostring(i))); setloc( Sink, gettablenum("location_Server",i,1), gettablenum("location_Server",i,2),0); } for(int i=1; i<=13; i++){ treenode Operator = createinstance(node("?Operator",library()),model()); setnodename( Operator, concat("Operator",numtostring(i))); setloc( Operator, gettablenum("location_Server",i,1), gettablenum("location_Server",i,2),0); setresetposition(Operator); } ``` 4. 利用兩個for loop來判斷Processor和Sink的距離是否小於250,同時從"Scenario"的table中,13取7個Operator來進行服務,若兩者皆成立的話則將Processor和Sink,還有Processor和Operator連接起來。 ```cpp= for(int i=1; i<=13; i++){ treenode Sink = node(concat("Sink",numtostring(i)),model()); treenode Operator = node(concat("Operator",numtostring(i)),model()); for(int j=1; j<=80; j++){ treenode Processor = node(concat("Processor",numtostring(j)),model()); if(distancetotravel(Processor,Sink)<250&&gettablenum("Scenario",i,1)); { contextdragconnection(Processor,Sink,"A"); contextdragconnection(Processor,Operator,"S"); } } } ``` 5. 設定Source的變數"interarrivaltime",value為gettablenum("Rate",i,1) 設定Processor的變數"cycletime",value為gettablenum("Rate",i,2)。 * 值得注意的一點是雖然Rate table中,是叫作Average service time,不過在Processor的變數名稱裡為"cycletime"。 ```cpp= for(int i=1; i<=80; i++){ treenode Source = node(concat("Source",numtostring(i)),model()); treenode Processor = node(concat("Processor",numtostring(i)),model()); setvarstr(Source,"interarrivaltime",concat("treenode current = ownerobject(c);return exponential(0,",numtostring(gettablenum("Rate",i,1),0,3),",0);")); setvarstr(Processor,"cycletime",concat("treenode current = ownerobject(c);treenode item = parnode(1);return exponential(0,",numtostring(gettablenum("Rate",i,2),0,3),",0);")); } ``` 6. 判斷Processor附近的Operator狀態是否為idle,且距離小於250,若條件成立,則將最短距離的Operator(shortest)指派給它 ; 若否則在"Failure" table中計次。 另外將整段code設為string,並回傳給Processor的變數"processdispatcher"和"transportdispatcher"。 ```cpp= for(int i=1; i<=80; i++){ treenode Processor = node(concat("Processor",numtostring(i)),model()); string s="\ int shortest=0;\n\ int shortest2=0;\n\ double distance=250;\n\ double distance2=250;\n\ int nrcp=nrcp(current);\n\ for(int j=1; j<=nrcp; j++){\n\ treenode Operator = centerobject(current,j);\n\ if(getstatestr(Operator)==\"idle\")\n\ {if(distancetotravel(current,Operator)<distance)\n\ {distance=distancetotravel(current,Operator);\n\ shortest=j;\n\ }\n\ }\n\ }\n\ if(shortest!=0)\n\ {return tonum(centerobject(current,shortest));\n\ }\n\ else {\n\ for(int j=1; j<=nrcp; j++){\n\ treenode Operator = centerobject(current,j);\n\ if(distancetotravel(current,Operator)<distance2)\n\ {distance2=distancetotravel(current,Operator);\n\ shortest2=j;\n\ }\n\ }\n\ settablenum(\"Failure\",1,1,gettablenum(\"Failure\",1,1)+1);\n\ return tonum(centerobject(current,shortest2));\n\ }"; setvarstr(Processor,"processdispatcher",concat("treenode current = ownerobject(c);treenode item = parnode(1);int trigger = parval(2);",s)); setvarstr(Processor,"transportdispatcher",concat("treenode current = ownerobject(c);treenode item = parnode(1);int trigger = parval(2);",s)); } ``` 7. 此段code和前述相差不多,主要是設定Processor的變數"sendtoport",讓Operator可以將病人送回去Sink。 * 值得注意的一點是最後一行code enablecode(var_s(Processor,"sendtoport")); 目的為activate "sendtoport"。 ```cpp= for(int i=1; i<=80; i++){ treenode Processor = node(concat("Processor",numtostring(i)),model()); string s="\ int shortest=0;\n\ int shortest2=0;\n\ double distance=250;\n\ double distance2=250;\n\ int nrcp=nrcp(current);\n\ for(int j=1; j<=nrcp; j++){\n\ treenode Operator = centerobject(current,j);\n\ if(getstatestr(Operator)==\"idle\")\n\ {if(distancetotravel(current,Operator)<distance)\n\ {distance=distancetotravel(current,Operator);\n\ shortest=j;\n\ }\n\ }\n\ }\n\ if(shortest!=0)\n\ {return shortest;}\n\ else {\n\ for(int j=1; j<=nrcp; j++){\n\ treenode Operator = centerobject(current,j);\n\ if(distancetotravel(current,Operator)<distance2)\n\ {distance2=distancetotravel(current,Operator);\n\ shortest2=j;\n\ }\n\ }\n\ return shortest2;\n\ }"; setvarstr(Processor,"sendtoport",concat("treenode current = ownerobject(c);treenode item = parnode(1);",s)); enablecode(var_s(Processor,"sendtoport")); } ``` 8. [Bonus]GUI 簡單的做了3個button,分別為RUN/STOP/RESET ![](https://i.imgur.com/WqU5S5U.png) Instructions to use my model --- 在Scripts中會看到多個檔案,請依照下列步驟進行 (會分開多個檔案的原因,主要是放便進行debug) 1. click the "reset" 2. click the "source" 3. click the "sink" 4. click the "connect" 5. click the "rate" 6. click the "pickoperator" 7. click the "sendtoport" If you want to start again, you can click the "reset", the model will become originally.