Loading...
Searching...
No Matches
TransportEngine.cs
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Globalization;
6using System.Threading;
7using GAMS;
8
9namespace TransportSeq
10{
23 {
24 static int Main(string[] args)
25 {
27 if (Environment.GetCommandLineArgs().Length > 1)
28 ws = new GAMSWorkspace(systemDirectory: Environment.GetCommandLineArgs()[1]);
29 else
30 ws = new GAMSWorkspace(workingDirectory: @"c:\data\tmp");
31
32 if (File.Exists(Path.Combine(ws.WorkingDirectory, "test.txt")))
33 File.Delete(Path.Combine(ws.WorkingDirectory, "test.txt"));
34
35 /*
36 * Set up configuration required for any job on GAMS Engine
37 */
38 GAMSEngineConfiguration engineConf = new GAMSEngineConfiguration(host: Environment.GetEnvironmentVariable("ENGINE_URL"),
39 username: Environment.GetEnvironmentVariable("ENGINE_USER"),
40 password: Environment.GetEnvironmentVariable("ENGINE_PASSWORD"),
41 space: Environment.GetEnvironmentVariable("ENGINE_NAMESPACE"));
42
43 /*
44 * Run with data from a string with GAMS syntax with explicit export to GDX file
45 */
46 GAMSJob tEdata = ws.AddJobFromString(GetDataText());
47 try
48 {
49 tEdata.RunEngine(engineConf, output: Console.Out);
50 }
51 catch (Exception ex)
52 {
53 Console.WriteLine("Exception caught:" + ex.Message);
54 return 1;
55 }
56 tEdata.OutDB.Export(Path.Combine(ws.WorkingDirectory, "tdata.gdx"));
57
58 Dictionary<string, double> expectedLevels = new Dictionary<string, double> { { "seattle.new-york", 0.0 }, { "seattle.chicago", 300.0 }, {"seattle.topeka", 0.0 },
59 { "san-diego.new-york", 325.0 }, {"san-diego.chicago", 0.0 }, {"san-diego.topeka", 275.0 } };
60
61 /*
62 * Run a job using an instance of GAMSOptions that defines the data include file
63 */
64 GAMSJob tEmodel = ws.AddJobFromString(GetModelText());
65 using (GAMSOptions opt = ws.AddOptions())
66 {
67 opt.Defines.Add("gdxincname", "tdata.gdx");
68 opt.AllModelTypes = "xpress";
69 try
70 {
71 tEmodel.RunEngine(engineConf, new HashSet<string> { "tdata.gdx" }, new Dictionary<string, string> { { "inex_string", "{\"type\": \"include\", \"files\": [\"*.gdx\"]}" } }, opt, output: Console.Out);
72 }
73 catch (Exception ex)
74 {
75 Console.WriteLine("Exception caught:" + ex.Message);
76 return 1;
77 }
78
79 foreach (GAMSVariableRecord rec in tEmodel.OutDB.GetVariable("x"))
80 {
81 Console.WriteLine("x(" + rec.Key(0) + "," + rec.Key(1) + "): level=" + rec.Level + " marginal=" + rec.Marginal);
82 if (expectedLevels[rec.Key(0) + "." + rec.Key(1)] != rec.Level)
83 {
84 Console.WriteLine("Unexpected result, expected level: " + expectedLevels[rec.Key(0) + "." + rec.Key(1)].ToString());
85 return 1;
86 }
87 }
88
89 if (File.Exists(Path.Combine(ws.WorkingDirectory, "test.txt")))
90 {
91 Console.WriteLine("Test.txt should not have sent back - inex_string failed");
92 return 1;
93 }
94 }
95
96 /*
97 * Same but with implicit database communication
98 */
100 using (GAMSOptions opt = ws.AddOptions())
101 {
102 GAMSJob tEa = ws.AddJobFromString(GetDataText());
103 GAMSJob tEb = ws.AddJobFromString(GetModelText());
104 try
105 {
106 tEa.RunEngine(engineConf, output: Console.Out);
107 }
108 catch (Exception ex)
109 {
110 Console.WriteLine("Exception caught:" + ex.Message);
111 return 1;
112 }
113 opt.Defines.Add("gdxincname", tEa.OutDB.Name);
114 opt.AllModelTypes = "xpress";
115 try
116 {
117 tEb.RunEngine(engineConf, gamsOptions: opt, checkpoint: cp, output: Console.Out, databases: tEa.OutDB);
118 }
119 catch (Exception ex)
120 {
121 Console.WriteLine("Exception caught:" + ex.Message);
122 return 1;
123 }
124 foreach (GAMSVariableRecord rec in tEb.OutDB.GetVariable("x"))
125 {
126 Console.WriteLine("x(" + rec.Key(0) + "," + rec.Key(1) + "): level=" + rec.Level + " marginal=" + rec.Marginal);
127 if (expectedLevels[rec.Key(0) + "." + rec.Key(1)] != rec.Level)
128 {
129 Console.WriteLine("Unexpected result, expected level: " + expectedLevels[rec.Key(0) + "." + rec.Key(1)].ToString());
130 return 1;
131 }
132 }
133
134 Dictionary<string, double>[] bmultExpected = new Dictionary<string, double>[2];
135 bmultExpected[0] = new Dictionary<string, double>() { { "bmult", 0.9 }, { "ms", 1 }, { "ss", 1 }, { "obj", 138.31 } };
136 bmultExpected[1] = new Dictionary<string, double>() { { "bmult", 1.2 }, { "ms", 4 }, { "ss", 1 }, { "obj", 184.41 } };
137
138 // Create a new GAMSJob that is initialized from the GAMSCheckpoint
139 foreach (Dictionary<string, double> scen in bmultExpected)
140 {
141 GAMSJob tEbmult = ws.AddJobFromString("bmult=" + scen["bmult"].ToString(CultureInfo.CreateSpecificCulture("en-US")) + "; solve transport min z use lp; ms=transport.modelstat; ss=transport.solvestat;", cp);
142 try
143 {
144 tEbmult.RunEngine(engineConf, output: Console.Out);
145 Console.WriteLine("Scenario bmult=" + scen["bmult"].ToString() + ":");
146 Console.WriteLine(" Modelstatus: " + tEbmult.OutDB.GetParameter("ms").FirstRecord().Value);
147 Console.WriteLine(" Solvestatus: " + tEbmult.OutDB.GetParameter("ss").FirstRecord().Value);
148 Console.WriteLine(" Obj : " + tEbmult.OutDB.GetVariable("z").FirstRecord().Level);
149 if (tEbmult.OutDB.GetParameter("bmult").FirstRecord().Value != scen["bmult"]) { Console.WriteLine("Unexpected input, expected bmult: " + scen["bmult"].ToString()); return 1; }
150 if (tEbmult.OutDB.GetParameter("ms").FirstRecord().Value != scen["ms"]) { Console.WriteLine("Unexpected result, expected ms: " + scen["ms"].ToString()); return 1; }
151 if (tEbmult.OutDB.GetParameter("ss").FirstRecord().Value != scen["ss"]) { Console.WriteLine("Unexpected result, expected ss: " + scen["ss"].ToString()); return 1; }
152 if (Math.Round(tEbmult.OutDB.GetVariable("z").FirstRecord().Level,2) != scen["obj"]) { Console.WriteLine("Unexpected result, expected obj: " + scen["obj"].ToString()); return 1; }
153
154 }
155 catch (Exception ex)
156 {
157 Console.WriteLine("Exception caught:" + ex.Message);
158 return 1;
159 }
160 }
161 }
162
163 /*
164 * Example how to interrupt Engine job
165 */
166 GAMSJob jc = ws.AddJobFromGamsLib("clad");
167
168 // Define an option file for the solver to be used
169 string optFile1Path = Path.Combine(ws.WorkingDirectory, "cplex.opt");
170 StreamWriter optFile1 = new StreamWriter(optFile1Path);
171 // Set relative stopping tolerance to 0 initially
172 optFile1.WriteLine("epgap 0");
173 // Activate interactive option setting on interrupt
174 optFile1.WriteLine("interactive 1");
175 // Define new option file to read on interrupt
176 optFile1.WriteLine("iafile cplex.op2");
177 optFile1.Close();
178
179 // Write new Cplex option file
180 string optFile2Path = Path.Combine(ws.WorkingDirectory, "cplex.op2");
181 StreamWriter optFile2 = new StreamWriter(optFile2Path);
182 optFile2.WriteLine("epgap 0.1");
183 optFile2.Close();
184
185 string logPath = Path.Combine(ws.WorkingDirectory, "ej.log");
186 using (GAMSOptions opt = ws.AddOptions())
187 using (TextWriter logFile = new StreamWriter(logPath))
188 {
189 opt.MIP = "cplex";
190 opt.OptFile = 1;
191 opt.SolveLink = GAMSOptions.ESolveLink.LoadLibrary;
192
193 Thread optThread = new Thread(new ThreadStart(delegate () { jc.RunEngine(engineConf, new HashSet<string> { optFile1Path, optFile2Path, "claddat.gdx" }, gamsOptions: opt, output: logFile); }));
194 optThread.Start();
195
196 while (true)
197 {
198 if (File.Exists(logPath) && (new FileInfo(logPath).Length == 0))
199 {
200 Thread.Sleep(500);
201 continue;
202 }
203 jc.Interrupt();
204 Console.WriteLine("Interrupted Cplex to continue with new option");
205 break;
206 }
207
208 // If j1 is still running, wait until it is finished
209 if (optThread.IsAlive)
210 optThread.Join();
211 }
212
213 // Check if everything worked as expected
214 Boolean interrupted = false;
215 using (var sr = new StreamReader(logPath, true))
216 {
217 for (string line; (line = sr.ReadLine()) != null;) //read line by line
218 if (line.Contains("Interrupted"))
219 {
220 interrupted = true;
221 break;
222 }
223 if(!interrupted)
224 {
225 Console.WriteLine("Expected the solver to be interrupted at least once.");
226 return 1;
227 }
228 }
229 Console.WriteLine("Interrupted succesfully");
230
231 return 0;
232 }
233
234 static String GetDataText()
235 {
236 String data = @"
237 Sets
238 i canning plants / seattle, san-diego /
239 j markets / new-york, chicago, topeka / ;
240
241 Parameters
242
243 a(i) capacity of plant i in cases
244 / seattle 350
245 san-diego 600 /
246
247 b(j) demand at market j in cases
248 / new-york 325
249 chicago 300
250 topeka 275 / ;
251
252 Table d(i,j) distance in thousands of miles
253 new-york chicago topeka
254 seattle 2.5 1.7 1.8
255 san-diego 2.5 1.8 1.4 ;
256
257 Scalar f freight in dollars per case per thousand miles / 90 /
258 bmult demand multiplier / 1 /;
259";
260 return data;
261 }
262
263static String GetModelText()
264 {
265 String model = @"
266 Sets
267 i canning plants
268 j markets
269
270 Parameters
271 a(i) capacity of plant i in cases
272 b(j) demand at market j in cases
273 d(i,j) distance in thousands of miles
274 Scalar f freight in dollars per case per thousand miles
275 bmult demand multiplier;
276
277$if not set gdxincname $abort 'no include file name for data file provided'
278$gdxLoad %gdxincname% i j a b d f bmult
279
280$echo test > test.txt
281
282 Parameter c(i,j) transport cost in thousands of dollars per case ;
283
284 c(i,j) = f * d(i,j) / 1000 ;
285
286 Variables
287 x(i,j) shipment quantities in cases
288 z total transportation costs in thousands of dollars ;
289
290 Positive Variable x ;
291
292 Equations
293 cost define objective function
294 supply(i) observe supply limit at plant i
295 demand(j) satisfy demand at market j ;
296
297 cost .. z =e= sum((i,j), c(i,j)*x(i,j)) ;
298
299 supply(i) .. sum(j, x(i,j)) =l= a(i) ;
300
301 demand(j) .. sum(i, x(i,j)) =g= bmult*b(j) ;
302
303 Model transport /all/ ;
304
305 Solve transport using lp minimizing z ;
306
307 Scalar ms 'model status', ss 'solve status';
308
309 Display x.l, x.m ;
310";
311
312 return model;
313 }
314
315 }
316}
GAMSVariable GetVariable(string variableIdentifier)
GAMSParameter GetParameter(string parameterIdentifier)
void Export(string filePath=null)
bool Interrupt()
GAMSDatabase OutDB
void RunEngine(GAMSEngineConfiguration engineConfiguration, HashSet< string > extraModelFiles=null, Dictionary< string, string > engineOptions=null, GAMSOptions gamsOptions=null, GAMSCheckpoint checkpoint=null, TextWriter output=null, Boolean createOutDB=true, Boolean removeResults=true, params GAMSDatabase[] databases)
Dictionary< string, string > Defines
new GAMSParameterRecord FirstRecord()
string Key(int index)
new GAMSVariableRecord FirstRecord()
GAMSJob AddJobFromString(string gamsSource, GAMSCheckpoint checkpoint=null, string jobName=null)
GAMSJob AddJobFromGamsLib(string model, GAMSCheckpoint checkpoint=null, string jobName=null)
GAMSCheckpoint AddCheckpoint(string checkpointName=null)
GAMSOptions AddOptions(GAMSOptions optFrom=null)
This is an example how to run a GAMSJob on GAMS Engine using the run_engine method: How to send along...