pythonforecast.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 file : $URL: http://svn.code.sf.net/p/frepple/code/trunk/modules/forecast/pythonforecast.cpp $ 00003 version : $LastChangedRevision: 1713 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2012-07-18 11:46:01 +0200 (Wed, 18 Jul 2012) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007-2012 by Johan De Taeye, frePPLe bvba * 00010 * * 00011 * This library is free software; you can redistribute it and/or modify it * 00012 * under the terms of the GNU Affero General Public License as published * 00013 * by the Free Software Foundation; either version 3 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00019 * GNU Affero General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Affero General Public * 00022 * License along with this program. * 00023 * If not, see <http://www.gnu.org/licenses/>. * 00024 * * 00025 ***************************************************************************/ 00026 00027 #include "forecast.h" 00028 00029 namespace module_forecast 00030 { 00031 00032 00033 PyObject* Forecast::getattro(const Attribute& attr) 00034 { 00035 if (attr.isA(Tags::tag_calendar)) 00036 return PythonObject(getCalendar()); 00037 else if (attr.isA(Tags::tag_discrete)) 00038 return PythonObject(getDiscrete()); 00039 return Demand::getattro(attr); 00040 } 00041 00042 00043 int Forecast::setattro(const Attribute& attr, const PythonObject& field) 00044 { 00045 if (attr.isA(Tags::tag_calendar)) 00046 { 00047 if (!field.check(Calendar::metadata)) 00048 { 00049 PyErr_SetString(PythonDataException, "forecast calendar must be of type calendar"); 00050 return -1; 00051 } 00052 Calendar* y = static_cast<Calendar*>(static_cast<PyObject*>(field)); 00053 setCalendar(y); 00054 } 00055 else if (attr.isA(Tags::tag_discrete)) 00056 setDiscrete(field.getBool()); 00057 else 00058 return Demand::setattro(attr, field); 00059 return 0; // OK 00060 } 00061 00062 00063 extern "C" PyObject* Forecast::setPythonTotalQuantity(PyObject *self, PyObject *args) 00064 { 00065 try 00066 { 00067 // Get the forecast model 00068 Forecast* forecast = static_cast<Forecast*>(self); 00069 00070 // Parse the Python arguments 00071 double value; 00072 PyObject* pystart; 00073 PyObject* pyend = NULL; 00074 int ok = PyArg_ParseTuple(args, "dO|O:setQuantity", &value, &pystart, &pyend); 00075 if (!ok) return NULL; 00076 00077 // Update the forecast 00078 PythonObject start(pystart), end(pyend); 00079 if (pyend) 00080 forecast->setTotalQuantity(DateRange(start.getDate(), end.getDate()), value); 00081 else 00082 forecast->setTotalQuantity(start.getDate(), value); 00083 } 00084 catch(...) 00085 { 00086 PythonType::evalException(); 00087 return NULL; 00088 } 00089 return Py_BuildValue(""); 00090 } 00091 00092 00093 extern "C" PyObject* Forecast::timeseries(PyObject *self, PyObject *args) 00094 { 00095 // Get the forecast model 00096 Forecast* forecast = static_cast<Forecast*>(self); 00097 00098 // Parse the Python arguments 00099 PyObject* history; 00100 PyObject* buckets = NULL; 00101 int ok = PyArg_ParseTuple(args, "O|O:timeseries", &history, &buckets); 00102 if (!ok) return NULL; 00103 00104 // Verify we can iterate over the arguments 00105 PyObject *historyiterator = PyObject_GetIter(history); 00106 PyObject *bucketiterator = NULL; 00107 if (!historyiterator) 00108 { 00109 PyErr_Format(PyExc_AttributeError,"Invalid type for time series"); 00110 return NULL; 00111 } 00112 if (buckets) bucketiterator = PyObject_GetIter(buckets); 00113 if (!bucketiterator) 00114 { 00115 PyErr_Format(PyExc_AttributeError,"Invalid type for time series"); 00116 return NULL; 00117 } 00118 00119 // Copy the history data into a C++ data structure 00120 double data[300]; 00121 unsigned int historycount = 0; 00122 PyObject *item; 00123 while ((item = PyIter_Next(historyiterator))) 00124 { 00125 data[historycount++] = PyFloat_AsDouble(item); 00126 Py_DECREF(item); 00127 if (historycount>=300) break; 00128 } 00129 Py_DECREF(historyiterator); 00130 00131 // Copy the bucket data into a C++ data structure 00132 Date bucketdata[300]; 00133 unsigned int bucketcount = 0; 00134 while ((item = PyIter_Next(bucketiterator))) 00135 { 00136 bucketdata[bucketcount++] = PythonObject(item).getDate(); 00137 Py_DECREF(item); 00138 if (bucketcount>=300) break; 00139 } 00140 Py_DECREF(bucketiterator); 00141 00142 Py_BEGIN_ALLOW_THREADS // Free the Python interpreter for other threads 00143 try 00144 { 00145 // Generate the forecast 00146 forecast->generateFutureValues 00147 (data, historycount, bucketdata, bucketcount, true); 00148 } 00149 catch (...) 00150 { 00151 Py_BLOCK_THREADS; 00152 PythonType::evalException(); 00153 return NULL; 00154 } 00155 Py_END_ALLOW_THREADS // Release the Python interpreter 00156 return Py_BuildValue(""); 00157 } 00158 00159 00160 PyObject* ForecastBucket::getattro(const Attribute& attr) 00161 { 00162 if (attr.isA(Tags::tag_startdate)) 00163 return PythonObject(getDueRange().getStart()); 00164 if (attr.isA(Tags::tag_enddate)) 00165 return PythonObject(getDueRange().getEnd()); 00166 if (attr.isA(Forecast::tag_total)) 00167 return PythonObject(getTotal()); 00168 if (attr.isA(Forecast::tag_consumed)) 00169 return PythonObject(getConsumed()); 00170 if (attr.isA(Tags::tag_weight)) 00171 return PythonObject(getWeight()); 00172 return Demand::getattro(attr); 00173 } 00174 00175 00176 int ForecastBucket::setattro(const Attribute& attr, const PythonObject& field) 00177 { 00178 if (attr.isA(Forecast::tag_total)) 00179 setTotal(field.getDouble()); 00180 else if (attr.isA(Forecast::tag_consumed)) 00181 setConsumed(field.getDouble()); 00182 else if (attr.isA(Tags::tag_weight)) 00183 setWeight(field.getDouble()); 00184 else 00185 return Demand::setattro(attr, field); 00186 return 0; // OK 00187 } 00188 00189 00190 } // end namespace