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