Cleaned up code
[baltrad-wrwp.git] / pywrwp / pywrwp.c
1 /* --------------------------------------------------------------------
2 Copyright (C) 2013 Swedish Meteorological and Hydrological Institute, SMHI
3
4 This is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This software is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with baltrad-wrwp.  If not, see <http://www.gnu.org/licenses/>.
16 ------------------------------------------------------------------------*/
17
18 /**
19  * Python module
20  * @file
21  * @author Anders Henja, SMHI
22  * @date 2013-09-17
23  */
24 #include <Python.h>
25 #include <math.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #define PYWRWP_MODULE /**< include correct part of pywrwp.h */
30 #include "pywrwp.h"
31
32 #include <pypolarvolume.h>
33 #include <pyverticalprofile.h>
34 #include "wrwp.h"
35
36 #include <arrayobject.h>
37 #include "pyrave_debug.h"
38 #include "rave_alloc.h"
39 #include "rave.h"
40
41 /**
42  * Debug this module
43  */
44 PYRAVE_DEBUG_MODULE("_wrwp");
45
46 /**
47  * Sets a python exception and goto tag
48  */
49 #define raiseException_gotoTag(tag, type, msg) \
50 {PyErr_SetString(type, msg); goto tag;}
51
52 /**
53  * Sets python exception and returns NULL
54  */
55 #define raiseException_returnNULL(type, msg) \
56 {PyErr_SetString(type, msg); return NULL;}
57
58 /**
59  * Error object for reporting errors to the python interpreeter
60  */
61 static PyObject* ErrorObject;
62
63
64 /*@{ Weather radar wind profiles */
65
66 /**
67  * Returns the native Wrwp_t instance.
68  * @param[in] pywrwp - the python wrwp instance
69  * @returns the native wrwp instance.
70  */
71 static Wrwp_t*
72 PyWrwp_GetNative(PyWrwp* pywrwp)
73 {
74   RAVE_ASSERT((pywrwp != NULL), "pywrwp == NULL");
75   return RAVE_OBJECT_COPY(pywrwp->wrwp);
76 }
77
78 /**
79  * Creates a python wrwp from a native wrwp or will create an
80  * initial native wrwp if p is NULL.
81  * @param[in] p - the native wrwp (or NULL)
82  * @returns the python wrwp product generator.
83  */
84 static PyWrwp*
85 PyWrwp_New(Wrwp_t* p)
86 {
87   PyWrwp* result = NULL;
88   Wrwp_t* cp = NULL;
89
90   if (p == NULL) {
91     cp = RAVE_OBJECT_NEW(&Wrwp_TYPE);
92     if (cp == NULL) {
93       RAVE_CRITICAL0("Failed to allocate memory for wrwp.");
94       raiseException_returnNULL(PyExc_MemoryError, "Failed to allocate memory for wrwp.");
95     }
96   } else {
97     cp = RAVE_OBJECT_COPY(p);
98     result = RAVE_OBJECT_GETBINDING(p); // If p already have a binding, then this should only be increfed.
99     if (result != NULL) {
100       Py_INCREF(result);
101     }
102   }
103
104   if (result == NULL) {
105     result = PyObject_NEW(PyWrwp, &PyWrwp_Type);
106     if (result != NULL) {
107       PYRAVE_DEBUG_OBJECT_CREATED;
108       result->wrwp = RAVE_OBJECT_COPY(cp);
109       RAVE_OBJECT_BIND(result->wrwp, result);
110     } else {
111       RAVE_CRITICAL0("Failed to create PyWrwp instance");
112       raiseException_gotoTag(done, PyExc_MemoryError, "Failed to allocate memory for PyWrwp.");
113     }
114   }
115
116 done:
117   RAVE_OBJECT_RELEASE(cp);
118   return result;
119 }
120
121 /**
122  * Deallocates the wrwp generator
123  * @param[in] obj the object to deallocate.
124  */
125 static void _pywrwp_dealloc(PyWrwp* obj)
126 {
127   /*Nothing yet*/
128   if (obj == NULL) {
129     return;
130   }
131   PYRAVE_DEBUG_OBJECT_DESTROYED;
132   RAVE_OBJECT_UNBIND(obj->wrwp, obj);
133   RAVE_OBJECT_RELEASE(obj->wrwp);
134   PyObject_Del(obj);
135 }
136
137 /**
138  * Creates a new instance of the wrwp generator.
139  * @param[in] self this instance.
140  * @param[in] args arguments for creation (NOT USED).
141  * @return the object on success, otherwise NULL
142  */
143 static PyObject* _pywrwp_new(PyObject* self, PyObject* args)
144 {
145   PyWrwp* result = PyWrwp_New(NULL);
146   return (PyObject*)result;
147 }
148
149
150 static PyObject* _pywrwp_generate(PyWrwp* self, PyObject* args)
151 {
152         PyObject* obj = NULL;
153         PyVerticalProfile* pyvp = NULL;
154         VerticalProfile_t* vp = NULL;
155
156         if(!PyArg_ParseTuple(args, "O",&obj)) {
157                 return NULL;
158         }
159
160         if (!PyPolarVolume_Check(obj)) {
161           raiseException_returnNULL(PyExc_AttributeError, "In argument must be a polar volume");
162         }
163
164         vp = Wrwp_generate(self->wrwp, ((PyPolarVolume*)obj)->pvol);
165
166         if (vp == NULL) {
167           raiseException_gotoTag(done, PyExc_RuntimeError, "Failed to generate vertical profile");
168         }
169
170         pyvp = PyVerticalProfile_New(vp);
171
172 done:
173   RAVE_OBJECT_RELEASE(vp);
174         return (PyObject*)pyvp;
175 }
176
177 /**
178  * All methods a wrwp generator can have
179  */
180 static struct PyMethodDef _pywrwp_methods[] =
181 {
182   {"generate", (PyCFunction)_pywrwp_generate, 1},
183   {NULL, NULL } /* sentinel */
184 };
185
186 /**
187  * Returns the specified attribute in the wrwp generator
188  * @param[in] self - the wrwp generator
189  */
190 static PyObject* _pywrwp_getattr(PyWrwp* self, char* name)
191 {
192   PyObject* res = NULL;
193   if (strcmp("dz", name) == 0) {
194     return PyInt_FromLong(Wrwp_getDZ(self->wrwp));
195   } else if (strcmp("hmax", name) == 0) {
196     return PyInt_FromLong(Wrwp_getHMAX(self->wrwp));
197   } else if (strcmp("dmin", name) == 0) {
198     return PyInt_FromLong(Wrwp_getDMIN(self->wrwp));
199   } else if (strcmp("dmax", name) == 0) {
200     return PyInt_FromLong(Wrwp_getDMAX(self->wrwp));
201   } else if (strcmp("emin", name) == 0) {
202     return PyFloat_FromDouble(Wrwp_getEMIN(self->wrwp));
203   } else if (strcmp("vmin", name) == 0) {
204     return PyFloat_FromDouble(Wrwp_getVMIN(self->wrwp));
205   }
206   res = Py_FindMethod(_pywrwp_methods, (PyObject*) self, name);
207   if (res)
208     return res;
209
210   PyErr_Clear();
211   PyErr_SetString(PyExc_AttributeError, name);
212   return NULL;
213 }
214
215 /**
216  * Returns the specified attribute in the wrwp generator
217  */
218 static int _pywrwp_setattr(PyWrwp* self, char* name, PyObject* val)
219 {
220   int result = -1;
221   if (name == NULL) {
222     goto done;
223   }
224   if (strcmp("dz", name) == 0) {
225     if (PyInt_Check(val)) {
226       Wrwp_setDZ(self->wrwp, PyInt_AsLong(val));
227     } else {
228       raiseException_gotoTag(done, PyExc_TypeError, "dz must be an integer");
229     }
230   } else if (strcmp("hmax", name) == 0) {
231     if (PyInt_Check(val)) {
232       Wrwp_setHMAX(self->wrwp, PyInt_AsLong(val));
233     } else {
234       raiseException_gotoTag(done, PyExc_TypeError, "hmax must be an integer");
235     }
236   } else if (strcmp("dmin", name) == 0) {
237     if (PyInt_Check(val)) {
238       Wrwp_setDMIN(self->wrwp, PyInt_AsLong(val));
239     } else {
240       raiseException_gotoTag(done, PyExc_TypeError, "dmin must be an integer");
241     }
242   } else if (strcmp("dmax", name) == 0) {
243     if (PyInt_Check(val)) {
244       Wrwp_setDMAX(self->wrwp, PyInt_AsLong(val));
245     } else {
246       raiseException_gotoTag(done, PyExc_TypeError, "dmax must be an integer");
247     }
248   } else if (strcmp("emin", name) == 0) {
249     if (PyFloat_Check(val)) {
250       Wrwp_setEMIN(self->wrwp, PyFloat_AsDouble(val));
251     } else if (PyInt_Check(val)) {
252       Wrwp_setEMIN(self->wrwp, (double)PyInt_AsLong(val));
253     } else {
254       raiseException_gotoTag(done, PyExc_TypeError, "emin must be an integer or a float");
255     }
256   } else if (strcmp("vmin", name) == 0) {
257     if (PyFloat_Check(val)) {
258       Wrwp_setVMIN(self->wrwp, PyFloat_AsDouble(val));
259     } else if (PyInt_Check(val)) {
260       Wrwp_setVMIN(self->wrwp, (double)PyInt_AsLong(val));
261     } else {
262       raiseException_gotoTag(done, PyExc_TypeError, "vmin must be an integer or a float");
263     }
264   }
265
266   result = 0;
267 done:
268   return result;
269 }
270 /*@} End of Weather radar wind profiles */
271
272 /*@{ Type definitions */
273 PyTypeObject PyWrwp_Type =
274 {
275   PyObject_HEAD_INIT(NULL)0, /*ob_size*/
276   "WrwpCore", /*tp_name*/
277   sizeof(PyWrwp), /*tp_size*/
278   0, /*tp_itemsize*/
279   /* methods */
280   (destructor)_pywrwp_dealloc, /*tp_dealloc*/
281   0, /*tp_print*/
282   (getattrfunc)_pywrwp_getattr, /*tp_getattr*/
283   (setattrfunc)_pywrwp_setattr, /*tp_setattr*/
284   0, /*tp_compare*/
285   0, /*tp_repr*/
286   0, /*tp_as_number */
287   0,
288   0, /*tp_as_mapping */
289   0 /*tp_hash*/
290 };
291
292 /*@} End of Type definitions */
293
294 /// --------------------------------------------------------------------
295 /// Module setup
296 /// --------------------------------------------------------------------
297 /*@{ Module setup */
298 static PyMethodDef functions[] = {
299   {"new", (PyCFunction)_pywrwp_new, 1},
300   {NULL,NULL} /*Sentinel*/
301 };
302
303 PyMODINIT_FUNC
304 init_wrwp(void)
305 {
306   PyObject *module=NULL,*dictionary=NULL;
307   static void *PyWrwp_API[PyWrwp_API_pointers];
308   PyObject *c_api_object = NULL;
309   PyWrwp_Type.ob_type = &PyType_Type;
310
311   module = Py_InitModule("_wrwp", functions);
312   if (module == NULL) {
313     return;
314   }
315   PyWrwp_API[PyWrwp_Type_NUM] = (void*)&PyWrwp_Type;
316   PyWrwp_API[PyWrwp_GetNative_NUM] = (void *)PyWrwp_GetNative;
317   PyWrwp_API[PyWrwp_New_NUM] = (void*)PyWrwp_New;
318
319   c_api_object = PyCObject_FromVoidPtr((void *)PyWrwp_API, NULL);
320
321   if (c_api_object != NULL) {
322     PyModule_AddObject(module, "_C_API", c_api_object);
323   }
324
325   dictionary = PyModule_GetDict(module);
326   ErrorObject = PyString_FromString("_wrwp.error");
327   if (ErrorObject == NULL || PyDict_SetItemString(dictionary, "error", ErrorObject) != 0) {
328     Py_FatalError("Can't define _wrwp.error");
329   }
330
331   import_array();
332   import_pypolarvolume();
333   import_pyverticalprofile();
334   PYRAVE_DEBUG_INITIALIZE;
335 }
336 /*@} End of Module setup */