ContentsIndexHome
Body Source
Body Source
  1: using System;
  2: using System.Collections.Generic;
  3: using System.Text;
  4: using Aimms;
  5: using System.IO;
  6: using System.Diagnostics;
  7: 
  8: namespace example
  9: {
 10: 
 11:     /// <summary>
 12:     /// This example demonstrates the custom handling of errors.
 13:     /// It overrides the default behavior in which AimmsExceptions are thrown in all error cases in two ways:
 14:     /// The LoggingCallback logs all minor errors, and keeps throwing the severe ones
 15:     /// The DebuggingCallback logs as well, and asserts where errors can only be expected if the model was called erroneously.
 16:     /// </summary>
 17:     class errorCallBack
 18:     {
 19:         class LoggingCallback : ICallBack
 20:         {
 21:             virtual public void onMessages(IList<AimmsMessage> messages)
 22:             {
 23:                 /* Overridden behavior:
 24:                    Only throw if an error is caused by the communication layer or the AIMMS model. 
 25:                    Send message to the Console instead in other cases
 26:                 */
 27: 
 28:                 for (int m = 0; m < messages.Count; ++m) {
 29:                     switch (messages[m].Code) {
 30:                         case AimmsMessageCode.AM_Info:
 31:                             Console.WriteLine("info: " + messages[m].Message);
 32:                             break;
 33:                         case AimmsMessageCode.AM_Warning:
 34:                             Console.WriteLine("warning: " + messages[m].Message);
 35:                             break;
 36:                         case AimmsMessageCode.AM_InvalidUse:
 37:                             Console.WriteLine("invalid use: " + messages[m].Message);
 38:                             break;
 39:                         case AimmsMessageCode.AM_Runtime:
 40:                             Console.WriteLine("runtime error: " + messages[m].Message);
 41:                             break;
 42:                         case AimmsMessageCode.AM_License:
 43:                             throw new AimmsLicenseException(messages[m].Message);
 44:                         case AimmsMessageCode.AM_Communication:
 45:                             throw new AimmsCommunicationException(messages[m].Message);
 46:                         case AimmsMessageCode.AM_General:  // AIMMS Model errors
 47:                             throw new AimmsException(messages[m].Code, messages[0].Message);
 48:                         default:
 49:                             throw new AimmsException(messages[m].Code, messages[0].Message);
 50:                     }
 51: 
 52:                     /* 
 53:             
 54:                     * The rationale behind this distinction is that in the cases in which now exceptions are thrown, 
 55:                       the state of the data is not known. For example: if during the flush of the buffers an error on 
 56:                       a specific value is detected by the AIMMS model, it is not known which part of the remaining data 
 57:                       is already written to the model. 
 58:                     */
 59: 
 60:                 }
 61:             }
 62:         };
 63: 
 64:         class DebuggingCallback : ICallBack
 65:         {
 66: 
 67:             virtual public void onMessages(IList<AimmsMessage> messages)
 68:             {
 69:                 /* Overridden behavior:
 70:            
 71:                     assert if an AM_InvalidUse is encountered, because that is an indication of a bug. 
 72:                     For example: adding a string to a numerical parameter gives AM_InvalidUse. 
 73:                 */
 74: 
 75:                 for (int m = 0; m < messages.Count; ++m) {
 76:                     switch (messages[m].Code) {
 77:                         case AimmsMessageCode.AM_InvalidUse:
 78:                             Console.WriteLine("invalid use: " + messages[m].Message);
 79:                             Debug.Assert(false);
 80:                             break;
 81:                         default:
 82:                             Console.WriteLine(messages[m].Code + ":" + messages[m].Message);
 83:                             break;
 84:                     }
 85: 
 86:                 }
 87:             }
 88: 
 89:         };
 90: 
 91: 
 92:         public static void run(ISession session, TextWriter os)
 93:         {
 94:             // Activate one of the lines below to attach the custom Callback of choice to the session.
 95:             LoggingCallback cb = new LoggingCallback();
 96:             // DebuggingCallback cb = new DebuggingCallback();
 97: 
 98:             session.setCallBack(cb);
 99: 
100:             //To illustrate the behavior of our callback, make some mistakes:
101: 
102:             //Try to retrieve the set Locations as a multidimensional parameter.
103:             //This is a InvalidUse error: 
104:             //  LoggingCallback will not throw
105:             //  DebuggingCallback will assert here. 
106:             IMultiDimData parameterLocations = session.openMultiDim("Locations");
107: 
108:             if (parameterLocations == null)
109:             {
110:                 os.WriteLine("Expected an InvalidUse error!");
111:             }
112: 
113:             IMultiDimData parameterSupply = session.openMultiDim("Supply");
114:             //Do not forget to check the result if the callback does not throw on each error!
115:             if (parameterSupply == null)
116:             {
117:                 os.WriteLine("Did not expect an error here!");
118:             }
119:             else
120:             {
121:                 // Since we did not add any depots, we will get a runtime error here:
122:                 parameterSupply.setValue(new Tuple("London"), 20.0);
123: 
124:                 // Using "insert" will resolve this error, since it adds London to the index domain of Supply if not existing. 
125:                 parameterSupply.insert(new Tuple("London"), 20.0);
126: 
127:                 // Supply is a numeric parameter: it will not allow strings as value:
128:                 // DebuggingCallback will assert.
129:                 parameterSupply.insert(new Tuple("Paris"), "thirty");
130:             }
131: 
132:             IMultiDimData parameterDemand = session.openMultiDim("Demand");
133: 
134:             if (parameterDemand == null)
135:             {
136:                 os.WriteLine("Did not expect an error here!");
137:             }
138:             else
139:             {
140:                 ITuple tup = parameterDemand.createTuple();
141: 
142:                 // "London" exists in the set Locations ( because we added it to Depots by inserting in Supply)
143:                 // But the index domain of Demand is Customers, which  is still empty.
144:                 // The nocheck_ functions are less expensive because they do not check this in advance.
145:                 // Cout will not show an error after these actions:
146:                 tup[0].nocheck_setLabel("London");
147:                 parameterDemand.setValue(tup, 90);
148:                 tup.close();
149: 
150:                 // But this performance improvement comes with a downside:
151:                 try
152:                 {
153:                     // The mistake will become apparent when the data is send to the model. 
154:                     // Then it is undetermined wether the inserted value for "London" in Supply is indeed inserted in Aimms.
155:                     // If Londen is added to the domainset and this set is flushed before the Supply is flushed,
156:                     // the Supply of Londen will be set to its new value without an error.
157:                     // If Londen is not added or Supply is flushed earlier (which may be due to an internal flush),
158:                     // then an error will occur and even other buffered modifications to Supply may not have been inserted in Aimms.
159:   
160:                     session.updateData();
161: 
162:                 }
163:                 catch (AimmsException e)
164:                 {
165:                     os.WriteLine(e.Message);
166:                 }
167: 
168:                 parameterSupply.close();
169:                 parameterDemand.close();
170:             }
171:         }
172:     }
173: }