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: }